Eric пре 1 година
родитељ
комит
3e311f3d66
100 измењених фајлова са 5332 додато и 504 уклоњено
  1. 7 0
      cooleshow-api/pom.xml
  2. 30 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/AdminFeignService.java
  3. 16 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/TenantFeignService.java
  4. 121 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/dto/TenantWrapper.java
  5. 37 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/AdminFeignServiceFallback.java
  6. 16 0
      cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/TenantFeignServiceFallback.java
  7. 88 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/SmsCodeController.java
  8. 18 0
      cooleshow-auth/auth-api/pom.xml
  9. 8 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/client/SysUserFeignService.java
  10. 8 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/client/fallback/SysUserFeignServiceFallback.java
  11. 10 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/LoginEntity.java
  12. 9 203
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/SysUser.java
  13. 31 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/UserPassword.java
  14. 95 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/WxConfigInfo.java
  15. 55 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/WxTemplateConfig.java
  16. 63 0
      cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/WxTemplateMessage.java
  17. 4 1
      cooleshow-auth/auth-server/pom.xml
  18. 1 1
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/config/ResourceServerConfig.java
  19. 14 10
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/config/WebSecurityConfig.java
  20. 3 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/filter/PhoneLoginAuthenticationFilter.java
  21. 30 8
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/handler/BaseAuthenticationFailureEvenHandler.java
  22. 15 1
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/handler/BaseAuthenticationSuccessEventHandler.java
  23. 156 82
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/provider/PhoneAuthenticationProvider.java
  24. 33 13
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/provider/service/DefaultUserDetailsService.java
  25. 5 6
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/service/CustomTokenServices.java
  26. 13 8
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/SysUserDao.java
  27. 27 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/WxConfigInfoMapper.java
  28. 27 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/WxTemplateConfigMapper.java
  29. 27 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/WxTemplateMessageMapper.java
  30. 63 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/wrapper/WxConfigInfoWrapper.java
  31. 63 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/wrapper/WxTemplateConfigWrapper.java
  32. 63 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/wrapper/WxTemplateMessageWrapper.java
  33. 2 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/enums/EClientType.java
  34. 76 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/enums/ELoginType.java
  35. 50 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/MWxMpService.java
  36. 43 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/WxCacheService.java
  37. 113 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/domain/WxConfigStorageWrapper.java
  38. 25 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/domain/WxContentWrapper.java
  39. 51 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/handler/WxMessageRouteEvent.java
  40. 292 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/impl/MWxMpServiceImpl.java
  41. 115 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/impl/WxCacheServiceImpl.java
  42. 16 4
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/SysUserService.java
  43. 67 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/WxConfigInfoService.java
  44. 43 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/WxTemplateConfigService.java
  45. 43 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/WxTemplateMessageService.java
  46. 44 12
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/SysUserServiceImpl.java
  47. 145 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/WxConfigInfoServiceImpl.java
  48. 65 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/WxTemplateConfigServiceImpl.java
  49. 65 0
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/WxTemplateMessageServiceImpl.java
  50. 9 6
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/TokenController.java
  51. 52 9
      cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/UserController.java
  52. 55 1
      cooleshow-auth/auth-server/src/main/resources/config/mybatis/SysUserMapper.xml
  53. 35 0
      cooleshow-auth/auth-server/src/main/resources/config/mybatis/WxConfigInfoMapper.xml
  54. 25 0
      cooleshow-auth/auth-server/src/main/resources/config/mybatis/WxTemplateConfigMapper.xml
  55. 27 0
      cooleshow-auth/auth-server/src/main/resources/config/mybatis/WxTemplateMessageMapper.xml
  56. 1 1
      cooleshow-cms/src/main/java/com/yonge/cooleshow/cms/controller/NewsController.java
  57. 11 0
      cooleshow-common/pom.xml
  58. 4 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/constant/AppConstant.java
  59. 39 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/constant/SysConfigConstant.java
  60. 21 15
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/controller/BaseController.java
  61. 3 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/entity/BaseEntity.java
  62. 30 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EActivationCode.java
  63. 34 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EImportType.java
  64. 31 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EPayerType.java
  65. 35 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EPaymentVersion.java
  66. 30 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/ESettlementFrom.java
  67. 34 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/ETenantUnBindAuditStatus.java
  68. 6 2
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/SysUserType.java
  69. 29 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EGoodsSource.java
  70. 56 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EGoodsType.java
  71. 25 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EOrderType.java
  72. 48 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EPaymentChannel.java
  73. 51 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EPaymentStatus.java
  74. 34 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EPaymentType.java
  75. 2 0
      cooleshow-common/src/main/java/com/yonge/cooleshow/common/security/SecurityConstants.java
  76. 1 0
      cooleshow-gateway/gateway-web/src/main/java/com/yonge/gateway/web/config/SwaggerDocumentConfig.java
  77. 51 8
      cooleshow-mall/mall-portal/src/main/java/com/yonge/cooleshow/portal/service/impl/OmsPortalOrderServiceImpl.java
  78. 19 0
      cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/SendPlatformAuditMessageTask.java
  79. 19 0
      cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/TenantPersonStatTask.java
  80. 1 0
      cooleshow-user/pom.xml
  81. 7 4
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/ImGroupController.java
  82. 130 97
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java
  83. 124 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/SysAreaController.java
  84. 71 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/SysGoodsPriceController.java
  85. 16 8
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java
  86. 160 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantAccountRecordController.java
  87. 67 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantActivationCodeController.java
  88. 266 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantAlbumController.java
  89. 105 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantEntryRecordController.java
  90. 96 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantInfoController.java
  91. 138 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantMemberController.java
  92. 86 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantUnbindHistoryController.java
  93. 72 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantUnbindRecordController.java
  94. 99 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/UnbindAuthUserController.java
  95. 3 1
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/UserOrderController.java
  96. 56 3
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/AdminClient.java
  97. 124 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenSysAreaController.java
  98. 49 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenSysConfigController.java
  99. 266 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/UserPaymentClient.java
  100. 168 0
      cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/SysAreaVo.java

+ 7 - 0
cooleshow-api/pom.xml

@@ -26,5 +26,12 @@
             <groupId>com.yonge.cooleshow</groupId>
             <artifactId>cooleshow-common</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.5.20</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 </project>

+ 30 - 0
cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/AdminFeignService.java

@@ -1,6 +1,13 @@
 package com.yonge.cooleshow.api.feign;
 
 import com.yonge.cooleshow.api.feign.dto.*;
+import com.yonge.cooleshow.api.feign.dto.CouponInfoApi;
+import com.yonge.cooleshow.api.feign.dto.EmployeeApi;
+import com.yonge.cooleshow.api.feign.dto.StudentApi;
+import com.yonge.cooleshow.api.feign.dto.StudentWrapper;
+import com.yonge.cooleshow.api.feign.dto.TeacherApi;
+import com.yonge.cooleshow.api.feign.dto.TenantWrapper;
+import com.yonge.cooleshow.api.feign.dto.UserFriendInfoVO;
 import com.yonge.cooleshow.api.feign.fallback.AdminFeignServiceFallback;
 import com.yonge.cooleshow.common.constant.AppConstant;
 import com.yonge.cooleshow.common.entity.ContractDto;
@@ -113,6 +120,22 @@ public interface AdminFeignService {
     @GetMapping(value = "/open/adminClient/getEmployee")
     HttpResponseResult<EmployeeApi> getEmployee(@RequestParam("userId") Long userId);
 
+    /**
+     * 机构信息
+     * @param tenantId 机构ID
+     * @return TenantWrapper.Tenant
+     */
+    @GetMapping(value = "/open/adminClient/getTenant")
+    HttpResponseResult<TenantWrapper.Tenant> getTenantInfo(@RequestParam("tenantId") Long tenantId);
+
+    /**
+     * 机构员工信息
+     * @param userId 用户ID
+     * @return TenantWrapper.Staff
+     */
+    @GetMapping(value = "/open/adminClient/getTenantStaff")
+    HttpResponseResult<TenantWrapper.Staff> getTenantStaff(@RequestParam("userId") Long userId);
+
 
     @PostMapping(value = "/open/adminClient/orderUpdate", consumes="application/json", produces="application/json")
     HttpResponseResult<Boolean> updateCouponOrderInfo(@RequestParam("couponIssueId") String couponIssueId,
@@ -164,6 +187,13 @@ public interface AdminFeignService {
     HttpResponseResult<StudentWrapper.UnionStudentResp> unionStudent(@RequestBody StudentWrapper.UnionStudent info);
 
 
+    /**
+     * 定时发送平台审核短信 下午5点
+     */
+    @GetMapping("/task/sendPlatformAuditMessage")
+    HttpResponseResult<Object> sendPlatformAuditMessage();
+
+
     @PostMapping(value = "/open/im/register")
     ImUserInfo register(@RequestParam("userId") String userId, @RequestParam("clientType") String clientType, @RequestParam("username") String username, @RequestParam("avatar") String avatar);
 }

+ 16 - 0
cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/TenantFeignService.java

@@ -0,0 +1,16 @@
+package com.yonge.cooleshow.api.feign;
+
+import com.yonge.cooleshow.api.feign.fallback.AdminFeignServiceFallback;
+import com.yonge.cooleshow.common.constant.AppConstant;
+import com.yonge.toolset.feign.config.FeignConfiguration;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@FeignClient(name = AppConstant.APPLICATION_TENANT + AppConstant.SERVER, configuration = FeignConfiguration.class,
+        fallback = AdminFeignServiceFallback.class)
+public interface TenantFeignService {
+
+    //机构人员汇总
+    @GetMapping(value = "/task/tenantPersonStat")
+    void tenantPersonStat();
+}

+ 121 - 0
cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/dto/TenantWrapper.java

@@ -0,0 +1,121 @@
+package com.yonge.cooleshow.api.feign.dto;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.yonge.cooleshow.common.enums.UserLockFlag;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+/**
+ * 机构员工表
+ * 2023-07-21 17:32:49
+ */
+public class TenantWrapper implements Serializable {
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel("tenant - 机构表")
+    public static class Tenant implements Serializable {
+
+        @ApiModelProperty("主键ID")
+        private Long id;
+
+        @ApiModelProperty("名称")
+        private String name;
+
+        @ApiModelProperty("logo")
+        private String logo;
+
+        @ApiModelProperty("省份编码")
+        private Integer provinceCode;
+
+        @ApiModelProperty("城市编码")
+        private Integer cityCode;
+
+        @ApiModelProperty("地区/街道")
+        private Integer regionCode;
+
+        @ApiModelProperty("联系人")
+        private String username;
+
+        @ApiModelProperty("管理员ID,用户ID")
+        private Long userId;
+
+        @ApiModelProperty("手机号")
+        private String phone;
+
+        @ApiModelProperty("启用/冻结")
+        private Boolean enableFlag;
+
+        @ApiModelProperty("简介")
+        @TableField(value = "brief_introduction_")
+        private String briefIntroduction;
+
+        public static Tenant from(String json) {
+            return JSON.parseObject(json, Tenant.class);
+        }
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" TenantStaff-机构员工表")
+    public static class Staff implements Serializable {
+
+        @ApiModelProperty("主键ID")
+        private Long id;
+
+        @ApiModelProperty("机构ID")
+        private Long tenantId;
+
+        @ApiModelProperty("机构状态")
+        private Boolean tenantEnableFlag;
+
+        @ApiModelProperty("用户ID")
+        private Long userId;
+
+        @ApiModelProperty("头像")
+        private String avatar;
+
+        @ApiModelProperty("昵称")
+        private String nickname;
+
+        @ApiModelProperty("IM授权签名")
+        private String imToken;
+
+        @ApiModelProperty("微信ID")
+        private String wechatId;
+
+        @ApiModelProperty("微信OpenID")
+        private String wxOpenid;
+
+        @ApiModelProperty("公众号关注标识")
+        private Boolean subscribeFlag;
+
+        @ApiModelProperty("管理员标识")
+        private Boolean manageAdmin;
+
+        @ApiModelProperty("介绍")
+        private String introduction;
+
+        @ApiModelProperty("帐号状态(注销,冻结,激活)")
+        private String status;
+
+        public static Staff from(String json) {
+            return JSON.parseObject(json, Staff.class);
+        }
+
+
+    }
+
+}

+ 37 - 0
cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/AdminFeignServiceFallback.java

@@ -2,6 +2,13 @@ package com.yonge.cooleshow.api.feign.fallback;
 
 import com.yonge.cooleshow.api.feign.AdminFeignService;
 import com.yonge.cooleshow.api.feign.dto.*;
+import com.yonge.cooleshow.api.feign.dto.CouponInfoApi;
+import com.yonge.cooleshow.api.feign.dto.EmployeeApi;
+import com.yonge.cooleshow.api.feign.dto.StudentApi;
+import com.yonge.cooleshow.api.feign.dto.StudentWrapper;
+import com.yonge.cooleshow.api.feign.dto.TeacherApi;
+import com.yonge.cooleshow.api.feign.dto.TenantWrapper;
+import com.yonge.cooleshow.api.feign.dto.UserFriendInfoVO;
 import com.yonge.cooleshow.common.entity.ContractDto;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.entity.MallOrderItemDto;
@@ -94,6 +101,28 @@ public class AdminFeignServiceFallback implements AdminFeignService {
         return null;
     }
 
+    /**
+     * 机构信息
+     *
+     * @param tenantId 机构ID
+     * @return TenantWrapper.Tenant
+     */
+    @Override
+    public HttpResponseResult<TenantWrapper.Tenant> getTenantInfo(Long tenantId) {
+        return null;
+    }
+
+    /**
+     * 机构员工信息
+     *
+     * @param userId 用户ID
+     * @return TenantWrapper.Staff
+     */
+    @Override
+    public HttpResponseResult<TenantWrapper.Staff> getTenantStaff(Long userId) {
+        return null;
+    }
+
     @Override
     public HttpResponseResult<Boolean> updateCouponOrderInfo(String couponIssueId, Boolean returnCoupon, String orderNo) {
         return null;
@@ -150,6 +179,14 @@ public class AdminFeignServiceFallback implements AdminFeignService {
         return null;
     }
 
+    /**
+     * 定时发送平台审核短信 下午5点
+     */
+    @Override
+    public HttpResponseResult<Object> sendPlatformAuditMessage() {
+        return null;
+    }
+
     @Override
     public ImUserInfo register(String userId, String clientType, String username, String avatar) {
         return null;

+ 16 - 0
cooleshow-api/src/main/java/com/yonge/cooleshow/api/feign/fallback/TenantFeignServiceFallback.java

@@ -0,0 +1,16 @@
+package com.yonge.cooleshow.api.feign.fallback;
+
+import com.yonge.cooleshow.api.feign.TenantFeignService;
+
+/**
+ * Description
+ *
+ * @author liujunchi
+ * @date 2022-05-06
+ */
+public class TenantFeignServiceFallback implements TenantFeignService {
+
+    @Override
+    public void tenantPersonStat() {
+    }
+}

+ 88 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/controller/SmsCodeController.java

@@ -0,0 +1,88 @@
+package com.yonge.cooleshow.tenant.controller;
+
+import com.wf.captcha.SpecCaptcha;
+import com.wf.captcha.utils.CaptchaUtil;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
+import com.yonge.cooleshow.biz.dal.service.SmsCodeService;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.security.SecurityConstants;
+import com.yonge.toolset.base.exception.BizException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+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.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.concurrent.TimeUnit;
+
+@RestController
+@RequestMapping("${app-config.url.tenant:}/code")
+@Api(tags = "验证码服务")
+public class SmsCodeController extends BaseController {
+
+    @Autowired
+    private SmsCodeService smsCodeService;
+    @Autowired
+    private RedisTemplate<String,String> redisTemplate;
+
+    @ApiOperation(value = "发送短信验证码")
+    @ApiImplicitParams({  @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String"),
+                          @ApiImplicitParam(name = "type", value = "类型(PASSWD:修改密码,LOGIN:登录或注册,BANK:绑定银行卡,PHONE:修改手机号,LOGOFF:用户注销)", required = true, dataType = "String") })
+    @PostMapping(value = "/sendSmsCode")
+    public Object sendLoginVerifyCode(String mobile,String type) throws Exception {
+        smsCodeService.sendValidCode(mobile, type, ClientEnum.TEACHER);
+        return succeed();
+    }
+
+    @ApiOperation(value = "校验短信验证码")
+    @ApiImplicitParams({ @ApiImplicitParam(name = "phone", value = "手机号", required = true, dataType = "String"),
+                         @ApiImplicitParam(name = "code", value = "短信验证码", required = true, dataType = "String"),
+                         @ApiImplicitParam(name = "type", value = "类型(PASSWD:修改密码,LOGIN:登录或注册,BANK:绑定银行卡,PHONE:修改手机号)", required = true, dataType = "String") })
+    @PostMapping(value = "/verifySmsCode")
+    public Object verifySmsCode(String phone,String code,String type) {
+        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(code)){
+            return failed(SecurityConstants.PARAM_VERIFY_EXCEPTION);
+        }
+        if(smsCodeService.verifyValidCode(phone, code, type)){
+            return succeed();
+        }
+        return failed("验证码校验失败");
+    }
+
+    @PostMapping(value = "/verifyImageCode")
+    @ApiOperation("校验登录图形验证码")
+    @ApiImplicitParams({ @ApiImplicitParam(name = "phone", value = "手机号", required = true, dataType = "String"),
+            @ApiImplicitParam(name = "code", value = "验证码", required = true, dataType = "String") })
+    public Object verifyImageCode(String phone,String code){
+        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(code)){
+            return failed(SecurityConstants.PARAM_VERIFY_EXCEPTION);
+        }
+        String redisKey = MessageTypeEnum.KAPTCHA_SESSION_KEY + phone;
+        if(redisTemplate.hasKey(redisKey)){
+            if(StringUtils.equalsIgnoreCase(redisTemplate.opsForValue().get(redisKey),code)){
+                return succeed();
+            }
+        }
+        return failed(SecurityConstants.VERIFY_FAILURE);
+    }
+
+    @RequestMapping("/getImageCode")
+    @ApiOperation("获取登录图片验证码")
+    @ApiImplicitParam(name = "phone", value = "手机号", required = true, dataType = "String")
+    public void getLoginImage(HttpServletRequest request, HttpServletResponse response,String phone) throws Exception {
+        if(StringUtils.isEmpty(phone)){
+            throw new BizException("请输入手机号");
+        }
+        SpecCaptcha specCaptcha = new SpecCaptcha(125, 45, 4);
+        redisTemplate.opsForValue().set(MessageTypeEnum.KAPTCHA_SESSION_KEY + phone,specCaptcha.text(),3, TimeUnit.MINUTES);
+        CaptchaUtil.out(specCaptcha, request, response);
+    }
+}

+ 18 - 0
cooleshow-auth/auth-api/pom.xml

@@ -33,5 +33,23 @@
 			<groupId>com.yonge.cooleshow</groupId>
 			<artifactId>cooleshow-common</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>com.yonge.cooleshow</groupId>
+			<artifactId>cooleshow-common</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-openfeign-core</artifactId>
+			<version>2.1.1.RELEASE</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.yonge.toolset</groupId>
+			<artifactId>utils</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.yonge.toolset</groupId>
+			<artifactId>utils</artifactId>
+		</dependency>
 	</dependencies>
 </project>

+ 8 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/client/SysUserFeignService.java

@@ -54,10 +54,18 @@ public interface SysUserFeignService {
 										   @RequestParam("clientId")String clientId,
 										   @RequestParam("clientSecret")String clientSecret);
 
+	@GetMapping(value = "user/getTenantByClient")
+	@ApiOperation(value = "获取机构编号")
+	HttpResponseResult<Long> getTenantByClient(@RequestParam("userId")Long userId,@RequestParam("clientId")String clientId);
+
 	@GetMapping(value = "exit")
 	@ApiOperation(value = "退出登录")
 	HttpResponseResult<String> logout();
 
+	@GetMapping(value = "exit/{clientId}/{phone}", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+	@ApiOperation(value = "退出登录")
+	HttpResponseResult<String> logout(@PathVariable("clientId") String clientId, @PathVariable("phone") String phone);
+
 	@PostMapping(value = "user/list")
 	HttpResponseResult<List<SysUser>> page(@RequestBody SysUserQueryInfo queryInfo);
 

+ 8 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/client/fallback/SysUserFeignServiceFallback.java

@@ -68,11 +68,19 @@ public class SysUserFeignServiceFallback implements SysUserFeignService {
 		return HttpResponseResult.failed("请求失败");
 	}
 
+	public HttpResponseResult<Long> getTenantByClient(Long userId,String clientId){
+		return HttpResponseResult.succeed(-1L);
+	}
+
 	@Override
 	public HttpResponseResult<String> logout() {
 		return HttpResponseResult.failed("请求失败");
 	}
 
+	@Override
+	public HttpResponseResult<String> logout(String phone, String client) {
+		return null;
+	}
 
 	@Override
 	public HttpResponseResult<List<SysUser>> page(SysUserQueryInfo queryInfo) {

+ 10 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/LoginEntity.java

@@ -20,6 +20,8 @@ public class LoginEntity {
     private String qrCode;
     //关联帐号授权码
     private String authToken;
+    // 登录类型
+    private String loginType;
     
     public Boolean getIsSurportRegister() {
 		return isSurportRegister;
@@ -92,4 +94,12 @@ public class LoginEntity {
     public void setAuthToken(String authToken) {
         this.authToken = authToken;
     }
+
+    public String getLoginType() {
+        return loginType;
+    }
+
+    public void setLoginType(String loginType) {
+        this.loginType = loginType;
+    }
 }

+ 9 - 203
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/SysUser.java

@@ -1,17 +1,20 @@
 package com.yonge.cooleshow.auth.api.entity;
 
+import com.alibaba.fastjson.JSON;
 import io.swagger.annotations.ApiModelProperty;
 
 import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
+import lombok.Data;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 
 /**
  * 对应数据库表(sys_user):
  */
+@Data
 public class SysUser implements Serializable{
 
 	/**
@@ -103,137 +106,8 @@ public class SysUser implements Serializable{
 
 	private String certificateType = "IDENTITY";
 
-	public String getCertificateType() {
-		return certificateType;
-	}
-
-	public void setCertificateType(String certificateType) {
-		this.certificateType = certificateType;
-	}
-
-	public String getRealName() {
-		return realName;
-	}
-
-	public void setRealName(String realName) {
-		this.realName = realName;
-	}
-
-	public String getImToken() {
-		return imToken;
-	}
-
-	public void setImToken(String imToken) {
-		this.imToken = imToken;
-	}
-
-	public Long getId() {
-		return id;
-	}
-
-	public void setId(Long id) {
-		this.id = id;
-	}
-
-	public void setUsername(String username) {
-		this.username = username;
-	}
-
-	public String getUsername() {
-		return this.username;
-	}
-
-	public void setPassword(String password) {
-		this.password = password;
-	}
-
-	public String getPassword() {
-		return this.password;
-	}
-
-	public void setSalt(String salt) {
-		this.salt = salt;
-	}
-
-	public String getSalt() {
-		return this.salt;
-	}
-
-	public void setPhone(String phone) {
-		this.phone = phone;
-	}
-
-	public String getPhone() {
-		return this.phone;
-	}
-
-	public void setAvatar(String avatar) {
-		this.avatar = avatar;
-	}
-
-	public String getAvatar() {
-		return this.avatar;
-	}
-
-	public void setCreateTime(java.util.Date createTime) {
-		this.createTime = createTime;
-	}
-
-	public java.util.Date getCreateTime() {
-		return this.createTime;
-	}
-
-	public void setUpdateTime(java.util.Date updateTime) {
-		this.updateTime = updateTime;
-	}
-
-	public java.util.Date getUpdateTime() {
-		return this.updateTime;
-	}
-
-	public Integer getLockFlag() {
-		return lockFlag;
-	}
-
-	public void setLockFlag(Integer lockFlag) {
-		this.lockFlag = lockFlag;
-	}
-
-	public Boolean getSuperAdmin() {
-		return isSuperAdmin;
-	}
-
-	public void setSuperAdmin(Boolean superAdmin) {
-		isSuperAdmin = superAdmin;
-	}
-
-	public Boolean getDelFlag() {
-		return delFlag;
-	}
-
-	public void setDelFlag(Boolean delFlag) {
-		this.delFlag = delFlag;
-	}
-
-	public void setWxOpenid(String wxOpenid) {
-		this.wxOpenid = wxOpenid;
-	}
-
-	public String getWxOpenid() {
-		return this.wxOpenid;
-	}
-
-	public void setQqOpenid(String qqOpenid) {
-		this.qqOpenid = qqOpenid;
-	}
-
-	public String getQqOpenid() {
-		return this.qqOpenid;
-	}
-
-	public String getUserType() {
-		return userType;
-	}
+	@ApiModelProperty(value = "机构编号")
+	private Long tenantId;
 
 	public void setUserType(String userType) {
 		if(StringUtils.isNotEmpty(userType) && userType.startsWith(",")){
@@ -242,80 +116,12 @@ public class SysUser implements Serializable{
 		this.userType = userType;
 	}
 
-	public Integer getGender() {
-		return gender;
-	}
-
-	public void setGender(Integer gender) {
-		this.gender = gender;
-	}
-
-	public String getNation() {
-		return nation;
-	}
-
-	public void setNation(String nation) {
-		this.nation = nation;
-	}
-
-	public Date getBirthdate() {
-		return birthdate;
-	}
-
-	public void setBirthdate(Date birthdate) {
-		this.birthdate = birthdate;
-	}
-
-	public String getEmail() {
-		return email;
-	}
-
-	public void setEmail(String email) {
-		this.email = email;
-	}
-
-	public String getIdCardNo() {
-		return idCardNo;
-	}
-
-	public void setIdCardNo(String idCardNo) {
-		this.idCardNo = idCardNo;
-	}
-
-	public String getWechatId() {
-		return wechatId;
-	}
-
-	public void setWechatId(String wechatId) {
-		this.wechatId = wechatId;
-	}
-
-	public Boolean getIsSuperAdmin() {
-		return isSuperAdmin;
-	}
-
-	public void setIsSuperAdmin(Boolean isSuperAdmin) {
-		this.isSuperAdmin = isSuperAdmin;
-	}
-
-	public List<Long> getRoles() {
-		return roles;
-	}
-
-	public void setRoles(List<Long> roles) {
-		this.roles = roles;
-	}
-
-	public Date getLastUsernameTime() {
-		return lastUsernameTime;
-	}
-
-	public void setLastUsernameTime(Date lastUsernameTime) {
-		this.lastUsernameTime = lastUsernameTime;
-	}
-
 	@Override
 	public String toString() {
 		return ToStringBuilder.reflectionToString(this);
 	}
+
+	public String jsonString() {
+		return JSON.toJSONString(this);
+	}
 }

+ 31 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/UserPassword.java

@@ -0,0 +1,31 @@
+package com.yonge.cooleshow.auth.api.entity;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@ApiModel("用户账号密码")
+@Data
+public class UserPassword {
+
+
+    @ApiModel("校验密码")
+    @Data
+    public static class CheckPassword {
+
+        @ApiModelProperty("密码")
+        @NotNull(message = "密码不能为空")
+        private String password;
+    }
+
+    @ApiModel("校验验证码")
+    @Data
+    public static class CheckVerityCode {
+
+        @ApiModelProperty("验证码")
+        @NotNull(message = "验证码不能为空")
+        private String code;
+    }
+}

+ 95 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/WxConfigInfo.java

@@ -0,0 +1,95 @@
+package com.yonge.cooleshow.auth.api.entity;
+
+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.util.Date;
+
+
+/**
+ * 微信配置信息
+ * 2023-02-01 14:21:57
+ */
+@Data
+@ApiModel(" WxConfigInfo-微信配置信息")
+@TableName("wx_config_info")
+public class WxConfigInfo implements Serializable {
+
+    @ApiModelProperty("主键标识")
+    @TableId(value = "id")
+    private Long id;
+
+    @ApiModelProperty("公众号名称")
+	@TableField(value = "mp_name")
+    private String mpName;
+
+    @ApiModelProperty("公众号ID")
+	@TableField(value = "appid")
+    private String appid;
+
+    @ApiModelProperty("接入密钥")
+	@TableField(value = "secret")
+    private String secret;
+
+    @ApiModelProperty("消息密钥")
+	@TableField(value = "token")
+    private String token;
+
+    @ApiModelProperty("加密模式密钥")
+	@TableField(value = "aeskey")
+    private String aeskey;
+
+    @ApiModelProperty("关注公众号提示信息")
+	@TableField(value = "content")
+    private String content;
+
+    @ApiModelProperty("商户ID")
+	@TableField(value = "merchant_id")
+    private String merchantId;
+
+    @ApiModelProperty("商户密钥")
+	@TableField(value = "merchant_key")
+    private String merchantKey;
+
+    @ApiModelProperty("微信帐单回调")
+	@TableField(value = "notify_url")
+    private String notifyUrl;
+
+    @ApiModelProperty("交易类型")
+	@TableField(value = "trade_type")
+    private String tradeType;
+
+    @ApiModelProperty("签名类型")
+	@TableField(value = "sign_type")
+    private String signType;
+
+    @ApiModelProperty("关注跳转地址")
+	@TableField(value = "subscribe_url")
+    private String subscribeUrl;
+
+    @ApiModelProperty("关联公众号")
+	@TableField(value = "mp_app_id")
+    private String mpAppId;
+
+    @ApiModelProperty("公众号类型")
+	@TableField(value = "mp_type")
+    private Integer mpType;
+
+    @ApiModelProperty("全局标识")
+	@TableField(value = "is_global")
+    private Boolean isGlobal;
+
+    @ApiModelProperty("状态")
+	@TableField(value = "status")
+    private Boolean status;
+
+    @ApiModelProperty("创建时间")
+	@TableField(value = "create_time")
+    private Date createTime;
+
+}

+ 55 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/WxTemplateConfig.java

@@ -0,0 +1,55 @@
+package com.yonge.cooleshow.auth.api.entity;
+
+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.util.Date;
+
+
+/**
+ * 微信模板配置
+ * 2023-02-01 14:21:57
+ */
+@Data
+@ApiModel(" WxTemplateConfig-微信模板配置")
+@TableName("wx_template_config")
+public class WxTemplateConfig implements Serializable {
+
+    @ApiModelProperty("主键")
+    @TableId(value = "id")
+    private Long id;
+
+    @ApiModelProperty("微信公众号")
+	@TableField(value = "appid")
+    private String appid;
+
+    @ApiModelProperty("消息指令")
+	@TableField(value = "command")
+    private String command;
+
+    @ApiModelProperty("微信模板id")
+	@TableField(value = "wx_template_id")
+    private String wxTemplateId;
+
+    @ApiModelProperty("模板消息地址")
+	@TableField(value = "url")
+    private String url;
+
+    @ApiModelProperty("描述")
+	@TableField(value = "description")
+    private String description;
+
+    @ApiModelProperty("状态")
+	@TableField(value = "status")
+    private Boolean status;
+
+    @ApiModelProperty("创建时间")
+	@TableField(value = "create_time")
+    private Date createTime;
+
+}

+ 63 - 0
cooleshow-auth/auth-api/src/main/java/com/yonge/cooleshow/auth/api/entity/WxTemplateMessage.java

@@ -0,0 +1,63 @@
+package com.yonge.cooleshow.auth.api.entity;
+
+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.util.Date;
+
+
+/**
+ * 微信模板消息内容
+ * 2023-02-01 14:21:57
+ */
+@Data
+@ApiModel(" WxTemplateMessage-微信模板消息内容")
+@TableName("wx_template_message")
+public class WxTemplateMessage implements Serializable {
+
+    @ApiModelProperty("主键列")
+    @TableId(value = "id")
+    private Long id;
+
+    @ApiModelProperty("应用标识")
+	@TableField(value = "appid")
+    private String appid;
+
+    @ApiModelProperty("指令")
+	@TableField(value = "command")
+    private String command;
+
+    @ApiModelProperty("内容")
+	@TableField(value = "content")
+    private String content;
+
+    @ApiModelProperty("标题")
+	@TableField(value = "title")
+    private String title;
+
+    @ApiModelProperty("版本")
+	@TableField(value = "version")
+    private Integer version;
+
+    @ApiModelProperty("类型WECHAT;APP")
+	@TableField(value = "type")
+    private String type;
+
+    @ApiModelProperty("描述")
+	@TableField(value = "description")
+    private String description;
+
+    @ApiModelProperty("状态")
+	@TableField(value = "status")
+    private Boolean status;
+
+    @ApiModelProperty("创建时间")
+	@TableField(value = "create_time")
+    private Date createTime;
+
+}

+ 4 - 1
cooleshow-auth/auth-server/pom.xml

@@ -8,7 +8,6 @@
         <artifactId>cooleshow-auth</artifactId>
         <version>1.0</version>
     </parent>
-    <groupId>com.yonge.cooleshow</groupId>
     <artifactId>auth-server</artifactId>
     <version>1.0</version>
     <name>auth-server</name>
@@ -23,6 +22,10 @@
             <artifactId>microsvc-config-jwt</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.microsvc.toolkit.middleware</groupId>
+            <artifactId>microsvc-middleware-wechat</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.springframework.security</groupId>
             <artifactId>spring-security-jwt</artifactId>
             <version>1.0.9.RELEASE</version>

+ 1 - 1
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/config/ResourceServerConfig.java

@@ -32,7 +32,7 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
 				"/user/noAuth/queryUserByPhone",
 				"/user/queryUserByPhone",
 				"/user/add",
-				"/user/queryUserById/*").hasIpAddress("0.0.0.0/0")
+				"/user/queryUserById/*","/user/getTenantByClient").hasIpAddress("0.0.0.0/0")
 				.anyRequest().authenticated().and().httpBasic();
 	}
 

+ 14 - 10
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/config/WebSecurityConfig.java

@@ -1,5 +1,15 @@
 package com.yonge.cooleshow.auth.config;
 
+import com.yonge.cooleshow.auth.core.filter.PhoneLoginAuthenticationFilter;
+import com.yonge.cooleshow.auth.core.filter.UsernameAuthenticationFilter;
+import com.yonge.cooleshow.auth.core.handler.BaseAuthenticationFailureEvenHandler;
+import com.yonge.cooleshow.auth.core.handler.BaseAuthenticationSuccessEventHandler;
+import com.yonge.cooleshow.auth.core.provider.PhoneAuthenticationProvider;
+import com.yonge.cooleshow.auth.core.provider.service.DefaultUserDetailsService;
+import com.yonge.cooleshow.auth.middleware.wechat.WxCacheService;
+import com.yonge.cooleshow.auth.service.SysUserDeviceService;
+import com.yonge.cooleshow.auth.service.SysUserService;
+import com.yonge.cooleshow.common.service.IdGeneratorService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -15,16 +25,6 @@ import org.springframework.security.crypto.factory.PasswordEncoderFactories;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 
-import com.yonge.cooleshow.auth.core.filter.PhoneLoginAuthenticationFilter;
-import com.yonge.cooleshow.auth.core.filter.UsernameAuthenticationFilter;
-import com.yonge.cooleshow.auth.core.handler.BaseAuthenticationFailureEvenHandler;
-import com.yonge.cooleshow.auth.core.handler.BaseAuthenticationSuccessEventHandler;
-import com.yonge.cooleshow.auth.core.provider.PhoneAuthenticationProvider;
-import com.yonge.cooleshow.auth.core.provider.service.DefaultUserDetailsService;
-import com.yonge.cooleshow.auth.service.SysUserDeviceService;
-import com.yonge.cooleshow.auth.service.SysUserService;
-import com.yonge.cooleshow.common.service.IdGeneratorService;
-
 @Configuration
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true)//会拦截注解了@PreAuthrize注解的配置.
@@ -48,6 +48,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 	@Autowired
 	private SysUserDeviceService sysUserDeviceService;
 
+	@Autowired
+	private WxCacheService wxCacheService;
+
 	@Override
 	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
 		auth.authenticationProvider(daoAuthenticationProvider());
@@ -110,6 +113,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
         provider.setSmsCodeService(smsCodeService);
         provider.setSysUserService(sysUserService);
         provider.setSysUserDeviceService(sysUserDeviceService);
+		provider.setWxCacheService(wxCacheService);
 		// 禁止隐藏用户未找到异常
 		provider.setHideUserNotFoundExceptions(false);
         return provider;

+ 3 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/filter/PhoneLoginAuthenticationFilter.java

@@ -26,6 +26,7 @@ public class PhoneLoginAuthenticationFilter extends AbstractAuthenticationProces
 	private static final String LOGIN_USER_TYPE = "loginUserType";
 	private static final String QR_CODE = "qrCode";
 	private static final String AUTH_TOKEN = "token";
+	private static final String LOGIN_TYPE = "loginType";
 
 	private static final String DEVICE_NUM = "deviceNum";
 
@@ -51,6 +52,7 @@ public class PhoneLoginAuthenticationFilter extends AbstractAuthenticationProces
 		String loginUserType = obtainParameter(request, LOGIN_USER_TYPE);
 		String qrCode = obtainParameter(request, QR_CODE);
 		String authToken = obtainParameter(request, AUTH_TOKEN);
+		String loginType = obtainParameter(request, LOGIN_TYPE);
 
 		String clientId = request.getParameter(clientIdParameter).toUpperCase();
 
@@ -71,6 +73,7 @@ public class PhoneLoginAuthenticationFilter extends AbstractAuthenticationProces
 		loginEntity.setDeviceNum(deviceNum);
 		loginEntity.setQrCode(qrCode);
 		loginEntity.setAuthToken(authToken);
+		loginEntity.setLoginType(loginType);
 
 		authRequest = new PhoneAuthenticationToken(SecurityConstants.PHONE_PRINCIPAL_PREFIX + principal, loginEntity);
 

+ 30 - 8
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/handler/BaseAuthenticationFailureEvenHandler.java

@@ -1,10 +1,7 @@
 package com.yonge.cooleshow.auth.core.handler;
 
-import java.io.IOException;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import org.apache.http.HttpStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -13,8 +10,9 @@ import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler;
 import org.springframework.stereotype.Component;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
 
 @Component
 public class BaseAuthenticationFailureEvenHandler extends ExceptionMappingAuthenticationFailureHandler {
@@ -30,16 +28,40 @@ public class BaseAuthenticationFailureEvenHandler extends ExceptionMappingAuthen
     	int resultCode = HttpStatus.SC_CONFLICT;
     	
         String message = exception.getLocalizedMessage();
+
+        String data = null;
         if (message.equals("Bad credentials")) {
             message = "用户名或密码错误";
         }else if(message.equals("User is disabled")){
+            resultCode = 5005;
             message = "账户被锁定";
         }else if(message.equals("404.9")){
         	message = "用户名或密码错误";
         	resultCode = 99;
+        } else if (message.startsWith("MA:5001:")) {
+            // 返回用户绑定openId
+            data = message.split(":")[2];
+            // 用户未绑定openId错误码
+            resultCode = 5001;
+            // 用户未绑定openId错误信息
+            message = "用户未绑定小程序账号";
+        } else if (message.startsWith("MA:5004:")) {
+            // 返回用户绑定openId
+            data = message.split(":")[2];
+            // 用户未绑定openId错误码
+            resultCode = 5004;
+            // 用户未绑定openId错误信息
+            message = "该机构已被冻结,请联系管理员";
+        } else if (message.startsWith("MA:5005:")) {
+            // 返回用户绑定openId
+            data = message.split(":")[2];
+            // 用户未绑定openId错误码
+            resultCode = 5005;
+            // 用户未绑定openId错误信息
+            message = "账号已冻结";
         }
         logger.info("登录失败,异常:{}", message);
-        HttpResponseResult result = new HttpResponseResult(false, resultCode, null, message);
+        HttpResponseResult result = new HttpResponseResult(false, resultCode, data, message);
         response.setContentType("application/json; charset=utf-8");
         response.getWriter().write(objectMapper.writeValueAsString(result));
     }

+ 15 - 1
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/handler/BaseAuthenticationSuccessEventHandler.java

@@ -11,6 +11,18 @@ import com.yonge.cooleshow.auth.service.SysUserLoginService;
 import com.yonge.cooleshow.auth.service.SysUserService;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.security.SecurityConstants;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.auth.api.entity.SysUserLogin;
+import com.yonge.cooleshow.auth.api.entity.SysUserLoginLog;
+import com.yonge.cooleshow.auth.config.RongCloudConfig;
+import com.yonge.cooleshow.auth.service.SysUserLoginLogService;
+import com.yonge.cooleshow.auth.service.SysUserLoginService;
+import com.yonge.cooleshow.auth.service.SysUserService;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.cooleshow.common.security.SecurityConstants;
+import io.rong.models.response.TokenResult;
+import io.rong.models.user.UserModel;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
@@ -76,7 +88,9 @@ public class BaseAuthenticationSuccessEventHandler extends SavedRequestAwareAuth
 		SysUser sysUser;
 		if(username.startsWith(SecurityConstants.USERNAME_PRINCIPAL_PREFIX)){
 			sysUser = sysUserService.queryByUsername(username.split(":")[1]);
-		}else {
+		} else if (username.startsWith(SecurityConstants.MA_PRINCIPAL_PREFIX)) {
+			sysUser = sysUserService.queryLockByPhone(username.split(":")[2]);
+		} else {
 			sysUser = sysUserService.queryLockByPhone(username.split(":")[1]);
 		}
 		/*if(StringUtils.isEmpty(sysUser.getImToken())){

+ 156 - 82
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/provider/PhoneAuthenticationProvider.java

@@ -1,14 +1,20 @@
 package com.yonge.cooleshow.auth.core.provider;
 
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import com.alibaba.fastjson.JSON;
 import com.microsvc.toolkit.config.jwt.utils.RsaKeyHelper;
+import com.microsvc.toolkit.middleware.wechat.WxServiceManager;
 import com.yonge.cooleshow.auth.api.dto.SysUserInfo;
 import com.yonge.cooleshow.auth.api.entity.LoginEntity;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.auth.config.token.PhoneAuthenticationToken;
+import com.yonge.cooleshow.auth.enums.ELoginType;
+import com.yonge.cooleshow.auth.middleware.wechat.WxCacheService;
 import com.yonge.cooleshow.auth.service.SysUserDeviceService;
 import com.yonge.cooleshow.auth.service.SysUserService;
+import com.yonge.cooleshow.common.security.SecurityConstants;
 import com.yonge.cooleshow.common.service.IdGeneratorService;
-import com.yonge.toolset.base.exception.BizException;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.security.authentication.BadCredentialsException;
@@ -25,8 +31,10 @@ import org.springframework.security.jwt.crypto.sign.RsaVerifier;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.security.interfaces.RSAPublicKey;
+import java.text.MessageFormat;
 import java.util.Date;
 import java.util.Objects;
+
 @Slf4j
 public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider {
 
@@ -38,6 +46,8 @@ public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider
 
     private SysUserDeviceService sysUserDeviceService;
 
+    private WxCacheService wxCacheService;
+
     @Override
     protected void additionalAuthenticationChecks(UserDetails userDetails, Authentication authentication) throws AuthenticationException {
         if (authentication.getCredentials() == null) {
@@ -59,111 +69,171 @@ public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider
         String qrCode = loginEntity.getQrCode();
         // 授权Token登录
         String authToken = loginEntity.getAuthToken();
-        if (StringUtils.isNotEmpty(qrCode)) {
-            // 二维码验证
-            boolean b = sysUserService.verifyQrCode(phone, qrCode);
-            if (!b) {
-                throw new BadCredentialsException("二维码校验失败");
+        // 用户登陆方式
+        ELoginType loginType = ELoginType.get(loginEntity.getLoginType());
+
+        if (ELoginType.WECHAT_MA == loginType) {
+            // 小程序登陆
+            // 根据小程序code获取openId;查询用户是否存在
+            // 查询配置信息, keyword =>小程序apppid
+            WxMaService wxMaService = WxServiceManager.getInstance().getWxMaService(phone, wxCacheService);
+            if (wxMaService == null) {
+                log.warn("genRequestAuthorityTokenInfo WX_APPID, appid={}, jscode={}", phone, smsCode);
+                throw new BadCredentialsException("小程序授权失败,请联系管理员");
             }
-        } else if (StringUtils.isNotEmpty(authToken)) {
-            // 授权authToken登录
+
+            String openid;
             try {
-                RSAPublicKey rsaPublicKey = RsaKeyHelper.getRSAPublicKey("jmedu", "dayaedu", "jmedu.jks", "dayaedu");
-                Jwt jwt = JwtHelper.decodeAndVerify(authToken, new RsaVerifier(rsaPublicKey));
+                // 校验请求jscode的合法
+                WxMaJscode2SessionResult sessionret = wxMaService.getUserService().getSessionInfo(smsCode);
 
-                //获取jwt原始内容
-                String claims = jwt.getClaims();
-                if (StringUtils.isEmpty(claims)) {
-                    throw new BizException("三方授权校验失败");
+                if (StringUtils.isAnyBlank(sessionret.getOpenid(), sessionret.getSessionKey())) {
+                    log.warn("genRequestAuthorityTokenInfo JSCODE, ret={}", JSON.toJSONString(sessionret));
+                    throw new BadCredentialsException("小程序授权失败,请重新授权");
                 }
-                log.info("retrieveUser claims={}", claims);
+                // 用户openid
+                openid = sessionret.getOpenid();
+
             } catch (Exception e) {
-                log.error("retrieveUser authToken={}", authToken, e);
+                log.error("genRequestAuthorityTokenInfo WX_OAUTH2, appid={}, jscode={}", phone, smsCode, e);
+                throw new BadCredentialsException("小程序授权已失效,请重新登陆");
             }
 
-        } else {
-            // 验证码验证
-            boolean b = smsCodeService.verifyValidCode(phone, smsCode, "SMS_VERIFY_CODE_LOGIN");
-            if (!b) {
-                throw new BadCredentialsException("验证码校验失败");
+            String clientId = loginEntity.getClientId();
+            String deviceNum = loginEntity.getDeviceNum();
+            // 根据用户授权openid,查询机构员工绑定信息
+            SysUser sysUser = sysUserService.getSysUserByOpenId(openid, clientId);
+            if (Objects.isNull(sysUser)) {
+                // 小程序未绑定账号
+                throw new UsernameNotFoundException("MA:5001:" + openid);
             }
-        }
-
-        String clientId = loginEntity.getClientId();
-        Boolean isRegister = loginEntity.getIsSurportRegister();
-        String loginUserType = loginEntity.getLoginUserType();
-        String deviceNum = loginEntity.getDeviceNum();
 
-        SysUserInfo userInfo = sysUserService.queryUserInfoByPhone(phone);
+            // 重置登陆账号信息
+            username = MessageFormat.format("{0}:{1}:{2}", SecurityConstants.MA_PRINCIPAL_PREFIX, openid, sysUser.getPhone());
 
-        if (userInfo == null) {
-            if (isRegister == false || StringUtils.equals("SYSTEM", clientId)) {
-                throw new LockedException("用户不存在");
+            // 绑定设备
+            if (StringUtils.isNotBlank(deviceNum)) {
+                sysUserDeviceService.bindDevice(clientId, sysUser.getId(), deviceNum);
             }
 
-            userInfo = sysUserService.registerUser(loginEntity.getPhone(), clientId, loginUserType);
+        } else {
 
-            if (Objects.nonNull(userInfo.getSysUser())) {
-                // 自动添加系统默认IM帐号为好友,并自动发送通知消息
-                sysUserService.sendSysCustomerServiceFriendMessage(userInfo.getSysUser(), clientId.toUpperCase());
-            }
+            // 其他登陆方式
+            if (StringUtils.isNotEmpty(qrCode)) {
+                // 二维码验证
+                boolean b = sysUserService.verifyQrCode(phone, qrCode);
+                if (!b) {
+                    throw new BadCredentialsException("二维码校验失败");
+                }
+            } else if (StringUtils.isNotEmpty(authToken)) {
+                // 授权authToken登录
+                try {
+                    RSAPublicKey rsaPublicKey = RsaKeyHelper.getRSAPublicKey("jmedu", "dayaedu", "jmedu.jks", "dayaedu");
+                    Jwt jwt = JwtHelper.decodeAndVerify(authToken, new RsaVerifier(rsaPublicKey));
 
-            if (StringUtils.isNotBlank(deviceNum)) {
-                sysUserDeviceService.bindDevice(clientId, userInfo.getSysUser().getId(), deviceNum);
-            }
-        } else {
-            SysUser user = userInfo.getSysUser();
-            if (user == null) {
-                throw new LockedException("用户不存在");
-            }
-            if (user.getLockFlag() == 1) {
-                throw new LockedException("用户已锁定");
-            }
+                    //获取jwt原始内容
+                    String claims = jwt.getClaims();
+                    if (StringUtils.isEmpty(claims)) {
+                        throw new BadCredentialsException("三方授权校验失败");
+                    }
+                    log.info("retrieveUser claims={}", claims);
+                } catch (Exception e) {
+                    log.error("retrieveUser authToken={}", authToken, e);
+                }
 
-            if (StringUtils.isNotBlank(deviceNum)) {
-                sysUserDeviceService.bindDevice(clientId, user.getId(), deviceNum);
-            }
-            //登录
-            if (userInfo.getSysUser().getUserType().contains(clientId)){
-                return login(username);
-            }
-            //官网登录
-            if(StringUtils.isNotEmpty(loginUserType) && userInfo.getSysUser().getUserType().contains(loginUserType)){
-                return login(username);
+            } else {
+                // 验证码验证
+                boolean b = smsCodeService.verifyValidCode(phone, smsCode, "SMS_VERIFY_CODE_LOGIN");
+                if (!b) {
+                    throw new BadCredentialsException("验证码校验失败");
+                }
             }
 
-            /**********************************注册*********************************************/
-            //不能注册的
-            if(isRegister == false || StringUtils.equals("SYSTEM", clientId)){
-                throw new LockedException("用户不存在");
-            }
+            String clientId = loginEntity.getClientId();
+            Boolean isRegister = loginEntity.getIsSurportRegister();
+            String loginUserType = loginEntity.getLoginUserType();
+            String deviceNum = loginEntity.getDeviceNum();
+
+            SysUserInfo userInfo = sysUserService.queryUserInfoByPhone(phone);
 
-            user.setUpdateTime(new Date());
-            if(StringUtils.isNotEmpty(loginUserType)){
-                if (StringUtils.equalsIgnoreCase(loginUserType, "TEACHER")) {
-                    user.setUserType(user.getUserType() + "," + loginUserType);
-                    sysUserService.saveTeacher(user);
-                } else if (StringUtils.equalsIgnoreCase(loginUserType, "STUDENT")) {
-                    user.setUserType(user.getUserType() + "," + loginUserType);
-                    sysUserService.saveStudent(user);
-                }else {
+            if (userInfo == null) {
+                if (isRegister == false || StringUtils.equals("SYSTEM", clientId)) {
                     throw new LockedException("用户不存在");
                 }
-            }else if(StringUtils.isNotEmpty(clientId)){
-                if (StringUtils.equalsIgnoreCase(clientId, "TEACHER")) {
-                    user.setUserType(user.getUserType() + "," + clientId);
-                    sysUserService.saveTeacher(user);
-                } else if (StringUtils.equalsIgnoreCase(clientId, "STUDENT")) {
-                    user.setUserType(user.getUserType() + "," + clientId);
-                    sysUserService.saveStudent(user);
-                } else {
+
+                userInfo = sysUserService.registerUser(loginEntity.getPhone(), clientId, loginUserType);
+
+                if (Objects.nonNull(userInfo.getSysUser())) {
+                    // 自动添加系统默认IM帐号为好友,并自动发送通知消息
+                    sysUserService.sendSysCustomerServiceFriendMessage(userInfo.getSysUser(), clientId.toUpperCase());
+                }
+
+                if (StringUtils.isNotBlank(deviceNum)) {
+                    sysUserDeviceService.bindDevice(clientId, userInfo.getSysUser().getId(), deviceNum);
+                }
+            } else {
+                SysUser user = userInfo.getSysUser();
+                if (user == null) {
                     throw new LockedException("用户不存在");
                 }
-            }else{
-                throw new LockedException("用户不存在");
+                if (user.getLockFlag() == 1) {
+                    throw new LockedException("用户已锁定");
+                }
+
+                if (StringUtils.isNotBlank(deviceNum)) {
+                    sysUserDeviceService.bindDevice(clientId, user.getId(), deviceNum);
+                }
+
+                // 学生账号修改隐藏为显示
+                if (StringUtils.equalsIgnoreCase(loginUserType, "STUDENT")
+                        || StringUtils.equalsIgnoreCase(clientId, "STUDENT")) {
+                    sysUserService.updateStudentHideFlag(userInfo.getSysUser().getId(), 0);
+                }
+
+                //登录
+                if (userInfo.getSysUser().getUserType().contains(clientId)){
+                    return login(username);
+                }
+                //官网登录
+                if(StringUtils.isNotEmpty(loginUserType) && userInfo.getSysUser().getUserType().contains(loginUserType)){
+                    return login(username);
+                }
+
+                /**********************************注册*********************************************/
+                //不能注册的
+                if(isRegister == false || StringUtils.equals("SYSTEM", clientId)){
+                    throw new LockedException("用户不存在");
+                }
+
+                user.setUpdateTime(new Date());
+                if(StringUtils.isNotEmpty(loginUserType)){
+                    if (StringUtils.equalsIgnoreCase(loginUserType, "TEACHER")) {
+                        user.setUserType(user.getUserType() + "," + loginUserType);
+                        sysUserService.saveTeacher(user);
+                    } else if (StringUtils.equalsIgnoreCase(loginUserType, "STUDENT")) {
+                        user.setUserType(user.getUserType() + "," + loginUserType);
+                        sysUserService.saveStudent(user);
+                    }else {
+                        throw new LockedException("用户不存在");
+                    }
+                }else if(StringUtils.isNotEmpty(clientId)){
+                    if (StringUtils.equalsIgnoreCase(clientId, "TEACHER")) {
+                        user.setUserType(user.getUserType() + "," + clientId);
+                        sysUserService.saveTeacher(user);
+                    } else if (StringUtils.equalsIgnoreCase(clientId, "STUDENT")) {
+                        user.setUserType(user.getUserType() + "," + clientId);
+                        sysUserService.saveStudent(user);
+                    } else {
+                        throw new LockedException("用户不存在");
+                    }
+                }else{
+                    throw new LockedException("用户不存在");
+                }
+                sysUserService.update(user);
             }
-            sysUserService.update(user);
+
         }
+
         return login(username);
     }
 
@@ -211,4 +281,8 @@ public class PhoneAuthenticationProvider extends AbstractAuthenticationProvider
     public void setSysUserDeviceService(SysUserDeviceService sysUserDeviceService) {
         this.sysUserDeviceService = sysUserDeviceService;
     }
+
+    public void setWxCacheService(WxCacheService wxCacheService) {
+        this.wxCacheService = wxCacheService;
+    }
 }

+ 33 - 13
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/provider/service/DefaultUserDetailsService.java

@@ -1,14 +1,17 @@
 package com.yonge.cooleshow.auth.core.provider.service;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import com.yonge.cooleshow.api.feign.AdminFeignService;
 import com.yonge.cooleshow.api.feign.dto.EmployeeApi;
 import com.yonge.cooleshow.api.feign.dto.StudentApi;
 import com.yonge.cooleshow.api.feign.dto.TeacherApi;
+import com.yonge.cooleshow.api.feign.dto.TenantWrapper;
+import com.yonge.cooleshow.auth.api.dto.SysUserInfo;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.auth.service.SysUserService;
 import com.yonge.cooleshow.common.enums.SysUserType;
 import com.yonge.cooleshow.common.enums.UserLockFlag;
+import com.yonge.cooleshow.common.security.AuthUser;
+import com.yonge.cooleshow.common.security.SecurityConstants;
 import com.yonge.cooleshow.common.util.WebUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -19,24 +22,16 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 
-import com.yonge.cooleshow.auth.api.dto.SysUserInfo;
-import com.yonge.cooleshow.auth.api.entity.SysUser;
-import com.yonge.cooleshow.auth.service.SysUserService;
-import com.yonge.cooleshow.common.security.AuthUser;
-import com.yonge.cooleshow.common.security.SecurityConstants;
-
 import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
 
 @Service
 public class DefaultUserDetailsService implements UserDetailsService {
 
     @Autowired
-    private PasswordEncoder passwordEncoder;
-
-    @Autowired
     private SysUserService sysUserService;
 
     @Resource
@@ -54,10 +49,17 @@ public class DefaultUserDetailsService implements UserDetailsService {
 
         SysUserInfo userInfo;
 
+        String openid = "";
         if (StringUtils.startsWith(username, SecurityConstants.PHONE_PRINCIPAL_PREFIX)) {
             userInfo = sysUserService.queryUserInfoByPhone(StringUtils.substringAfter(username, SecurityConstants.PHONE_PRINCIPAL_PREFIX));
         } else if (StringUtils.startsWith(username, SecurityConstants.USERNAME_PRINCIPAL_PREFIX)) {
             userInfo = sysUserService.queryUserInfoByUsername(StringUtils.substringAfter(username, SecurityConstants.USERNAME_PRINCIPAL_PREFIX));
+        } else if (StringUtils.startsWith(username, SecurityConstants.MA_PRINCIPAL_PREFIX)) {
+            String[] values = username.split(":");
+            // 设置用户的openId
+            openid = values[1];
+            // 根据手机号查询用户信息
+            userInfo = sysUserService.queryUserInfoByPhone(values[2]);
         } else {
             userInfo = sysUserService.queryUserInfoByUsername(username);
         }
@@ -93,6 +95,19 @@ public class DefaultUserDetailsService implements UserDetailsService {
             if (UserLockFlag.LOCKED.equals(data.getLockFlag())) {
                 throw new LockedException("账户被锁定");
             }
+        } else if (SysUserType.ORGANIZATION.getCode().equals(clientId)) {
+            TenantWrapper.Staff tenantStaff = adminFeignService.getTenantStaff(sysUser.getId()).getData();
+            if (tenantStaff == null) {
+                throw new UsernameNotFoundException("账户不存在");
+            }
+            if (UserLockFlag.LOCKED.name().equals(tenantStaff.getStatus())) {
+                // 账号被锁定
+                throw new UsernameNotFoundException("MA:5005:" + openid);
+            }
+            if (Boolean.FALSE.equals(tenantStaff.getTenantEnableFlag())) {
+                // 机构锁定
+                throw new UsernameNotFoundException("MA:5004:" + openid);
+            }
         }
 
         List<GrantedAuthority> authorities = null;
@@ -104,6 +119,11 @@ public class DefaultUserDetailsService implements UserDetailsService {
             authorities = AuthorityUtils.createAuthorityList(userInfo.getPermissions());
         }
 
+        if (userType.contains("STUDENT")) {
+            // 学生账号修改隐藏为显示
+            sysUserService.updateStudentHideFlag(userInfo.getSysUser().getId(), 0);
+        }
+
         if (authorities == null) {
             authorities = new ArrayList<>();
         }

+ 5 - 6
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/core/service/CustomTokenServices.java

@@ -1,10 +1,6 @@
 package com.yonge.cooleshow.auth.core.service;
 
-import java.util.Collection;
-import java.util.Date;
-import java.util.Set;
-import java.util.UUID;
-
+import com.yonge.cooleshow.common.security.SecurityConstants;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.security.authentication.AuthenticationManager;
@@ -34,7 +30,10 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.Assert;
 
-import com.yonge.cooleshow.common.security.SecurityConstants;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Set;
+import java.util.UUID;
 
 /**
  * Base implementation for token services using random UUID values for the access token and refresh token values. The

+ 13 - 8
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/SysUserDao.java

@@ -1,19 +1,16 @@
 package com.yonge.cooleshow.auth.dal.dao;
 
-import java.util.List;
-
-import com.yonge.cooleshow.common.enums.SysUserType;
-import io.swagger.models.auth.In;
-import org.apache.ibatis.annotations.Param;
-
 import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
 import com.yonge.cooleshow.auth.api.dto.SysUserQueryInfo;
 import com.yonge.cooleshow.auth.api.dto.UserSetReq;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
-import com.yonge.cooleshow.common.enums.UserLockFlag;
 import com.yonge.cooleshow.auth.api.vo.UserSetVo;
-import com.yonge.toolset.mybatis.dal.BaseDAO;
 import com.yonge.cooleshow.common.entity.ImUserModel;
+import com.yonge.cooleshow.common.enums.UserLockFlag;
+import com.yonge.toolset.mybatis.dal.BaseDAO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 public interface SysUserDao extends BaseDAO<Long, SysUser> {
 
@@ -175,9 +172,17 @@ public interface SysUserDao extends BaseDAO<Long, SysUser> {
 
     void updateLockStatus(@Param("userId")Long userId, @Param("lockFlag") Integer lockFlag, @Param("sysUserType")  String sysUserType);
 
+    Long getTenantByClient(@Param("userId") Long userId, @Param("clientId") String clientId);
+
+    SysUser getSysUserByOpenId(@Param("openId") String openId, @Param("clientId") String clientId);
+
     int logoffByPhone(@Param("num") int num, @Param("phone") String phone);
 
     void updateLockStatusByPhone(@Param("phone") String phone);
 
     int countByPhone(@Param("phone") String phone);
+
+    void updateStudentHideFlag(@Param("userId") Long userId, @Param("hideFlag") int hideFlag);
+
+    void updateAvatar(@Param("clientId") String clientId, @Param("avatar") String avatar,@Param("id") Long id);
 }

+ 27 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/WxConfigInfoMapper.java

@@ -0,0 +1,27 @@
+package com.yonge.cooleshow.auth.dal.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.yonge.cooleshow.auth.api.entity.WxConfigInfo;
+import com.yonge.cooleshow.auth.dal.wrapper.WxConfigInfoWrapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 微信配置信息
+ * 2023-02-01 14:21:57
+ */
+@Repository
+public interface WxConfigInfoMapper extends BaseMapper<WxConfigInfo> {
+
+	/**
+	 * 分页查询
+	 * @param page IPage<WxConfigInfoWrapper.WxConfigInfo>
+	 * @param param WxConfigInfoWrapper.WxConfigInfoQuery
+	 * @return List<WxConfigInfoWrapper.WxConfigInfo>
+	 */
+	List<WxConfigInfo> selectPage(@Param("page") IPage<WxConfigInfo> page, @Param("param") WxConfigInfoWrapper.WxConfigInfoQuery param);
+
+}

+ 27 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/WxTemplateConfigMapper.java

@@ -0,0 +1,27 @@
+package com.yonge.cooleshow.auth.dal.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateConfig;
+import com.yonge.cooleshow.auth.dal.wrapper.WxTemplateConfigWrapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 微信模板配置
+ * 2023-02-01 14:21:57
+ */
+@Repository
+public interface WxTemplateConfigMapper extends BaseMapper<WxTemplateConfig> {
+
+	/**
+	 * 分页查询
+	 * @param page IPage<WxTemplateConfigWrapper.WxTemplateConfig>
+	 * @param param WxTemplateConfigWrapper.WxTemplateConfigQuery
+	 * @return List<WxTemplateConfigWrapper.WxTemplateConfig>
+	 */
+	List<WxTemplateConfig> selectPage(@Param("page") IPage<WxTemplateConfig> page, @Param("param") WxTemplateConfigWrapper.WxTemplateConfigQuery param);
+
+}

+ 27 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/dao/WxTemplateMessageMapper.java

@@ -0,0 +1,27 @@
+package com.yonge.cooleshow.auth.dal.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateMessage;
+import com.yonge.cooleshow.auth.dal.wrapper.WxTemplateMessageWrapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 微信模板消息内容
+ * 2023-02-01 14:21:57
+ */
+@Repository
+public interface WxTemplateMessageMapper extends BaseMapper<WxTemplateMessage> {
+
+	/**
+	 * 分页查询
+	 * @param page IPage<WxTemplateMessageWrapper.WxTemplateMessage>
+	 * @param param WxTemplateMessageWrapper.WxTemplateMessageQuery
+	 * @return List<WxTemplateMessageWrapper.WxTemplateMessage>
+	 */
+	List<WxTemplateMessage> selectPage(@Param("page") IPage<WxTemplateMessage> page, @Param("param") WxTemplateMessageWrapper.WxTemplateMessageQuery param);
+
+}

+ 63 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/wrapper/WxConfigInfoWrapper.java

@@ -0,0 +1,63 @@
+package com.yonge.cooleshow.auth.dal.wrapper;
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Optional;
+
+/**
+ * 微信配置信息
+ * 2023-02-01 14:21:57
+ */
+@ApiModel(value = "WxConfigInfoWrapper对象", description = "微信配置信息查询对象")
+public class WxConfigInfoWrapper {
+
+    @Data
+	@Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" WxConfigInfoQuery-微信配置信息")
+    public static class WxConfigInfoQuery implements QueryInfo {
+
+    	@ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        @ApiModelProperty("关键字匹配")
+		private String keyword;
+
+        public String getKeyword() {
+            return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
+        }
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static WxConfigInfoQuery from(String json) {
+            return JSON.parseObject(json, WxConfigInfoQuery.class);
+        }
+    }
+
+	@ApiModel(" WxConfigInfo-微信配置信息")
+    public static class WxConfigInfo {
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static WxConfigInfo from(String json) {
+            return JSON.parseObject(json, WxConfigInfo.class);
+        }
+	}
+
+}

+ 63 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/wrapper/WxTemplateConfigWrapper.java

@@ -0,0 +1,63 @@
+package com.yonge.cooleshow.auth.dal.wrapper;
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Optional;
+
+/**
+ * 微信模板配置
+ * 2023-02-01 14:21:57
+ */
+@ApiModel(value = "WxTemplateConfigWrapper对象", description = "微信模板配置查询对象")
+public class WxTemplateConfigWrapper {
+
+    @Data
+	@Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" WxTemplateConfigQuery-微信模板配置")
+    public static class WxTemplateConfigQuery implements QueryInfo {
+
+    	@ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        @ApiModelProperty("关键字匹配")
+		private String keyword;
+
+        public String getKeyword() {
+            return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
+        }
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static WxTemplateConfigQuery from(String json) {
+            return JSON.parseObject(json, WxTemplateConfigQuery.class);
+        }
+    }
+
+	@ApiModel(" WxTemplateConfig-微信模板配置")
+    public static class WxTemplateConfig {
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static WxTemplateConfig from(String json) {
+            return JSON.parseObject(json, WxTemplateConfig.class);
+        }
+	}
+
+}

+ 63 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/dal/wrapper/WxTemplateMessageWrapper.java

@@ -0,0 +1,63 @@
+package com.yonge.cooleshow.auth.dal.wrapper;
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Optional;
+
+/**
+ * 微信模板消息内容
+ * 2023-02-01 14:21:57
+ */
+@ApiModel(value = "WxTemplateMessageWrapper对象", description = "微信模板消息内容查询对象")
+public class WxTemplateMessageWrapper {
+
+    @Data
+	@Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" WxTemplateMessageQuery-微信模板消息内容")
+    public static class WxTemplateMessageQuery implements QueryInfo {
+
+    	@ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        @ApiModelProperty("关键字匹配")
+		private String keyword;
+
+        public String getKeyword() {
+            return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
+        }
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static WxTemplateMessageQuery from(String json) {
+            return JSON.parseObject(json, WxTemplateMessageQuery.class);
+        }
+    }
+
+	@ApiModel(" WxTemplateMessage-微信模板消息内容")
+    public static class WxTemplateMessage {
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static WxTemplateMessage from(String json) {
+            return JSON.parseObject(json, WxTemplateMessage.class);
+        }
+	}
+
+}

+ 2 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/enums/EClientType.java

@@ -11,6 +11,8 @@ import com.yonge.toolset.base.enums.BaseEnum;
 public enum EClientType implements BaseEnum<String, EClientType> {
     TEACHER("老师端"),
     STUDENT("学生端"),
+    TENANT_STUDENT("机构-学生端"),
+    ORGANIZATION("机构-小程序"),
     SYSTEM("平台端"),
     WEBSITE("官网"),
     ;

+ 76 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/enums/ELoginType.java

@@ -0,0 +1,76 @@
+package com.yonge.cooleshow.auth.enums;
+
+import com.yonge.toolset.base.enums.BaseEnum;
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 登录方式
+ * Created by Eric.Shang on 2022/11/8.
+ */
+@Getter
+public enum ELoginType implements BaseEnum<String, ELoginType> {
+
+    PASSWORD("用户密码"),
+    CAPTCHA("图形验证码"),
+    SMS("短信验证码"),
+    WECHAT_OPENID("微信公众号"),
+    WECHAT_MA("微信小程序"),
+    ;
+
+    private final String message;
+
+    ELoginType(String message) {
+        this.message = message;
+    }
+
+    /**
+     * 获取枚举类的code值
+     *
+     * @return T
+     */
+    @Override
+    public String getCode() {
+        return this.name();
+    }
+
+    /**
+     * 用户登录方式有效性校验
+     * @param name 登录方式
+     * @return boolean
+     */
+    public static boolean invalid(String name) {
+        if (StringUtils.isNotEmpty(name)) {
+
+            ELoginType[] values = ELoginType.values();
+            for (ELoginType item : values) {
+
+                if (item.name().equals(name.toUpperCase())) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 获取登录方式
+     * @param dataType 登录类型
+     * @return ELoginType
+     */
+    public static ELoginType get(String dataType) {
+
+        if (StringUtils.isNoneBlank(dataType)) {
+
+            for (ELoginType item : ELoginType.values()) {
+
+                if (item.getCode().equals(dataType.toUpperCase())) {
+                    return item;
+                }
+            }
+
+        }
+
+        return PASSWORD;
+    }
+}

+ 50 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/MWxMpService.java

@@ -0,0 +1,50 @@
+package com.yonge.cooleshow.auth.middleware.wechat;
+
+import com.microsvc.toolkit.middleware.wechat.WxMpBaseService;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * Created by Eric.Shang on 2/3/17.
+ */
+public interface MWxMpService extends WxMpBaseService {
+
+    /**
+     * 校验公众号签名
+     * @param appid 公众号标识
+     * @param timestamp 时间戳
+     * @param nonce 随机数
+     * @param signature 签名
+     * @return boolean
+     */
+    boolean checkWxMpSignature(String appid, String timestamp, String nonce, String signature);
+
+    /**
+     * 校验小程序签名
+     * @param appid 公众号标识
+     * @param timestamp 时间戳
+     * @param nonce 随机数
+     * @param signature 签名
+     * @return boolean
+     */
+    boolean checkWxMaSignature(String appid, String timestamp, String nonce, String signature);
+
+    /**
+     * 构造oauth2授权的url连接, 网页授权获取用户基本信息
+     * @param appid 公众号标识
+     * @param scope 授权类型
+     * @param state 状态
+     * @param redirectURI 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode
+     * @return String
+     */
+    String oauth2buildAuthorizationUrl(String appid, String redirectURI, String scope, String state);
+
+    /**
+     * 用code网页授权获取用户基本信息
+     * @param appid 公众号标识
+     * @param code 授权code
+     * @return String
+     * @throws WxErrorException WxErrorException
+     */
+    String getOAuth2OpenId(String appid, String code) throws WxErrorException;
+
+}

+ 43 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/WxCacheService.java

@@ -0,0 +1,43 @@
+package com.yonge.cooleshow.auth.middleware.wechat;
+
+import com.microsvc.toolkit.middleware.wechat.MWxCacheService;
+import com.yonge.cooleshow.auth.api.entity.WxConfigInfo;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateConfig;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateMessage;
+
+/**
+ * Created by Eric.Shang on 4/1/18.
+ */
+public interface WxCacheService extends MWxCacheService {
+
+    /**
+     * 模板消息内容
+     * @param appId 公众号标识
+     * @param cmd 消息类型
+     * @return WxTemplateMessage
+     */
+    WxTemplateMessage findWxTemplateMessageBaseInfo(String appId, String cmd);
+
+    /**
+     * 模板消息配置
+     * @param appId 公众号标识
+     * @param cmd 消息类型
+     * @return WxTemplateConfig
+     */
+    WxTemplateConfig findWxTemplateConfigBaseInfo(String appId, String cmd);
+
+    /**
+     * 查询公众号通知消息内容
+     * @param appId 公众号Id
+     * @return WxConfigInfo
+     */
+    WxConfigInfo findMPSubscribeNotifyMessageBaseInfo(String appId);
+
+    /**
+     * 更新公众号关注状态
+     * @param appId 应用ID
+     * @param openId 来源用户
+     * @param subscribe 订阅状态
+     */
+    void updateMpSubscribeStatusInfo(String appId, String openId, Boolean subscribe);
+}

+ 113 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/domain/WxConfigStorageWrapper.java

@@ -0,0 +1,113 @@
+package com.yonge.cooleshow.auth.middleware.wechat.domain;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
+import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
+import com.alibaba.fastjson.JSON;
+import com.yonge.cooleshow.auth.api.entity.WxConfigInfo;
+import com.yonge.cooleshow.auth.middleware.wechat.handler.WxMessageRouteEvent;
+import lombok.Data;
+import me.chanjar.weixin.mp.api.WxMpMessageRouter;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
+import me.chanjar.weixin.mp.config.WxMpConfigStorage;
+import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
+
+import java.io.Serializable;
+
+/**
+ * Created by Eric.Shang on 4/3/17.
+ */
+@Data
+public class WxConfigStorageWrapper implements Serializable {
+
+    // 公众号
+    private WxMpService wxMpService;
+    private WxMpConfigStorage storage;
+    private WxConfigInfo config;
+    private WxMpMessageRouter router;
+
+    public static WxConfigStorageWrapper build() {
+        return new WxConfigStorageWrapper();
+    }
+
+    /*
+    公共号配置
+     */
+    private WxMpConfigStorage wxMpConfigStorage() {
+        // 默认实现方式,基于内存存储
+        WxMpDefaultConfigImpl info = new WxMpDefaultConfigImpl();
+        info.setAppId(getConfig().getAppid());
+        info.setSecret(getConfig().getSecret());
+        info.setAesKey(getConfig().getAeskey());
+        info.setToken(getConfig().getToken());
+
+        return info;
+    }
+
+    public WxConfigStorageWrapper config(String config) {
+
+        this.config(JSON.parseObject(config, WxConfigInfo.class)).setStorage(wxMpConfigStorage());
+
+        WxMpService wxService = new WxMpServiceImpl();
+        wxService.setWxMpConfigStorage(getStorage());
+
+        return this.wxMpService(wxService).router(WxMessageRouteEvent.router(wxService));
+    }
+
+    public WxConfigStorageWrapper config(WxConfigInfo config) {
+        this.config = config;
+        return this;
+    }
+
+    public WxConfigStorageWrapper wxMpService(WxMpService wxMpService) {
+        this.wxMpService = wxMpService;
+        return this;
+    }
+
+    public WxConfigStorageWrapper router(WxMpMessageRouter router) {
+        this.router = router;
+        return this;
+    }
+
+    /*
+    小程序配置
+     */
+    private WxMaService wxMaService;
+    private WxMaConfig maConfig;
+    private WxMaMessageRouter maMessageRouter;
+
+    private WxMaConfig wxMaConfigStorage() {
+        // 小程序默认配置实现, 基于内存存储
+        WxMaDefaultConfigImpl info = new WxMaDefaultConfigImpl();
+        info.setAppid(getConfig().getAppid());
+        info.setSecret(getConfig().getSecret());
+        info.setAesKey(getConfig().getAeskey());
+        info.setToken(getConfig().getToken());
+
+        return info;
+    }
+
+    public WxConfigStorageWrapper maConfig(String config) {
+
+        this.config(JSON.parseObject(config, WxConfigInfo.class)).setMaConfig(wxMaConfigStorage());
+
+        WxMaService maService = new WxMaServiceImpl();
+        maService.setWxMaConfig(getMaConfig());
+
+        return this.wxMaService(maService).maMessageRouter(WxMessageRouteEvent.maRouter(maService));
+    }
+
+
+    public WxConfigStorageWrapper wxMaService(WxMaService wxMaService) {
+        this.wxMaService = wxMaService;
+        return this;
+    }
+
+    public WxConfigStorageWrapper maMessageRouter(WxMaMessageRouter maMessageRouter) {
+        this.maMessageRouter = maMessageRouter;
+        return this;
+    }
+}

+ 25 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/domain/WxContentWrapper.java

@@ -0,0 +1,25 @@
+package com.yonge.cooleshow.auth.middleware.wechat.domain;
+
+import com.alibaba.fastjson.JSONArray;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *
+ * 微信消息(图文消息,文本消息等)
+ * Created by Eric.Shang on 9/1/18.
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxContentWrapper implements Serializable {
+
+    private JSONArray welcome;
+    private String contact;
+
+}

+ 51 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/handler/WxMessageRouteEvent.java

@@ -0,0 +1,51 @@
+package com.yonge.cooleshow.auth.middleware.wechat.handler;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
+import com.microsvc.toolkit.middleware.wechat.handler.ContactUSHandler;
+import com.microsvc.toolkit.middleware.wechat.handler.LocationHandler;
+import com.microsvc.toolkit.middleware.wechat.handler.NullHandler;
+import com.microsvc.toolkit.middleware.wechat.handler.ScanHandler;
+import com.microsvc.toolkit.middleware.wechat.handler.SubscribeHandler;
+import com.microsvc.toolkit.middleware.wechat.handler.UnsubscribeHandler;
+import me.chanjar.weixin.common.api.WxConsts;
+import me.chanjar.weixin.mp.api.WxMpMessageRouter;
+import me.chanjar.weixin.mp.api.WxMpService;
+
+/**
+ * 微信消息路由配置
+ * Created by Eric.Shang on 6/3/17.
+ */
+public final class WxMessageRouteEvent {
+
+    // 联系我们事件配置
+    private static final String EVENT_KEY_CONTACT_US = "WX_CONTACT_US";
+
+    private WxMessageRouteEvent() {
+    }
+
+    /**
+     * 微信消息路由处理中心
+     * @param wxMpService 公众号实例
+     * @return WxMpMessageRouter
+     */
+    public static WxMpMessageRouter router(WxMpService wxMpService) {
+        return new WxMpMessageRouter(wxMpService)
+                .rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.SCAN).handler(new ScanHandler()).end()
+                .rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.SUBSCRIBE).handler(new SubscribeHandler()).end()
+                .rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.UNSUBSCRIBE).handler(new UnsubscribeHandler()).end()
+                .rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.LOCATION).handler(new LocationHandler()).end()
+                .rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION).handler(new LocationHandler()).end()
+                .rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.CLICK).eventKey(EVENT_KEY_CONTACT_US).handler(new ContactUSHandler()).end()
+                .rule().async(false).handler(new NullHandler()).end();
+    }
+
+    /**
+     * 小程序消息路由处理中心
+     * @param wxMaService wxMaService
+     * @return WxMaMessageRouter
+     */
+    public static WxMaMessageRouter maRouter(WxMaService wxMaService) {
+        return new WxMaMessageRouter(wxMaService).rule().end();
+    }
+}

+ 292 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/impl/MWxMpServiceImpl.java

@@ -0,0 +1,292 @@
+package com.yonge.cooleshow.auth.middleware.wechat.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaMessage;
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Maps;
+import com.microsvc.toolkit.common.tools.ThreadPool;
+import com.microsvc.toolkit.middleware.wechat.WxServiceManager;
+import com.yonge.cooleshow.auth.api.entity.WxConfigInfo;
+import com.yonge.cooleshow.auth.middleware.wechat.MWxMpService;
+import com.yonge.cooleshow.auth.middleware.wechat.WxCacheService;
+import com.yonge.cooleshow.auth.middleware.wechat.domain.WxConfigStorageWrapper;
+import com.yonge.cooleshow.auth.middleware.wechat.domain.WxContentWrapper;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage;
+import me.chanjar.weixin.mp.bean.result.WxMpUser;
+import me.chanjar.weixin.mp.config.WxMpConfigStorage;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Objects;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * 公众号事件消息通知
+ * Created by Eric.Shang on 2/3/17.
+ */
+@Slf4j
+@Service
+public class MWxMpServiceImpl implements MWxMpService {
+
+    private final ConcurrentMap<String, WxConfigStorageWrapper> wxMap = Maps.newConcurrentMap();
+
+    @Autowired
+    private WxCacheService wxCacheService;
+
+    /**
+     * 校验公众号签名
+     *
+     * @param appid 公众号标识
+     * @param timestamp 时间戳
+     * @param nonce     随机数
+     * @param signature 签名
+     * @return boolean
+     */
+    @Override
+    public boolean checkWxMpSignature(String appid, String timestamp, String nonce, String signature) {
+        WxMpService wxMpService = WxServiceManager.getInstance().getWxMpService(appid, wxCacheService);
+        if (wxMpService == null) {
+            log.warn("checkWxMpSignature invalid, appid={}, nonce={} signature={}", appid, nonce, signature);
+            return false;
+        }
+        return wxMpService.checkSignature(timestamp, nonce, signature);
+
+    }
+
+    /**
+     * 校验小程序签名
+     *
+     * @param appid 公众号标识
+     * @param timestamp 时间戳
+     * @param nonce     随机数
+     * @param signature 签名
+     * @return boolean
+     */
+    @Override
+    public boolean checkWxMaSignature(String appid, String timestamp, String nonce, String signature) {
+        WxMaService wxMaService = WxServiceManager.getInstance().getWxMaService(appid, wxCacheService);
+        if (wxMaService == null) {
+            log.warn("checkWxMaSignature invalid, appid={}, nonce={} signature={}", appid, nonce, signature);
+            return false;
+        }
+        return wxMaService.checkSignature(timestamp, nonce, signature);
+
+    }
+
+    /**
+     * 构造oauth2授权的url连接, 网页授权获取用户基本信息
+     * @param appid 公众号标识
+     * @param scope 授权类型
+     * @param state 状态
+     * @param redirectURI 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode
+     * @return String
+     */
+    @Override
+    public String oauth2buildAuthorizationUrl(String appid, String redirectURI, String scope, String state) {
+        WxMpService wxMpService = WxServiceManager.getInstance().getWxMpService(appid, wxCacheService);
+        if (wxMpService == null) {
+            log.warn("oauth2buildAuthorizationUrl invalid, appid={}, url={}, scope={}, state={}", appid, redirectURI,
+                    scope, state);
+            return "";
+        }
+        return wxMpService.getOAuth2Service().buildAuthorizationUrl(redirectURI, scope, state);
+
+    }
+
+    /**
+     * 用code网页授权获取用户基本信息
+     *
+     * @param appid 公众号标识
+     * @param code 授权code
+     * @return String
+     * @throws WxErrorException WxErrorException
+     */
+    @Override
+    public String getOAuth2OpenId(String appid, String code) throws WxErrorException {
+        WxMpService wxMpService = WxServiceManager.getInstance().getWxMpService(appid, wxCacheService);
+        if (wxMpService == null) {
+            log.warn("getOAuth2OpenId invalid, appid={}, code={}", appid, code);
+            return "";
+        }
+
+        return wxMpService.getOAuth2Service().getAccessToken(code).getOpenId();
+    }
+
+    /**
+     * 根据appid返回配置实例对象
+     *
+     * @param appid 公众号ID
+     * @return WxMpConfigStorage
+     */
+    @Override
+    public WxMpConfigStorage getWxMpConfigStorage(String appid) {
+
+        // 公众号配置信息
+        return wxMap.get(appid).getStorage();
+    }
+
+    /**
+     * 微信路由事件消息
+     *
+     * @param appId     公众号ID
+     * @param inMessage WxMpXmlMessage
+     * @return WxMpXmlOutMessage
+     */
+    @Override
+    public WxMpXmlOutMessage route(String appId, WxMpXmlMessage inMessage) {
+        if (StringUtils.isEmpty(appId)) {
+            log.warn("route invalid appid={}", appId);
+            return null;
+        }
+        if (!wxMap.containsKey(appId)) {
+            String wxConfig = wxCacheService.findWxConfigBaseInfo(appId);
+            if (StringUtils.isNotEmpty(wxConfig)) {
+                wxMap.put(appId, WxConfigStorageWrapper.build().config(wxConfig));
+            }
+        }
+        return wxMap.get(appId).getRouter().route(inMessage);
+    }
+
+    /**
+     * 关注微信公众号提示信息
+     *
+     * @param wxMpService WxMpService
+     * @param wxMessage WxMpXmlMessage
+     * @return WxMpXmlOutMessage
+     */
+    @Override
+    public WxMpXmlOutMessage wxMpSubscribePromptInfo(final WxMpService wxMpService, final WxMpXmlMessage wxMessage) {
+
+        // 查询关注公众号通知消息
+        String appId = wxMpService.getWxMpConfigStorage().getAppId();
+
+        // 获取用户信息
+        try {
+            final WxMpUser wxMpUser = wxMpService.getUserService().userInfo(wxMessage.getFromUser());
+            ThreadPool.getExecutor().submit(() -> {
+
+                // 更新公众号关注状态
+                wxCacheService.updateMpSubscribeStatusInfo(appId, wxMessage.getFromUser(), wxMpUser.getSubscribe());
+            });
+        } catch (WxErrorException e) {
+            log.error("wxMpSubscribePromptInfo openid={}", wxMessage.getFromUser(), e);
+        }
+
+        WxConfigInfo configInfo = wxCacheService.findMPSubscribeNotifyMessageBaseInfo(appId);
+        if (Objects.isNull(configInfo) || StringUtils.isBlank(configInfo.getContent())) {
+            log.warn("wxMpSubscribePromptInfo invalid req, appid={}", appId);
+            return null;
+        }
+        log.debug("wxMpSubscribePromptInfo appid={}, info={}", appId, JSON.toJSONString(configInfo));
+        // 回复图文消息
+        WxContentWrapper wrapper = JSON.parseObject(configInfo.getContent(), WxContentWrapper.class);
+
+        return WxMpXmlOutMessage.NEWS().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
+                .articles(JSON.parseArray(wrapper.getWelcome().toString(), WxMpXmlOutNewsMessage.Item.class)).build();
+    }
+
+    /**
+     * 修正用户当前位置信息
+     *
+     * @param wxMessage WxMpXmlMessage
+     * @return WxMpXmlOutMessage
+     */
+    @Override
+    public WxMpXmlOutMessage updateUserLocationInfo(WxMpXmlMessage wxMessage) {
+
+        return null;
+    }
+
+    /**
+     * 用户取消关注事件处理
+     *
+     * @param wxMessage WxMpXmlMessage
+     * @return WxMpXmlOutMessage
+     */
+    @Override
+    public WxMpXmlOutMessage wxMpUnsubscribeInfo(WxMpXmlMessage wxMessage) {
+
+        // 公众号取消关注通知
+        wxCacheService.updateMpSubscribeStatusInfo("", wxMessage.getFromUser(), false);
+
+        return null;
+    }
+
+    /**
+     * 微信扫码消息通知
+     *
+     * @param wxMessage WxMpXmlMessage
+     * @return WxMpXmlOutMessage
+     */
+    @Override
+    public WxMpXmlOutMessage wxScanNotifyInfo(WxMpXmlMessage wxMessage) {
+        /*
+        * 扫描带参数二维码事件
+        *
+        * 消息事件类型:
+        * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140454
+        * */
+
+        return null;
+    }
+
+    /**
+     * 微信点击联系我们
+     *
+     * @param wxMpService WxMpService
+     * @param wxMessage WxMpXmlMessage
+     * @return WxMpXmlOutMessage
+     */
+    @Override
+    public WxMpXmlOutMessage wxClickEventContactUSInfo(WxMpService wxMpService, WxMpXmlMessage wxMessage) {
+        // 查询关注公众号通知消息
+        String appid = wxMpService.getWxMpConfigStorage().getAppId();
+        WxConfigInfo configInfo = wxCacheService.findMPSubscribeNotifyMessageBaseInfo(appid);
+        if (Objects.isNull(configInfo)) {
+            log.warn("wxMpSubscribePromptInfo invalid req, appid={}", appid);
+            return null;
+        }
+        WxContentWrapper wrapper = JSON.parseObject(JSON.toJSONString(configInfo), WxContentWrapper.class);
+        return WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
+                .content(wrapper.getContact()).build();
+    }
+
+    /**
+     * 根据appid返回配置实例对象
+     * @param appid 公众号ID
+     * @return WxMpConfigStorage
+     */
+    @Override
+    public WxMaConfig getWxMaConfigStorage(String appid) {
+        // 公众号配置
+        return wxMap.get(appid).getMaConfig();
+    }
+
+    /**
+     * 小程序路由事件消息
+     * @param appid 公众号ID
+     * @param inMessage WxMpXmlMessage
+     */
+    @Override
+    public void maRoute(String appid, WxMaMessage inMessage) {
+        if (StringUtils.isNotEmpty(appid)) {
+            if (!wxMap.containsKey(appid)) {
+                String wxConfig = wxCacheService.findWxConfigBaseInfo(appid);
+                if (StringUtils.isNotEmpty(wxConfig)) {
+                    wxMap.put(appid, WxConfigStorageWrapper.build().config(wxConfig));
+                }
+            }
+            wxMap.get(appid).getMaMessageRouter().route(inMessage);
+        } else {
+            log.warn("route invalid appid={}", appid);
+        }
+    }
+
+}

+ 115 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/middleware/wechat/impl/WxCacheServiceImpl.java

@@ -0,0 +1,115 @@
+package com.yonge.cooleshow.auth.middleware.wechat.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.yonge.cooleshow.auth.api.entity.WxConfigInfo;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateConfig;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateMessage;
+import com.yonge.cooleshow.auth.middleware.wechat.WxCacheService;
+import com.yonge.cooleshow.auth.service.WxConfigInfoService;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RBucket;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.text.MessageFormat;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 微信配置信息
+ * Created by Eric.Shang on 4/1/18.
+ */
+@Slf4j
+@Service
+public class WxCacheServiceImpl implements WxCacheService {
+
+    @Autowired
+    private RedissonClient redissonClient;
+    @Autowired
+    private WxConfigInfoService wxConfigInfoService;
+
+    // 微信相关缓存信息
+    private static final String WX_CONFIG_KEY = "wxcfg:{0}"; // wxcfg:[#appid#]
+
+    /**
+     * 模板消息内容
+     *
+     * @param appId 公众号标识
+     * @param cmd 消息类型
+     * @return WxTemplateMessage
+     */
+    @Override
+    public WxTemplateMessage findWxTemplateMessageBaseInfo(String appId, String cmd) {
+
+        // 公众号模板信息内容
+        return wxConfigInfoService.findWxTemplateMessageByCommand(appId, cmd);
+    }
+
+    /**
+     * 模板消息配置
+     *
+     * @param appId 公众号标识
+     * @param cmd   消息类型
+     * @return WxTemplateConfig
+     */
+    @Override
+    public WxTemplateConfig findWxTemplateConfigBaseInfo(String appId, String cmd) {
+
+        return wxConfigInfoService.findWxTemplateConfigWhen(appId, cmd);
+    }
+
+    /**
+     * 查询公众号配置信息
+     *
+     * @param appId 公众号ID
+     * @return String
+     */
+    @Override
+    public String findWxConfigBaseInfo(String appId) {
+
+        // 缓存微信配置信息
+        String hash = MessageFormat.format(WX_CONFIG_KEY, appId);
+        RBucket<Object> bucket = redissonClient.getBucket(hash);
+        // 缓存数据已失效,重新生成缓存数据
+        if (!bucket.isExists()) {
+            WxConfigInfo config = wxConfigInfoService.findWxConfigInfoByAppId(appId);
+            if (config == null) {
+                log.warn("findWxConfigBaseInfo 公众号配置不存在, appId={}", appId);
+                return "";
+            }
+
+            // 缓存数据, 默认缓存7天
+            bucket.set(JSON.toJSONString(config), 7, TimeUnit.DAYS);
+
+            // 直接返回
+            return JSON.toJSONString(config);
+        }
+
+        return (String) bucket.get();
+    }
+
+    /**
+     * 查询公众号通知消息内容
+     *
+     * @param appId 公众号Id
+     * @return WxConfigInfo
+     */
+    @Override
+    public WxConfigInfo findMPSubscribeNotifyMessageBaseInfo(String appId) {
+
+        // 查询微信公众号配置信息
+        return wxConfigInfoService.findWxConfigInfoByAppId(appId);
+    }
+
+    /**
+     * 更新公众号关注状态
+     *
+     * @param appId     应用ID
+     * @param openId  来源用户
+     * @param subscribe 订阅状态
+     */
+    @Override
+    public void updateMpSubscribeStatusInfo(String appId, String openId, Boolean subscribe) {
+
+    }
+}

+ 16 - 4
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/SysUserService.java

@@ -1,7 +1,5 @@
 package com.yonge.cooleshow.auth.service;
 
-import java.util.List;
-
 import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
 import com.yonge.cooleshow.auth.api.dto.SysUserInfo;
 import com.yonge.cooleshow.auth.api.dto.SysUserQueryInfo;
@@ -10,10 +8,10 @@ import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.auth.api.vo.UserSetVo;
 import com.yonge.cooleshow.auth.enums.EClientType;
 import com.yonge.cooleshow.common.entity.ImUserModel;
-import com.yonge.cooleshow.common.enums.SysUserType;
-import com.yonge.cooleshow.common.enums.UserLockFlag;
 import com.yonge.toolset.mybatis.service.BaseService;
 
+import java.util.List;
+
 public interface SysUserService extends BaseService<Long, SysUser> {
 
     /**
@@ -212,5 +210,19 @@ public interface SysUserService extends BaseService<Long, SysUser> {
      */
     SysUser queryUserInfoWithIMToken(Long userId, EClientType clientType);
 
+    //根据用户类型获取机构编号
+    Long getTenantByClient(Long userId, String clientId);
+
+    /**
+     * 根据openId获取用户信息
+     * @param openId 用户openId
+     * @param clientId 客户端ID
+     * @return SysUser
+     */
+    SysUser getSysUserByOpenId(String openId, String clientId);
+
     void logoffByPhone(String phone);
+
+
+    void updateStudentHideFlag(Long userId, int hideFlag);
 }

+ 67 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/WxConfigInfoService.java

@@ -0,0 +1,67 @@
+package com.yonge.cooleshow.auth.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.yonge.cooleshow.auth.api.entity.WxConfigInfo;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateConfig;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateMessage;
+import com.yonge.cooleshow.auth.dal.wrapper.WxConfigInfoWrapper;
+
+/**
+ * 微信配置信息
+ * 2023-02-01 14:21:57
+ */
+public interface WxConfigInfoService extends IService<WxConfigInfo>  {
+
+	/**
+     * 查询详情
+     * @param id 详情ID
+     * @return WxConfigInfo
+     */
+	WxConfigInfo detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<WxConfigInfo>
+     * @param query WxConfigInfoWrapper.WxConfigInfoQuery
+     * @return IPage<WxConfigInfo>
+     */
+    IPage<WxConfigInfo> selectPage(IPage<WxConfigInfo> page, WxConfigInfoWrapper.WxConfigInfoQuery query);
+
+    /**
+     * 添加
+     * @param wxConfigInfo WxConfigInfoWrapper.WxConfigInfo
+     * @return Boolean
+     */
+     Boolean add(WxConfigInfoWrapper.WxConfigInfo wxConfigInfo);
+
+    /**
+     * 更新
+     * @param wxConfigInfo WxConfigInfoWrapper.WxConfigInfo
+     * @return Boolean
+     */
+     Boolean update(WxConfigInfoWrapper.WxConfigInfo wxConfigInfo);
+
+    /**
+     * 公众号模板信息内容
+     * @param appId 公众号Id
+     * @param cmd 消息指令
+     * @return WxTemplateMessage
+     */
+    WxTemplateMessage findWxTemplateMessageByCommand(String appId, String cmd);
+
+    /**
+     * 公众号模板消息配置
+     * @param appId 公众号Id
+     * @param cmd 指令
+     * @return WxTemplateConfig
+     */
+    WxTemplateConfig findWxTemplateConfigWhen(String appId, String cmd);
+
+    /**
+     * 公众号配置
+     * @param appId 公众号Id
+     * @return WxConfigInfo
+     */
+    WxConfigInfo findWxConfigInfoByAppId(String appId);
+}

+ 43 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/WxTemplateConfigService.java

@@ -0,0 +1,43 @@
+package com.yonge.cooleshow.auth.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateConfig;
+import com.yonge.cooleshow.auth.dal.wrapper.WxTemplateConfigWrapper;
+
+/**
+ * 微信模板配置
+ * 2023-02-01 14:21:57
+ */
+public interface WxTemplateConfigService extends IService<WxTemplateConfig>  {
+
+	/**
+     * 查询详情
+     * @param id 详情ID
+     * @return WxTemplateConfig
+     */
+	WxTemplateConfig detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<WxTemplateConfig>
+     * @param query WxTemplateConfigWrapper.WxTemplateConfigQuery
+     * @return IPage<WxTemplateConfig>
+     */
+    IPage<WxTemplateConfig> selectPage(IPage<WxTemplateConfig> page, WxTemplateConfigWrapper.WxTemplateConfigQuery query);
+
+    /**
+     * 添加
+     * @param wxTemplateConfig WxTemplateConfigWrapper.WxTemplateConfig
+     * @return Boolean
+     */
+     Boolean add(WxTemplateConfigWrapper.WxTemplateConfig wxTemplateConfig);
+
+    /**
+     * 更新
+     * @param wxTemplateConfig WxTemplateConfigWrapper.WxTemplateConfig
+     * @return Boolean
+     */
+     Boolean update(WxTemplateConfigWrapper.WxTemplateConfig wxTemplateConfig);
+
+}

+ 43 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/WxTemplateMessageService.java

@@ -0,0 +1,43 @@
+package com.yonge.cooleshow.auth.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateMessage;
+import com.yonge.cooleshow.auth.dal.wrapper.WxTemplateMessageWrapper;
+
+/**
+ * 微信模板消息内容
+ * 2023-02-01 14:21:57
+ */
+public interface WxTemplateMessageService extends IService<WxTemplateMessage>  {
+
+	/**
+     * 查询详情
+     * @param id 详情ID
+     * @return WxTemplateMessage
+     */
+	WxTemplateMessage detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<WxTemplateMessage>
+     * @param query WxTemplateMessageWrapper.WxTemplateMessageQuery
+     * @return IPage<WxTemplateMessage>
+     */
+    IPage<WxTemplateMessage> selectPage(IPage<WxTemplateMessage> page, WxTemplateMessageWrapper.WxTemplateMessageQuery query);
+
+    /**
+     * 添加
+     * @param wxTemplateMessage WxTemplateMessageWrapper.WxTemplateMessage
+     * @return Boolean
+     */
+     Boolean add(WxTemplateMessageWrapper.WxTemplateMessage wxTemplateMessage);
+
+    /**
+     * 更新
+     * @param wxTemplateMessage WxTemplateMessageWrapper.WxTemplateMessage
+     * @return Boolean
+     */
+     Boolean update(WxTemplateMessageWrapper.WxTemplateMessage wxTemplateMessage);
+
+}

+ 44 - 12
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/SysUserServiceImpl.java

@@ -4,7 +4,11 @@ import com.alibaba.fastjson.JSON;
 import com.google.common.collect.Lists;
 import com.yonge.cooleshow.api.feign.AdminFeignService;
 import com.yonge.cooleshow.api.feign.dto.UserFriendInfoVO;
-import com.yonge.cooleshow.auth.api.dto.*;
+import com.yonge.cooleshow.auth.api.dto.QRLoginDto;
+import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
+import com.yonge.cooleshow.auth.api.dto.SysUserInfo;
+import com.yonge.cooleshow.auth.api.dto.SysUserQueryInfo;
+import com.yonge.cooleshow.auth.api.dto.UserSetReq;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.auth.api.vo.UserSetVo;
 import com.yonge.cooleshow.auth.config.CustomerServiceConfig;
@@ -42,6 +46,7 @@ import java.text.MessageFormat;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Random;
 import java.util.stream.Collectors;
 
@@ -115,12 +120,12 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
         userInfo.setSysUser(sysUser);
 
         List<String> roleCodeList = sysUserRoleService.queryRoleCodeListByUserId(sysUser.getId());
-        userInfo.setRoles(roleCodeList.toArray(new String[roleCodeList.size()]));
+        userInfo.setRoles(roleCodeList.toArray(new String[0]));
 
         List<Long> roleIdList = sysUserRoleService.queryRoleIdListByUserId(sysUser.getId());
         List<String> permissionList = sysRoleMenuService.queryPermissionsByRoleIdList(roleIdList);
 
-        userInfo.setPermissions(permissionList.toArray(new String[permissionList.size()]));
+        userInfo.setPermissions(permissionList.toArray(new String[0]));
 
         return userInfo;
     }
@@ -286,6 +291,19 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
         }
         //更新融云用户基本信息
         this.updateRongCloudUserInfo(id, setReq.getClientType());
+
+        // 更新老师、学生头像
+        String clientId = setReq.getClientId();
+        if(StringUtils.isEmpty(clientId)) {
+            clientId =setReq.getClientType();
+        }
+        if (StringUtils.isNotEmpty(setReq.getAvatar()) && StringUtils.isNotEmpty(clientId)) {
+            if (EClientType.STUDENT.getCode().equals(setReq.getClientType()) ||
+                    EClientType.TEACHER.getCode().equals(setReq.getClientType()) ||
+                    EClientType.SYSTEM.getCode().equals(setReq.getClientType())) {
+                sysUserDao.updateAvatar(clientId, setReq.getAvatar(), id);
+            }
+        }
     }
 
     @Override
@@ -368,17 +386,8 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
         SysUser sysUser = sysUserDao.get(userId);
 
         if (EClientType.STUDENT == clientType && Objects.nonNull(sysUser)) {
-
             // 重新请求生成IM会话TOKEN
             try {
-
-                /*HttpResponseResult<Boolean> recv = teacherFeignService.userTeacherIdentityInfo(userId);
-
-                if (Objects.nonNull(recv) && recv.getData()) {
-                    // 同时一个手机号,拥手老师、学生身份时,为学生创建新的IMToken
-
-                }*/
-
                 String name = sysUser.getUsername();
                 if(StringUtils.isEmpty(name)){
                     name = sysUser.getRealName();
@@ -404,6 +413,24 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
     }
 
     @Override
+    public Long getTenantByClient(Long userId, String clientId) {
+        // 查询用户机构信息,若没有则返回-1
+        return Optional.ofNullable(sysUserDao.getTenantByClient(userId, clientId.toUpperCase())).orElse(-1L);
+    }
+
+    /**
+     * 根据openId获取用户信息
+     *
+     * @param openId 用户openId
+     * @param clientId 客户端ID
+     * @return SysUser
+     */
+    @Override
+    public SysUser getSysUserByOpenId(String openId, String clientId) {
+        return sysUserDao.getSysUserByOpenId(openId, clientId);
+    }
+
+    @Override
     @Transactional(rollbackFor = Exception.class)
     public void logoffByPhone(String phone) {
         int num = sysUserDao.countByPhone(phone);
@@ -417,4 +444,9 @@ public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implement
         //退出登录
         tokenService.revokeTokenByPhone(phone);
     }
+
+    @Override
+    public void updateStudentHideFlag(Long userId, int hideFlag) {
+        sysUserDao.updateStudentHideFlag(userId, hideFlag);
+    }
 }

+ 145 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/WxConfigInfoServiceImpl.java

@@ -0,0 +1,145 @@
+package com.yonge.cooleshow.auth.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.auth.api.entity.WxConfigInfo;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateConfig;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateMessage;
+import com.yonge.cooleshow.auth.dal.dao.WxConfigInfoMapper;
+import com.yonge.cooleshow.auth.dal.wrapper.WxConfigInfoWrapper;
+import com.yonge.cooleshow.auth.service.WxConfigInfoService;
+import com.yonge.cooleshow.auth.service.WxTemplateConfigService;
+import com.yonge.cooleshow.auth.service.WxTemplateMessageService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 微信配置信息
+ * 2023-02-01 14:21:57
+ */
+@Slf4j
+@Service
+public class WxConfigInfoServiceImpl extends ServiceImpl<WxConfigInfoMapper, WxConfigInfo> implements WxConfigInfoService {
+
+    @Autowired
+    private WxTemplateConfigService wxTemplateConfigService;
+    @Autowired
+    private WxTemplateMessageService wxTemplateMessageService;
+
+	/**
+     * 查询详情
+     * @param id 详情ID
+     * @return WxConfigInfo
+     */
+	@Override
+    public WxConfigInfo detail(Long id) {
+
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 分页查询
+     * @param page IPage<WxConfigInfo>
+     * @param query WxConfigInfoWrapper.WxConfigInfoQuery
+     * @return IPage<WxConfigInfo>
+     */
+    @Override
+    public IPage<WxConfigInfo> selectPage(IPage<WxConfigInfo> page, WxConfigInfoWrapper.WxConfigInfoQuery query) {
+
+        return page.setRecords(baseMapper.selectPage(page, query));
+    }
+
+    /**
+     * 添加
+     * @param wxConfigInfo WxConfigInfoWrapper.WxConfigInfo
+     * @return Boolean
+     */
+    @Override
+    public Boolean add(WxConfigInfoWrapper.WxConfigInfo wxConfigInfo) {
+
+        return this.save(JSON.parseObject(wxConfigInfo.jsonString(), WxConfigInfo.class));
+    }
+
+    /**
+     * 更新
+     * @param wxConfigInfo WxConfigInfoWrapper.WxConfigInfo
+     * @return Boolean
+     */
+    @Override
+    public Boolean update(WxConfigInfoWrapper.WxConfigInfo wxConfigInfo){
+
+        return this.updateById(JSON.parseObject(wxConfigInfo.jsonString(), WxConfigInfo.class));
+    }
+
+    /**
+     * 公众号模板信息内容
+     *
+     * @param appId 公众号Id
+     * @param cmd   消息指令
+     * @return WxTemplateMessage
+     */
+    @Override
+    public WxTemplateMessage findWxTemplateMessageByCommand(String appId, String cmd) {
+
+        List<WxTemplateMessage> records = wxTemplateMessageService.lambdaQuery()
+            .eq(WxTemplateMessage::getAppid, appId)
+            .eq(WxTemplateMessage::getCommand, cmd)
+            .eq(WxTemplateMessage::getStatus, true)
+            .list();
+
+        if (CollectionUtils.isEmpty(records)) {
+            return null;
+        }
+
+        return records.get(0);
+    }
+
+    /**
+     * 公众号模板消息配置
+     *
+     * @param appId 公众号Id
+     * @param cmd   指令
+     * @return WxTemplateConfig
+     */
+    @Override
+    public WxTemplateConfig findWxTemplateConfigWhen(String appId, String cmd) {
+
+        List<WxTemplateConfig> records = wxTemplateConfigService.lambdaQuery()
+            .eq(WxTemplateConfig::getAppid, appId)
+            .eq(WxTemplateConfig::getCommand, cmd)
+            .eq(WxTemplateConfig::getStatus, true)
+            .list();
+
+        if (CollectionUtils.isEmpty(records)) {
+            return null;
+        }
+
+        return records.get(0);
+    }
+
+    /**
+     * 公众号配置
+     *
+     * @param appId 公众号Id
+     * @return WxConfigInfo
+     */
+    @Override
+    public WxConfigInfo findWxConfigInfoByAppId(String appId) {
+
+        List<WxConfigInfo> records = lambdaQuery()
+            .eq(WxConfigInfo::getAppid, appId)
+            .eq(WxConfigInfo::getStatus, true)
+            .list();
+
+        if (CollectionUtils.isEmpty(records)) {
+            return null;
+        }
+
+        return records.get(0);
+    }
+}

+ 65 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/WxTemplateConfigServiceImpl.java

@@ -0,0 +1,65 @@
+package com.yonge.cooleshow.auth.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateConfig;
+import com.yonge.cooleshow.auth.dal.dao.WxTemplateConfigMapper;
+import com.yonge.cooleshow.auth.dal.wrapper.WxTemplateConfigWrapper;
+import com.yonge.cooleshow.auth.service.WxTemplateConfigService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * 微信模板配置
+ * 2023-02-01 14:21:57
+ */
+@Slf4j
+@Service
+public class WxTemplateConfigServiceImpl extends ServiceImpl<WxTemplateConfigMapper, WxTemplateConfig> implements WxTemplateConfigService {
+
+	/**
+     * 查询详情
+     * @param id 详情ID
+     * @return WxTemplateConfig
+     */
+	@Override
+    public WxTemplateConfig detail(Long id) {
+
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 分页查询
+     * @param page IPage<WxTemplateConfig>
+     * @param query WxTemplateConfigWrapper.WxTemplateConfigQuery
+     * @return IPage<WxTemplateConfig>
+     */
+    @Override
+    public IPage<WxTemplateConfig> selectPage(IPage<WxTemplateConfig> page, WxTemplateConfigWrapper.WxTemplateConfigQuery query) {
+
+        return page.setRecords(baseMapper.selectPage(page, query));
+    }
+
+    /**
+     * 添加
+     * @param wxTemplateConfig WxTemplateConfigWrapper.WxTemplateConfig
+     * @return Boolean
+     */
+    @Override
+    public Boolean add(WxTemplateConfigWrapper.WxTemplateConfig wxTemplateConfig) {
+
+        return this.save(JSON.parseObject(wxTemplateConfig.jsonString(), WxTemplateConfig.class));
+    }
+
+    /**
+     * 更新
+     * @param wxTemplateConfig WxTemplateConfigWrapper.WxTemplateConfig
+     * @return Boolean
+     */
+    @Override
+    public Boolean update(WxTemplateConfigWrapper.WxTemplateConfig wxTemplateConfig){
+
+        return this.updateById(JSON.parseObject(wxTemplateConfig.jsonString(), WxTemplateConfig.class));
+    }
+}

+ 65 - 0
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/service/impl/WxTemplateMessageServiceImpl.java

@@ -0,0 +1,65 @@
+package com.yonge.cooleshow.auth.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.auth.api.entity.WxTemplateMessage;
+import com.yonge.cooleshow.auth.dal.dao.WxTemplateMessageMapper;
+import com.yonge.cooleshow.auth.dal.wrapper.WxTemplateMessageWrapper;
+import com.yonge.cooleshow.auth.service.WxTemplateMessageService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * 微信模板消息内容
+ * 2023-02-01 14:21:57
+ */
+@Slf4j
+@Service
+public class WxTemplateMessageServiceImpl extends ServiceImpl<WxTemplateMessageMapper, WxTemplateMessage> implements WxTemplateMessageService {
+
+	/**
+     * 查询详情
+     * @param id 详情ID
+     * @return WxTemplateMessage
+     */
+	@Override
+    public WxTemplateMessage detail(Long id) {
+
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 分页查询
+     * @param page IPage<WxTemplateMessage>
+     * @param query WxTemplateMessageWrapper.WxTemplateMessageQuery
+     * @return IPage<WxTemplateMessage>
+     */
+    @Override
+    public IPage<WxTemplateMessage> selectPage(IPage<WxTemplateMessage> page, WxTemplateMessageWrapper.WxTemplateMessageQuery query) {
+
+        return page.setRecords(baseMapper.selectPage(page, query));
+    }
+
+    /**
+     * 添加
+     * @param wxTemplateMessage WxTemplateMessageWrapper.WxTemplateMessage
+     * @return Boolean
+     */
+    @Override
+    public Boolean add(WxTemplateMessageWrapper.WxTemplateMessage wxTemplateMessage) {
+
+        return this.save(JSON.parseObject(wxTemplateMessage.jsonString(), WxTemplateMessage.class));
+    }
+
+    /**
+     * 更新
+     * @param wxTemplateMessage WxTemplateMessageWrapper.WxTemplateMessage
+     * @return Boolean
+     */
+    @Override
+    public Boolean update(WxTemplateMessageWrapper.WxTemplateMessage wxTemplateMessage){
+
+        return this.updateById(JSON.parseObject(wxTemplateMessage.jsonString(), WxTemplateMessage.class));
+    }
+}

+ 9 - 6
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/TokenController.java

@@ -33,7 +33,6 @@ import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.oauth2.common.OAuth2AccessToken;
 import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
-import org.springframework.security.oauth2.provider.token.TokenStore;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -49,6 +48,7 @@ import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.Base64;
 import java.util.Calendar;
+import java.util.Locale;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
@@ -64,9 +64,6 @@ public class TokenController extends BaseController {
     private ResourceServerTokenServices resourceServerTokenServices;
 
     @Autowired
-    private TokenStore tokenStore;
-
-    @Autowired
     private RestTemplate restTemplate;
 
     @Autowired
@@ -88,6 +85,7 @@ public class TokenController extends BaseController {
             @ApiImplicitParam(name = "phone", value = "手机号", required = true, dataType = "String"),
             @ApiImplicitParam(name = "smsCode", value = "验证码", required = true, dataType = "String"),
             @ApiImplicitParam(name = "isSurportRegister", value = "是否在登录时注册", dataType = "Boolean"),
+            @ApiImplicitParam(name = "loginType", value = "登陆类型", dataType = "String", defaultValue = "PASSWORD"),
             @ApiImplicitParam(name = "loginUserType", value = "登录用户类型 STUDENT TEACHER(官网登录)", dataType = "String")
     })
     public Object smsLogin() {
@@ -98,7 +96,11 @@ public class TokenController extends BaseController {
     public SysUser queryUserInfo() {
         AuthUser authUser = SecurityUtils.getUser();
         if (authUser != null) {
-            return userService.get(authUser.getUserId());
+            // 获取用户信息
+            SysUser sysUser = userService.get(authUser.getUserId());
+            // 获取用户机构信息
+            sysUser.setTenantId(userService.getTenantByClient(authUser.getUserId(),authUser.getClientId()));
+            return sysUser;
         }
         return null;
     }
@@ -108,6 +110,7 @@ public class TokenController extends BaseController {
     public Object apiQueryUserInfo(@RequestParam(value = "clientType", required = false, defaultValue = "TEACHER") String clientType) {
 
         // 校验客户端类型
+        clientType = clientType.toUpperCase(Locale.ENGLISH);
         if (EClientType.invalid(clientType)) {
             return failed("无效的客户端类型");
         }
@@ -115,7 +118,7 @@ public class TokenController extends BaseController {
         AuthUser authUser = SecurityUtils.getUser();
         if (authUser != null) {
             SysUser sysUser = userService.queryUserInfo(authUser.getUserId());
-
+            sysUser.setTenantId(userService.getTenantByClient(authUser.getUserId(),authUser.getClientId()));
             ImUserInfo register = adminFeignService.register(sysUser.getId().toString(), clientType, sysUser.getUsername(), sysUser.getAvatar());
 
             sysUser.setImToken(register.getImToken());

+ 52 - 9
cooleshow-auth/auth-server/src/main/java/com/yonge/cooleshow/auth/web/controller/UserController.java

@@ -6,6 +6,7 @@ import com.yonge.cooleshow.auth.api.dto.UpdatePasswordDto;
 import com.yonge.cooleshow.auth.api.dto.UserSetReq;
 import com.yonge.cooleshow.auth.api.entity.SysRole;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.auth.api.entity.UserPassword;
 import com.yonge.cooleshow.auth.api.vo.UserSetVo;
 import com.yonge.cooleshow.auth.core.service.CustomTokenServices;
 import com.yonge.cooleshow.auth.service.SysConfigService;
@@ -40,18 +41,15 @@ import org.springframework.http.MediaType;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
 import java.text.MessageFormat;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 @RestController()
@@ -133,6 +131,11 @@ public class UserController extends BaseController {
         return sysUserService.get(userId);
     }
 
+    @GetMapping(value = "/getTenantByClient")
+    public HttpResponseResult<Long> getTenantByClient(@RequestParam("userId")Long userId, @RequestParam("clientId")String clientId) {
+        return HttpResponseResult.succeed(sysUserService.getTenantByClient(userId,clientId));
+    }
+
     @PostMapping(value = "/updateSysUser", consumes = MediaType.APPLICATION_JSON_VALUE)
     public HttpResponseResult<Boolean> updateSysUser(@RequestBody SysUser user) {
         user.setUpdateTime(new Date());
@@ -149,8 +152,9 @@ public class UserController extends BaseController {
     @ApiOperation(value = "设置用户密码")
     @PostMapping(value = "/setPassword", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
     @ApiImplicitParams({@ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String"),
-            @ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Long")})
-    public Object setPassword(String password, Long id) {
+            @ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Long"),
+            @ApiImplicitParam(name = "code", value = "验证码", required = false, dataType = "String")})
+    public Object setPassword(String password, Long id,String code) {
         if (StringUtils.isEmpty(password) || null == id) {
             return failed("参数校验失败");
         }
@@ -158,6 +162,12 @@ public class UserController extends BaseController {
         if (sysUser == null) {
             return failed("用户不存在");
         }
+        if(StringUtils.isNotEmpty(code)){
+            if (!smsCodeService.verifyValidCode(sysUser.getPhone(), code,
+                    "SMS_VERIFY_CODE_UPDATE_PSW")) {
+                return failed("验证码错误");
+            }
+        }
 
         password = new BCryptPasswordEncoder().encode(password);
         sysUser.setPassword(password);
@@ -662,4 +672,37 @@ public class UserController extends BaseController {
     public HttpResponseResult<List<SysUser>> page(@RequestBody SysUserQueryInfo queryInfo) {
         return succeed(sysUserService.queryEmployeeList(queryInfo));
     }
+
+    @ApiOperation(value = "获取配置的客服电话和邮箱")
+    @PostMapping(value = "/queryConfig")
+    public HttpResponseResult<Map<String,String>> queryConfig() {
+        Map<String,String> result = new HashMap<>(2);
+        result.put("customerServiceEmail",sysConfigService.findConfigValue("customer_service_email"));
+        result.put("customerServicePhone",sysConfigService.findConfigValue("customer_service_phone"));
+        return succeed(result);
+    }
+
+    @PostMapping("/checkPassword")
+    @ApiOperation(value = "校验密码")
+    public Object checkPassword(@Validated @RequestBody UserPassword.CheckPassword checkPassword){
+        AuthUser authUser = SecurityUtils.getUser();
+        SysUser sysUser = sysUserService.get(authUser.getUserId());
+        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+        if(!encoder.matches(checkPassword.getPassword(),sysUser.getPassword())){
+            throw new BizException("原密码错误");
+        }
+        return succeed();
+    }
+
+    @PostMapping("/checkVerityCode")
+    @ApiOperation(value = "校验验证码")
+    public Object checkVerityCode(@Validated @RequestBody UserPassword.CheckVerityCode checkVerityCode) {
+        AuthUser authUser = SecurityUtils.getUser();
+        SysUser sysUser = sysUserService.get(authUser.getUserId());
+        if (!smsCodeService.verifyValidCode(sysUser.getPhone(), checkVerityCode.getCode(),
+                "SMS_VERIFY_CODE_UPDATE_PSW")) {
+            return failed("验证码错误");
+        }
+        return succeed();
+    }
 }

+ 55 - 1
cooleshow-auth/auth-server/src/main/resources/config/mybatis/SysUserMapper.xml

@@ -31,6 +31,7 @@
         <result column="is_super_admin_" property="isSuperAdmin"/>
         <result column="certificate_type_" property="certificateType"/>
         <result column="last_username_time_" property="lastUsernameTime"/>
+        <result column="tenant_id_" property="tenantId"/>
     </resultMap>
 
     <!-- 查询条件 -->
@@ -75,7 +76,7 @@
         ON DUPLICATE KEY UPDATE user_id_ = VALUES(user_id_)
     </insert>
     <insert id="saveStudent">
-        INSERT INTO student (user_id_,create_time_,update_time_) VALUES(#{userId},NOW(),NOW())
+        INSERT INTO student (user_id_,create_time_,update_time_,hide_flag_) VALUES(#{userId},NOW(),NOW(),0)
         ON DUPLICATE KEY UPDATE user_id_ = VALUES(user_id_)
     </insert>
 
@@ -304,6 +305,24 @@
         where cs.teacher_id_ = #{userId}
           and status_ in ('NOT_START','ING')
     </select>
+    <select id="getTenantByClient" resultType="java.lang.Long">
+        select tenant_id_ from
+        <choose>
+            <when test="clientId == 'STUDENT'">
+                student
+            </when>
+            <when test="clientId == 'TEACHER'">
+                teacher
+            </when>
+            <when test="clientId == 'ORGANIZATION'">
+                tenant_staff
+            </when>
+            <otherwise>
+                employee
+            </otherwise>
+        </choose>
+        where user_id_ = #{userId}
+    </select>
 
     <update id="updateLockStatus">
         <if test="sysUserType == 'STUDENT'">
@@ -328,4 +347,39 @@
         SELECT count(1) FROM sys_user WHERE phone_ LIKE CONCAT('%',#{phone},'%')
     </select>
 
+    <select id="getSysUserByOpenId" resultType="com.yonge.cooleshow.auth.api.entity.SysUser">
+        SELECT t1.*
+        FROM sys_user t1 LEFT JOIN
+        <choose>
+            <when test="clientId == 'STUDENT'">
+                student
+            </when>
+            <when test="clientId == 'TEACHER'">
+                teacher
+            </when>
+            <when test="clientId == 'ORGANIZATION'">
+                tenant_staff
+            </when>
+            <otherwise>
+                employee
+            </otherwise>
+        </choose> t2 ON (t1.id_ = t2.user_id_)
+        WHERE t1.del_flag_ = 0 and t2.wx_openid_ = #{openId} LIMIT 1
+    </select>
+
+    <update id="updateStudentHideFlag">
+        update student set hide_flag_ = #{hideFlag} where user_id_ = #{userId}
+    </update>
+
+    <update id="updateAvatar">
+        <if test="clientId == 'STUDENT'">
+            update student set avatar_ = #{avatar} where user_id_ = #{id}
+        </if>
+        <if test="clientId == 'TEACHER'">
+            update teacher set avatar_ = #{avatar} where user_id_ = #{id}
+        </if>
+        <if test="clientId == 'SYSTEM'">
+            update sys_user set avatar_ = #{avatar} where id_ = #{id}
+        </if>
+    </update>
 </mapper>

+ 35 - 0
cooleshow-auth/auth-server/src/main/resources/config/mybatis/WxConfigInfoMapper.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE  mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.yonge.cooleshow.auth.dal.dao.WxConfigInfoMapper">
+
+
+
+    <!-- 表字段 -->
+    <sql id="baseColumns">
+         t.id AS id
+        , t.mp_name AS mpName
+        , t.appid AS appid
+        , t.secret AS secret
+        , t.token AS token
+        , t.aeskey AS aeskey
+        , t.content AS content
+        , t.merchant_id AS merchantId
+        , t.merchant_key AS merchantKey
+        , t.notify_url AS notifyUrl
+        , t.trade_type AS tradeType
+        , t.sign_type AS signType
+        , t.subscribe_url AS subscribeUrl
+        , t.mp_app_id AS mpAppId
+        , t.mp_type AS mpType
+        , t.is_global AS isGlobal
+        , t.status AS status
+        , t.create_time AS createTime
+        </sql>
+
+    <select id="selectPage" resultType="com.yonge.cooleshow.auth.api.entity.WxConfigInfo">
+		SELECT
+        	<include refid="baseColumns" />
+		FROM wx_config_info t
+	</select>
+
+</mapper>

+ 25 - 0
cooleshow-auth/auth-server/src/main/resources/config/mybatis/WxTemplateConfigMapper.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE  mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.yonge.cooleshow.auth.dal.dao.WxTemplateConfigMapper">
+
+
+
+    <!-- 表字段 -->
+    <sql id="baseColumns">
+         t.id AS id
+        , t.appid AS appid
+        , t.command AS command
+        , t.wx_template_id AS wxTemplateId
+        , t.url AS url
+        , t.description AS description
+        , t.status AS status
+        , t.create_time AS createTime
+        </sql>
+
+    <select id="selectPage" resultType="com.yonge.cooleshow.auth.api.entity.WxTemplateConfig">
+		SELECT
+        	<include refid="baseColumns" />
+		FROM wx_template_config t
+	</select>
+
+</mapper>

+ 27 - 0
cooleshow-auth/auth-server/src/main/resources/config/mybatis/WxTemplateMessageMapper.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE  mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.yonge.cooleshow.auth.dal.dao.WxTemplateMessageMapper">
+
+
+
+    <!-- 表字段 -->
+    <sql id="baseColumns">
+         t.id AS id
+        , t.appid AS appid
+        , t.command AS command
+        , t.content AS content
+        , t.title AS title
+        , t.version AS version
+        , t.type AS type
+        , t.description AS description
+        , t.status AS status
+        , t.create_time AS createTime
+        </sql>
+
+    <select id="selectPage" resultType="com.yonge.cooleshow.auth.api.entity.WxTemplateMessage">
+		SELECT
+        	<include refid="baseColumns" />
+		FROM wx_template_message t
+	</select>
+
+</mapper>

+ 1 - 1
cooleshow-cms/src/main/java/com/yonge/cooleshow/cms/controller/NewsController.java

@@ -118,7 +118,7 @@ public class NewsController extends BaseController {
 					return failed("封面不能为空");
 				}
 			} else if ("VIDEO".equals(newsInfo.getAttribute2())){
-				if (StringUtil.isEmpty(newsInfo.getLinkUrl())) {
+				if (StringUtil.isEmpty(newsInfo.getVideoCoverImage())) {
 					return failed("视频地址不能为空");
 				}
 			}

+ 11 - 0
cooleshow-common/pom.xml

@@ -60,5 +60,16 @@
 			<artifactId>mybatis-plus-annotation</artifactId>
 			<version>3.0.7.1</version>
 		</dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-core</artifactId>
+            <version>5.8.9</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-extra</artifactId>
+            <version>5.8.9</version>
+        </dependency>
 	</dependencies>
 </project>

+ 4 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/constant/AppConstant.java

@@ -23,6 +23,10 @@ public interface AppConstant {
      */
     String APPLICATION_ADMIN = "admin";
     /**
+     * 管理端
+     */
+    String APPLICATION_TENANT = "tenant";
+    /**
      * 老师端
      */
     String APPLICATION_TEACHER = "teacher";

+ 39 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/constant/SysConfigConstant.java

@@ -369,4 +369,43 @@ public interface SysConfigConstant {
      */
     String ICON_FANS_GROUP_DEFAULT = "icon_fans_group_default";
 
+
+    /**
+     * 客服电话
+     */
+    String CUSTOMER_SERVICE_PHONE = "customer_service_phone";
+
+    /**
+     * 客服邮箱
+     */
+    String CUSTOMER_SERVICE_EMAIL = "customer_service_email";
+
+    /**
+     * 机构人员解绑申请超时时间,天
+     */
+    String TENANT_USER_UNBIND_EXPIRE_TIME = "tenant_user_unbind_expire_time";
+
+    /**
+     * 机构人员解绑手机号
+     */
+    String TENANT_USER_UNBIND_PHONE = "tenant_user_unbind_phone";
+    /**
+     *  子账户创建回调url
+     */
+    String SUB_ACCOUNT_CREATE_CALLBACK_URL = "sub_account_create_callback_url";
+
+    /**
+     * 机构默认logo
+     */
+    String TENANT_DEFAULT_HEAD = "tenant_default_head";
+
+    /**
+     * 老师默认头像
+     */
+    String TEACHER_AVATAR = "teacher_avatar";
+
+    /**
+     * 学生默认头像
+     */
+    String STUDENT_AVATAR = "student_avatar";
 }

+ 21 - 15
cooleshow-common/src/main/java/com/yonge/cooleshow/common/controller/BaseController.java

@@ -1,14 +1,11 @@
 package com.yonge.cooleshow.common.controller;
 
-import java.net.URLEncoder;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import javax.servlet.http.HttpServletRequest;
-
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.exception.ThirdpartyException;
+import com.yonge.toolset.utils.http.HttpUtil;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.exception.ExceptionUtils;
@@ -23,12 +20,13 @@ import org.springframework.web.bind.MethodArgumentNotValidException;
 import org.springframework.web.bind.annotation.ControllerAdvice;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.yonge.cooleshow.common.entity.HttpResponseResult;
-import com.yonge.toolset.base.exception.BizException;
-import com.yonge.toolset.base.exception.ThirdpartyException;
-import com.yonge.toolset.utils.http.HttpUtil;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @ControllerAdvice
 public class BaseController {
@@ -111,6 +109,14 @@ public class BaseController {
             if (e.getMessage().equals("205")) {
                 return failed(HttpStatus.RESET_CONTENT, e.getMessage());
             }
+
+            // 自定义错误码
+            if (e instanceof BizException) {
+                BizException bizException = (BizException) e;
+                return getResponseData(false, bizException.getCode(), null, bizException.getMessage());
+            }
+
+            // 默认返回错误码
             return failed(e.getMessage());
         } else if (e instanceof AccessDeniedException) {
             return failed("禁止访问");

+ 3 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/entity/BaseEntity.java

@@ -1,7 +1,10 @@
 package com.yonge.cooleshow.common.entity;
 
+import lombok.Data;
+
 import java.io.Serializable;
 
+@Data
 public class BaseEntity implements Serializable {
 
 }

+ 30 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EActivationCode.java

@@ -0,0 +1,30 @@
+package com.yonge.cooleshow.common.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum EActivationCode implements BaseEnum<String, EActivationCode> {
+
+    SEND("已发"),
+    WAIT("未发"),
+    ;
+
+    @EnumValue
+    private String code;
+
+    private String desc;
+
+    EActivationCode(String desc) {
+        this.code = this.name();
+        this.desc = desc;
+    }
+
+    @Override
+    public String getCode() {
+        return name();
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 34 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EImportType.java

@@ -0,0 +1,34 @@
+package com.yonge.cooleshow.common.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+ * 活动类型 EVALUATION 评测活动
+ *
+ * @Author: liweifan
+ * @Data: 2022/4/7 15:48
+ */
+public enum EImportType implements BaseEnum<String, EImportType> {
+
+    TENANT("机构收入")
+    ;
+
+    @EnumValue
+    private String code;
+    private String msg;
+
+    EImportType(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 31 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EPayerType.java

@@ -0,0 +1,31 @@
+package com.yonge.cooleshow.common.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum EPayerType implements BaseEnum<String, EPayerType> {
+
+    ADAPAY("adapay"),
+    YEEPAY("yeepay"),
+    ORIGINAL("original"),
+    ;
+
+    @EnumValue
+    private String code;
+
+    private String desc;
+
+    EPayerType(String desc) {
+        this.code = this.name();
+        this.desc = desc;
+    }
+
+    @Override
+    public String getCode() {
+        return name();
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 35 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/EPaymentVersion.java

@@ -0,0 +1,35 @@
+package com.yonge.cooleshow.common.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+ * 活动资源类型
+ *
+ * @Author: liweifan
+ * @Data: 2022/4/7 15:48
+ */
+public enum EPaymentVersion implements BaseEnum<String, EPaymentVersion> {
+
+    V1("20230726前 原生支付"),
+    V2("20230726后,机构"),
+    ;
+
+    @EnumValue
+    private String code;
+    private String msg;
+
+    EPaymentVersion(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 30 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/ESettlementFrom.java

@@ -0,0 +1,30 @@
+package com.yonge.cooleshow.common.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+public enum ESettlementFrom implements BaseEnum<String, ESettlementFrom> {
+
+    TEACHER("结算给老师"),
+    TENANT("结算给机构"),
+    NO("不结算"),
+    ;
+
+    @EnumValue
+    private String code;
+    private String msg;
+
+    ESettlementFrom(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 34 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/ETenantUnBindAuditStatus.java

@@ -0,0 +1,34 @@
+package com.yonge.cooleshow.common.enums;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+
+/**
+ * 机构用户解绑审核状态
+ */
+public enum ETenantUnBindAuditStatus implements BaseEnum<String, ETenantUnBindAuditStatus> {
+
+    DOING("审核中"),
+    PASS("审核通过"),
+    UNPASS("审核不通过"),
+    CANCEL("撤销"),
+    CLOSE("关闭");
+
+    @EnumValue
+    private final String code;
+    private final String msg;
+
+    ETenantUnBindAuditStatus(String msg) {
+        this.code = this.name();
+        this.msg = msg;
+    }
+
+    @Override
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 6 - 2
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/SysUserType.java

@@ -2,11 +2,15 @@ package com.yonge.cooleshow.common.enums;
 
 import com.baomidou.mybatisplus.annotation.EnumValue;
 import com.yonge.toolset.base.enums.BaseEnum;
-import org.apache.commons.lang3.StringUtils;
 
 public enum SysUserType implements BaseEnum<String, SysUserType> {
 
-    STUDENT("学生"), TEACHER("指导老师"), SYSTEM("系统內置");
+    STUDENT("学生"),
+    TEACHER("指导老师"),
+    SYSTEM("系统內置"),
+    ORGANIZATION("机构"),
+    ;
+
     @EnumValue
     private String code;
 

+ 29 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EGoodsSource.java

@@ -0,0 +1,29 @@
+package com.yonge.cooleshow.common.enums.payment;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.cooleshow.common.enums.ActivityShareEnum;
+import com.yonge.toolset.base.enums.BaseEnum;
+import lombok.Getter;
+
+/**
+ * 商品来源
+ */
+@Getter
+public enum EGoodsSource implements BaseEnum<String, EGoodsSource> {
+
+    MALL("商城"),
+    VIP("数字化器乐学练工具"),
+    ;
+
+    private final String msg;
+
+    @EnumValue
+    private final String code;
+
+    EGoodsSource(String msg) {
+        this.msg = msg;
+
+        this.code = this.name();
+    }
+
+}

+ 56 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EGoodsType.java

@@ -0,0 +1,56 @@
+package com.yonge.cooleshow.common.enums.payment;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.google.common.collect.Lists;
+import com.yonge.toolset.base.enums.BaseEnum;
+import lombok.Getter;
+
+import java.util.List;
+
+/**
+ * 商品类型类型
+ */
+@Getter
+public enum EGoodsType implements BaseEnum<String, EGoodsType> {
+
+    VIP("数字化器乐学练工具", "VIP"),
+    INSTRUMENTS("乐器购买", "MALL"),
+    TEXTBOOK("教材", "MALL"),
+    ;
+
+    private final String msg;
+    private final String source;
+
+    @EnumValue
+    private final String code;
+
+    EGoodsType(String msg, String source) {
+        this.msg = msg;
+        this.source = source;
+
+        this.code = this.name();
+    }
+
+    /**
+     * 商城商品类型
+     * @return List<EGoodsType>
+     */
+    public static List<EGoodsType> mallGoodsTypes() {
+
+        return Lists.newArrayList(INSTRUMENTS);
+    }
+
+    /**
+     * 商品类型匹配
+     * @param code 商品编码
+     * @return boolean
+     */
+    public static boolean match(String code) {
+        for (EGoodsType eGoodsType : EGoodsType.values()) {
+            if (eGoodsType.getCode().equals(code)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 25 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EOrderType.java

@@ -0,0 +1,25 @@
+package com.yonge.cooleshow.common.enums.payment;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.yonge.toolset.base.enums.BaseEnum;
+import lombok.Getter;
+
+@Getter
+public enum EOrderType implements BaseEnum<String, EOrderType> {
+
+    VIP("数字化器乐学练工具"),
+    SCHOOL_REGISTER("学生报名"),
+    ;
+
+
+    private final String name;
+
+    @EnumValue
+    private final String code;
+
+    EOrderType(String name) {
+        this.name = name;
+
+        this.code = this.name();
+    }
+}

+ 48 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EPaymentChannel.java

@@ -0,0 +1,48 @@
+package com.yonge.cooleshow.common.enums.payment;
+
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 三方支付渠道
+ */
+@Getter
+public enum EPaymentChannel {
+
+    ALIPAY_QR("alipay_qr", "支付宝正扫", 1),
+    ALIPAY_WAP("alipay_wap", "支付宝H5支付", 1),
+    WX_PUB("wx_pub", "微信公众号支付", 2),
+    WX_LITE("wx_lite", "微信小程序支付", 2),
+    ;
+
+    private final String msg;
+    private final int payType;
+
+    private final String code;
+
+    EPaymentChannel(String code, String msg, int payType) {
+        this.code = code;
+        this.msg = msg;
+        this.payType = payType;
+    }
+
+    /**
+     * 支付渠道
+     * @param code 渠道商
+     * @return EPaymentChannel
+     */
+    public static EPaymentChannel get(String code) {
+
+        EPaymentChannel[] values = EPaymentChannel.values();
+        if (StringUtils.isNotBlank(code)) {
+
+            for (EPaymentChannel item : values) {
+                if (item.getCode().equals(code)) {
+                    return item;
+                }
+            }
+        }
+        return WX_PUB;
+    }
+
+}

+ 51 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EPaymentStatus.java

@@ -0,0 +1,51 @@
+package com.yonge.cooleshow.common.enums.payment;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.google.common.collect.Lists;
+import lombok.Getter;
+
+import java.util.List;
+
+/**
+ * 订单支付状态
+ */
+@Getter
+public enum EPaymentStatus  {
+
+    WAIT_PAY("待支付"),
+    PAYING("支付中"),
+    PAID("已付款"),
+    TIMEOUT("订单超时"),
+    FAIL("支付失败"),
+    CLOSED("订单关闭"),
+    REFUNDED("已退款"),
+    ;
+
+    private final String msg;
+
+    @EnumValue
+    private final String code;
+
+    EPaymentStatus(String msg) {
+        this.msg = msg;
+
+        this.code = this.name();
+    }
+
+    /**
+     * 乐团报名状态
+     * @return List<EPaymentStatus>
+     */
+    public static List<EPaymentStatus> registerStatus() {
+        return Lists.newArrayList(PAID);
+    }
+
+    /**
+     * 乐团报名订单
+     * WAIT_PAY, PAYING, 只能是已支付和退款中的订单
+     * @return List<EPaymentStatus>
+     */
+    public static List<EPaymentStatus> registerOrder() {
+        return Lists.newArrayList(PAID);
+    }
+}

+ 34 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/enums/payment/EPaymentType.java

@@ -0,0 +1,34 @@
+package com.yonge.cooleshow.common.enums.payment;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import lombok.Getter;
+
+/**
+ * 订单支付类型
+ */
+@Getter
+public enum EPaymentType {
+
+    VIP("开通会员"),
+    PRACTICE("陪练课购买"),
+    LIVE("直播课购买"),
+    VIDEO("视频课购买"),
+    MUSIC("单曲点播"),
+    PIANO_ROOM("琴房时长"),
+    ACTI_REGIST("活动报名"),
+    ALBUM("专辑购买"),
+    TENANT_ALBUM("平台专辑"),
+    ;
+
+    private final String msg;
+
+    @EnumValue
+    private final String code;
+
+    EPaymentType(String msg) {
+        this.msg = msg;
+
+        this.code = this.name();
+    }
+
+}

+ 2 - 0
cooleshow-common/src/main/java/com/yonge/cooleshow/common/security/SecurityConstants.java

@@ -6,6 +6,8 @@ public interface SecurityConstants {
 
 	String PHONE_PRINCIPAL_PREFIX = "phone:";
 
+	String MA_PRINCIPAL_PREFIX = "ma";
+
 	String PARAM_VERIFY_EXCEPTION = "参数校验异常";
 
 	String VERIFY_FAILURE = "校验失败";

+ 1 - 0
cooleshow-gateway/gateway-web/src/main/java/com/yonge/gateway/web/config/SwaggerDocumentConfig.java

@@ -28,6 +28,7 @@ public class SwaggerDocumentConfig implements SwaggerResourcesProvider {
 		resources.add(swaggerResource("MALL_ADMIN服务", "/mall-admin-server/v2/api-docs", "2.0"));
 		resources.add(swaggerResource("MALL_PORTAL服务", "/mall-portal-server/v2/api-docs", "2.0"));
 		resources.add(swaggerResource("网络教室", "/classroom-server/v2/api-docs", "2.0"));
+		resources.add(swaggerResource("TENANT服务", "/tenant-server/v2/api-docs", "2.0"));
 		return resources;
 	}
 

+ 51 - 8
cooleshow-mall/mall-portal/src/main/java/com/yonge/cooleshow/portal/service/impl/OmsPortalOrderServiceImpl.java

@@ -5,31 +5,65 @@ import cn.hutool.core.collection.CollUtil;
 import com.alibaba.fastjson.JSON;
 import com.github.pagehelper.PageHelper;
 import com.yonge.cooleshow.api.feign.AdminFeignService;
-import com.yonge.cooleshow.api.feign.StudentFeignService;
 import com.yonge.cooleshow.api.feign.dto.CouponInfoApi;
 import com.yonge.cooleshow.api.feign.dto.StudentWrapper;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.common.entity.ContractDto;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.entity.MallOrderItemDto;
 import com.yonge.cooleshow.common.enums.PostStatusEnum;
-import com.yonge.cooleshow.common.entity.ContractDto;
 import com.yonge.cooleshow.common.service.IdGeneratorService;
 import com.yonge.cooleshow.mall.common.api.CommonPage;
 import com.yonge.cooleshow.mall.common.enums.OrderCacheEnum;
 import com.yonge.cooleshow.mall.common.exception.Asserts;
 import com.yonge.cooleshow.mall.common.service.RedisService;
-import com.yonge.cooleshow.mbg.mapper.*;
-import com.yonge.cooleshow.mbg.model.*;
+import com.yonge.cooleshow.mbg.mapper.OmsOrderItemMapper;
+import com.yonge.cooleshow.mbg.mapper.OmsOrderMapper;
+import com.yonge.cooleshow.mbg.mapper.OmsOrderSettingMapper;
+import com.yonge.cooleshow.mbg.mapper.PmsProductMapper;
+import com.yonge.cooleshow.mbg.mapper.PmsSkuStockMapper;
+import com.yonge.cooleshow.mbg.mapper.SmsCouponHistoryMapper;
+import com.yonge.cooleshow.mbg.mapper.UmsIntegrationConsumeSettingMapper;
+import com.yonge.cooleshow.mbg.mapper.UserOrderRefundMapper;
+import com.yonge.cooleshow.mbg.model.OmsOrder;
+import com.yonge.cooleshow.mbg.model.OmsOrderCourier;
+import com.yonge.cooleshow.mbg.model.OmsOrderExample;
+import com.yonge.cooleshow.mbg.model.OmsOrderItem;
+import com.yonge.cooleshow.mbg.model.OmsOrderItemExample;
+import com.yonge.cooleshow.mbg.model.OmsOrderSetting;
+import com.yonge.cooleshow.mbg.model.OmsOrderSettingExample;
+import com.yonge.cooleshow.mbg.model.PmsProduct;
+import com.yonge.cooleshow.mbg.model.PmsSkuStock;
+import com.yonge.cooleshow.mbg.model.SmsCouponHistory;
+import com.yonge.cooleshow.mbg.model.SmsCouponHistoryExample;
+import com.yonge.cooleshow.mbg.model.SmsCouponProductCategoryRelation;
+import com.yonge.cooleshow.mbg.model.SmsCouponProductRelation;
+import com.yonge.cooleshow.mbg.model.UmsIntegrationConsumeSetting;
+import com.yonge.cooleshow.mbg.model.UmsMember;
+import com.yonge.cooleshow.mbg.model.UmsMemberReceiveAddress;
+import com.yonge.cooleshow.mbg.model.UserOrderPayment;
+import com.yonge.cooleshow.mbg.model.UserOrderRefund;
 import com.yonge.cooleshow.portal.component.CancelOrderSender;
 import com.yonge.cooleshow.portal.dao.PortalOrderDao;
 import com.yonge.cooleshow.portal.dao.PortalOrderItemDao;
 import com.yonge.cooleshow.portal.dao.PortalProductDao;
-import com.yonge.cooleshow.portal.domain.*;
+import com.yonge.cooleshow.portal.domain.CartPromotionItem;
+import com.yonge.cooleshow.portal.domain.ConfirmOrderResult;
+import com.yonge.cooleshow.portal.domain.OmsOrderDetail;
+import com.yonge.cooleshow.portal.domain.OrderParam;
+import com.yonge.cooleshow.portal.domain.ProductStock;
+import com.yonge.cooleshow.portal.domain.SmsCouponHistoryDetail;
 import com.yonge.cooleshow.portal.dto.OrderCreate;
 import com.yonge.cooleshow.portal.dto.OrderPayReq;
 import com.yonge.cooleshow.portal.dto.OrderPayRes;
-import com.yonge.cooleshow.portal.service.*;
+import com.yonge.cooleshow.portal.service.OmsCartItemService;
+import com.yonge.cooleshow.portal.service.OmsOrderCourierService;
+import com.yonge.cooleshow.portal.service.OmsPortalOrderService;
+import com.yonge.cooleshow.portal.service.UmsMemberCouponService;
+import com.yonge.cooleshow.portal.service.UmsMemberReceiveAddressService;
+import com.yonge.cooleshow.portal.service.UmsMemberService;
+import com.yonge.cooleshow.portal.service.UserOrderPaymentService;
 import com.yonge.toolset.base.exception.BizException;
 import com.yonge.toolset.base.result.BaseResult;
 import com.yonge.toolset.base.util.StringUtil;
@@ -37,7 +71,11 @@ import com.yonge.toolset.payment.base.enums.OpenEnum;
 import com.yonge.toolset.payment.base.enums.PayChannelEnum;
 import com.yonge.toolset.payment.base.enums.PaymentClientEnum;
 import com.yonge.toolset.payment.base.enums.TradeStatusEnum;
-import com.yonge.toolset.payment.base.model.*;
+import com.yonge.toolset.payment.base.model.DeviceInfo;
+import com.yonge.toolset.payment.base.model.DivMember;
+import com.yonge.toolset.payment.base.model.OrderDetil;
+import com.yonge.toolset.payment.base.model.Payment;
+import com.yonge.toolset.payment.base.model.RefundBill;
 import com.yonge.toolset.payment.base.model.callback.PaymentCallBack;
 import com.yonge.toolset.payment.core.props.PaymentProperties;
 import com.yonge.toolset.payment.core.service.PaymentClient;
@@ -55,7 +93,12 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 

+ 19 - 0
cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/SendPlatformAuditMessageTask.java

@@ -0,0 +1,19 @@
+package com.yonge.cooleshow.task.jobs;
+
+import com.yonge.cooleshow.api.feign.AdminFeignService;
+import com.yonge.cooleshow.task.core.BaseTask;
+import com.yonge.cooleshow.task.core.TaskException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class SendPlatformAuditMessageTask extends BaseTask {
+
+    @Autowired
+    private AdminFeignService adminFeignService;
+
+    @Override
+    public void execute() throws TaskException {
+        Object o = adminFeignService.sendPlatformAuditMessage();
+    }
+}

+ 19 - 0
cooleshow-task/src/main/java/com/yonge/cooleshow/task/jobs/TenantPersonStatTask.java

@@ -0,0 +1,19 @@
+package com.yonge.cooleshow.task.jobs;
+
+import com.yonge.cooleshow.api.feign.TenantFeignService;
+import com.yonge.cooleshow.task.core.BaseTask;
+import com.yonge.cooleshow.task.core.TaskException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TenantPersonStatTask extends BaseTask {
+
+    @Autowired
+    private TenantFeignService tenantFeignService;
+
+    @Override
+    public void execute() throws TaskException {
+        tenantFeignService.tenantPersonStat();
+    }
+}

+ 1 - 0
cooleshow-user/pom.xml

@@ -41,5 +41,6 @@
 		<module>user-admin</module>
 		<module>user-biz</module>
         <module>user-website</module>
+        <module>user-tenant</module>
     </modules>
 </project>

+ 7 - 4
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/ImGroupController.java

@@ -1,7 +1,6 @@
 package com.yonge.cooleshow.admin.controller;
 
 
-import com.alibaba.fastjson.JSONObject;
 import com.yonge.cooleshow.biz.dal.dto.ImGroupSearchDto;
 import com.yonge.cooleshow.biz.dal.entity.ImGroup;
 import com.yonge.cooleshow.biz.dal.entity.ImHistoryMessage;
@@ -25,12 +24,16 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.BindingResult;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
-import java.io.File;
-import java.net.URL;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;

+ 130 - 97
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java

@@ -1,41 +1,19 @@
 package com.yonge.cooleshow.admin.controller;
 
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
-import io.swagger.annotations.ApiOperation;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Date;
-import java.util.List;
-
-import javax.servlet.http.HttpServletResponse;
-import javax.validation.Valid;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
 import com.yonge.cooleshow.biz.dal.dto.VipSubmitReq;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.VipRecordSearch;
+import com.yonge.cooleshow.biz.dal.entity.Student;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.MemberPriceSettingsService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
 import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
 import com.yonge.cooleshow.biz.dal.vo.VipRecordVo;
+import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.UserLockFlag;
@@ -46,6 +24,30 @@ import com.yonge.toolset.base.page.PageInfo;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import com.yonge.toolset.utils.date.DateUtil;
 import com.yonge.toolset.utils.excel.POIUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+import java.util.List;
 
 @RestController
 @RequestMapping("/student")
@@ -54,8 +56,7 @@ public class StudentController extends BaseController {
     @Autowired
     private StudentService studentService;
 
-
-    @Autowired
+    @Resource
     private SysUserFeignService sysUserFeignService;
 
     @Autowired
@@ -64,56 +65,55 @@ public class StudentController extends BaseController {
     @Autowired
     private VipCardRecordService vipCardRecordService;
 
-
     @GetMapping("/detail/{id}")
     @ApiOperation(value = "详情", notes = "传入id")
     @ApiImplicitParams({
             @ApiImplicitParam(name = "id", value = "id", paramType = "path", dataType = "long", required = true),
     })
     @PreAuthorize("@pcs.hasPermissions('student/detail')")
-    public HttpResponseResult<StudentVo> detail(@PathVariable("id") Long id){
-		StudentVo detail = studentService.detail(id);
-		return succeed(detail);
-	}
+    public HttpResponseResult<StudentVo> detail(@PathVariable("id") Long id) {
+        StudentVo detail = studentService.detail(id);
+        return succeed(detail);
+    }
 
     @PostMapping("/page")
     @ApiOperation(value = "查询分页", notes = "传入StudentSearch")
     @PreAuthorize("@pcs.hasPermissions('student/page')")
     public HttpResponseResult<PageInfo<StudentVo>> page(@RequestBody StudentSearch query) {
-    	
-    	if(StringUtils.isNotBlank(query.getUserStatus())){
-    		switch (query.getUserStatus()) {
-			case "LOCKED":
-				query.setDelFlag(YesOrNoEnum.NO);
-				query.setLockFlag(UserLockFlag.LOCKED);
-				break;
-			case "CLOSED":
-				query.setDelFlag(YesOrNoEnum.YES);
-				break;
-
-			default:
-				query.setDelFlag(YesOrNoEnum.NO);
-				query.setLockFlag(UserLockFlag.NORMAL);
-				break;
-			}
-    	}
-    	
-		IPage<StudentVo> pages = studentService.selectPage(PageUtil.getPage(query), query);
-		List<StudentVo> rows = pages.getRecords();
-		
-		for(StudentVo vo : rows){
-			if(vo.getDelFlag() == YesOrNoEnum.YES){
-				vo.setUserStatus(UserStatusEnum.CLOSED);
-			}else{
-				if(vo.getLockFlag() == UserLockFlag.LOCKED){
-					vo.setUserStatus(UserStatusEnum.LOCKED);
-				}else{
-					vo.setUserStatus(UserStatusEnum.NORMAL);
-				}
-			}
-		}
+
+        if (StringUtils.isNotBlank(query.getUserStatus())) {
+            switch (query.getUserStatus()) {
+                case "LOCKED":
+                    query.setDelFlag(YesOrNoEnum.NO);
+                    query.setLockFlag(UserLockFlag.LOCKED);
+                    break;
+                case "CLOSED":
+                    query.setDelFlag(YesOrNoEnum.YES);
+                    break;
+
+                default:
+                    query.setDelFlag(YesOrNoEnum.NO);
+                    query.setLockFlag(UserLockFlag.NORMAL);
+                    break;
+            }
+        }
+
+        IPage<StudentVo> pages = studentService.selectPage(PageUtil.getPage(query), query);
+        List<StudentVo> rows = pages.getRecords();
+
+        for (StudentVo vo : rows) {
+            if (vo.getDelFlag() == YesOrNoEnum.YES) {
+                vo.setUserStatus(UserStatusEnum.CLOSED);
+            } else {
+                if (vo.getLockFlag() == UserLockFlag.LOCKED) {
+                    vo.setUserStatus(UserStatusEnum.LOCKED);
+                } else {
+                    vo.setUserStatus(UserStatusEnum.NORMAL);
+                }
+            }
+        }
         return succeed(PageUtil.pageInfo(pages));
-	}
+    }
 
     @ApiOperation(value = "学生列表导出")
     @PostMapping("export")
@@ -121,45 +121,45 @@ public class StudentController extends BaseController {
     public void export(HttpServletResponse response, @RequestBody StudentSearch queryInfo) throws IOException {
         queryInfo.setPage(1);
         queryInfo.setRows(49999);
-    	
-    	if(StringUtils.isNotBlank(queryInfo.getUserStatus())){
-    		switch (queryInfo.getUserStatus()) {
-			case "LOCKED":
-				queryInfo.setDelFlag(YesOrNoEnum.NO);
-				queryInfo.setLockFlag(UserLockFlag.LOCKED);
-				break;
-			case "CLOSED":
-				queryInfo.setDelFlag(YesOrNoEnum.YES);
-				break;
-
-			default:
-				queryInfo.setDelFlag(YesOrNoEnum.NO);
-				queryInfo.setLockFlag(UserLockFlag.NORMAL);
-				break;
-			}
-    	}
+
+        if (StringUtils.isNotBlank(queryInfo.getUserStatus())) {
+            switch (queryInfo.getUserStatus()) {
+                case "LOCKED":
+                    queryInfo.setDelFlag(YesOrNoEnum.NO);
+                    queryInfo.setLockFlag(UserLockFlag.LOCKED);
+                    break;
+                case "CLOSED":
+                    queryInfo.setDelFlag(YesOrNoEnum.YES);
+                    break;
+
+                default:
+                    queryInfo.setDelFlag(YesOrNoEnum.NO);
+                    queryInfo.setLockFlag(UserLockFlag.NORMAL);
+                    break;
+            }
+        }
         List<StudentVo> rows = studentService.selectPage(PageUtil.getPage(queryInfo), queryInfo).getRecords();
         if (rows.size() < 1) {
             throw new BizException("没有可导出数据");
         }
-		
-		for(StudentVo vo : rows){
-			if(vo.getDelFlag() == YesOrNoEnum.YES){
-				vo.setUserStatus(UserStatusEnum.CLOSED);
-			}else{
-				if(vo.getLockFlag() == UserLockFlag.LOCKED){
-					vo.setUserStatus(UserStatusEnum.LOCKED);
-				}else{
-					vo.setUserStatus(UserStatusEnum.NORMAL);
-				}
-			}
-		}
+
+        for (StudentVo vo : rows) {
+            if (vo.getDelFlag() == YesOrNoEnum.YES) {
+                vo.setUserStatus(UserStatusEnum.CLOSED);
+            } else {
+                if (vo.getLockFlag() == UserLockFlag.LOCKED) {
+                    vo.setUserStatus(UserStatusEnum.LOCKED);
+                } else {
+                    vo.setUserStatus(UserStatusEnum.NORMAL);
+                }
+            }
+        }
         OutputStream outputStream = response.getOutputStream();
         try {
             HSSFWorkbook workbook = POIUtil.exportExcel(new String[]{"学生编号", "学生姓名", "真实姓名", "性别", "出生日期",
-                    "年龄", "专业", "手机号码", "是否是会员", "注册时间","用户状态"}, new String[]{
-                    "userId","username" , "realName", "gender.msg", "birthdate", "age", "subjectName", "phone",
-                    "isVip.msg", "createTime", "userStatus.msg"}, rows);
+                    "年龄", "专业", "手机号码", "是否是会员", "注册时间", "用户状态", "学生来源"}, new String[]{
+                    "userId", "username", "realName", "gender.msg", "birthdate", "age", "subjectName", "phone",
+                    "isVip.msg", "createTime", "userStatus.msg", "tenantName"}, rows);
             response.setContentType("application/octet-stream");
             response.setHeader("Content-Disposition", "attac:wq" +
                     "hment;filename=学生列表-" + DateUtil.getDate(new Date()) + ".xls");
@@ -185,7 +185,7 @@ public class StudentController extends BaseController {
     @PreAuthorize("@pcs.hasPermissions('student/addVip')")
     public HttpResponseResult<Boolean> addVip(@Valid @RequestBody VipSubmitReq vipSubmitReq) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();
-        if (sysUser == null  || sysUser.getId() == null) {
+        if (sysUser == null || sysUser.getId() == null) {
             return failed("用户信息获取失败");
         }
         return succeed(memberPriceSettingsService.addVip(vipSubmitReq, ClientEnum.STUDENT, sysUser));
@@ -200,4 +200,37 @@ public class StudentController extends BaseController {
         recordSearch.setClient(ClientEnum.STUDENT);
         return succeed(vipCardRecordService.vipRecord(recordSearch));
     }
+
+    @PostMapping("/updateTenant")
+    @ApiOperation(value = "修改机构")
+    public HttpResponseResult<Boolean> updateTenant(@RequestBody StudentWrapper.StudentUpdateTenant updateTenant) {
+        SysUser user = sysUserFeignService.queryUserById(updateTenant.getStudentId());
+        if (user == null || null == user.getId()) {
+            return failed(HttpStatus.FORBIDDEN, "请登录");
+        }
+
+        Student student = studentService.getById(user.getId());
+        if (student == null) {
+            return failed("未查询到学生的信息");
+        }
+
+        if (student.getTenantId() == null || student.getTenantId() == -1L) {
+            return failed("非机构用户不允许更换机构");
+        }
+
+        studentService.updateTenant(student, updateTenant.getTenantId());
+        return succeed();
+    }
+
+
+    @PostMapping("/add")
+    @ApiOperation(value = "新增", notes = "传入Student")
+    public HttpResponseResult<Boolean> add(@Validated @RequestBody StudentWrapper.Student student) {
+        SysUser sysUser = sysUserFeignService.queryUserByMobile(student.getPhone());
+        if (sysUser != null && sysUser.getUserType().contains(ClientEnum.STUDENT.getCode())) {
+            throw new BizException("学生账号已经存在");
+        }
+        studentService.save(student);
+        return succeed();
+    }
 }

+ 124 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/SysAreaController.java

@@ -0,0 +1,124 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.google.common.collect.Lists;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.webportal.exception.BizException;
+import com.yonge.cooleshow.admin.io.request.SysAreaVo;
+import com.yonge.cooleshow.biz.dal.entity.SysArea;
+import com.yonge.cooleshow.biz.dal.service.SysAreaService;
+import com.yonge.cooleshow.biz.dal.wrapper.SysAreaWrapper;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Validated
+@RestController
+@RequestMapping("/sysArea")
+@Api(tags = "区域表")
+public class SysAreaController {
+
+    @Autowired
+    private SysAreaService sysAreaService;
+
+	/**
+	 * 查询单条
+	 * @param id 详情ID
+	 * @return R<SysAreaVo.SysArea>
+	 */
+	@ApiOperation(value = "详情", notes = "传入id")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "id", dataType = "long")
+    })
+    @GetMapping("/detail/{id}")
+    public HttpResponseResult<SysAreaWrapper.SysArea> detail(@PathVariable("id") Long id) {
+
+        return HttpResponseResult.succeed(sysAreaService.detail(id));
+	}
+
+	/**
+	 * 根据code查询
+	 * @param code 详情ID
+	 * @return R<SysAreaVo.SysArea>
+	 */
+	@ApiOperation(value = "根据code查询", notes = "传入code")
+    @GetMapping("/queryByCode/{code}")
+    public HttpResponseResult<SysArea> queryByCode(@PathVariable("code") Integer code) {
+
+		List<Integer> codeList = new ArrayList<Integer>();
+		codeList.add(code);
+		List<SysArea> list = sysAreaService.queryByCodes(codeList);
+
+		if(list == null || list.size() == 0){
+			throw BizException.from("根据code查询区域表失败");
+		}
+
+        return HttpResponseResult.succeed(list.get(0));
+	}
+
+    /**
+	 * 查询分页
+	 * @param query SysAreaVo.SysAreaQuery
+	 * @return R<PageInfo<SysAreaVo.SysAreaList>>
+	 */
+    @ApiOperation(value = "查询分页", notes = "传入sysAreaSearch")
+    @PreAuthorize("@auditsvc.hasPermissions('sysArea/page', {'BACKEND'})")
+    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<SysAreaWrapper.SysArea>> page(@RequestBody SysAreaWrapper.SysAreaQuery query) {
+
+        IPage<SysAreaWrapper.SysArea> pages = sysAreaService.selectPage(QueryInfo.getPage(query), query);
+
+        return HttpResponseResult.succeed(QueryInfo.pageInfo(pages));
+	}
+
+    /**
+     * 查询全部区域
+     * @return R<List<SysAreaVo.Province>>
+     */
+    @ApiOperation(value = "查询全部区域", notes = "查询全部区域")
+    @GetMapping("/queryAllProvince")
+    public HttpResponseResult<List<SysAreaVo.Province>> queryAllProvince() {
+
+        List<SysAreaVo.Province> provinces = Lists.newArrayList();
+
+        // 全部城市信息
+        Map<Integer, List<SysArea>> areaMap = sysAreaService.lambdaQuery().list().stream()
+            .filter(x -> x.getDelFlag().equals("0"))
+            .collect(Collectors.groupingBy(SysArea::getParentOrganId));
+
+        SysAreaVo.Province provinceVo;
+        SysAreaVo.City cityVo;
+        for (SysArea province : areaMap.get(0)) {
+
+            provinceVo = JSON.parseObject(JSON.toJSONString(province), SysAreaVo.Province.class)
+                .cities(Lists.newArrayList());
+            provinces.add(provinceVo);
+
+            // 城市信息
+            for (SysArea city : areaMap.get(province.getId())) {
+
+                cityVo = JSON.parseObject(JSON.toJSONString(city), SysAreaVo.City.class);
+                provinceVo.getAreas().add(cityVo);
+
+                if (areaMap.containsKey(city.getId())) {
+                    cityVo.setAreas(JSON.parseArray(JSON.toJSONString(areaMap.get(city.getId())), SysAreaVo.District.class));
+                }
+            }
+        }
+
+        return HttpResponseResult.succeed(provinces);
+    }
+}

+ 71 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/SysGoodsPriceController.java

@@ -0,0 +1,71 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.biz.dal.entity.SysGoodsPrice;
+import com.yonge.cooleshow.biz.dal.service.SysGoodsPriceService;
+import com.yonge.cooleshow.biz.dal.wrapper.SysGoodsPriceWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.page.PageInfo;
+import com.yonge.toolset.mybatis.support.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 商品价格设置
+ * 2023-07-21 17:32:49
+ */
+
+@RestController
+@RequestMapping("/sysGoodsPrice")
+@Api(value = "商品价格", tags = "商品价格")
+public class SysGoodsPriceController extends BaseController {
+
+    @Autowired
+    SysGoodsPriceService sysGoodsPriceService;
+
+    /**
+     * 查询分页
+     * @param query
+     */
+    @PostMapping("/page")
+    @ApiOperation(value = "查询分页", notes = "sysGoodsPrice")
+    @PreAuthorize("@pcs.hasPermissions('sysGoodsPrice/page')")
+    public HttpResponseResult<PageInfo<SysGoodsPrice>> page(@RequestBody SysGoodsPriceWrapper.SysGoodsPriceQuery query) {
+        IPage<SysGoodsPrice> pages = sysGoodsPriceService.selectPage(QueryInfo.getPage(query), query);
+        return HttpResponseResult.succeed(PageUtil.pageInfo(pages));
+    }
+
+
+    /**
+     * 修改
+     * @param sysGoodsPrice
+     */
+    @PostMapping("/update")
+    @ApiOperation(value = "修改", notes = "sysGoodsPrice")
+    @PreAuthorize("@pcs.hasPermissions('sysGoodsPrice/update')")
+    public HttpResponseResult<Boolean> update(@RequestBody SysGoodsPriceWrapper.SysGoodsPrice sysGoodsPrice) {
+
+        return HttpResponseResult.succeed(sysGoodsPriceService.update(sysGoodsPrice));
+    }
+
+    /**
+     * 新增
+     * @param sysGoodsPrice
+     */
+    @PostMapping("/add")
+    @ApiOperation(value = "新增", notes = "sysGoodsPrice")
+    @PreAuthorize("@pcs.hasPermissions('sysGoodsPrice/add')")
+    public HttpResponseResult<Boolean> add(@RequestBody SysGoodsPriceWrapper.SysGoodsPrice sysGoodsPrice) {
+        return HttpResponseResult.succeed(sysGoodsPriceService.add(sysGoodsPrice));
+    }
+
+
+}

+ 16 - 8
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java

@@ -2,7 +2,6 @@ package com.yonge.cooleshow.admin.controller;
 
 import com.alibaba.fastjson.JSON;
 import com.yonge.cooleshow.admin.io.request.TeacherBindingUserVo;
-import com.yonge.cooleshow.admin.io.request.coupon.CouponIssueVo;
 import com.yonge.cooleshow.biz.dal.queryInfo.TeacherBindingUserQueryInfo;
 import com.yonge.cooleshow.biz.dal.queryInfo.TeacherQueryInfo;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
@@ -12,7 +11,6 @@ import com.yonge.cooleshow.biz.dal.vo.userBindingTeacher.UserBindingTeacherWrapp
 import com.yonge.cooleshow.admin.io.request.teacher.TeacherVO;
 import com.yonge.cooleshow.biz.dal.vo.MyFens;
 import com.yonge.cooleshow.biz.dal.wrapper.teacher.TeacherWrapper;
-import com.yonge.toolset.base.page.QueryInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -22,17 +20,16 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Date;
 import java.util.List;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -78,7 +75,7 @@ import static com.yonge.cooleshow.common.entity.HttpResponseResult.succeed;
 @Api(value = "教师表", tags = "教师表")
 public class TeacherController extends BaseController {
 
-    @Autowired
+    @Resource
     private SysUserFeignService sysUserFeignService;
     @Autowired
     private TeacherService teacherService;
@@ -165,9 +162,20 @@ public class TeacherController extends BaseController {
     @ApiOperation(value = "新增或修改", notes = "传入teacher")
     @PreAuthorize("@pcs.hasPermissions('teacher/submit')")
     public HttpResponseResult<Boolean> submit(@Valid @RequestBody TeacherSubmitReq teacherSubmitReq) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        teacherSubmitReq.setUpdateBy(sysUser.getId());
         return teacherService.submit(teacherSubmitReq);
     }
 
+    @PostMapping("/updateTenant")
+    @ApiOperation(value = "新增或修改", notes = "传入teacher")
+    @PreAuthorize("@pcs.hasPermissions('teacher/updateTenant')")
+    public HttpResponseResult<Boolean> updateTenant(@Valid @RequestBody TeacherWrapper.UpdateTenant updateTenant) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        teacherService.updateTenant(updateTenant,sysUser.getId());
+        return succeed();
+    }
+
     @ApiOperation(value = "老师列表导出")
     @PostMapping("export")
     @PreAuthorize("@pcs.hasPermissions('teacher/export')")
@@ -215,9 +223,9 @@ public class TeacherController extends BaseController {
         OutputStream outputStream = response.getOutputStream();
         try {
             HSSFWorkbook workbook = POIUtil.exportExcel(new String[]{"老师编号", "昵称", "姓名", "手机号", "老师类型",
-                    "注册时间", "认证时间", "状态", "是否是会员", "徽章"}, new String[]{
-                    "userId", "username", "realName", "phone", "entryFlag.code == 1 ? '达人' : '游客'", "createTime", "entryAuthDate",
-                    "userStatus.msg", "isVip.code == 1 ? '是' : '否'", "tag"}, rows);
+                    "注册时间", "认证时间", "状态", "是否是会员", "徽章", "机构"}, new String[]{
+                    "userId", "username", "realName", "phone", "entryFlag.code == 1 ? '达人' : '游客'", "createTime",
+                    "entryAuthDate","userStatus.msg", "isVip.code == 1 ? '是' : '否'", "tag", "tenantName"}, rows);
             response.setContentType("application/octet-stream");
             response.setHeader("Content-Disposition", "attac:wq" +
                     "hment;filename=老师列表-" + DateUtil.getDate(new Date()) + ".xls");

+ 160 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantAccountRecordController.java

@@ -0,0 +1,160 @@
+package com.yonge.cooleshow.admin.controller;
+
+import cn.hutool.core.net.URLEncodeUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.template.R;
+import com.microsvc.toolkit.common.tools.DownloadManager;
+import com.microsvc.toolkit.middleware.oss.OssPluginContext;
+import com.microsvc.toolkit.middleware.oss.impl.TencentOssPlugin;
+import com.yonge.cooleshow.biz.dal.entity.FileImportInfo;
+import com.yonge.cooleshow.biz.dal.enums.AccountBizTypeEnum;
+import com.yonge.cooleshow.biz.dal.enums.InOrOutEnum;
+import com.yonge.cooleshow.biz.dal.service.ExcelAnalyseCoreService;
+import com.yonge.cooleshow.biz.dal.service.TenantAccountRecordService;
+import com.yonge.cooleshow.biz.dal.wrapper.FileImportInfoWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAccountRecordWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantActivationCodeWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.cooleshow.common.enums.PostStatusEnum;
+import com.yonge.toolset.base.page.PageInfo;
+import com.yonge.toolset.mybatis.support.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
+import org.joda.time.DateTime;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.File;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+@RestController
+@RequestMapping("/tenantAccountRecord")
+@Api(value = "机构账户流水表", tags = "机构账户流水表")
+public class TenantAccountRecordController extends BaseController {
+
+    @Autowired
+    private TenantAccountRecordService tenantAccountRecordService;
+
+    @Autowired
+    private OssPluginContext ossPluginContext;
+
+    @Autowired
+    private ExcelAnalyseCoreService excelAnalyseCoreService;
+    /**
+     * 查询分页
+     */
+    @PostMapping("/page")
+    @ApiOperation(value = "机构流水", notes = "TenantAccountRecordQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantAccountRecord/page')")
+    public HttpResponseResult<PageInfo<TenantAccountRecordWrapper.TenantAccountRecord>> page(@RequestBody TenantAccountRecordWrapper.TenantAccountRecordQuery query) {
+
+
+        IPage<TenantAccountRecordWrapper.TenantAccountRecord> pages = tenantAccountRecordService.selectPage(PageUtil.getPage(query), query);
+
+        // 统计数据
+        TenantAccountRecordWrapper.TenantAccountRecordStat statistics = tenantAccountRecordService.getStatistics(query);
+        if (statistics == null) {
+            statistics = new TenantAccountRecordWrapper.TenantAccountRecordStat();
+        }
+
+        PageInfo<TenantAccountRecordWrapper.TenantAccountRecord> tenantAccountRecordPageInfo = PageUtil.pageInfo(pages);
+        tenantAccountRecordPageInfo.setStatInfo(statistics);
+        return succeed(tenantAccountRecordPageInfo);
+    }
+
+
+
+    /**
+     * 导出
+     */
+    @PostMapping("/export")
+    @ApiOperation(value = "机构流水", notes = "TenantAccountRecordQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantAccountRecord/export')")
+    public HttpResponseResult<TenantActivationCodeWrapper.ExportFile> export(@RequestBody TenantAccountRecordWrapper.TenantAccountRecordQuery query) {
+        query.setRows(-1);
+        query.setInOrOut(InOrOutEnum.IN.getCode());
+
+        IPage<TenantAccountRecordWrapper.TenantAccountRecord> pages = tenantAccountRecordService.selectPage(PageUtil.getPage(query), query);
+
+        // 构建数据
+        List<TenantAccountRecordWrapper.TenantAccountRecord> records = pages.getRecords();
+
+        if (CollectionUtils.isEmpty(records)) {
+            records = new ArrayList<>();
+        }
+
+        List<TenantAccountRecordWrapper.TenantAccountRecordExport> list = JSON.parseArray(JSON.toJSONString(records), TenantAccountRecordWrapper.TenantAccountRecordExport.class);
+
+        for (TenantAccountRecordWrapper.TenantAccountRecordExport tenantAccountRecord : list) {
+            tenantAccountRecord.setBizType(AccountBizTypeEnum.valueOf(tenantAccountRecord.getBizType()).getMsg());
+            tenantAccountRecord.setSettlement(PostStatusEnum.RECORDED.getCode().equals(tenantAccountRecord.getPostStatus())?"是":"否");
+        }
+
+        return succeed(generateExportExcelFile(list,TenantAccountRecordWrapper.TenantAccountRecordExport.class,"机构收入导出","机构收入导出"));
+    }
+
+
+
+    /**
+     * 导出
+     */
+    @PostMapping("/import")
+    @ApiOperation(value = "机构流水", notes = "TenantAccountRecordQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantAccountRecord/import')")
+    public HttpResponseResult<FileImportInfo> importFile(@RequestBody FileImportInfoWrapper.FileImport wrapper) {
+
+        wrapper.setImportUrl(URLEncodeUtil.encode(wrapper.getImportUrl()));
+
+        // 读取数据
+        return HttpResponseResult.succeed(excelAnalyseCoreService.analyseReadExcelData(
+                JSON.parseObject(JSON.toJSONString(wrapper), FileImportInfoWrapper.FileImportInfo.class)));
+    }
+
+    private TenantActivationCodeWrapper.ExportFile generateExportExcelFile(List<?> orderExports, Class<?> clazz, String fileName, String sheetName) {
+
+        // OSS上传文件目录
+        String uploadOssPath = MessageFormat.format("excel-download/{0}", DateTime.now().toString("yyyy-MM"));
+
+        // 文件上传下载地址
+        String uploadPath = MessageFormat.format("{0}/{1}-{2}.xlsx", uploadOssPath, fileName, DateTime.now().toString("MMddHHmmss"));
+
+        // 本地文件地址
+        String localPath = DownloadManager.getInstance().path(uploadPath);
+
+        // 模板文件保存在springboot项目的resources/static下
+        // Resource resource = new ClassPathResource("static/预报名模板导出.xlsx");
+
+        EasyExcel
+                .write(localPath, clazz)
+                //.withTemplate(resource.getStream()) // 利用模板的输出流
+                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
+                .sheet(0, sheetName)
+                .doWrite(orderExports);
+
+        // 上传本地文件到OSS服务器
+        String downloadPath = ossPluginContext.getPluginService(TencentOssPlugin.PLUGIN_NAME)
+                .uploadFile(uploadOssPath, new File(localPath));
+
+        // 删除本地缓存文件
+        DownloadManager.getInstance().deleteOnExit(localPath);
+
+        // 学生统计下载
+        return TenantActivationCodeWrapper.ExportFile
+                .builder()
+                .fileName(MessageFormat.format("{0}.xlsx", fileName))
+                .downloadPath(downloadPath)
+                .build();
+    }
+
+}

+ 67 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantActivationCodeController.java

@@ -0,0 +1,67 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.biz.dal.entity.TenantAlbumPurchase;
+import com.yonge.cooleshow.biz.dal.service.TenantActivationCodeService;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumPurchaseService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantActivationCodeWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.page.PageInfo;
+import com.yonge.toolset.mybatis.support.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/tenantActivationCode")
+@Api(tags = "机构激活码")
+public class TenantActivationCodeController extends BaseController {
+
+    @Autowired
+    private TenantActivationCodeService tenantActivationCodeService;
+
+    @Autowired
+    private TenantAlbumPurchaseService tenantAlbumPurchaseService;
+
+
+    @ApiOperation(value = "查询分页", notes = "机构激活码- 传入 TenantActivationCodeVo.TenantActivationCodeQuery")
+    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<TenantActivationCodeWrapper.TenantActivationCode>> page(
+            @RequestBody TenantActivationCodeWrapper.TenantActivationCodeQuery query) {
+
+        if (StringUtils.isBlank(query.getOrderNo())) {
+            throw new BizException("订单号不能为空");
+        }
+        // 查询订单购买的专辑
+        TenantAlbumPurchase albumPurchase = tenantAlbumPurchaseService.getByOrderNo(query.getOrderNo());
+        if (albumPurchase == null) {
+            return succeed(new PageInfo<>());
+        }
+        query.setActivationStatus(true);
+        query.setTenantAlbumPurchaseId(albumPurchase.getId());
+        // 查询数据
+        IPage<TenantActivationCodeWrapper.TenantActivationCode> pages =
+                tenantActivationCodeService.selectPage(QueryInfo.getPage(query), query);
+        PageInfo<TenantActivationCodeWrapper.TenantActivationCode> pageInfo = PageUtil.pageInfo(pages);
+
+        if (query.getTenantAlbumPurchaseId() != null) {
+            pageInfo.setStatInfo(albumPurchase);
+        }
+
+        return succeed(pageInfo);
+    }
+
+}

+ 266 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantAlbumController.java

@@ -0,0 +1,266 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.admin.io.request.TenantAlbumVo;
+import com.yonge.cooleshow.api.feign.dto.TenantWrapper;
+import com.yonge.cooleshow.biz.dal.dto.search.StudentMusicSheetSearch;
+import com.yonge.cooleshow.biz.dal.entity.*;
+import com.yonge.cooleshow.biz.dal.enums.SubjectTypeEnum;
+import com.yonge.cooleshow.biz.dal.service.*;
+import com.yonge.cooleshow.biz.dal.vo.MusicSheetVo;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumWrapper;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.page.PageInfo;
+import com.yonge.toolset.mybatis.support.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @Author:haonan
+ * @Date:2023/7/27 18:26
+ * @Filename:TenantAlbumController
+ */
+
+@RestController
+@RequestMapping("/tenantAlbum")
+@Api(value = "机构专辑管理", tags = "机构专辑管理")
+public class TenantAlbumController {
+    @Autowired
+    TenantAlbumService tenantAlbumService;
+
+    @Autowired
+    private TenantAlbumMusicService tenantAlbumMusicService;
+
+    @Autowired
+    private TenantAlbumRefService tenantAlbumRefService;
+
+    @Autowired
+    private TenantInfoService tenantInfoService;
+
+    @Autowired
+    private MusicSheetService musicSheetService;
+
+    @Autowired
+    private SubjectService subjectService;
+
+    @Autowired
+    private MusicTagService musicTagService;
+
+    /**
+     * 查询分页
+     *
+     * @param query
+     */
+    @PostMapping("/page")
+    @ApiOperation(value = "查询分页", notes = "tenantAlbum")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbum/page')")
+    public HttpResponseResult<PageInfo<TenantAlbumWrapper.TenantAlbum>> page(@RequestBody TenantAlbumWrapper.TenantAlbumQuery query) {
+        IPage<TenantAlbumWrapper.TenantAlbum> pages = tenantAlbumService.selectPage(QueryInfo.getPage(query), query);
+        return HttpResponseResult.succeed(PageUtil.pageInfo(pages));
+    }
+
+
+    /**
+     * 查询详情
+     *
+     * @param id 详情ID
+     * @return TenantAlbum
+     */
+    @PostMapping("/detail")
+    @ApiOperation(value = "查询详情", notes = "detail")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbum/detail')")
+    public HttpResponseResult<TenantAlbumWrapper.TenantAlbum> detail(@RequestParam("id") Long id) {
+        TenantAlbum tenantAlbum = tenantAlbumService.detail(id);
+        if (tenantAlbum == null) {
+            throw new BizException("专辑信息不存在");
+        }
+
+        TenantAlbumWrapper.TenantAlbum vo = JSON.parseObject(JSON.toJSONString(tenantAlbum),
+                TenantAlbumWrapper.TenantAlbum.class);
+
+        //查关联表
+        TenantAlbumRef one = tenantAlbumRefService.lambdaQuery().eq(TenantAlbumRef::getTenantAlbumId, id)
+                .last("limit 1").one();
+        vo.setTenantId(one.getTenantId().toString());
+        //查询曲目表
+
+        TenantInfo tenantInfo = tenantInfoService.getById(one.getTenantId());
+        vo.setTenantName(tenantInfo.getName());
+        List<TenantAlbumMusic> tenantAlbumMusics = tenantAlbumMusicService.lambdaQuery()
+                .eq(TenantAlbumMusic::getTenantAlbumId, id)
+                .eq(TenantAlbumMusic::getDelFlag, false)
+                .list();
+
+        Map<SubjectTypeEnum, List<TenantAlbumMusic>> groupByType =
+                tenantAlbumMusics.stream().collect(Collectors.groupingBy(TenantAlbumMusic::getSubjectType));
+
+
+        List<Long> musicSheetIdlist = tenantAlbumMusics.stream().map(next -> next.getMusicSheetId()).distinct().collect(Collectors.toList());
+
+
+        StudentMusicSheetSearch search = new StudentMusicSheetSearch();
+        search.setMusicSheetIdlist(musicSheetIdlist);
+        search.setPage(1);
+        search.setRows(9999);
+        IPage<MusicSheetVo> records = musicSheetService.selectStudentPage(PageUtil.getPage(search), search, null);
+        Map<Long, MusicSheetVo> idMsMap = records.getRecords().stream()
+                .collect(Collectors.toMap(MusicSheet::getId, Function.identity()));
+        List<TenantAlbumWrapper.MusicSheetData> musicSheetData = vo.getMusicSheetData();
+        groupByType.forEach((key, value) -> {
+            value.sort(Comparator.comparing(TenantAlbumMusic::getSortNumber));
+            TenantAlbumWrapper.MusicSheetData sheetData = new TenantAlbumWrapper.MusicSheetData();
+            sheetData.setSubjectType(key);
+            List<TenantAlbumWrapper.TenantAlbumSheet> tenantAlbumSheets = value.stream().map(next -> {
+
+                TenantAlbumWrapper.TenantAlbumSheet tenantAlbumSheet = new TenantAlbumWrapper.TenantAlbumSheet();
+                BeanUtils.copyProperties(next, tenantAlbumSheet);
+                Long musicSheetId = tenantAlbumSheet.getMusicSheetId();
+                MusicSheetVo musicSheet = idMsMap.getOrDefault(musicSheetId, new MusicSheetVo());
+                tenantAlbumSheet.setMusicSheetName(musicSheet.getMusicSheetName());
+                tenantAlbumSheet.setMusicTag(musicSheet.getMusicTag());
+                tenantAlbumSheet.setComposer(musicSheet.getComposer());
+                tenantAlbumSheet.setMusicSubject(musicSheet.getMusicSubject());
+                return tenantAlbumSheet;
+            }).collect(Collectors.toList());
+            tenantAlbumSheets.stream().forEach(t->{
+                String musicSubject = t.getMusicSubject();
+
+                if (StringUtils.isNotBlank(musicSubject)){
+                    //设置对应声部名称
+                    List<Subject> subject = subjectService.findBySubjectByIdList(musicSubject);
+                    if (CollectionUtils.isNotEmpty(subject)) {
+                        t.setMusicSubjectName(subject.get(0).getName());
+                    }
+                }
+
+
+                //设置对应标签名称
+                String musicTag = t.getMusicTag();
+                if (StringUtils.isNotBlank(musicTag)){
+                    String[] split = musicTag.split(",");
+                    for (String s : split) {
+                        List<Long> list = new ArrayList<>();
+                        list.add(Long.parseLong(s));
+                        String tagName = musicTagService.getMusicTagNames(list);
+                        t.setMusicTagName(tagName);
+                    }
+                }
+
+            });
+
+
+            sheetData.setTenantAlbumSheetList(tenantAlbumSheets);
+            musicSheetData.add(sheetData);
+            vo.setMusicSheetData(musicSheetData);
+        });
+
+        return HttpResponseResult.succeed(vo);
+    }
+
+
+    /**
+     * 新增专辑
+     */
+    @PostMapping("/save")
+    @ApiOperation(value = "新增专辑", notes = "新增专辑")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbum/save')")
+    public HttpResponseResult<Boolean> save(@Validated @RequestBody TenantAlbumVo.TenantAlbum album) {
+        //判断当前机构是否已经绑定机构专辑
+        Long tenantId = album.getTenantId();
+        List<TenantAlbumMusic> list = tenantAlbumMusicService.lambdaQuery().eq(TenantAlbumMusic::getTenantId, tenantId).list();
+        if (CollectionUtils.isNotEmpty(list)){
+            throw new BizException("当前机构已有专辑");
+        }
+
+        TenantAlbum tenantAlbum = JSON.parseObject(album.jsonString(), TenantAlbum.class);
+        List<TenantAlbumVo.MusicSheetData> musicSheetData = album.getMusicSheetData();
+
+        List<TenantAlbumWrapper.MusicSheetData> musicSheetDataList = musicSheetData.stream().map(next ->{
+                    //TenantAlbumWrapper.MusicSheetData sheetData =new TenantAlbumWrapper.MusicSheetData();
+                    TenantAlbumWrapper.MusicSheetData sheetData =new TenantAlbumWrapper.MusicSheetData();
+
+                    List<TenantAlbumVo.MusicObject> musicSheetList = next.getMusicSheetList();
+                    sheetData.getTenantAlbumSheetList().addAll( musicSheetList.stream().map(m->{
+                        TenantAlbumWrapper.TenantAlbumSheet tenantAlbumSheet = new TenantAlbumWrapper.TenantAlbumSheet();
+                        tenantAlbumSheet.setLevel(m.getLevel());
+                        tenantAlbumSheet.setType(m.getType());
+                        tenantAlbumSheet.setId(m.getId().toString());
+                       return tenantAlbumSheet;
+                    }).collect(Collectors.toList()));
+                    sheetData.setSubjectType(next.getSubjectType());
+                    return sheetData;
+        }
+        ).collect(Collectors.toList());
+        tenantAlbumService.insertTenantAlbum(album.getTenantId(), tenantAlbum, musicSheetDataList);
+        return HttpResponseResult.succeed();
+    }
+
+    @PostMapping("/update")
+    @ApiOperation(value = "修改专辑", notes = "修改专辑")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbum/update')")
+    public HttpResponseResult<Boolean> update( @RequestBody TenantAlbumVo.TenantAlbum album) {
+
+        //判断当前机构是否已经绑定机构专辑
+        Long tenantId = album.getTenantId();
+        List<TenantAlbumMusic> list = tenantAlbumMusicService.lambdaQuery().eq(TenantAlbumMusic::getTenantId, tenantId).list();
+        if (CollectionUtils.isNotEmpty(list)){
+            list.stream().forEach(i->{
+                if (!i.getTenantAlbumId().equals(album.getId())){
+                    throw new BizException("当前机构已有专辑");
+                }
+            });
+        }
+
+        TenantAlbum tenantAlbum = JSON.parseObject(album.jsonString(), TenantAlbum.class);
+        List<TenantAlbumVo.MusicSheetData> musicSheetData = album.getMusicSheetData();
+
+        List<TenantAlbumWrapper.MusicSheetData> musicSheetDataList = musicSheetData.stream().map(next ->{
+            //TenantAlbumWrapper.MusicSheetData sheetData =new TenantAlbumWrapper.MusicSheetData();
+            TenantAlbumWrapper.MusicSheetData sheetData =new TenantAlbumWrapper.MusicSheetData();
+
+            List<TenantAlbumVo.MusicObject> musicSheetList = next.getMusicSheetList();
+            sheetData.getTenantAlbumSheetList().addAll( musicSheetList.stream().map(m->{
+                TenantAlbumWrapper.TenantAlbumSheet tenantAlbumSheet = new TenantAlbumWrapper.TenantAlbumSheet();
+                tenantAlbumSheet.setLevel(m.getLevel());
+                tenantAlbumSheet.setType(m.getType());
+                tenantAlbumSheet.setId(m.getId().toString());
+                return tenantAlbumSheet;
+            }).collect(Collectors.toList()));
+            sheetData.setSubjectType(next.getSubjectType());
+            return sheetData;
+        }).collect(Collectors.toList());
+        tenantAlbumService.updateAlbum(album.getTenantId(), tenantAlbum, musicSheetDataList);
+        return HttpResponseResult.succeed();
+    }
+
+    @PostMapping("/updateStatus")
+    @ApiOperation(value = "启用/冻结", notes = "启用/冻结")
+    @PreAuthorize("@pcs.hasPermissions('tenantAlbum/updateStatus')")
+    public HttpResponseResult<Boolean> updateStatus(@Validated @RequestBody TenantAlbumVo.UpdateStatus status) {
+        tenantAlbumService.lambdaUpdate()
+                .set(TenantAlbum::getStatus, status.getStatus())
+                .eq(TenantAlbum::getId, status.getId())
+                .update();
+        return HttpResponseResult.succeed();
+    }
+
+}

+ 105 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantEntryRecordController.java

@@ -0,0 +1,105 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
+import com.yonge.cooleshow.biz.dal.service.TenantApplyRecordService;
+import com.yonge.cooleshow.biz.dal.service.TenantEntryRecordService;
+import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantApplyRecordWrapper;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantInfoWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.page.PageInfo;
+import com.yonge.toolset.mybatis.support.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.poi.ss.formula.functions.T;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @Author:haonan
+ * @Date:2023/8/1 19:02
+ * @Filename:TenantEntryRecordController
+ */
+@RestController
+@RequestMapping("/tenantApply")
+@Api(value = "机构审核", tags = "机构审核")
+public class TenantEntryRecordController extends BaseController {
+
+    @Autowired
+    TenantApplyRecordService tenantApplyRecordService;
+
+    @Autowired
+    SysUserFeignService sysUserFeignService;
+
+    @Autowired
+    TenantInfoService tenantInfoService;
+
+    /**
+     * 机构入驻审核分页查询
+     */
+    @PostMapping("/applyPage")
+    @ApiOperation(value = "机构申请查询", notes = "机构申请查询")
+    @PreAuthorize("@pcs.hasPermissions('tenantApply/applyPage')")
+    public HttpResponseResult<PageInfo<TenantApplyRecordWrapper.TenantApplyRecord>> applyPage(@RequestBody TenantApplyRecordWrapper.TenantApplyRecordQuery query) {
+
+        IPage<TenantApplyRecordWrapper.TenantApplyRecord> pages = tenantApplyRecordService.selectPage(QueryInfo.getPage(query), query);
+        return succeed(PageUtil.pageInfo(pages));
+    }
+
+
+    /**
+     * 机构入驻审核历史记录查询
+     */
+
+    @PostMapping("/historyPage")
+    @ApiOperation(value = "机构审核历史记录", notes = "机构审核历史记录")
+    @PreAuthorize("@pcs.hasPermissions('tenantApply/historyPage')")
+    public HttpResponseResult<PageInfo<TenantApplyRecordWrapper.TenantApply>> historyPage(@RequestBody TenantApplyRecordWrapper.TenantApplyRecordQuery query) {
+
+       IPage<TenantApplyRecordWrapper.TenantApply> pages = tenantApplyRecordService.historyPage(QueryInfo.getPage(query), query);
+        return succeed(PageUtil.pageInfo(pages));
+    }
+
+
+    /**
+     * 机构入驻审核本次提交查询
+     */
+    @PostMapping("/queryNow")
+    @ApiOperation(value = "机构审核本次提交", notes = "机构审核本次提交")
+    @PreAuthorize("@pcs.hasPermissions('tenantApply/queryNow')")
+    public HttpResponseResult<TenantApplyRecordWrapper.TenantApplyRecord> queryNow(@RequestBody TenantApplyRecordWrapper.TenantApplyRecordQuery query) {
+
+        TenantApplyRecordWrapper.TenantApplyRecord tenantApplyRecord = tenantApplyRecordService.queryNow(query);
+        return succeed(tenantApplyRecord);
+    }
+
+    /**
+     * 机构入驻审核功能
+     */
+    @PostMapping("/entry")
+    @ApiOperation(value = "机构审核功能", notes = "机构审核功能")
+    @PreAuthorize("@pcs.hasPermissions('tenantApply/entry')")
+    public HttpResponseResult<Boolean> entry(@RequestBody TenantApplyRecordWrapper.TenantEntry entry) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        /*TenantInfo tenantInfo = tenantInfoService.lambdaQuery().eq(TenantInfo::getUserId, sysUser.getId())
+                .last("limit 1").one();
+        if (tenantInfo == null) {
+            throw new BizException("非法请求");
+        }*/
+        Long verifyUserId = sysUser.getId();
+
+        return succeed(tenantApplyRecordService.entry(entry,verifyUserId));
+    }
+
+
+}

+ 96 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantInfoController.java

@@ -0,0 +1,96 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.admin.io.request.TenantInfoVo;
+import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
+import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantInfoWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.page.PageInfo;
+import com.yonge.toolset.mybatis.support.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+/**
+ * @Author:haonan
+ * @Date:2023/7/24 9:57
+ * @Filename:TenantInfoController
+ */
+@RestController
+@RequestMapping("/tenantInfo")
+@Api(value = "机构管理", tags = "机构管理")
+public class TenantInfoController extends BaseController {
+
+    @Autowired
+    TenantInfoService tenantInfoService;
+
+    /**
+     * 查询分页
+     *
+     * @param query
+     */
+    @PostMapping("/page")
+    @ApiOperation(value = "查询分页", notes = "TenantInfo")
+    @PreAuthorize("@pcs.hasPermissions('tenantInfo/page')")
+    public HttpResponseResult<PageInfo<TenantInfoWrapper.TenantInfo>> page(@RequestBody TenantInfoWrapper.TenantInfoQuery query) {
+
+        IPage<TenantInfoWrapper.TenantInfo> pages = tenantInfoService.selectPage(query);
+        return succeed(PageUtil.pageInfo(pages));
+    }
+
+
+    /**
+     * 插入数据
+     */
+    @PostMapping("/add")
+    @ApiOperation(value = "更新", notes = "传入TenantInfo")
+    @PreAuthorize("@pcs.hasPermissions('tenantInfo/add')")
+    public HttpResponseResult<Boolean> add( @RequestBody TenantInfoVo.TenantInfo info) {
+        return succeed(tenantInfoService.add(JSON.parseObject(info.jsonString(), TenantInfo.class)));
+    }
+
+    /**
+     * 修改数据
+     */
+    @PostMapping("/update")
+    @ApiOperation(value = "修改", notes = "传入TenantInfo")
+    @PreAuthorize("@pcs.hasPermissions('tenantInfo/update')")
+    public HttpResponseResult<Boolean> update( @RequestBody TenantInfoVo.TenantInfo info) {
+        return succeed(tenantInfoService.update(JSON.parseObject(info.jsonString(), TenantInfo.class)));
+    }
+
+    /**
+     * 冻结
+     */
+    @PostMapping("/updateStatus")
+    @ApiOperation(value = "冻结", notes = "传入id和布尔类型")
+    @PreAuthorize("@pcs.hasPermissions('tenantInfo/updateStatus')")
+    public HttpResponseResult<Boolean> updateStatus(@RequestBody TenantInfoWrapper.UpdateStatus updateStatus) {
+        tenantInfoService.updateStatus(updateStatus);
+        return succeed();
+    }
+
+    /**
+     * 查询详情
+     *
+     * @param id
+     */
+    @PostMapping("/detail")
+    @ApiOperation(value = "查询详情", notes = "查询详情")
+    @PreAuthorize("@pcs.hasPermissions('tenantInfo/detail')")
+    public HttpResponseResult<TenantInfoWrapper.TenantInfo> detail(@RequestParam("id")Long id) {
+
+        TenantInfoWrapper.TenantInfo info = tenantInfoService.detailTenantInfo(id);
+        return succeed(info);
+    }
+
+}

+ 138 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantMemberController.java

@@ -0,0 +1,138 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import com.yonge.cooleshow.biz.dal.service.TenantMemberService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantMemberWrapper;
+import com.yonge.cooleshow.biz.dal.entity.TenantMember;
+
+import javax.validation.Valid;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * @Author:haonan
+ * @Date:2023/8/10 13:40
+ * @Filename:TenantMemberController
+ */
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/tenantMember")
+@Api(tags = "机构子账户表")
+public class TenantMemberController extends BaseController {
+
+    @Autowired
+    private TenantMemberService tenantMemberService;
+
+    @ApiOperation(value = "详情", notes = "机构子账户表-根据详情ID查询单条, 传入id")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/detail', {'BACKEND'})")
+    @PostMapping("/detail/{id}")
+    public R<TenantMember> detail(@PathVariable("id") Long id) {
+
+        TenantMember wrapper = tenantMemberService.detail(id);
+
+        return R.from(wrapper);
+    }
+
+    @ApiOperation(value = "查询分页", notes = "机构子账户表- 传入 TenantMemberWrapper.TenantMemberQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/page', {'BACKEND'})")
+    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<TenantMemberWrapper.TenantMember>> page(@RequestBody TenantMemberWrapper.TenantMemberQuery query) {
+
+        IPage<TenantMemberWrapper.TenantMember> pages = tenantMemberService.selectPage(QueryInfo.getPage(query), query);
+
+        return succeed(QueryInfo.pageInfo(pages));
+    }
+
+    @ApiOperation(value = "新增", notes = "机构子账户表- 传入 TenantMemberWrapper.InsertTenantMember")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/add', {'BACKEND'})")
+    @PostMapping("/add")
+    public HttpResponseResult add(@Valid @RequestBody TenantMemberWrapper.InsertOrUpdateTenantMember tenantMember) throws IOException {
+
+        File file = new File("/var/tmp/" + tenantMember.getMultipartFile().getOriginalFilename());
+        tenantMember.setFile(file);
+        InputStream inputStream = tenantMember.getMultipartFile().getInputStream();
+
+        try {
+            if (!file.getParentFile().exists()) {
+                file.getParentFile().mkdirs();
+            }
+            FileOutputStream fos = new FileOutputStream(file);
+            IOUtils.copy(inputStream, fos);
+            // 新增数据
+            return HttpResponseResult.succeed(tenantMemberService.add(tenantMember));
+        } catch (Exception e) {
+            return failed(e.getMessage());
+        } finally {
+            IOUtils.closeQuietly(inputStream);
+            FileUtils.deleteQuietly(file);
+        }
+    }
+
+    @ApiOperation(value = "修改", notes = "机构子账户表- 传入 TenantMemberWrapper.InsertTenantMember")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/update', {'BACKEND'})")
+    @PostMapping("/update")
+    public HttpResponseResult update(@RequestBody TenantMemberWrapper.InsertOrUpdateTenantMember tenantMember) throws IOException {
+        File file = new File("/var/tmp/" + tenantMember.getMultipartFile().getOriginalFilename());
+        tenantMember.setFile(file);
+        InputStream inputStream = tenantMember.getMultipartFile().getInputStream();
+
+        try {
+            if (!file.getParentFile().exists()) {
+                file.getParentFile().mkdirs();
+            }
+            FileOutputStream fos = new FileOutputStream(file);
+            IOUtils.copy(inputStream, fos);
+            // 新增数据
+            return HttpResponseResult.succeed(tenantMemberService.update(tenantMember));
+        } catch (Exception e) {
+            return failed(e.getMessage());
+        } finally {
+            IOUtils.closeQuietly(inputStream);
+            FileUtils.deleteQuietly(file);
+        }
+    }
+
+
+    @ApiOperation(value = "修改结算账户", notes = "机构子账户表- 传入 TenantMemberWrapper.UpdateCount")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/updateCount', {'BACKEND'})")
+    @PostMapping("/updateCount")
+    public HttpResponseResult updateCount(@RequestBody TenantMemberWrapper.UpdateCount tenantMember) {
+
+        // 更新数据
+        return HttpResponseResult.succeed(tenantMemberService.updateCount(tenantMember));
+    }
+
+
+    @ApiOperation(value = "删除", notes = "机构子账户表- 传入id")
+    @PreAuthorize("@pcs.hasPermissions('tenantMember/remove', {'BACKEND'})")
+    @PostMapping("/remove")
+    public R<Boolean> remove(@RequestParam Long id) {
+
+        return R.from(tenantMemberService.removeById(id));
+    }
+}

+ 86 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantUnbindHistoryController.java

@@ -0,0 +1,86 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.biz.dal.entity.Employee;
+import com.yonge.cooleshow.biz.dal.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
+import com.yonge.cooleshow.biz.dal.entity.TenantUnbindHistory;
+import com.yonge.cooleshow.biz.dal.service.EmployeeService;
+import com.yonge.cooleshow.biz.dal.service.SysUserService;
+import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
+import com.yonge.cooleshow.biz.dal.service.TenantStaffService;
+import com.yonge.cooleshow.biz.dal.service.TenantUnbindHistoryService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantUnbindHistoryWrapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.jws.Oneway;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/tenantUnbindHistory")
+@Api(tags = "机构解绑历史表")
+public class TenantUnbindHistoryController {
+
+    @Autowired
+    private TenantUnbindHistoryService tenantUnbindHistoryService;
+
+    @Autowired
+    private SysUserService sysUserService;
+
+    @Autowired
+    private TenantInfoService tenantInfoService;
+
+    @ApiOperation(value = "查询分页", notes = "机构解绑历史表- 传入 TenantUnbindHistoryWrapper.TenantUnbindHistoryQuery")
+    @PostMapping("/page")
+    public R<PageInfo<TenantUnbindHistoryWrapper.TenantUnbindHistory>> page(@RequestBody TenantUnbindHistoryWrapper.TenantUnbindHistoryQuery query) {
+
+        IPage<TenantUnbindHistory> pages = tenantUnbindHistoryService.selectPage(QueryInfo.getPage(query), query);
+
+        List<TenantUnbindHistory> records = pages.getRecords();
+        if (records.isEmpty()) {
+            return R.from(QueryInfo.pageInfo(pages, new ArrayList<>()));
+        }
+        List<Long> userIds =
+                pages.getRecords().stream().map(TenantUnbindHistory::getVerifyUserId).distinct()
+                        .collect(Collectors.toList());
+        Map<Long, SysUser> mapByIds = sysUserService.getMapByIds(userIds);
+
+        List<Long> tenantIds =
+                pages.getRecords().stream().map(TenantUnbindHistory::getTenantId).distinct()
+                        .collect(Collectors.toList());
+        Map<Long, TenantInfo> tenantInfoMap = tenantInfoService.getMapByIds(tenantIds);
+        List<TenantUnbindHistoryWrapper.TenantUnbindHistory> histories = records.stream().map(next -> {
+            TenantUnbindHistoryWrapper.TenantUnbindHistory tenantUnbindHistory =
+                    JSON.parseObject(JSON.toJSONString(next), TenantUnbindHistoryWrapper.TenantUnbindHistory.class);
+            SysUser orDefault = mapByIds.getOrDefault(next.getVerifyUserId(), new SysUser());
+            tenantUnbindHistory.setVerifyUserName(orDefault.getUsername());
+            if(tenantInfoMap.containsKey(next.getTenantId())){
+                TenantInfo tenantInfo = tenantInfoMap.get(next.getTenantId());
+                tenantUnbindHistory.setTenantUserName(tenantInfo.getUsername());
+                tenantUnbindHistory.setTenantPhone(tenantInfo.getPhone());
+            }
+            return tenantUnbindHistory;
+
+        }).collect(Collectors.toList());
+        return R.from(QueryInfo.pageInfo(pages, histories));
+    }
+}

+ 72 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/TenantUnbindRecordController.java

@@ -0,0 +1,72 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.service.EmployeeService;
+import com.yonge.cooleshow.biz.dal.service.TenantUnbindRecordService;
+import com.yonge.cooleshow.biz.dal.vo.EmployeeVo;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantUnbindRecordWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.cooleshow.common.enums.UserLockFlag;
+import com.yonge.toolset.base.exception.BizException;
+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.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/tenantUnbindRecord")
+@Api(tags = "机构解绑申请记录")
+public class TenantUnbindRecordController extends BaseController {
+
+    @Autowired
+    private TenantUnbindRecordService tenantUnbindRecordService;
+
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+
+    @Autowired
+    private EmployeeService employeeService;
+
+    @ApiOperation(value = "查询分页", notes = "机构解绑申请记录- 传入 TenantUnbindRecordVo.TenantUnbindRecordQuery")
+    @PreAuthorize("@pcs.hasPermissions('tenantUnbindRecord/page')")
+    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<TenantUnbindRecordWrapper.TenantUnbindRecord>>
+    page(@RequestBody TenantUnbindRecordWrapper.TenantUnbindRecordQuery query) {
+        // 查询数据
+        IPage<TenantUnbindRecordWrapper.TenantUnbindRecord> pages =
+                tenantUnbindRecordService.selectPage(QueryInfo.getPage(query), query);
+        return succeed(QueryInfo.pageInfo(pages, pages.getRecords()));
+    }
+
+    @ApiOperation(value = "审核")
+    @PostMapping("/audit")
+    @PreAuthorize("@pcs.hasPermissions('tenantUnbindRecord/audit')")
+    public HttpResponseResult<Boolean> audit(@RequestBody TenantUnbindRecordWrapper.Audio audio) {
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        if (sysUser == null) {
+            throw new BizException("请登录");
+        }
+        EmployeeVo employeeVo = employeeService.detail(sysUserFeignService.queryUserInfo().getId());
+        if (employeeVo == null || UserLockFlag.LOCKED.equals(employeeVo.getLockFlag())) {
+            throw new BizException("权限不足");
+        }
+        tenantUnbindRecordService.tenantUserUnbindAudit(audio, sysUser.getId(),true);
+        return succeed();
+    }
+}

+ 99 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/UnbindAuthUserController.java

@@ -0,0 +1,99 @@
+package com.yonge.cooleshow.admin.controller;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.toolset.base.exception.BizException;
+import com.yonge.toolset.base.page.PageInfo;
+import com.yonge.toolset.mybatis.support.PageUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import springfox.documentation.annotations.ApiIgnore;
+
+import com.yonge.cooleshow.biz.dal.service.UnbindAuthUserService;
+import com.yonge.cooleshow.biz.dal.wrapper.UnbindAuthUserWrapper;
+import com.yonge.cooleshow.biz.dal.entity.UnbindAuthUser;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("/unbindAuthUser")
+@Api(tags = "解绑审核人员设置")
+public class UnbindAuthUserController {
+
+    @Autowired
+    private UnbindAuthUserService unbindAuthUserService;
+
+    
+    @ApiOperation(value = "查询分页", notes = "解绑审核人员设置- 传入 UnbindAuthUserWrapper.UnbindAuthUserQuery") 
+    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<UnbindAuthUserWrapper.UnbindAuthUser>> page(@RequestBody UnbindAuthUserWrapper.UnbindAuthUserQuery query) {
+        
+        IPage<UnbindAuthUserWrapper.UnbindAuthUser> pages = unbindAuthUserService.selectPage(QueryInfo.getPage(query), query);
+        
+        return HttpResponseResult.succeed(PageUtil.pageInfo(pages));
+	}
+    
+    @ApiOperation(value = "新增", notes = "解绑审核人员设置- 传入 UnbindAuthUserWrapper.UnbindAuthUser")
+	@PostMapping("/save")
+	public HttpResponseResult<JSONObject> add(@Validated @RequestBody UnbindAuthUser unbindAuthUser) {
+
+        if (unbindAuthUser.getUserId() == null) {
+            throw new BizException("用户ID不能为空");
+        }
+
+        List<UnbindAuthUser> list = unbindAuthUserService.list();
+        if (!CollectionUtils.isEmpty(list)) {
+            unbindAuthUser.setId(list.get(0).getId());
+        }
+        // 新增数据
+        unbindAuthUserService.save(unbindAuthUser);
+        
+        return HttpResponseResult.succeed();
+	}
+    
+    @ApiOperation(value = "修改", notes = "解绑审核人员设置- 传入 UnbindAuthUserWrapper.UnbindAuthUser")
+	@PostMapping("/update")
+	public HttpResponseResult<JSONObject> update(@Validated @RequestBody UnbindAuthUser unbindAuthUser) {
+
+        if (unbindAuthUser.getId() == null) {
+            throw new BizException("ID不能为空");
+        }
+
+        if (unbindAuthUser.getUserId() == null) {
+            throw new BizException("用户ID不能为空");
+        }
+        // 更新数据
+        unbindAuthUserService.updateById(unbindAuthUser);
+
+        return HttpResponseResult.succeed();
+	}
+
+	@ApiOperation(value = "删除", notes = "解绑审核人员设置- 传入id")
+	@PostMapping("/remove")
+	public HttpResponseResult<Boolean> remove(@RequestParam Long id) {
+    
+		return HttpResponseResult.succeed(unbindAuthUserService.removeById(id));
+	}
+}

+ 3 - 1
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/UserOrderController.java

@@ -59,7 +59,9 @@ public class UserOrderController extends BaseController {
     @ApiOperation(value = "查询导出", notes = "传入orderSearch")
     @PreAuthorize("@pcs.hasPermissions('userOrder/export')")
     public void export(@RequestBody OrderSearch query) {
-        List<UserOrderVo> userOrderVos = userOrderService.selectAllList(query);
+        query.setRows(-1);
+        IPage<UserOrderVo> pages = userOrderService.selectPage(PageUtil.getPage(query), query);
+        List<UserOrderVo> userOrderVos = pages.getRecords();
         List<UserOrderExport> list = new ArrayList<>();
         userOrderVos.forEach(o -> {
             UserOrderExport export = new UserOrderExport();

+ 56 - 3
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/AdminClient.java

@@ -1,14 +1,18 @@
 package com.yonge.cooleshow.admin.controller.open;
 
+import com.alibaba.fastjson.JSON;
 import com.microsvc.toolkit.config.jwt.utils.RsaKeyHelper;
 import com.yonge.cooleshow.admin.io.request.coupon.CouponOrderVO;
 import com.yonge.cooleshow.api.feign.dto.CouponInfoApi;
 import com.yonge.cooleshow.api.feign.dto.EmployeeApi;
 import com.yonge.cooleshow.api.feign.dto.StudentApi;
 import com.yonge.cooleshow.api.feign.dto.TeacherApi;
+import com.yonge.cooleshow.api.feign.dto.TenantWrapper;
 import com.yonge.cooleshow.biz.dal.entity.Employee;
 import com.yonge.cooleshow.biz.dal.entity.Student;
 import com.yonge.cooleshow.biz.dal.entity.Teacher;
+import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
+import com.yonge.cooleshow.biz.dal.entity.TenantStaff;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.enums.coupon.CouponCategoryEnum;
 import com.yonge.cooleshow.biz.dal.enums.coupon.CouponUseStateEnum;
@@ -17,6 +21,8 @@ import com.yonge.cooleshow.biz.dal.service.CouponInfoService;
 import com.yonge.cooleshow.biz.dal.service.EmployeeService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
 import com.yonge.cooleshow.biz.dal.service.TeacherService;
+import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
+import com.yonge.cooleshow.biz.dal.service.TenantStaffService;
 import com.yonge.cooleshow.biz.dal.service.UserFirstTimeService;
 import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
 import com.yonge.cooleshow.biz.dal.wrapper.coupon.CouponOrderWrapper;
@@ -24,12 +30,13 @@ import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
 import com.yonge.cooleshow.common.enums.UserFirstTimeTypeEnum;
 import com.yonge.toolset.base.exception.BizException;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.jwt.Jwt;
@@ -46,12 +53,14 @@ import java.math.BigDecimal;
 import java.security.interfaces.RSAPublicKey;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
+@Slf4j
 @RestController
 @RequestMapping("/open/adminClient")
 public class AdminClient extends BaseController {
-    private final static Logger log = LoggerFactory.getLogger(UserOrderClient.class);
 
     @Autowired
     private UserFirstTimeService userFirstTimeService;
@@ -68,6 +77,12 @@ public class AdminClient extends BaseController {
     @Autowired
     private CouponInfoService couponInfoService;
 
+    @Autowired
+    private TenantStaffService tenantStaffService;
+
+    @Autowired
+    private TenantInfoService tenantInfoService;
+
     @GetMapping("/recordTime")
     public HttpResponseResult<Boolean> recordTime(
             @RequestParam("userId") Long userId,
@@ -132,6 +147,44 @@ public class AdminClient extends BaseController {
         return succeed(employeeApi);
     }
 
+    @ApiOperation(value = "机构信息查询", notes = "tenantId -> 机构ID")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "tenantId", value = "机构ID", required = true, dataType = "Long", paramType = "query")
+    })
+    @GetMapping("/getTenant")
+    public HttpResponseResult<TenantWrapper.Tenant> getTenant(@RequestParam("tenantId") Long tenantId) {
+
+        TenantWrapper.Tenant build = TenantWrapper.Tenant.builder().build();
+
+        TenantInfo tenantInfo = tenantInfoService.getById(tenantId);
+        if (Objects.nonNull(tenantInfo)) {
+            build = TenantWrapper.Tenant.from(JSON.toJSONString(tenantInfo));
+        }
+
+        return succeed(build);
+    }
+
+    @ApiOperation(value = "机构员工信息查询", notes = "userId -> 机构用户ID")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", value = "机构用户ID", required = true, dataType = "Long", paramType = "query")
+    })
+    @GetMapping("/getTenantStaff")
+    public HttpResponseResult<TenantWrapper.Staff> getTenantStaff(@RequestParam("userId") Long userId) {
+
+        // 默认返回值
+        TenantWrapper.Staff ret = TenantWrapper.Staff.builder().build();
+
+        TenantStaff staff = tenantStaffService.getByUserId(userId);
+        if (Objects.nonNull(staff)) {
+            ret = TenantWrapper.Staff.from(JSON.toJSONString(staff));
+            ret.setStatus(staff.getStatus().name());
+            Long tenantId = staff.getTenantId();
+            TenantInfo tenantInfo = tenantInfoService.getById(Optional.ofNullable(tenantId).orElse(-1L));
+            ret.setTenantEnableFlag(Optional.ofNullable(tenantInfo).map(TenantInfo::getEnableFlag).orElse(false));
+        }
+        return succeed(ret);
+    }
+
     /**
      * 订单优惠券信息
      * @return HttpResponseResult<CouponOrderVO.CouponPageInfo>

+ 124 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenSysAreaController.java

@@ -0,0 +1,124 @@
+package com.yonge.cooleshow.admin.controller.open;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.google.common.collect.Lists;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.webportal.exception.BizException;
+import com.yonge.cooleshow.admin.io.request.SysAreaVo;
+import com.yonge.cooleshow.biz.dal.entity.SysArea;
+import com.yonge.cooleshow.biz.dal.service.SysAreaService;
+import com.yonge.cooleshow.biz.dal.wrapper.SysAreaWrapper;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Validated
+@RestController
+@RequestMapping("/open/sysArea")
+@Api(tags = "区域表")
+public class OpenSysAreaController {
+
+    @Autowired
+    private SysAreaService sysAreaService;
+
+    /**
+     * 查询单条
+     * @param id 详情ID
+     * @return R<SysAreaVo.SysArea>
+     */
+    @ApiOperation(value = "详情", notes = "传入id")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "id", dataType = "long")
+    })
+    @GetMapping("/detail/{id}")
+    public HttpResponseResult<SysAreaWrapper.SysArea> detail(@PathVariable("id") Long id) {
+
+        return HttpResponseResult.succeed(sysAreaService.detail(id));
+    }
+
+    /**
+     * 根据code查询
+     * @param code 详情ID
+     * @return R<SysAreaVo.SysArea>
+     */
+    @ApiOperation(value = "根据code查询", notes = "传入code")
+    @GetMapping("/queryByCode/{code}")
+    public HttpResponseResult<SysArea> queryByCode(@PathVariable("code") Integer code) {
+
+        List<Integer> codeList = new ArrayList<Integer>();
+        codeList.add(code);
+        List<SysArea> list = sysAreaService.queryByCodes(codeList);
+
+        if(list == null || list.size() == 0){
+            throw BizException.from("根据code查询区域表失败");
+        }
+
+        return HttpResponseResult.succeed(list.get(0));
+    }
+
+    /**
+     * 查询分页
+     * @param query SysAreaVo.SysAreaQuery
+     * @return R<PageInfo<SysAreaVo.SysAreaList>>
+     */
+    @ApiOperation(value = "查询分页", notes = "传入sysAreaSearch")
+    @PreAuthorize("@auditsvc.hasPermissions('sysArea/page', {'BACKEND'})")
+    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<SysAreaWrapper.SysArea>> page(@RequestBody SysAreaWrapper.SysAreaQuery query) {
+
+        IPage<SysAreaWrapper.SysArea> pages = sysAreaService.selectPage(QueryInfo.getPage(query), query);
+
+        return HttpResponseResult.succeed(QueryInfo.pageInfo(pages));
+    }
+
+    /**
+     * 查询全部区域
+     * @return R<List<SysAreaVo.Province>>
+     */
+    @ApiOperation(value = "查询全部区域", notes = "查询全部区域")
+    @GetMapping("/queryAllProvince")
+    public HttpResponseResult<List<SysAreaVo.Province>> queryAllProvince() {
+
+        List<SysAreaVo.Province> provinces = Lists.newArrayList();
+
+        // 全部城市信息
+        Map<Integer, List<SysArea>> areaMap = sysAreaService.lambdaQuery().list().stream()
+                .filter(x -> x.getDelFlag().equals("0"))
+                .collect(Collectors.groupingBy(SysArea::getParentOrganId));
+
+        SysAreaVo.Province provinceVo;
+        SysAreaVo.City cityVo;
+        for (SysArea province : areaMap.get(0)) {
+
+            provinceVo = JSON.parseObject(JSON.toJSONString(province), SysAreaVo.Province.class)
+                    .cities(Lists.newArrayList());
+            provinces.add(provinceVo);
+
+            // 城市信息
+            for (SysArea city : areaMap.get(province.getId())) {
+
+                cityVo = JSON.parseObject(JSON.toJSONString(city), SysAreaVo.City.class);
+                provinceVo.getAreas().add(cityVo);
+
+                if (areaMap.containsKey(city.getId())) {
+                    cityVo.setAreas(JSON.parseArray(JSON.toJSONString(areaMap.get(city.getId())), SysAreaVo.District.class));
+                }
+            }
+        }
+
+        return HttpResponseResult.succeed(provinces);
+    }
+}

+ 49 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenSysConfigController.java

@@ -0,0 +1,49 @@
+package com.yonge.cooleshow.admin.controller.open;
+
+import com.yonge.cooleshow.biz.dal.entity.SysConfig;
+import com.yonge.cooleshow.biz.dal.service.SysConfigService;
+import com.yonge.cooleshow.common.constant.SysConfigConstant;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.json.JSONObject;
+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.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * 系统配置控制层
+ */
+@RestController
+@Api(tags = "系统参数设置")
+@RequestMapping(value = "/open/sysConfig")
+public class OpenSysConfigController extends BaseController {
+
+    @Autowired
+    private SysConfigService sysConfigService;
+
+    @ApiOperation(value = "查询客服手机号")
+    @GetMapping(value = "/queryCustomerServicePhone")
+    public HttpResponseResult<String> queryCustomerServicePhone() {
+        SysConfig sysConfig = sysConfigService.findByParamName(SysConfigConstant.CUSTOMER_SERVICE_PHONE);
+        return succeed(sysConfig.getParamValue());
+    }
+
+    @ApiOperation(value = "查询客服联系方式,电话和邮箱")
+    @GetMapping(value = "/queryCustomerService")
+    public HttpResponseResult<Map<String, String>> queryCustomerService() {
+        SysConfig email = sysConfigService.findByParamName(SysConfigConstant.CUSTOMER_SERVICE_EMAIL);
+        SysConfig phone = sysConfigService.findByParamName(SysConfigConstant.CUSTOMER_SERVICE_PHONE);
+        Map<String, String> result = new HashMap<>();
+        result.put("email", email == null ? "" : email.getParamValue());
+        result.put("phone", phone == null ? "" : phone.getParamValue());
+        return succeed(result);
+    }
+
+}

+ 266 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/controller/open/UserPaymentClient.java

@@ -0,0 +1,266 @@
+package com.yonge.cooleshow.admin.controller.open;
+
+import cn.hutool.extra.servlet.ServletUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.huifu.adapay.core.AdapayCore;
+import com.huifu.adapay.core.util.AdapaySign;
+import com.microsvc.toolkit.common.response.template.R;
+import com.microsvc.toolkit.common.webportal.exception.BizException;
+import com.microsvc.toolkit.config.jwt.utils.JwtUserInfo;
+import com.microsvc.toolkit.middleware.payment.common.api.PaymentServiceContext;
+import com.microsvc.toolkit.middleware.payment.common.api.entity.PaymentResp;
+import com.microsvc.toolkit.middleware.payment.common.api.entity.RefundResp;
+import com.yeepay.g3.sdk.yop.encrypt.DigitalEnvelopeDTO;
+import com.yeepay.g3.sdk.yop.utils.DigitalEnvelopeUtils;
+import com.yeepay.g3.sdk.yop.utils.RSAKeyUtils;
+import com.yonge.cooleshow.biz.dal.entity.PaymentMerchantConfig;
+import com.yonge.cooleshow.biz.dal.entity.TenantMember;
+import com.yonge.cooleshow.biz.dal.entity.UserOrderRefund;
+import com.yonge.cooleshow.biz.dal.entity.UserOrderRefundBill;
+import com.yonge.cooleshow.biz.dal.enums.AuthStatusEnum;
+import com.yonge.cooleshow.biz.dal.service.*;
+import com.yonge.cooleshow.biz.dal.wrapper.UserPaymentOrderWrapper;
+import com.yonge.cooleshow.common.enums.EPayerType;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Date;
+import java.util.Objects;
+
+@Slf4j
+@RestController
+@RequestMapping("/open/userOrder")
+@Api(tags = "开放权限接口-支付回调")
+public class UserPaymentClient {
+
+    @Autowired
+    private PaymentServiceContext paymentServiceContext;
+    @Autowired
+    private UserPaymentCoreService userPaymentCoreService;
+    @Autowired
+    private UserPaymentOrderService userPaymentOrderService;
+
+    @Autowired
+    private UserOrderService userOrderService;
+
+    @Autowired
+    private TenantMemberService tenantMemberService;
+
+    @Autowired
+    private PaymentMerchantConfigService paymentMerchantConfigService;
+
+    @Autowired
+    private UserOrderRefundBillService userOrderRefundBillService;
+    /**
+     * 支付消息回调
+     * @param request HttpServletRequest
+     * @return String
+     */
+    @ApiOperation(value = "支付消息回调", notes = "三方支付平台支付消息通知")
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "vendor", value = "服务提供方", dataType = "String")
+    })
+    @RequestMapping(value = "/payment/callback/{vendor}", method = {RequestMethod.GET, RequestMethod.POST})
+    public String payment(@PathVariable("vendor") String vendor, HttpServletRequest request) {
+
+        // 支付回调消息
+        PaymentResp paymentResp = paymentServiceContext.getPaymentService(vendor).callbackNotifyForPay(request);
+        if (Objects.isNull(paymentResp)) {
+            return null;
+        }
+        log.info("payment vendor={}, paymentResp={}", vendor, JSON.toJSONString(paymentResp));
+        // 支付订单确认
+        UserPaymentOrderWrapper.UserPaymentOrder paymentOrder = userPaymentOrderService
+                .getUserPaymentOrderByOrderNo( paymentResp.getMerOrderNo());
+        if (Objects.isNull(paymentOrder)) {
+            return paymentResp.getMsg();
+        }
+
+        // 执行支付回调流程
+        userPaymentCoreService.executePaymentCallback(paymentResp);
+
+        return paymentServiceContext.getPaymentService(vendor).returnNotifyResult(request);
+    }
+
+    @ApiOperation(value = "用户付款", notes = "用户付款")
+    @PostMapping("/executePayment/v2")
+    public R<UserPaymentOrderWrapper.PaymentReq> executePayment(@Validated @RequestBody UserPaymentOrderWrapper.PaymentOrderReqConfig config,
+                                                                HttpServletRequest request) {
+
+        // 用户登录状态校验
+        if (StringUtils.isBlank(config.getUserId())) {
+            throw BizException.from("用户未登录");
+        }
+
+        // 用户下单请求
+        UserPaymentOrderWrapper.PaymentOrderReqConfig reqConfig = UserPaymentOrderWrapper.PaymentOrderReqConfig.from(config.jsonString());
+
+        // 支付三方
+        reqConfig.setPaymentVendor(config.getPaymentVendor());
+        // 请示IP地址
+        reqConfig.setIp(ServletUtil.getClientIP(request));
+
+        JwtUserInfo<Object> userInfo = JwtUserInfo.builder()
+            .userId(config.getUserId())
+            .clientType(config.getUserType().getCode())
+            .build();
+        // 创建用户支付数据
+        UserPaymentOrderWrapper.PaymentReq paymentConfig = userPaymentCoreService.executePayment(userInfo, reqConfig);
+        if (Objects.isNull(paymentConfig)) {
+            throw BizException.from("用户支付请求错误");
+        }
+
+        return R.from(paymentConfig);
+    }
+
+
+    /**
+     * 退款消息回调
+     * @param request HttpServletRequest
+     * @return String
+     */
+    @ApiOperation(value = "退款消息回调", notes = "三方支付平台退款消息通知")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "vendor", value = "服务提供方", dataType = "String")
+    })
+    @RequestMapping(value = "/refund/callback/{vendor}", method = {RequestMethod.GET, RequestMethod.POST})
+    public String refund(@PathVariable("vendor") String vendor, HttpServletRequest request) {
+
+        RefundResp refundResp = paymentServiceContext.getPaymentService(vendor).callbackNotifyForRefund(request);
+        if (Objects.isNull(refundResp)) {
+            log.info("refund REFUND_FAILED, vendor={}", vendor);
+            return null;
+        }
+        log.info("refund vendor={}, refundResp={}", vendor, JSON.toJSONString(refundResp));
+
+        // 执行退款回调流程
+        userPaymentCoreService.refundPaymentCallback(refundResp);
+
+        return paymentServiceContext.getPaymentService(vendor).returnNotifyResult(request);
+    }
+
+    @PostMapping("/callback/adapay")
+    public String callback(HttpServletRequest request) {
+        try {
+            // 验签请参data
+            String data = request.getParameter("data");
+            // 验签请参sign
+            String sign = request.getParameter("sign");
+
+            // 验签
+            if (!AdapaySign.verifySign(data, sign, AdapayCore.PUBLIC_KEY)) {
+                return "验签失败";
+            }
+
+            JSONObject dataObj = JSON.parseObject(data);
+
+            String memberId = dataObj.getString("member_id");
+
+            TenantMember tenantMember = tenantMemberService.getByMemberId(memberId, EPayerType.YEEPAY);
+            if(tenantMember == null){
+                return "账户["+ memberId +"]在系统中不存在";
+            }
+            tenantMember.setUpdateTime(new Date());
+
+            String transType = request.getParameter("type");
+
+            switch (transType) {
+
+                case "corp_member.succeeded":// 企业子账户开户成功
+                    String settleAccountId = dataObj.getString("settle_account_id");
+                    tenantMember.setSettleAccountId(settleAccountId);
+                    tenantMember.setStatus(AuthStatusEnum.PASS);
+
+                    break;
+
+                case "corp_member.failed":// 企业子账户开户失败
+                    tenantMember.setStatus(AuthStatusEnum.UNPASS);
+                    tenantMember.setMemo(dataObj.getString("audit_desc"));
+
+                    break;
+
+                case "corp_member_update.succeeded":// 更新企业用户对象成功
+                    tenantMember.setStatus(AuthStatusEnum.PASS);
+
+                    break;
+
+                case "corp_member_update.failed":// 更新企业用户对象失败
+                    tenantMember.setStatus(AuthStatusEnum.UNPASS);
+                    tenantMember.setMemo(dataObj.getString("audit_desc"));
+
+                    break;
+
+                default:
+                    break;
+            }
+
+            tenantMemberService.updateById(tenantMember);
+
+        } catch (Exception e) {
+            return e.getMessage();
+        }
+
+        return "succeeded";
+    }
+
+
+    @PostMapping("/callback/yeepay/{requestNo}")
+    public String callback(@PathVariable("requestNo") String requestNo, HttpServletRequest request) {
+
+        TenantMember tenantMember = tenantMemberService.getByRequestNo(requestNo);
+        if(tenantMember == null){
+            return "请求编号["+ requestNo +"]在系统中不存在";
+        }
+        tenantMember.setUpdateTime(new Date());
+
+        PaymentMerchantConfig paymentMerchantConfig = paymentMerchantConfigService.getByPaymentVendor(tenantMember.getPayerName());
+        if(paymentMerchantConfig == null){
+            throw new BizException("机构[{}][{}]商户信息找不到", tenantMember.getTenantId(), EPayerType.YEEPAY.getCode());
+        }
+
+        try {
+
+            String content = request.getParameter("response");
+
+            // 构造结果通知请求对象
+            DigitalEnvelopeDTO dto = new DigitalEnvelopeDTO();
+            dto.setCipherText(content);
+            PrivateKey privateKey = RSAKeyUtils.string2PrivateKey(paymentMerchantConfig.getRsaPrivateKey());
+            PublicKey publicKey = RSAKeyUtils.string2PublicKey(paymentMerchantConfig.getRsaPublicKey());
+
+            dto = DigitalEnvelopeUtils.decrypt(dto, privateKey, publicKey);
+
+            log.info("易宝支付回调信息:response:{} plaintText:{}", content, dto.getPlainText());
+
+            JSONObject dataObj = JSON.parseObject(dto.getPlainText());
+
+            if("COMPLETED".equals(dataObj.getString("applicationStatus"))) {
+                //审核成功
+                tenantMember.setStatus(AuthStatusEnum.PASS);
+                tenantMemberService.updateById(tenantMember);
+            }else if("REVIEW_BACK".equals(dataObj.getString("applicationStatus"))) {
+                //审核驳回
+                tenantMember.setStatus(AuthStatusEnum.UNPASS);
+                tenantMember.setMemo(dataObj.getString("auditOpinion"));
+                tenantMemberService.updateById(tenantMember);
+            }
+
+            return "SUCCESS";
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 168 - 0
cooleshow-user/user-admin/src/main/java/com/yonge/cooleshow/admin/io/request/SysAreaVo.java

@@ -0,0 +1,168 @@
+package com.yonge.cooleshow.admin.io.request;
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 区域表
+ * 2022-11-23 18:28:58
+ */
+@ApiModel(value = "SysAreaVo对象", description = "区域表查询视图对象")
+public class SysAreaVo {
+
+    @Data
+    @ApiModel(" SysAreaList-区域表")
+    public static class SysAreaQuery implements QueryInfo {
+
+    	@ApiModelProperty("父节点")
+    	private Integer parentId;
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+    }
+
+    @Data
+    @ApiModel(" SysArea-区域表")
+    public static class SysArea {
+
+
+		@ApiModelProperty("")
+        private Integer id;
+
+
+		@ApiModelProperty("名称")
+        private String name;
+
+
+		@ApiModelProperty("编码")
+        private Integer code;
+
+
+		@ApiModelProperty("创建时间")
+        private Date createTime;
+
+
+		@ApiModelProperty("修改时间")
+        private Date updateTime;
+
+
+		@ApiModelProperty("是否删除  -1:已删除  0:正常")
+        private String delFlag;
+
+
+		@ApiModelProperty("父节点编号")
+        private Integer parentOrganId;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+    }
+
+    @Data
+    @ApiModel(" SysAreaList-区域表")
+    public static class SysAreaList {
+
+
+		@ApiModelProperty("")
+        private Integer id;
+
+
+		@ApiModelProperty("名称")
+        private String name;
+
+
+		@ApiModelProperty("编码")
+        private Integer code;
+
+
+		@ApiModelProperty("创建时间")
+        private Date createTime;
+
+
+		@ApiModelProperty("修改时间")
+        private Date updateTime;
+
+
+		@ApiModelProperty("是否删除  -1:已删除  0:正常")
+        private String delFlag;
+
+
+		@ApiModelProperty("父节点编号")
+        private Integer parentOrganId;
+
+        @ApiModelProperty("区域数")
+        private Integer number;
+    }
+
+    @Data
+    @ApiModel("省份")
+    public static class Province implements Serializable {
+
+        @ApiModelProperty("主键Id")
+        private Integer id;
+
+        @ApiModelProperty("名称")
+        private String name;
+
+        @ApiModelProperty("编码")
+        private Integer code;
+
+        @ApiModelProperty("父节点编号")
+        private Integer parentOrganId;
+
+        @ApiModelProperty("城市")
+        private List<City> areas;
+
+
+        public Province cities(List<City> cities) {
+            this.areas = cities;
+            return this;
+        }
+    }
+
+    @Data
+    @ApiModel("城市")
+    public static class City implements Serializable {
+
+        @ApiModelProperty("主键Id")
+        private Integer id;
+
+        @ApiModelProperty("名称")
+        private String name;
+
+        @ApiModelProperty("编码")
+        private Integer code;
+
+        @ApiModelProperty("父节点编号")
+        private Integer parentOrganId;
+
+        @ApiModelProperty("地区/街道")
+        private List<District> areas;
+
+    }
+
+    @Data
+    @ApiModel("地区/街道")
+    public static class District implements Serializable {
+
+        @ApiModelProperty("主键Id")
+        private Integer id;
+
+        @ApiModelProperty("名称")
+        private String name;
+
+        @ApiModelProperty("编码")
+        private Integer code;
+    }
+}

Неке датотеке нису приказане због велике количине промена