mj-li 2 months ago
commit
6b687ed9bc
89 changed files with 5426 additions and 0 deletions
  1. 84 0
      .gitignore
  2. 61 0
      healthy-frontend-app/pom.xml
  3. 17 0
      healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/HealthyFrontendApplication.java
  4. 16 0
      healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/ApplicationRunnerApp.java
  5. 32 0
      healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/CaffeineCacheConfig.java
  6. 51 0
      healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/RequestFilter.java
  7. 67 0
      healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/Swager2Config.java
  8. 71 0
      healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/SwaggerInterceptor.java
  9. 32 0
      healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/WebMvcConfig.java
  10. 92 0
      healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/intercepter/HttpRequestUtil.java
  11. 97 0
      healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/intercepter/WebHttpServletRequestWrapper.java
  12. 31 0
      healthy-frontend-app/src/main/resources/application-dev.yml
  13. 27 0
      healthy-frontend-app/src/main/resources/application-prod.yml
  14. 88 0
      healthy-frontend-app/src/main/resources/application.yml
  15. 59 0
      healthy-frontend-app/src/main/resources/logback-spring.xml
  16. 119 0
      healthy-frontend-common/pom.xml
  17. 99 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/BusinessBaseErrorEnum.java
  18. 89 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/BusinessException.java
  19. 47 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/GlobalExceptionHandler.java
  20. 21 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/IErrorCodeEnum.java
  21. 38 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/WechatBaseErrorEnum.java
  22. 137 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/AnalysisApiHelper.java
  23. 76 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/HisApiHelper.java
  24. 594 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/HisWebApiHelper.java
  25. 44 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/WbmdOaApiHelper.java
  26. 37 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/config/HisWebConfig.java
  27. 50 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/config/SysProjectConfig.java
  28. 14 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/AnalysisDataDTO.java
  29. 19 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/GenerateSchemeDTO.java
  30. 25 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/HisGenerateSchemeDTO.java
  31. 30 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/HisPatientDTO.java
  32. 17 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/HisPromotionCodeDTO.java
  33. 17 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/WechatQrCodeDTO.java
  34. 37 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/AnalysisDataModel.java
  35. 20 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/GenerateSchemeModel.java
  36. 11 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisAccessTokenModel.java
  37. 16 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisBaseModel.java
  38. 14 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisDeptListModel.java
  39. 55 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisDeptModel.java
  40. 14 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisDoctorListModel.java
  41. 51 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisDoctorModel.java
  42. 14 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisPatientListModel.java
  43. 65 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisPatientModel.java
  44. 22 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisPromotionCodeModel.java
  45. 14 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisSchemeUrlModel.java
  46. 13 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisWxTokenModel.java
  47. 25 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/PatBindModel.java
  48. 89 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/PatInfoModel.java
  49. 22 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/WbmdOaModel.java
  50. 16 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/WbmdOaResult.java
  51. 110 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/modules/Result.java
  52. 66 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/util/IpUtils.java
  53. 33 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/util/IpWhite.java
  54. 63 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinAccessTokenService.java
  55. 45 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinLoginMiniService.java
  56. 81 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinLoginMpService.java
  57. 24 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinPageAccessTokenService.java
  58. 88 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinSendTempMsgService.java
  59. 29 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/bos/ThirdUnifyUserLoginBO.java
  60. 36 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/constant/XXWeiXinErrorEnum.java
  61. 12 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/AccessTokenDTO.java
  62. 22 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/BindMobileByWxDTO.java
  63. 13 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/LoginAuthTokenDTO.java
  64. 12 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/RefreshTokenDTO.java
  65. 26 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/SendTempMsgDTO.java
  66. 28 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/SendWxWorkMsgDTO.java
  67. 37 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/ThirdUnifyUserLoginDTO.java
  68. 11 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/UnionIdDTO.java
  69. 40 0
      healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/helper/ThirdUserLoginWeixinConvert.java
  70. 26 0
      healthy-frontend-custuser/pom.xml
  71. 34 0
      healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/AnalysisController.java
  72. 123 0
      healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/CustUserWxLoginController.java
  73. 36 0
      healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/CustUserWxSendTempMsgController.java
  74. 81 0
      healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/CustomerApiController.java
  75. 127 0
      healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/HisApiController.java
  76. 39 0
      healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/WbmdOaController.java
  77. 640 0
      healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/WechatController.java
  78. 204 0
      healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/WechatThirdController.java
  79. 127 0
      healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/WechatWorkController.java
  80. 99 0
      healthy-frontend-mq/pom.xml
  81. 37 0
      healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/controller/FrontendDemoController.java
  82. 18 0
      healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/listener/FrontendDemoListener.java
  83. 23 0
      healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/model/ActiveMqTypeEnum.java
  84. 21 0
      healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/model/MqMessageModel.java
  85. 44 0
      healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/model/MqSendDelayModel.java
  86. 39 0
      healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/model/MqSendModel.java
  87. 16 0
      healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/service/ActiveMqService.java
  88. 86 0
      healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/service/impl/ActiveMqServiceImpl.java
  89. 34 0
      pom.xml

+ 84 - 0
.gitignore

@@ -0,0 +1,84 @@
+# maven output files
+/target/
+*/target/
+**/target/
+
+# virtual machine crash logs
+hs_err_pid*
+/bin/
+/build/
+*/bin/
+*/gen/
+*/out/
+
+# Java class files
+*.class
+
+# Files for the Dalvik VM
+*.dex
+
+#Built application files
+*.apk
+*.ap_
+proguard/
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+# *.jar
+*.war
+*.ear
+
+# Eclipse Project files
+.classpath
+*/.classpath
+**/.classpath
+.project
+*/.project
+**/.project
+.factorypath
+*/.factorypath
+**/.factorypath
+.settings/
+/.settings/
+*/.settings/
+**/.settings/
+*/.apt_generated/
+**/.apt_generated/
+*/.apt_generated_tests/
+**/.apt_generated_tests/
+
+# IntelliJ IDEA Project files
+.idea
+*.iml
+*/*.iml
+**/*.iml
+*.ipr
+*.iws
+out
+*/.DS_Store
+**/.DS_Store
+.DS_Store
+Thumbs.db
+/.idea/
+*/.idea/
+**/.idea/
+.idea/
+
+#gradle wrapper
+gradle/
+/.gradle/
+# Gradle files
+.gradle/
+build/
+*/build/
+**/build/
+gradlew
+gradlew.bat
+
+# Log Files
+*.log
+
+# VSCode
+.vscode

+ 61 - 0
healthy-frontend-app/pom.xml

@@ -0,0 +1,61 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>healthy-frontend-java</artifactId>
+        <groupId>com.xxh.cloud.frontend</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>healthy-frontend-app</artifactId>
+    <packaging>jar</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>com.xxh.cloud.frontend</groupId>
+            <artifactId>healthy-frontend-custuser</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+<!--        <dependency>-->
+<!--            <groupId>com.xxh.cloud.frontend</groupId>-->
+<!--            <artifactId>healthy-frontend-mq</artifactId>-->
+<!--            <version>${project.version}</version>-->
+<!--        </dependency>-->
+    </dependencies>
+
+    <build>
+        <finalName>healthy-frontend-1.0.0</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <!-- <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <encoding>UTF-8</encoding>
+                    <compilerArguments>
+                        <verbose />
+                        <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</bootclasspath>
+                    </compilerArguments>
+                </configuration>
+            </plugin> -->
+        </plugins>
+    </build>
+</project>

+ 17 - 0
healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/HealthyFrontendApplication.java

@@ -0,0 +1,17 @@
+package com.xxh.cloud.frontend;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.ComponentScan;
+
+@EnableCaching
+@SpringBootApplication
+@ComponentScan(basePackages = { "com.xxh.cloud" })
+public class HealthyFrontendApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(HealthyFrontendApplication.class, args);
+    }
+
+}

+ 16 - 0
healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/ApplicationRunnerApp.java

@@ -0,0 +1,16 @@
+package com.xxh.cloud.frontend.config;
+
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+/**
+ * 项目启动初始化
+ * */
+@Component
+public class ApplicationRunnerApp implements ApplicationRunner {
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        System.out.println("---------------APP START-------app------------");
+    }
+}

+ 32 - 0
healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/CaffeineCacheConfig.java

@@ -0,0 +1,32 @@
+package com.xxh.cloud.frontend.config;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.caffeine.CaffeineCacheManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Author: limj
+ * @Date: 2023/11/11
+ */
+@Configuration
+@EnableCaching
+public class CaffeineCacheConfig {
+    @Bean
+    public CacheManager cacheManager(){
+        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
+        //Caffeine配置
+        Caffeine<Object, Object> caffeine = Caffeine.newBuilder()
+                //最后一次写入后经过固定时间过期
+                .expireAfterWrite(7100, TimeUnit.SECONDS)
+                //maximumSize=[long]: 缓存的最大条数
+                .maximumSize(1000);
+        cacheManager.setCaffeine(caffeine);
+        return cacheManager;
+    }
+}
+

+ 51 - 0
healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/RequestFilter.java

@@ -0,0 +1,51 @@
+package com.xxh.cloud.frontend.config;
+
+import cn.hutool.core.util.StrUtil;
+import com.xxh.cloud.frontend.config.intercepter.WebHttpServletRequestWrapper;
+import com.xxh.cloud.frontend.common.modules.exception.BusinessException;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+@WebFilter(urlPatterns = "/*",filterName = "sqlFilter")
+@Configuration
+public class RequestFilter implements Filter {
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException, BusinessException {
+//        System.out.println("+++++++ 拦截器 WebServletRequestReplacedFilter");
+        WebHttpServletRequestWrapper requestWrapper = null;
+        if (request instanceof HttpServletRequest) {
+            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+            String url = httpServletRequest.getRequestURL().toString();
+            String method= httpServletRequest.getMethod();
+            String contentType= httpServletRequest.getContentType();
+            System.out.println(StrUtil.format("url={}, method ={} ,ContentType={} ",url, method,contentType));
+            // 上传文件的form直接通过
+            if(StrUtil.isNotEmpty(contentType) && contentType.contains("multipart/form-data")){
+                chain.doFilter(request, response);
+            }
+            // 判断 post_json
+            if(!HttpMethod.GET.name().toUpperCase().equals(method.toUpperCase())){
+                requestWrapper = new WebHttpServletRequestWrapper(httpServletRequest);
+            }
+        }
+        if (requestWrapper == null) {
+            chain.doFilter(request, response);
+        } else {
+            String bodyContext = requestWrapper.getBodyContent();
+            System.out.println("拦截器 bodyContext = "+ bodyContext);
+            chain.doFilter(requestWrapper, response);
+        }
+    }
+}

+ 67 - 0
healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/Swager2Config.java

@@ -0,0 +1,67 @@
+package com.xxh.cloud.frontend.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.handler.MappedInterceptor;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.ParameterBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Parameter;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+@EnableSwagger2
+@ComponentScan(basePackages = {"com.xxh"})
+public class Swager2Config {
+
+    @Value("${saas.swagger.basic.username:admin}")
+    private String username;
+    @Value("${saas.swagger.basic.password:admin}")
+    private String password;
+
+    /* 必须在此处配置拦截器,要不然拦不到swagger的静态资源 */
+    @Bean
+    @ConditionalOnProperty(name = "saas.swagger.basic.enable", havingValue = "true")
+    public MappedInterceptor getMappedInterceptor() {
+        return new MappedInterceptor(
+                new String[]{"/swagger-ui.html","/swagger/**", "/swagger-resources","/swagger-resources/**"
+                        ,"/webjars/**", "/v2/api-docs"},
+                new SwaggerInterceptor("username", "password"));
+    }
+
+    @Bean
+    public Docket createRestApi() {
+        //添加head参数start
+        List<Parameter> pars = new ArrayList<Parameter>();
+        pars.add(new ParameterBuilder().name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build());
+       //pars.add(new ParameterBuilder().name("saas").description("公司编号").modelRef(new ModelRef("string")).parameterType("header").required(false).build());
+        pars.add(new ParameterBuilder().name("lang").description("语言").modelRef(new ModelRef("string")).parameterType("header").required(false).build());
+
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .select()
+                .apis(RequestHandlerSelectors.basePackage("com.xxh"))
+                .paths(PathSelectors.any())
+                .build()
+                .globalOperationParameters(pars);
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("API接口定义")
+                .description("API接口定义说明")
+                .version("1.0")
+                .build();
+    }
+}

+ 71 - 0
healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/SwaggerInterceptor.java

@@ -0,0 +1,71 @@
+package com.xxh.cloud.frontend.config;
+
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.util.FileCopyUtils;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+import sun.misc.BASE64Decoder;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class SwaggerInterceptor extends HandlerInterceptorAdapter {
+    private String username;
+    private String password;
+    public SwaggerInterceptor(String username, String password) {
+        this.username = username;
+        this.password = password;
+    }
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        String authorization = request.getHeader("Authorization");
+        boolean isAuthSuccess = httpBasicAuth(authorization);
+        if (!isAuthSuccess) {
+            response.setCharacterEncoding("utf-8");
+            response.setStatus(401);
+//            response.setStatus(401,"Unauthorized");
+            response.setHeader("WWW-authenticate", "Basic realm=\"Realm\"");
+            try (PrintWriter writer = response.getWriter()) {
+                writer.print("Forbidden, unauthorized user");
+            }
+        }
+        return isAuthSuccess;
+    }
+    public boolean httpBasicAuth(String authorization) throws IOException {
+        if (authorization != null && authorization.split(" ").length == 2) {
+            String userAndPass = new String(new BASE64Decoder().decodeBuffer(authorization.split(" ")[1]));
+            String username = userAndPass.split(":").length == 2 ? userAndPass.split(":")[0] : null;
+            String password = userAndPass.split(":").length == 2 ? userAndPass.split(":")[1] : null;
+            if (this.username.equals(username) && this.password.equals(password)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        String uri = request.getRequestURI();
+        AntPathMatcher pathMatcher = new AntPathMatcher();
+        if (!pathMatcher.match("/swagger-ui.html", uri)
+                && !pathMatcher.match("/swagger/**", uri)
+                && !pathMatcher.match("/swagger-resources", uri)
+                && !pathMatcher.match("/swagger-resources/**", uri)
+                && !pathMatcher.match("/webjars/**", uri)
+                && !pathMatcher.match("/v2/api-docs", uri)) {
+            response.setStatus(404);
+            return;
+        }
+        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+        Resource[] resources = resolver.getResources("classpath:/META-INF/resources" + uri);
+        if (resources != null && resources.length > 0) {
+            FileCopyUtils.copy(resources[0].getInputStream(), response.getOutputStream());
+        } else {
+            response.setStatus(404);
+        }
+    }
+
+}

+ 32 - 0
healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/WebMvcConfig.java

@@ -0,0 +1,32 @@
+package com.xxh.cloud.frontend.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import java.util.List;
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+    /**
+     * Spring的拦截器配置
+     * */
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        // 权限注解拦截器
+        System.out.println("----------------权限注解拦截器-------------------------");
+//        registry.addInterceptor(new AuthorizationAnnotationInterceptor(redisUtils));
+    }
+
+    /**
+     * controller请求扩展点配置
+     * */
+    @Override
+    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
+        //@LoginUser配置
+        System.out.println("----------------LoginUser配置-------------------------");
+//        argumentResolvers.add(new LoginUserHandlerMethodArgumentResolver(false));
+    }
+}

+ 92 - 0
healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/intercepter/HttpRequestUtil.java

@@ -0,0 +1,92 @@
+package com.xxh.cloud.frontend.config.intercepter;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+
+public class HttpRequestUtil {
+
+	public static String getBodyContent(HttpServletRequest request) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        try  {
+            InputStream inputStream = request.getInputStream();
+            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                sb.append(line);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return sb.toString();
+    }
+
+
+
+    public static String getPostData(HttpServletRequest request) {
+        StringBuilder data = new StringBuilder();
+        String line;
+        BufferedReader reader;
+        try {
+            reader = request.getReader();
+            while (null != (line = reader.readLine())) {
+                data.append(line);
+            }
+        } catch (IOException e) {
+            return null;
+        }
+        return data.toString();
+    }
+
+
+//
+//    public static String getBodyString(HttpServletRequest request) throws IOException {
+//        StringBuilder sb = new StringBuilder();
+//        InputStream inputStream = null;
+//        BufferedReader reader = null;
+//        try {
+//            inputStream = request.getInputStream();
+//            reader = new BufferedReader(
+//                    new InputStreamReader(inputStream, Charset.forName("UTF-8")));
+//
+//            char[] bodyCharBuffer = new char[1024];
+//            int len = 0;
+//            while ((len = reader.read(bodyCharBuffer)) != -1) {
+//                sb.append(new String(bodyCharBuffer, 0, len));
+//            }
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//        } finally {
+//            if (inputStream != null) {
+//                try {
+//                    inputStream.close();
+//                } catch (IOException e) {
+//                    e.printStackTrace();
+//                }
+//            }
+//            if (reader != null) {
+//                try {
+//                    reader.close();
+//                } catch (IOException e) {
+//                    e.printStackTrace();
+//                }
+//            }
+//        }
+//        return sb.toString();
+//    }
+
+
+
+
+
+
+
+
+
+
+
+	
+}

+ 97 - 0
healthy-frontend-app/src/main/java/com/xxh/cloud/frontend/config/intercepter/WebHttpServletRequestWrapper.java

@@ -0,0 +1,97 @@
+package com.xxh.cloud.frontend.config.intercepter;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.*;
+
+public class WebHttpServletRequestWrapper extends HttpServletRequestWrapper {
+
+	//
+	private  byte[] body;
+
+	//
+	private String content;
+
+	//
+	private final Map<String, String> customHeaders;
+	
+
+    public WebHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
+        super(request);
+        this.customHeaders = new HashMap<String, String>();
+        this.content= HttpRequestUtil.getBodyContent(request);
+        this.body = this.content.getBytes(Charset.forName("UTF-8"));
+    }
+    
+    
+    public void putHeader(String name, String value){
+        this.customHeaders.put(name, value);
+    }
+
+    @Override
+    public String getHeader(String name) {
+        String headerValue = customHeaders.get(name);
+        if (headerValue != null){
+            return headerValue;
+        }
+        return ((HttpServletRequest) getRequest()).getHeader(name);
+    }
+
+    @Override
+    public Enumeration<String> getHeaderNames() {
+        Set<String> set = new HashSet<String>(customHeaders.keySet());
+        @SuppressWarnings("unchecked")
+        Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
+        while (e.hasMoreElements()) {
+            String n = e.nextElement();
+            set.add(n);
+        }
+        return Collections.enumeration(set);
+    }
+
+    /***/
+    public String getBodyContent() {
+        return this.content;
+    }
+
+    /***/
+    public void setBodyContent(String content){
+        this.content=content;
+        this.body = this.content.getBytes(Charset.forName("UTF-8"));
+    }
+    
+    @Override
+    public BufferedReader getReader() throws IOException {
+        return new BufferedReader(new InputStreamReader(getInputStream()));
+    }
+ 
+    @Override
+    public ServletInputStream getInputStream() throws IOException {
+        final ByteArrayInputStream bais = new ByteArrayInputStream(this.body);
+        return new ServletInputStream() {
+            @Override
+            public int read() throws IOException {
+                return bais.read();
+            }
+            @Override
+            public boolean isFinished() {
+                return false;
+            }
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+            @Override
+            public void setReadListener(ReadListener readListener) {
+            }
+        };
+    }
+	
+}

+ 31 - 0
healthy-frontend-app/src/main/resources/application-dev.yml

@@ -0,0 +1,31 @@
+
+sys-config:
+  # 获取token 访问his还是wx
+  access: wx
+  his:
+    host: http://172.18.84.18:13024
+    key: kw%cHIwSEs#V^Ree&(vYiFKixG1zn.oW$3Jc0Mh@C
+  wx:
+    appid: wxbe14c70a4dcb3a0c
+    secret: a46036cbb80c1c5d7ce21a98b1041969
+    temp-msg:
+      check-enable: true
+      white: o6jK358cVF3c-lzV4Ft4e1ExusBw,o6jK352u-eNoiEeQb2KsUKwAF8_c,o6jK3576qgmYkckfyYqrzFvgMGgs,o6jK35yeY0do8oG_Hhpldu_3KWbs
+
+wechat:
+  mp:
+    token: R7ubF2cTVv3Wk
+    encodingAesKey: PV6BOK2qL5IGm1KglV9SCNRYOVLSOhfoZIL2nkYfhu1
+    eventDealUrl: https://dev1.cloud-seal.com/hipo-business/sys/healthy/wechat/reply
+    # eventDealUrl: http://localhost:8080/sys/healthy/wechat/reply
+  open:
+    appid: wxb044d310a603d404
+    token: m1KglV9SCNRYOV
+    encodingAesKey: YOVLSOhfoZIL2PV6BOK2qL5IGm1KglV9SCNRnkYfhu1
+    componentVerifyTicketUrl:
+    componentEventDealUrl: https://dev1.cloud-seal.com/hipo-business/sys/healthy/wechat/reply
+
+xxl:
+  ip:
+    white:
+      enable: false

+ 27 - 0
healthy-frontend-app/src/main/resources/application-prod.yml

@@ -0,0 +1,27 @@
+
+sys-config:
+  # 获取token 访问his还是wx
+  access: wx
+  his:
+    host: http://172.18.84.18:13024
+    key: kw%cHIwSEs#V^Ree&(vYiFKixG1zn.oW$3Jc0Mh@C
+  wx:
+    appid: wxbe14c70a4dcb3a0c
+    secret: a46036cbb80c1c5d7ce21a98b1041969
+    temp-msg:
+      check-enable: true
+      white: o6jK358cVF3c-lzV4Ft4e1ExusBw,o6jK352u-eNoiEeQb2KsUKwAF8_c,o6jK3576qgmYkckfyYqrzFvgMGgs
+
+wechat:
+  mp:
+    token: OK2qL5IGm1Kgl
+    encodingAesKey: PV6BOK2qL5IGm2KglV9SCNRYOVLSOhfoZIL6nkYfhu2
+    eventDealUrl: http://172.18.84.102:8080/api/wbmd3h/sys/healthy/wechat/reply
+    # eventDealUrl: http://localhost:8080/sys/healthy/wechat/reply
+
+xxl:
+  ip:
+    white:
+      enable: true
+      list: "10.10.18.5"
+  

+ 88 - 0
healthy-frontend-app/src/main/resources/application.yml

@@ -0,0 +1,88 @@
+server:
+  port: 8081
+  servlet:
+    context-path: /
+  netty:
+    connection-timeout:
+
+management:
+  endpoints:
+    web:
+      exposure:
+        include: '*'
+spring:
+  application:
+    name: healthy-frontend
+  profiles: 
+    active: dev
+  #jackson json解析
+  jackson:
+    time-zone: GMT+8
+    serialization:
+      #关闭jackson 对json做解析
+      fail-on-empty-beans: false
+  mvc:
+    pathmatch:
+      matching-strategy: ANT_PATH_MATCHER
+  activemq:
+    #    broker-url: tcp://101.132.255.47:61616  #activeMQ的ip和端口号
+    broker-url: tcp://127.0.0.1:61616  #activeMQ的ip和端口号
+    user: admin   #activeMq账号
+    password: admin #activeMq密码
+    close-timeout: 15s   # 在考虑结束之前等待的时间
+    in-memory: true      # 默认代理URL是否应该在内存中。如果指定了显式代理,则忽略此值。
+    non-blocking-redelivery: false  # 是否在回滚回滚消息之前停止消息传递。这意味着当启用此命令时,消息顺序不会被保留。
+    send-timeout: 0     # 等待消息发送响应的时间。设置为0等待永远。
+    pool:
+      enabled: true       #连接池启动
+      max-connections: 10 #最大连接数
+    #本地开发关闭jms
+    jms:
+      enable: true
+
+# 日志
+logging:
+  config: classpath:logback-spring.xml
+  # 输出级别
+  level:
+    com.xxh: info
+  #    org.springframework: debug
+  file:
+    # 指定路径
+    path: logs
+  logback:
+    rollingpolicy:
+      # 最大保存天数
+      max-history: 7
+      # 每个文件最大大小
+      max-file-size: 5MB
+
+saas:
+  swagger:
+    basic:
+      enable: false
+      username: swaggerAdmin
+      password: f609bc57-808b-11ee-92d4-00163e1b779d
+
+# his:
+#   config:
+#     host: http://172.18.84.18:13024
+#     key: kw%cHIwSEs#V^Ree&(vYiFKixG1zn.oW$3Jc0Mh@C
+
+sys-config:
+  # 获取token 访问his还是wx
+  access: wx
+  his:
+    host: http://172.18.84.18:13024
+    key: kw%cHIwSEs#V^Ree&(vYiFKixG1zn.oW$3Jc0Mh@C
+  wx:
+    appid: wx51f04a5a60505616
+    secret: 9ef6b98c5cc2599a8eb39ab7dbc410aa
+    temp-msg:
+      check-enable: true
+      white: o6jK358cVF3c-lzV4Ft4e1ExusBw,o6jK352u-eNoiEeQb2KsUKwAF8_c,o6jK3576qgmYkckfyYqrzFvgMGgs,o6jK35yeY0do8oG_Hhpldu_3KWbs
+
+his:
+  host: https://hlwyy.bydsfy.com:10053
+  # host: https://172.18.84.91:10053
+  sign-key: KejYvc77zdzf7epuMs2UB2RdeP5QU5V6bqwvDdY2HBKtdZXD9Bv5F7FMHBPmJFK7

+ 59 - 0
healthy-frontend-app/src/main/resources/logback-spring.xml

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration  scan="true" scanPeriod="60 seconds" debug="false">
+    <contextName>logback</contextName>
+    <springProperty scope="context" name="logging.path" source="logging.path" defaultValue="../logs"/>
+    <springProperty scope="context" name="logName" source="spring.application.name" defaultValue="app.log"/>
+    <property name="log.path" value="${logging.path}/${logName}"/>
+    <springProperty scope="context" name="server.port" source="server.port" defaultValue="8080"/>
+
+    <!--输出到控制台-->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <!--按天生成日志-->
+    <appender name="logFile"  class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <Prudent>true</Prudent>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>
+                ${log.path}/${logName}_${server.port}.log_%d{yyyy-MM-dd}.log
+            </FileNamePattern>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <Pattern>
+                %d{yyyy-MM-dd HH:mm:ss} -%msg%n
+            </Pattern>
+        </layout>
+    </appender>
+
+    <logger name="com.company"   level="debug"  additivity="false">
+        <appender-ref ref="console"/>
+        <appender-ref ref="logFile" />
+    </logger>
+
+    <root level="error">
+        <appender-ref ref="console"/>
+        <appender-ref ref="logFile" />
+    </root>
+
+
+
+    <!-- 开发、测试环境 -->
+    <!--
+	<springProfile name="dev,test">
+		<logger name="org.springframework.web" level="INFO" />
+		<logger name="com.company" level="DEBUG" />
+	</springProfile>
+ 	-->
+
+    <!-- 生产环境 -->
+    <!--
+    <springProfile name="prod">
+        <logger name="org.springframework.web" level="ERROR" />
+        <logger name="com.company" level="ERROR" />
+    </springProfile>
+     -->
+
+</configuration>

+ 119 - 0
healthy-frontend-common/pom.xml

@@ -0,0 +1,119 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>healthy-frontend-java</artifactId>
+        <groupId>com.xxh.cloud.frontend</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>healthy-frontend-common</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.ben-manes.caffeine</groupId>
+            <artifactId>caffeine</artifactId>
+        </dependency>
+
+        <!-- Swagger -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>${swagger2bootstrap2ui.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.5.22</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.5.22</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>${fastjson.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.company.cloud.sdk</groupId>
+            <artifactId>weixin-java-mp</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.company.cloud.sdk</groupId>
+            <artifactId>weixin-java-mini</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>com.company.cloud.sdk</groupId>
+            <artifactId>weixin-java-open</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>com.company.cloud.sdk</groupId>
+            <artifactId>weixin-java-work</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15to18</artifactId>
+            <version>1.69</version>
+        </dependency>
+
+    </dependencies>
+
+
+</project>

+ 99 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/BusinessBaseErrorEnum.java

@@ -0,0 +1,99 @@
+package com.xxh.cloud.frontend.common.modules.exception;
+
+
+/**
+ * 错误编码,由5位数字组成,前2位为模块编码,后3位为业务编码
+ * <p>
+ * 如:10001(10代表系统模块,001代表业务代码)
+ * </p>
+ */
+
+public enum BusinessBaseErrorEnum implements IErrorCodeEnum {
+
+
+    INTERNAL_SERVER_ERROR(500,"内部服务器错误"),
+
+    UNAUTHORIZED(401,"未授权"),
+
+    NOT_NULL(10001,"不能为空"),
+
+    DB_RECORD_EXISTS(10002,"数据记录存在"),
+
+    DB_RECORD_NOT_EXISTS(10003,"数据记录不存在"),
+    PARAMS_GET_ERROR(10004,"获取参数错误"),
+
+    Config_GET_ERROR(10005,"参数配置错误"),
+
+    Illegal_Operation_ERROR ( 10006,"已上架不能操作"),
+
+    Run_Rule_ERROR (10007,"执行规则引擎错误"),
+
+    Password_Null_ERROE ( 10008,"密码不能为空"),
+
+    Password_Security_Level_ERROE ( 10009,"密码安全级别不足"),
+
+    DataSource_Config_ERROR(10010,"数据源配置错误"),
+
+
+
+    Run_QL_ERROR (10011,"执行QL引擎错误"),
+
+    Config_QL_ERROR (10012,"QL规则配置错误"),
+
+//   IDENTIFIER_NOT_NULL ( 10006,""),
+//
+//   CAPTCHA_ERROR (10007,"验证码错误"),
+
+//
+
+//   PASSWORD_ERROR ( 10009,"密码错误"),
+
+//   SUPERIOR_DEPT_ERROR ( 10011,"上级部门错误"),
+//
+//   SUPERIOR_MENU_ERROR ( 10012,"上级菜单错误"),
+
+//   DATA_SCOPE_PARAMS_ERROR ( 10013,""),
+//
+//   DEPT_SUB_DELETE_ERROR ( 10014,"子部门删除错误"),
+//
+//   DEPT_USER_DELETE_ERROR ( 10015,""),
+//
+//   UPLOAD_FILE_EMPTY (10019,""),
+//
+//   TOKEN_NOT_EMPTY ( 10020,""),
+//
+//   TOKEN_INVALID ( 10021,""),
+//
+//   ACCOUNT_LOCK ( 10022,""),
+//
+//   OSS_UPLOAD_FILE_ERROR ( 10024,""),
+
+   REDIS_ERROR ( 10027,"Redis错误"),
+
+
+//
+//   JOB_ERROR ( 10028,""),
+   INVALID_SYMBOL ( 10029,"无效符号")
+
+    ;
+    private int code;
+    private String msg;
+
+    private BusinessBaseErrorEnum() {
+    }
+
+    BusinessBaseErrorEnum(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    @Override
+    public int getCode() {
+        return code;
+    }
+
+    @Override
+    public String getMsg() {
+        return msg;
+    }
+}

+ 89 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/BusinessException.java

@@ -0,0 +1,89 @@
+package com.xxh.cloud.frontend.common.modules.exception;
+
+
+import java.util.Arrays;
+
+/**
+ * 自定义异常
+ */
+public class BusinessException extends RuntimeException {
+	private static final long serialVersionUID = 1L;
+
+    private int code;
+	private String msg;
+
+	public BusinessException(int code) {
+		this.code = code;
+	}
+
+	public BusinessException(int code, Throwable e) {
+		super(e);
+		this.code = code;
+	}
+
+
+	public BusinessException(int code, String msg) {
+		this.code = code;
+		this.msg = msg;
+	}
+
+	public BusinessException(int code , String msg, Throwable e) {
+		super(e);
+		this.code = code;
+		this.msg = msg;
+	}
+
+
+
+	public BusinessException(IErrorCodeEnum errorCode) {
+		this.code = errorCode.getCode();
+		this.msg = errorCode.getMsg();
+	}
+
+
+	public BusinessException(IErrorCodeEnum errorCode, String... params) {
+		this.code = errorCode.getCode();
+		this.msg = errorCode.getMsg() + ":" + Arrays.toString(params);
+		//todo:
+	}
+
+	public BusinessException(IErrorCodeEnum errorCode, Throwable e) {
+		super(e);
+		this.code = errorCode.getCode();
+		this.msg = errorCode.getMsg();
+	}
+
+
+	public BusinessException(String msg) {
+		super(msg);
+		this.code =  BusinessBaseErrorEnum.INTERNAL_SERVER_ERROR.getCode();
+		this.msg = msg;
+	}
+
+	public BusinessException(String msg, Throwable e) {
+		super(msg, e);
+		this.code = BusinessBaseErrorEnum.INTERNAL_SERVER_ERROR.getCode();
+		this.msg = msg;
+	}
+
+
+	//XxhErrorEnum
+
+
+	public String getMsg() {
+		return msg;
+	}
+
+	public void setMsg(String msg) {
+		this.msg = msg;
+	}
+
+	public int getCode() {
+		return code;
+	}
+
+	public void setCode(int code) {
+		this.code = code;
+	}
+
+}

+ 47 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/GlobalExceptionHandler.java

@@ -0,0 +1,47 @@
+package com.xxh.cloud.frontend.common.modules.exception;
+
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+
+    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+
+    /**
+     * 处理XxhException异常
+     */
+    @ExceptionHandler(BusinessException.class)
+    public Result handleRenException(BusinessException ex){
+        System.out.println("++++++++++++ XxhException ");
+        Result result = new Result();
+        result.error(ex.getCode(), ex.getMsg());
+        return result;
+    }
+
+    /**
+     * 处理Exception异常
+     */
+    @ExceptionHandler(Exception.class)
+    public Result handleException(Exception ex){
+        System.out.println("++++++++++++ 处理 Exception 异常");
+        logger.error(ex.getMessage(), ex);
+        this.saveLog(ex);
+        Result<String> result = new Result();
+        result.error(ex.getMessage());
+        return result;
+    }
+
+
+    private void saveLog(Exception ex){
+        //todo:anros saveLog
+    }
+
+
+}

+ 21 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/IErrorCodeEnum.java

@@ -0,0 +1,21 @@
+package com.xxh.cloud.frontend.common.modules.exception;
+
+/**
+ * 错误码
+ * */
+public interface IErrorCodeEnum {
+
+    /**
+     * 错误码
+     * @return
+     */
+    public int getCode();
+
+    /**
+     * 错误信息
+     * @return
+     */
+    public String getMsg();
+
+
+}

+ 38 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/exception/WechatBaseErrorEnum.java

@@ -0,0 +1,38 @@
+package com.xxh.cloud.frontend.common.modules.exception;
+
+
+/**
+ * 错误编码,由5位数字组成,前2位为模块编码,后3位为业务编码
+ * <p>
+ * 如:10001(10代表系统模块,001代表业务代码)
+ * </p>
+ */
+
+public enum WechatBaseErrorEnum implements IErrorCodeEnum {
+
+
+    TEMP_MSG_WHITE_NONE(9801,"该用户未配置白名单!"),
+
+
+    ;
+    private int code;
+    private String msg;
+
+    private WechatBaseErrorEnum() {
+    }
+
+    WechatBaseErrorEnum(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    @Override
+    public int getCode() {
+        return code;
+    }
+
+    @Override
+    public String getMsg() {
+        return msg;
+    }
+}

+ 137 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/AnalysisApiHelper.java

@@ -0,0 +1,137 @@
+package com.xxh.cloud.frontend.common.modules.his;
+
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpRequest;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.xxh.cloud.frontend.common.modules.his.model.AnalysisDataModel;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.stereotype.Component;
+
+// 会诊结论目标解析
+@Slf4j
+@Component
+public class AnalysisApiHelper {
+
+    // 会诊结论目标解析URL
+    private static String analysisUrl = "https://slife.bydsfy.com/llm/chat/chat"; // TODO
+
+    // 获取会诊结论目标解析数据
+    public static AnalysisDataModel getAnalysisData(String content) {
+        Map<String, String> reqMap = new HashMap<>();
+        reqMap.put("conversation_id", "");
+        reqMap.put("history_len", "-1");
+        reqMap.put("stream", "false");
+        reqMap.put("model_name", "Qwen-14B-Chat");
+        reqMap.put("temperature", "0.7");
+        reqMap.put("prompt_name", "consultation_result");
+        reqMap.put("platform", "3");
+        reqMap.put("deviceNo", "");
+        reqMap.put("version", "1.0.0");
+        reqMap.put("query", content);
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("会诊结论目标解析参数 >>>>>>:{}", body);
+
+        String result = loopPostHttp(analysisUrl, body, 0);
+        if (StrUtil.isBlank(result)) {
+            return null;
+        }
+
+        log.info("会诊结论目标解析结果 <<<< {}", result);
+
+        AnalysisDataModel dataModel = new AnalysisDataModel();
+        dataModel.setSourceData(result);
+
+        if (StrUtil.isNotBlank(result)) {
+            try {
+                JSONObject jsonObject = JSON.parseObject(result.replace("data:", ""));
+                String text = jsonObject.getString("text");
+
+                if (StrUtil.isNotBlank(text)) {
+                    text = text.replace("```json", "").replace("```", "");
+
+                    Map<String, String> map = JSONObject.parseObject(text, new TypeReference<Map<String, String>>(){});
+                    
+                    dataModel.setIsFollowUp("N");
+                    String isFollowUp = map.get("是否随访");
+                    if ("是".equals(isFollowUp)) {
+                        dataModel.setIsFollowUp("Y");
+                    }
+
+                    dataModel.setFollowUpDate(map.get("随访时间"));
+                    dataModel.setFollowUpDateUnit(map.get("随访时间单位"));
+
+                    dataModel.setIsChangeDept("N");
+                    String isChangeDept = map.get("是否转科室治疗");
+                    if ("是".equals(isChangeDept)) {
+                        dataModel.setIsChangeDept("Y");
+                    }
+
+                    dataModel.setTreatmentMethods(map.get("治疗的方式"));
+                    dataModel.setCheckContent(map.get("建议完善检查内容"));
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        return dataModel;
+    }
+
+    // 调用失败则暂停5秒重新请求,最多重调5次
+    private static String loopPostHttp(String url, String body, Integer loopNum) {
+        try {
+            String result = HttpRequest.post(url)
+                .body(body)
+                .execute().body();
+    
+            return result;
+        } catch (Exception e) {
+            log.info("POST调用异常: {} ", url);
+            e.printStackTrace();
+            
+            // 最多循环5次
+            if (loopNum < 5) {
+                // 先暂停
+                log.info("休眠5000ms");
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e1) {
+                    e1.printStackTrace();
+                }
+                // 出现异常再次调用
+                return loopPostHttp(url, body, loopNum + 1);
+            }
+        }
+
+        return null;
+    }
+
+    public static void main(String[] args) {
+        // getAnalysisData("病史敬悉,简要病史:患者周爱侠,女,58岁,因反复胸闷1周入院;患者时有咳嗽咳痰,痰中带鲜血,近3月偶发,间断出现,每次量不多,咳痰后喉部疼痛不适,平素伴有口干、口苦,偶有反酸嗳气;无鼻腔出血,大便颜色正常。查体:咽部粘膜光滑,双侧扁桃体不大,无充血溃烂。辅助检查:胸部CT提示:两肺少许炎症、右肺上叶后段结节(低危),与前片(2022-08-12)比较无明显变化,随诊;左肺上叶钙化灶。考虑诊断:反流性咽喉炎建议:1.同意贵科诊治2.完善电子鼻咽喉镜检查排除鼻咽部及咽喉部病变等,必要时消化科会诊,行胃镜检查排除消化道出血,3.可予以PPI抑酸保胃、金嗓利咽胶囊等药物治疗;4.我科随访,1周随访一次。");
+        // getAnalysisData("病史敬悉,简要病史:患者马再荣,男,76岁,因反复咳痰喘6年余,再发加重伴双下肢无力3天入院,体格检查:神清,精神一般,营养与发育中等,呼吸稍促,轻度喘息貌,步入病房,查体合作,对答切题,全身皮肤粘膜无黄染,浅表淋巴结未触及肿大,头颅无畸形,双瞳孔等大等圆,直径3.0mm,对光反射灵敏,耳鼻无异常分泌物,口唇无紫绀,咽无充血,颈软,气管居中,甲状腺无肿大,桶状胸,触诊语颤减弱,叩诊过清音,双肺呼吸音低,可闻及少许干湿罗音及哮鸣音,心前区无隆起,心尖搏动无弥散,心脏相对浊音界无扩大,心律齐,各瓣膜区未闻及明显杂音,心音剑突下响;腹软,无压痛、反跳痛,肝脾肋下未触及,叩诊呈鼓音,肠鸣音无亢进,约3-5次/分;脊柱及四肢无畸形,未见杵状指,活动自如,双下肢无水肿,生理反射存在,病理反射未引出,双侧巴士征阴性;布、克氏征(-);辅助检查:2024-09-26128层胸部HRCT(薄层)慢性支气管炎伴少许感染、肺气肿、肺大泡形成纵隔多发淋巴结显示冠脉钙化;心包积液两侧胸膜局限性增厚肝脏密度不均匀减低,建议增强检查。腹部CT提示肝脏多发转移瘤。考虑诊断:肝转移性癌,慢性支气管炎急性发作肺气肿胆囊结石陈旧性脑梗死高血压病3级(极高危)肺大疱三尖瓣返流(轻中度)建议:1.同意在本科室继续诊治2.目前不需要做检验检查;3.建议MDT会诊;4.我科不随访。");
+        // getAnalysisData("病史敬悉,简要病史:患者周宗树,男,70岁,因间断咳痰喘9月余,再发十余天入院。患者四肢水肿、胸闷、气喘,入院后查心电图示:“1.窦性心律2.ST-T改变”,BNP示:“1614pg/ml”,考虑心衰考虑诊断:1.肺部感染2.肝硬化失代偿期3.酒精性肝炎4.腹腔积液5.2型糖尿病6.原发性高血压7.左肺占位(上叶)8.右肺结节(中叶)9.脑梗死恢复期10.髋关节置换术后(双侧股骨头)11.心功能衰竭建议:1.同意在贵科治疗2.改善心功能,肾功能治疗;3.给予xxx治疗等(包括药物、手术/操作等)/同意贵科诊治;4.我科不随访。");
+        // getAnalysisData("病史敬悉,简要病史:患者系脑干出血术后两月余;近期反复发热。考虑诊断:脑干出血术后,发热待查建议:1.同意贵科诊治;2.建议完善腰椎穿刺化验脑脊液排除颅内感染;3.予以抗感染对症治疗,若患者明确颅内感染,可留置腰大池引流;4.我科不随访。");
+        // getAnalysisData("病史敬悉,简要病史:双侧耳鸣听力下降10天,无耳流水;耳鸣呈持续性嗡嗡声;无视物旋转。查体:双侧外耳道畅,鼓膜完整无充血,光锥存在考虑诊断:感音神经性聋建议:1.完善听力检查2.必要时转入进一步治疗;3.-;4.我科不随访。");
+        // getAnalysisData("会诊结论病史敬悉,简要病史:1.患者女,57岁,因发热1周入院,2.患者1周前出现发热,最高39.5℃,伴畏寒畏寒、寒战,当地诊所予以口服药物(具体不详)治疗,但效不佳,我院门诊,拟“发热待查”收住我科,考虑诊断:1.左侧肾积水伴输尿管结石2.左肾出血可能3.余同贵科诊断建议:1.同意贵科诊断2.患者左侧输尿管结石,肾脏出血可能,转入我科进一步治疗3.我科随访,1天随访一次。");
+        // getAnalysisData("病史敬悉,简要病史:患者张良斋,男,80岁,因反复胸闷气喘3年,心肺复苏治疗十余天入院,患者尿管置入困难考虑诊断:泌尿系疾患建议:1.同意贵科诊治2.留置尿管失败;3.病情允许,必要时行膀胱造瘘术;4.不适我科随诊,谢邀");
+        // getAnalysisData("病史敬悉,简要病史:患者,男,87岁考虑诊断:PSA升高建议:1.同意贵科诊治2.病情允许完善前列腺磁共振平扫+增强检查,必要时前列腺穿刺活检;3不适我科随诊");
+        AnalysisDataModel data = getAnalysisData("病史敬悉,简要病史:面部对称无畸形,耳屏前无压痛,开口度约三横指。口内:恒牙列,咬合关系可,左上腭见黏膜溃疡,上覆灰褐色假膜,创面基本愈合,口腔卫生差。考虑诊断:口腔溃疡建议:1.同意在本科室继续诊治2.目前不需要做检验检查;3.同意贵科诊治;4.我科不随访。");
+        System.out.println("==== " + JSON.toJSONString(data));
+    }
+
+
+    
+
+}
+
+

+ 76 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/HisApiHelper.java

@@ -0,0 +1,76 @@
+package com.xxh.cloud.frontend.common.modules.his;
+
+
+import cn.hutool.http.HttpRequest;
+import com.alibaba.fastjson.JSONObject;
+import com.xxh.cloud.frontend.common.modules.his.config.SysProjectConfig;
+import com.xxh.cloud.frontend.common.modules.his.dto.GenerateSchemeDTO;
+import com.xxh.cloud.frontend.common.modules.his.model.GenerateSchemeModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisAccessTokenModel;
+import com.xxh.cloud.frontend.common.modules.his.model.PatBindModel;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+
+@Slf4j
+@Component
+public class HisApiHelper {
+
+    // 获取accessToken
+    private static String accessTokenUrl = "/api/customize/getAccessToken";
+
+    // 获取关联就诊卡号列表
+    private static String patInfoUrl = "/api/customize/getPatInfoByOpenId";
+
+    // 获取schemeurl
+    private static String schemeUrl = "/api/customize/generatescheme";
+
+
+    public static Result<HisAccessTokenModel> getAccessToken(SysProjectConfig config) {
+        String result = HttpRequest.post(config.getHost() + accessTokenUrl)
+                .form("key", config.getKey())
+                .execute().body();
+//        String result = "{\"code\":0,\"msg\":\"success\",\"data\":{\"jsTicket\":\"LIKLckvwlJT9cWIhEQTwfGKqz2-w-FGuBew9PQLmE4N7XxJ4H0w_0zIJMm4juEJ2P_SRhJdawhjbHPYJ24OTHg\",\"accToken\":\"74_lxg_-TPLPV2kQGVoHXifIN7OpeHtf15B6FmO3zSb5naQpn5a7L5kusU2nHCEdmG4oP3utDVdwiFJEoiNRafg7aYBNDG7IVGwbmL3qEMUL9pdPitv8zrjJVfNnEoKXDgAEADQW\"}}";
+        log.info("获取token----" + result);
+        return new Result<>(result, HisAccessTokenModel.class);
+    }
+
+    public static PatBindModel getPatBind(SysProjectConfig config, String userId) {
+        String result = HttpRequest.post(config.getHost() + patInfoUrl)
+                .form("key", config.getKey())
+                .form("userId", userId)
+                .execute().body();
+//        String result = "{\"code\":0,\"data\":[{\"birthday\":\"1983-02-20\",\"relationType\":5,\"patientMobile\":\"18621566608\",\"patientName\":\"李明\",\"idTypeName\":\"身份证\",\"patCardNo\":\"5001285739\",\"patientSex\":\"M\",\"idType\":1,\"patientId\":4799929934901673994,\"patHisNo\":\"5001285739\",\"patientType\":0,\"patCardType\":21,\"patInNo\":\"\",\"idNo\":\"310113198302200814\",\"extFields\":\"{\\\"qrCodeText\\\":\\\"417E7B2E83CD17B8651652AC54E98132F041659E17E9CC6C622B83A59C8B7BBB:1::3400A0006APPF0098\\\",\\\"healthCardId\\\":\\\"417E7B2E83CD17B8651652AC54E98132F041659E17E9CC6C622B83A59C8B7BBB\\\"}\",\"isDefault\":0,\"relationName\":\"他人\",\"patCardNoEncry\":\"gD0zGxPsj2LAgI/FroFFHQ==\",\"healthCardFlag\":2,\"patCardTypeName\":\"院内就诊卡\",\"bindStatus\":1},{\"birthday\":\"1985-10-23\",\"relationType\":5,\"patientMobile\":\"18095681616\",\"patientName\":\"王翀\",\"idTypeName\":\"身份证\",\"patCardNo\":\"5000359206\",\"patientSex\":\"M\",\"idType\":1,\"patientId\":4706068853493334017,\"patHisNo\":\"5000359206\",\"patientType\":0,\"patCardType\":21,\"patInNo\":\"\",\"idNo\":\"340621198510230332\",\"extFields\":\"{\\\"qrCodeText\\\":\\\"BD2B78EAB6C419CD88245783605501453FC701619CE78BE85177D2F17FAE52A5:1::3400A0006APPF0098\\\",\\\"healthCardId\\\":\\\"BD2B78EAB6C419CD88245783605501453FC701619CE78BE85177D2F17FAE52A5\\\"}\",\"isDefault\":1,\"relationName\":\"他人\",\"patCardNoEncry\":\"FShUj1EXvue8Uxl+Epw9nQ==\",\"healthCardFlag\":2,\"patCardTypeName\":\"院内就诊卡\",\"bindStatus\":1}]}";
+        log.info("获取关联就诊卡号----" + result);
+        return JSONObject.parseObject(result, PatBindModel.class);
+    }
+
+    public static Result<GenerateSchemeModel> generateScheme(SysProjectConfig config, GenerateSchemeDTO params) {
+        String result = HttpRequest.post(config.getHost() + schemeUrl)
+                .form("accessToken", params.getAccessToken())
+                .form("deptCode", params.getDeptCode())
+                .form("doctorCode", params.getDoctorCode())
+                .execute().body();
+//        String result = "{\"code\":0,\"msg\":\"success\",\"data\":{\"errcode\":0,\"errmsg\":\"ok\",\"openlink\":\"weixin://dl/business/?t=zPkEbEFpgae\"}}";
+        log.info("获取schemeurl----" + result);
+        return new Result<>(result, GenerateSchemeModel.class);
+    }
+
+    // 发送短信
+
+
+
+    public static void main(String[] args) {
+//        String bodyJson = JSONObject.toJSONString(new AccessTokenParams("GVbIW6PDULXEcEzq", "EFlt6A8rnzJC1bg8"));
+//        Map<String, String> headers = new HashMap<>();
+//        headers.put("token", "AUK_1697567919187300352");
+//        String result = HttpRequest.post("https://dev1.cloud-seal.com/api/healthy-dev/h/mgr/custUser/queryByAll")
+//                .headerMap(headers, true)
+//                .body(bodyJson)
+//                .execute().body();
+//        System.out.println(result);
+//
+    }
+
+}

+ 594 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/HisWebApiHelper.java

@@ -0,0 +1,594 @@
+package com.xxh.cloud.frontend.common.modules.his;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.URLUtil;
+import cn.hutool.crypto.SmUtil;
+import cn.hutool.http.HttpRequest;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.xxh.cloud.frontend.common.modules.his.config.HisWebConfig;
+import com.xxh.cloud.frontend.common.modules.his.dto.HisGenerateSchemeDTO;
+import com.xxh.cloud.frontend.common.modules.his.dto.HisPatientDTO;
+import com.xxh.cloud.frontend.common.modules.his.dto.HisPromotionCodeDTO;
+import com.xxh.cloud.frontend.common.modules.his.model.HisBaseModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisDeptListModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisDoctorListModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisPatientListModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisPromotionCodeModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisSchemeUrlModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisWxTokenModel;
+import com.xxh.cloud.frontend.common.modules.his.model.PatBindModel;
+import com.xxh.cloud.frontend.common.modules.his.model.PatInfoModel;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.stereotype.Component;
+
+/**
+ * 互联网医院
+ */
+@Slf4j
+@Component
+public class HisWebApiHelper {
+
+    // host
+    // 内网:https://172.18.84.91:10053
+    // 外网:https://hlwyy.bydsfy.com:10053
+    // private static final String host = "https://hlwyy.bydsfy.com:10053";
+
+    // 获取微信accesstoken
+    private static String accessToken = "/patient/vd3/getWxToken";
+
+    // 获取就诊人信息
+    private static String patientByUnionIdUrl = "/patient/v1/other/getPatientByUnionId";
+
+    // 批量获取就诊人信息
+    private static String getPatientByTimestamp = "/patient/vd3/getPatientByTimestamp";
+
+    // 获取科室信息
+    private static String deptsInfoUrl = "/patient/vd3/getDeptsInfo";
+
+    // 获取医生信息 
+    private static String doctorsInfoUrl = "/patient/vd3/getDoctorsInfo";
+
+    // 获取schemaUrl信息
+    private static String wxMiniSchemeUrl = "/patient/vd3/getWxMiniSchemeUrl";
+
+    // 获取schemaUrl跳转路径参数
+    private static String jumpPath = "pages/tab_bar/hospHome/hospHome";
+
+    // 获取推荐码信息
+    private static String getPromotionCodeUrl = "/patient/vd3/getPromotionCodeInfo";
+
+    // 保存推荐码信息
+    private static String savePromotionCodeUrl = "/patient/vd3/savePromotionCode";
+
+    // 获取accessToken信息
+    public static HisWxTokenModel getAccessToken(HisWebConfig config, String type) {
+        Map<String, String> reqMap = new HashMap<>();
+        reqMap.put("type", type);
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("获取微信accessToken参数 >>>>>>:{}", body);
+
+        String result = loopPostHttp(config.getHost() + accessToken, getSign(config.getSignKey(), body), body, 0);
+        if (StrUtil.isBlank(result)) {
+            return null;
+        }
+        
+        HisBaseModel<HisWxTokenModel> resultModel = JSONObject.parseObject(result, new TypeReference<HisBaseModel<HisWxTokenModel>>(){});
+        if (null == resultModel) {
+            return null;
+        }
+
+        return resultModel.getData();
+    }
+
+    // 获取就诊人信息
+    public static PatBindModel getPatientByUnionId(HisWebConfig config, String unionid) {
+        PatBindModel patBindModel = new PatBindModel();
+
+        Map<String, String> reqMap = new HashMap<>();
+        reqMap.put("unionid", unionid);
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("获取就诊人信息参数 >>>>>>:{}", body);
+
+        String result = loopPostHttp(config.getHost() + patientByUnionIdUrl, getSign(config.getSignKey(), body), body, 0);
+        if (StrUtil.isBlank(result)) {
+            return patBindModel;
+        }
+
+        System.out.println(result);
+
+        HisBaseModel<HisPatientListModel> resultModel = JSONObject.parseObject(result, new TypeReference<HisBaseModel<HisPatientListModel>>(){});
+        if (null == resultModel) {
+            return patBindModel;
+        }
+
+        patBindModel.setCode(resultModel.getStatus());
+        patBindModel.setMsg(resultModel.getMsg());
+
+        List<PatInfoModel> patInfoList = new ArrayList<>();
+        if (null != resultModel.getData() && CollUtil.isNotEmpty(resultModel.getData().getPatients())) {
+            resultModel.getData().getPatients().forEach(i -> {
+                PatInfoModel patInfo = new PatInfoModel();
+                patInfo.setBirthday(i.getBirthday());
+                patInfo.setPatientId(i.getHisPatientId());
+                patInfo.setPatHisNo(i.getHisPatientId());
+                patInfo.setPatientName(i.getName());
+                patInfo.setPatientMobile(i.getLinkPhone());
+                patInfo.setIdNo(i.getPaperNo());
+                patInfo.setIdType("1"); // 1:二代身份证 2:港澳居民身份证 3:台湾居民身份证 4:护照
+                patInfo.setPatientSex("女".equals(i.getSex()) ? "F" : "M");
+
+                patInfo.setIsDefault(i.getIsDefault());
+                patInfo.setRelationName(i.getLinkRelationName());
+
+                patInfo.setOpenId(i.getOpenId());
+                patInfo.setUnionid(i.getUnionid());
+
+                patInfo.setCreateDate(i.getCreateDate());
+                patInfo.setUpdateDate(i.getUpdateDate());
+
+                patInfo.setEnable(i.getEnable());
+
+                patInfoList.add(patInfo);
+            });
+        }
+        patBindModel.setData(patInfoList);
+
+
+        return patBindModel;
+    }
+
+    // 获取就诊人信息
+    public static PatBindModel getPatientByThirdId(HisWebConfig config, HisPatientDTO params) {
+        PatBindModel patBindModel = new PatBindModel();
+
+        Map<String, String> reqMap = new HashMap<>();
+        reqMap.put("hospitalId", "80158");
+        if (StrUtil.isNotBlank(params.getOpenid())) {
+            reqMap.put("openid", params.getOpenid());
+        }
+        if (StrUtil.isNotBlank(params.getUnionid())) {
+            reqMap.put("unionid", params.getUnionid());
+        }
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("获取就诊人信息参数 >>>>>>:{}", body);
+
+        String result = loopPostHttp(config.getHost() + patientByUnionIdUrl, getSign(config.getSignKey(), body), body, 0);
+        if (StrUtil.isBlank(result)) {
+            return patBindModel;
+        }
+
+        System.out.println(result);
+
+        HisBaseModel<HisPatientListModel> resultModel = JSONObject.parseObject(result, new TypeReference<HisBaseModel<HisPatientListModel>>(){});
+        if (null == resultModel) {
+            return patBindModel;
+        }
+
+        patBindModel.setCode(resultModel.getStatus());
+        patBindModel.setMsg(resultModel.getMsg());
+
+        List<PatInfoModel> patInfoList = new ArrayList<>();
+        if (null != resultModel.getData() && CollUtil.isNotEmpty(resultModel.getData().getPatients())) {
+            resultModel.getData().getPatients().forEach(i -> {
+                PatInfoModel patInfo = new PatInfoModel();
+                patInfo.setBirthday(i.getBirthday());
+                patInfo.setPatientId(i.getHisPatientId());
+                patInfo.setPatHisNo(i.getHisPatientId());
+                patInfo.setPatientName(i.getName());
+                patInfo.setPatientMobile(i.getLinkPhone());
+                patInfo.setIdNo(i.getPaperNo());
+                patInfo.setIdType("1"); // 1:二代身份证 2:港澳居民身份证 3:台湾居民身份证 4:护照
+                patInfo.setPatientSex("女".equals(i.getSex()) ? "F" : "M");
+
+                patInfo.setIsDefault(i.getIsDefault());
+                patInfo.setRelationName(i.getLinkRelationName());
+                if (StrUtil.isBlank(i.getLinkRelationName()) && StrUtil.isNotBlank(i.getRelation())) {
+                    patInfo.setRelationName(i.getRelation());
+                }
+                patInfo.setRelationType(relationType(i.getRelationId()));
+
+                patInfo.setOpenId(i.getOpenId());
+                patInfo.setUnionid(i.getUnionid());
+
+                patInfo.setCreateDate(i.getCreateDate());
+                patInfo.setUpdateDate(i.getUpdateDate());
+
+                patInfo.setEnable(i.getEnable());
+
+                patInfoList.add(patInfo);
+            });
+        }
+        patBindModel.setData(patInfoList);
+
+
+        return patBindModel;
+    }
+
+    // 原关系:0-本人,1-父母,2-子女,3-夫妻,4-亲属,5-朋友,6-其他
+    // 整理后的关系:1:本人 2:配偶 3:父母 4:子女 5:他人
+    private static String relationType(String relationId) {
+        if (StrUtil.isBlank(relationId)) {
+            return null;
+        }
+
+        if ("0".equals(relationId)) {
+            return "1";
+        } else if ("1".equals(relationId)) {
+            return "3";
+        } else if ("2".equals(relationId)) {
+            return "4";
+        } else if ("3".equals(relationId)) {
+            return "2";
+        } else {
+            return "5";
+        }
+    }
+
+    // 时间戳获取就诊人信息
+    public static HisPatientListModel getPatientByTimestamp(HisWebConfig config, HisPatientDTO params) {
+        Map<String, Object> reqMap = new HashMap<>();
+        reqMap.put("startTime", DateUtil.format(DateUtil.parseDateTime(params.getStartTime()), "yyyyMMddHHmmss"));
+        reqMap.put("endTime", DateUtil.format(DateUtil.parseDateTime(params.getEndTime()), "yyyyMMddHHmmss"));
+        reqMap.put("pageNoReq", params.getPage());
+        reqMap.put("pageSizeReq", params.getRows());
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("获取就诊人信息参数 >>>>>>:{}", body);
+
+        System.out.println("参数:" + body);
+
+        String result = loopPostHttp(config.getHost() + getPatientByTimestamp, getSign(config.getSignKey(), body), body, 0);
+        if (StrUtil.isBlank(result)) {
+            return null;
+        }
+
+        HisBaseModel<HisPatientListModel> resultModel = JSONObject.parseObject(result, new TypeReference<HisBaseModel<HisPatientListModel>>(){});
+        if (null == resultModel) {
+            return null;
+        }
+
+        log.info("获取就诊人信息 <<<< {}", resultModel.getData().getPatients().size());
+        return resultModel.getData();
+    }
+
+    // 获取科室信息
+    public static HisDeptListModel getDeptsInfo(HisWebConfig config) {
+        Map<String, String> reqMap = new HashMap<>();
+        reqMap.put("hospitalId", "80158");
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("获取科室信息参数 >>>>>>:{}", body);
+
+        String result = loopPostHttp(config.getHost() + deptsInfoUrl, getSign(config.getSignKey(), body), body, 0);
+        if (StrUtil.isBlank(result)) {
+            return null;
+        }
+        
+        HisBaseModel<HisDeptListModel> resultModel = JSONObject.parseObject(result, new TypeReference<HisBaseModel<HisDeptListModel>>(){});
+        if (null == resultModel) {
+            return null;
+        }
+
+        return resultModel.getData();
+    }
+
+    // 获取医生信息 
+    // 1:获取全部医生
+    public static HisDoctorListModel getDoctorsInfo(HisWebConfig config, String showModel) {
+        Map<String, String> reqMap = new HashMap<>();
+        if (StrUtil.isBlank(showModel)) {
+            showModel = "1";
+        }
+        reqMap.put("showModel", showModel);
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("获取医生信息参数 >>>>>>:{}", body);
+
+        String result = loopPostHttp(config.getHost() + doctorsInfoUrl, getSign(config.getSignKey(), body), body, 0);
+        if (StrUtil.isBlank(result)) {
+            return null;
+        }
+        
+        HisBaseModel<HisDoctorListModel> resultModel = JSONObject.parseObject(result, new TypeReference<HisBaseModel<HisDoctorListModel>>(){});
+        if (null == resultModel) {
+            return null;
+        }
+
+        return resultModel.getData();
+    }
+
+    // 获取schemeurl
+    public static HisSchemeUrlModel getWxMiniSchemeUrl(HisWebConfig config, HisGenerateSchemeDTO params) {
+        Map<String, String> reqMap = new HashMap<>();
+        reqMap.put("hospId", "80158");
+        if ("1".equals(params.getType())) { // 医生
+            reqMap.put("jumpPath", jumpPath);
+            reqMap.put("queryParam", "actionType=76&drId=" + params.getDoctorId());
+        } else if ("2".equals(params.getType())) { // 科室排班
+            String queryParam = URLUtil.encode("actionType=75&deptId=" + params.getDeptId() + "&deptName=" + params.getDeptName() + "&hisDeptId=" + params.getHisDeptId() + "&regType=2&scheduleMode=0");
+            reqMap.put("jumpPath", jumpPath);
+            reqMap.put("queryParam", queryParam);
+        } else if ("3".equals(params.getType())) { // 门诊缴费
+            String queryParam = URLUtil.encode("actionType=03");
+            reqMap.put("jumpPath", jumpPath);
+            reqMap.put("queryParam", queryParam);
+        } else if ("4".equals(params.getType())) { // 排队候诊
+            String queryParam = URLUtil.encode("actionType=11");
+            reqMap.put("jumpPath", jumpPath);
+            reqMap.put("queryParam", queryParam);
+        }else if ("5".equals(params.getType())) { // 自助入院
+            String queryParam = URLUtil.encode("actionType=41");
+            reqMap.put("jumpPath", jumpPath);
+            reqMap.put("queryParam", queryParam);
+        }else if ("6".equals(params.getType())) { // 在线复诊
+            String queryParam = URLUtil.encode("actionType=15");
+            reqMap.put("jumpPath", jumpPath);
+            reqMap.put("queryParam", queryParam);
+        }else if ("7".equals(params.getType())) { // 报告查询
+            String queryParam = URLUtil.encode("actionType=05");
+            reqMap.put("jumpPath", jumpPath);
+            reqMap.put("queryParam", queryParam);
+        }else if ("8".equals(params.getType())) { // 药品清单
+            String queryParam = URLUtil.encode("actionType=35");
+            reqMap.put("jumpPath", jumpPath);
+            reqMap.put("queryParam", queryParam);
+        }
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("获取schemeurl参数 >>>>>>:{}", body);
+
+        String result = loopPostHttp(config.getHost() + wxMiniSchemeUrl, getSign(config.getSignKey(), body), body, 0);
+        if (StrUtil.isBlank(result)) {
+            return null;
+        }
+
+        log.info("获取schemeurl <<<< {}", result);
+        
+        HisBaseModel<HisSchemeUrlModel> resultModel = JSONObject.parseObject(result, new TypeReference<HisBaseModel<HisSchemeUrlModel>>(){});
+        if (null == resultModel) {
+            return null;
+        }
+
+        return resultModel.getData();
+    }
+
+    // 获取推荐码信息 
+    public static HisPromotionCodeModel getPromotionCodeUrl(HisWebConfig config, HisPromotionCodeDTO params) {
+        Map<String, String> reqMap = new HashMap<>();
+        reqMap.put("promotionCode", params.getPromotionCode());
+        reqMap.put("promotionCodeType", params.getPromotionCodeType());
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("获取推荐码参数 >>>>>>:{}", body);
+
+        String result = loopPostHttp(config.getHost() + getPromotionCodeUrl, getSign(config.getSignKey(), body), body, 0);
+        if (StrUtil.isBlank(result)) {
+            return null;
+        }
+
+        log.info("获取推荐码结果 <<<< {}", result);
+        
+        HisBaseModel<HisPromotionCodeModel> resultModel = JSONObject.parseObject(result, new TypeReference<HisBaseModel<HisPromotionCodeModel>>(){});
+        if (null == resultModel) {
+            return null;
+        }
+
+        return resultModel.getData();
+    }
+
+    // 保存推荐码信息 
+    public static HisPromotionCodeModel savePromotionCodeUrl(HisWebConfig config, String promotionId) {
+        Map<String, String> reqMap = new HashMap<>();
+        reqMap.put("promotionCode", promotionId);
+
+        String body = JSON.toJSONString(reqMap);
+        log.info("保存推荐码信息参数 >>>>>>:{}", body);
+
+        String result = loopPostHttp(config.getHost() + savePromotionCodeUrl, getSign(config.getSignKey(), body), body, 0);
+        if (StrUtil.isBlank(result)) {
+            return null;
+        }
+
+        log.info("保存推荐码结果 <<<< {}", result);
+        
+        HisBaseModel<HisPromotionCodeModel> resultModel = JSONObject.parseObject(result, new TypeReference<HisBaseModel<HisPromotionCodeModel>>(){});
+        if (null == resultModel) {
+            return null;
+        }
+
+        return resultModel.getData();
+    }
+
+    // 调用失败则暂停5秒重新请求,最多重调5次
+    private static String loopPostHttp(String url, Map<String, String> headers, String body, Integer loopNum) {
+        try {
+            String result = HttpRequest.post(url)
+                .addHeaders(headers)
+                .body(body)
+                .execute().body();
+    
+            return result;
+        } catch (Exception e) {
+            log.info("POST调用异常: {} ", url);
+            e.printStackTrace();
+            
+            // 最多循环5次
+            if (loopNum < 5) {
+                // 先暂停
+                log.info("休眠5000ms");
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e1) {
+                    e1.printStackTrace();
+                }
+                // 出现异常再次调用
+                return loopPostHttp(url, headers, body, loopNum + 1);
+            }
+        }
+
+        return null;
+    }
+
+    private static Map<String, String> getSign(String signKey, String body) {
+
+        String nonce = IdUtil.simpleUUID();
+        Long timestamp = System.currentTimeMillis();
+        String salt = nonce.substring(5);
+        // String signKey = "KejYvc77zdzf7epuMs2UB2RdeP5QU5V6bqwvDdY2HBKtdZXD9Bv5F7FMHBPmJFK7";
+
+        String sm3Body = SmUtil.sm3(body).toLowerCase();
+        String sign = SmUtil.sm3(signKey + nonce + salt + sm3Body).toLowerCase();
+
+        Map<String, String> headerMap = new HashMap<>();
+        headerMap.put("nonce", nonce);
+        headerMap.put("timestamp", String.valueOf(timestamp));
+        headerMap.put("hospitalId", "80158");
+        headerMap.put("signature", sign);
+        headerMap.put("appType", "40");
+
+        log.info("header 信息:{}", JSON.toJSONString(headerMap));
+
+        return headerMap;
+    }
+    
+    public static void main(String[] args) {
+        HisWebConfig config = new HisWebConfig();
+        config.setHost("https://hlwyy.bydsfy.com:10053");
+        // config.setHost("https://172.18.84.91:10053");
+        config.setSignKey("KejYvc77zdzf7epuMs2UB2RdeP5QU5V6bqwvDdY2HBKtdZXD9Bv5F7FMHBPmJFK7");
+
+        // HisWxTokenModel token = getAccessToken(config, "2");
+        // System.out.println(JSON.toJSONString(token));
+
+
+        // 获取关联就诊卡号>>>> config={"host":"http://172.18.84.102:8081/api/frontend"}; params=o4qwy6hYRvfAx-O4QOgMZHh9H10Q
+
+        // 王建军:o6jK353r1vzxKANJJizc8oQ65vfk      o4qwy6n2YVdeo_A5raTS1Maj1ps4
+
+        // 马文洁:o6jK357Cm6dmVuIk8R9rRz604yiQ      o4qwy6tlgBr1xbCzU91uOlNSIulQ
+
+        // 董瑞兴:o6jK358hHVyrt7rooS6XcQgAw01k      o4qwy6h5M4TDjgTPP1DL2f-aoWi8
+
+        // 赵宇晴:o6jK35xJtO_XaCtvBrXy2WiMCmnU
+
+        // 王宏宇:o6jK358cVF3c-lzV4Ft4e1ExusBw      o4qwy6ovCnm3x1nJBTgE0D0oSloQ
+
+        // 李明:o6jK352u-eNoiEeQb2KsUKwAF8_c        o4qwy6u8VC18xb0Za47Dic1zzEb8
+
+        // zs   o4qwy6txe8UH5LejGC8Tn9q7PWA4
+        // 通过unionid获取家属信息
+        // PatBindModel patientList = getPatientByUnionId(config, "o4qwy6nkRC1Jc0U_5PLVs93CfxAE");
+        // System.out.println(JSON.toJSONString(patientList));
+
+
+        /** 2024-08-12拉取的最近60条数据(2024-08-12 00:01:24   -   2024-08-12 11:01:54) 
+         * 1 表示有信息但没患者名称编号等
+         *  0 表示没有患者信息
+         */
+
+        // 通过openid或unionid获取家属信息  o6jK350Wg0oQHyI_Ia44J5dErkCk  o4qwy6spmV29f87lqzBiNyfL-NZo
+        // System.out.println(System.currentTimeMillis());
+        HisPatientDTO hisPatientDTO = new HisPatientDTO();
+        // // hisPatientDTO.setOpenid("o6jK358kbesGCZRqlGrsjPLh6Hdg");
+        // // hisPatientDTO.setOpenid("o6jK356aXluC_uTj7AtP4Z4sThQ4");
+        // // hisPatientDTO.setUnionid("o4qwy6jMmJNu64HQux60evyq9Brc");
+        // // hisPatientDTO.setOpenid("o6jK350Wg0oQHyI_Ia44J5dErkCk");
+        // // hisPatientDTO.setUnionid("o4qwy6spmV29f87lqzBiNyfL-NZo");
+        hisPatientDTO.setOpenid("o6jK358hHVyrt7rooS6XcQgAw01k");
+        // hisPatientDTO.setUnionid("o4qwy6txe8UH5LejGC8Tn9q7PWA4");
+        getPatientByThirdId(config, hisPatientDTO);
+        // System.out.println(System.currentTimeMillis());
+
+        // o6jK35zCgXVyIgb00owR-8WQ_T-U     o4qwy6nkRC1Jc0U_5PLVs93CfxAE
+        // 批量获取患者信息
+        // HisPatientDTO hisPatientDTO = new HisPatientDTO();
+        // hisPatientDTO.setPage(1);
+        // hisPatientDTO.setRows(500);
+        // hisPatientDTO.setStartTime("2024-10-25 17:20:00");
+        // hisPatientDTO.setEndTime("2024-10-25 17:30:00");
+        // HisPatientListModel patientListByTimestamp = getPatientByTimestamp(config, hisPatientDTO);
+        // System.out.println(JSON.toJSONString(patientListByTimestamp));
+
+        // HisDeptListModel deptList = getDeptsInfo(config);
+        // System.out.println(JSON.toJSONString(deptList));
+
+
+        // HisDoctorListModel doctorList = getDoctorsInfo(config, "1");
+        // System.out.println(JSON.toJSONString(doctorList));
+
+
+        // // 医生主页
+        // HisGenerateSchemeDTO doctorParams = new HisGenerateSchemeDTO();
+        // doctorParams.setType("1");
+        // doctorParams.setDoctorId("1111201667");
+        // HisSchemeUrlModel doctor = getWxMiniSchemeUrl(config, doctorParams);
+        // System.out.println(JSON.toJSONString(doctor));
+
+        // 挂号排版
+        // HisGenerateSchemeDTO doctorParams = new HisGenerateSchemeDTO();
+        // doctorParams.setType("2");
+        // doctorParams.setDeptId("1111137800");
+        // doctorParams.setDeptName("生殖医学科门诊");
+        // doctorParams.setHisDeptId("3451");
+        // HisSchemeUrlModel register = getWxMiniSchemeUrl(config, doctorParams);
+        // System.out.println(JSON.toJSONString(register));
+
+        // SchemeUrl
+        // HisGenerateSchemeDTO params3 = new HisGenerateSchemeDTO();
+        // params3.setType("3");
+        // System.out.println("门诊缴费------: " + getWxMiniSchemeUrl(config, params3).getSchemeUrl());
+        
+        // HisGenerateSchemeDTO params4 = new HisGenerateSchemeDTO();
+        // params4.setType("4");
+        // System.out.println("排队候诊------: " + getWxMiniSchemeUrl(config, params4).getSchemeUrl());
+        
+        // HisGenerateSchemeDTO params5 = new HisGenerateSchemeDTO();
+        // params5.setType("5");
+        // System.out.println("自助入院------: " + getWxMiniSchemeUrl(config, params5).getSchemeUrl());
+        
+        // HisGenerateSchemeDTO params6 = new HisGenerateSchemeDTO();
+        // params6.setType("6");
+        // System.out.println("在线复诊------: " + getWxMiniSchemeUrl(config, params6).getSchemeUrl());
+        
+        // HisGenerateSchemeDTO params7 = new HisGenerateSchemeDTO();
+        // params7.setType("7");
+        // System.out.println("报告查询------: " + getWxMiniSchemeUrl(config, params7).getSchemeUrl());
+        
+        // HisGenerateSchemeDTO params8 = new HisGenerateSchemeDTO();
+        // params8.setType("8");
+        // System.out.println("药品清单------: " + getWxMiniSchemeUrl(config, params8).getSchemeUrl());
+
+
+
+        // 推荐码
+        // HisPromotionCodeDTO hisPromotionCodeDTO = new HisPromotionCodeDTO();
+        // hisPromotionCodeDTO.setPromotionCode("000166");
+        // hisPromotionCodeDTO.setPromotionCodeType("1");
+        // HisPromotionCodeModel promotionCode = getPromotionCodeUrl(config, hisPromotionCodeDTO);
+
+        // System.out.println();
+
+        // if (null != promotionCode && StrUtil.isNotBlank(promotionCode.getPromotionCode()) && StrUtil.isNotBlank(promotionCode.getPromotionCodeId())) {
+        //     savePromotionCodeUrl(config, promotionCode.getPromotionCodeId());
+        // }
+
+        // savePromotionCodeUrl(config, "30001");
+    }
+
+}

+ 44 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/WbmdOaApiHelper.java

@@ -0,0 +1,44 @@
+package com.xxh.cloud.frontend.common.modules.his;
+
+
+import cn.hutool.http.HttpRequest;
+import com.alibaba.fastjson.JSONObject;
+import com.xxh.cloud.frontend.common.modules.his.config.SysProjectConfig;
+import com.xxh.cloud.frontend.common.modules.his.dto.GenerateSchemeDTO;
+import com.xxh.cloud.frontend.common.modules.his.model.GenerateSchemeModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisAccessTokenModel;
+import com.xxh.cloud.frontend.common.modules.his.model.PatBindModel;
+import com.xxh.cloud.frontend.common.modules.his.model.WbmdOaModel;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+@Slf4j
+@Component
+public class WbmdOaApiHelper {
+
+    // 皖北OA_企业微信授权登陆
+    private static String wecomAuthorUrl = "http://wecom.api.bydsfy.com/mobile/weixin/api/wecomAuthor/wecom/author";
+
+    public static WbmdOaModel wecomAuthor(String code) {
+        Map<String, String> paramsMap = new HashMap<>();
+        paramsMap.put("WecomSource", "Slife");
+        paramsMap.put("Code", code);
+        log.info("皖北OA_企业微信授权登陆参数 >>>>>>:{}", JSONObject.toJSONString(paramsMap));
+        String result = HttpRequest.post(wecomAuthorUrl)
+                .body(JSONObject.toJSONString(paramsMap))
+                .execute().body();
+        log.info("皖北OA_企业微信授权登陆返回 >>>>>>:{}", result);
+        return JSONObject.parseObject(result, WbmdOaModel.class);
+    }
+
+
+    public static void main(String[] args) {
+//        System.out.println(wecomAuthor("code"));
+    }
+
+}

+ 37 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/config/HisWebConfig.java

@@ -0,0 +1,37 @@
+package com.xxh.cloud.frontend.common.modules.his.config;
+
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@Getter
+@Setter
+public class HisWebConfig {
+
+    /** 海慈的host **/
+    @Value("${his.host:null}")
+    private String host;
+
+    /** 海慈的key **/
+    @Value("${his.sign-key:null}")
+    private String signKey;
+
+    @Value("${his.white:null}")
+    private String white;
+
+    public List<String> whiteList(){
+        if (StrUtil.isNotEmpty(this.white)) {
+            return CollUtil.newArrayList(this.white.split(","));
+        } else {
+            return new ArrayList<>();
+        }
+    }
+}

+ 50 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/config/SysProjectConfig.java

@@ -0,0 +1,50 @@
+package com.xxh.cloud.frontend.common.modules.his.config;
+
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@Getter
+@Setter
+public class SysProjectConfig {
+
+    /** accesstoken来源 his/wx **/
+    @Value("${sys-config.access:wx}")
+    private String access;
+
+    /** 海慈的host **/
+    @Value("${sys-config.his.host:null}")
+    private String host;
+
+    /** 海慈的key **/
+    @Value("${sys-config.his.key:null}")
+    private String key;
+
+    @Value("${sys-config.wx.appid:null}")
+    private String appid;
+
+    @Value("${sys-config.wx.secret:null}")
+    private String secret;
+
+    @Value("${sys-config.wx.temp-msg.check-enable:false}")
+    private boolean checkEnable;
+
+    @Value("${sys-config.wx.temp-msg.white:null}")
+    private String white;
+
+    public List<String> whiteList(){
+        if (StrUtil.isNotEmpty(this.white)) {
+            return CollUtil.newArrayList(this.white.split(","));
+        } else {
+            return new ArrayList<>();
+        }
+    }
+}

+ 14 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/AnalysisDataDTO.java

@@ -0,0 +1,14 @@
+package com.xxh.cloud.frontend.common.modules.his.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AnalysisDataDTO {
+
+    @ApiModelProperty(value = "content")
+    private String content;
+
+}

+ 19 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/GenerateSchemeDTO.java

@@ -0,0 +1,19 @@
+package com.xxh.cloud.frontend.common.modules.his.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class GenerateSchemeDTO {
+
+    @ApiModelProperty(value = "微信小程序的accessToken")
+    private String accessToken;
+
+    @ApiModelProperty(value = "科室编码")
+    private String deptCode;
+
+    @ApiModelProperty(value = "医生编码")
+    private String doctorCode;
+}

+ 25 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/HisGenerateSchemeDTO.java

@@ -0,0 +1,25 @@
+package com.xxh.cloud.frontend.common.modules.his.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisGenerateSchemeDTO {
+
+    @ApiModelProperty(value = "schemaUrl类型[1.医生主页  2.挂号排班]")
+    private String type;
+
+    @ApiModelProperty(value = "互联网医院医生ID")
+    private String doctorId;
+
+    @ApiModelProperty(value = "互联网医院科室ID")
+    private String deptId;
+
+    @ApiModelProperty(value = "互联网医院科室名称")
+    private String deptName;
+
+    @ApiModelProperty(value = "院端科室ID")
+    private String hisDeptId;
+}

+ 30 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/HisPatientDTO.java

@@ -0,0 +1,30 @@
+package com.xxh.cloud.frontend.common.modules.his.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisPatientDTO {
+
+    @ApiModelProperty(value = "页码")
+    private Integer page = 1;
+
+    @ApiModelProperty(value = "每页记录数")
+    private Integer rows = 10;
+    
+    @ApiModelProperty(value = "")
+    private String startTime;
+
+    @ApiModelProperty(value = "")
+    private String endTime;
+
+
+    @ApiModelProperty(value = "openid")
+    private String openid;
+
+    @ApiModelProperty(value = "unionid")
+    private String unionid;
+
+}

+ 17 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/HisPromotionCodeDTO.java

@@ -0,0 +1,17 @@
+package com.xxh.cloud.frontend.common.modules.his.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisPromotionCodeDTO {
+
+    @ApiModelProperty(value = "推广码Code")
+    private String promotionCode;
+
+    @ApiModelProperty(value = "推广码类型:1 员工 2 科室 3 其他")
+    private String promotionCodeType;
+
+}

+ 17 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/dto/WechatQrCodeDTO.java

@@ -0,0 +1,17 @@
+package com.xxh.cloud.frontend.common.modules.his.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class WechatQrCodeDTO {
+
+    @ApiModelProperty(value = "微信accessToken")
+    private String accessToken;
+
+    @ApiModelProperty(value = "二维码参数")
+    private String qrcodeParams;
+
+}

+ 37 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/AnalysisDataModel.java

@@ -0,0 +1,37 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 会诊结论目标解析数据
+ */
+@Getter
+@Setter
+public class AnalysisDataModel {
+
+    // Y/N
+    @ApiModelProperty(value = "是否本科室随访")
+    private String isFollowUp;
+
+    @ApiModelProperty(value = "随访时间")
+    private String followUpDate;
+
+    @ApiModelProperty(value = "随访时间单位")
+    private String followUpDateUnit;
+
+    @ApiModelProperty(value = "建议完善检查内容")
+    private String checkContent;
+
+    // Y/N
+    @ApiModelProperty(value = "是否转入本科室治疗")
+    private String isChangeDept;
+
+    @ApiModelProperty(value = "治疗的方式")
+    private String treatmentMethods;
+
+    @ApiModelProperty(value = "原始数据")
+    private String sourceData;
+
+}

+ 20 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/GenerateSchemeModel.java

@@ -0,0 +1,20 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class GenerateSchemeModel {
+
+    @ApiModelProperty(value = "返回code")
+    private Integer errcode;
+
+    @ApiModelProperty(value = "返回信息")
+    private String errmsg;
+
+    @ApiModelProperty(value = "链接")
+    private String openlink;
+
+}

+ 11 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisAccessTokenModel.java

@@ -0,0 +1,11 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Data;
+
+@Data
+public class HisAccessTokenModel {
+
+    private String jsTicket;
+
+    private String accToken;
+}

+ 16 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisBaseModel.java

@@ -0,0 +1,16 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisBaseModel<T> {
+
+    // 
+    private Integer status;
+
+    private String msg;
+
+    private T data;
+}

+ 14 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisDeptListModel.java

@@ -0,0 +1,14 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisDeptListModel {
+
+    private List<HisDeptModel> depts;
+
+}

+ 55 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisDeptModel.java

@@ -0,0 +1,55 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisDeptModel {
+
+    // 医院ID
+    private String hospitalId;
+
+    // 互联网医院科室ID
+    private String deptId;
+
+    // 院端HIS系统中科室的ID
+    private String hisDeptId;
+
+    // HIS上级科室ID
+    private String hisParentId;
+
+    // 层级CODE
+    private String gradeCode;
+
+    // 科室名
+    private String name;
+
+    // 科室名拼音
+    private String namePinYin;
+
+    // 图片地址
+    private String imgUrl;
+
+    // 科室在医院的位置,楼层,诊室等
+    private String location;
+
+    // 针对科室,对患者的特别提示
+    private String notice;
+
+    // 描述
+    private String description;
+
+    // 备注等信息
+    private String remark;
+
+    // 院区名称
+    private String branchName;
+
+    // 是否是院区
+    private String isBranch;
+
+    // 联系
+    private String contactNo;
+
+}

+ 14 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisDoctorListModel.java

@@ -0,0 +1,14 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisDoctorListModel {
+
+    private List<HisDoctorModel> doctorsInfoDtos;
+
+}

+ 51 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisDoctorModel.java

@@ -0,0 +1,51 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisDoctorModel {
+
+    // 互联网医院医生ID
+    private String doctorId;
+
+    // 院端HIS系统中医生的ID
+    private String hisDoctorId;
+
+    // 医生姓名
+    private String doctorName;
+
+    // 医生性别
+    private String gender;
+
+    // 医生所在科室
+    private String deptName;
+
+    // 头像
+    private String headImg;
+
+    // 医生职称
+    private String levelName;
+
+    // 医生职称Id
+    private String levelId;
+
+    // 医生简介
+    private String description;
+
+    // 是否专家
+    private String expert;
+
+    // 互联网科室医生ID
+    private String deptId;
+
+    // 擅长
+    private String skill;
+
+    // 手机号
+    private String contactPhone;
+
+    // 院端科室ID
+    private String hisDeptId;
+}

+ 14 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisPatientListModel.java

@@ -0,0 +1,14 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import java.util.List;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisPatientListModel {
+
+    private List<HisPatientModel> patients;
+
+}

+ 65 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisPatientModel.java

@@ -0,0 +1,65 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisPatientModel {
+
+    // 门诊号
+    private String hisPatientId;
+
+    // 住院号
+    private String inPatientNo;
+
+    // 患者姓名
+    private String name;
+
+    // 身份证号
+    private String paperNo;
+
+    // 性别 男 女
+    private String sex;
+
+    // 生日
+    private String birthday;
+
+    private String nativePlace;
+
+    // 紧急联系人电话
+    private String linkPhone;
+
+    // 紧急联系人
+    private String linkName;
+
+    // 紧急联系人与患者关系
+    private String linkRelationName;
+
+    // 国籍
+    private String country;
+
+    // 默认患者 0-否  1-是(废弃)
+    private String isDefault;
+
+    // 微信openid
+    private String openId;
+
+    // 家庭绑定关系
+    private String unionid;
+    
+    // 创建时间
+    private String createDate;
+
+    // 更新时间
+    private String updateDate;
+    
+    // 0 无效 1 有效
+    private String enable;
+    
+    // 关系
+    private String relation;
+    
+    // 0-本人,1-父母,2-子女,3-夫妻,4-亲属,5-朋友,6-其他
+    private String relationId;
+}

+ 22 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisPromotionCodeModel.java

@@ -0,0 +1,22 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisPromotionCodeModel {
+
+    // 推广码ID
+    private String promotionCodeId;
+
+    // 推广码Code
+    private String promotionCode;
+
+    // 推广码名称
+    private String promotionName;
+
+    // 备注
+    private String remark;
+
+}

+ 14 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisSchemeUrlModel.java

@@ -0,0 +1,14 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisSchemeUrlModel {
+
+    private String schemeUrl;
+
+    private String urlLink;
+
+}

+ 13 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/HisWxTokenModel.java

@@ -0,0 +1,13 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class HisWxTokenModel {
+
+    // 微信token
+    private String token;
+
+}

+ 25 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/PatBindModel.java

@@ -0,0 +1,25 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 就诊卡号列表
+ */
+@Getter
+@Setter
+public class PatBindModel {
+
+    @ApiModelProperty(value = "返回code")
+    private Integer code;
+
+    @ApiModelProperty(value = "返回信息")
+    private String msg;
+
+    @ApiModelProperty(value = "卡列表")
+    private List<PatInfoModel> data;
+
+}

+ 89 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/PatInfoModel.java

@@ -0,0 +1,89 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 就诊卡号信息
+ */
+@Getter
+@Setter
+public class PatInfoModel {
+
+    @ApiModelProperty(value = "生日")
+    private String birthday;
+
+    @ApiModelProperty(value = "就诊人Id")
+    private String patientId;
+
+    @ApiModelProperty(value = "就诊人姓名")
+    private String patientName;
+
+    @ApiModelProperty(value = "联系电话")
+    private String patientMobile;
+
+    @ApiModelProperty(value = "就诊人证件号")
+    private String idNo;
+
+    @ApiModelProperty(value = "就诊人证件类型 1:二代身份证 2:港澳居民身份证 3:台湾居民身份证 4:护照")
+    private String idType;
+
+    @ApiModelProperty(value = "就诊人证件类型名称")
+    private String idTypeName;
+
+    @ApiModelProperty(value = "就诊人门诊id")
+    private String patHisNo;
+
+    @ApiModelProperty(value = "医院卡号id")
+    private String patCardNo;
+
+    @ApiModelProperty(value = "医院卡号类型 21:院内就诊卡 22:市民卡 23:医保卡")
+    private String patCardType;
+
+    @ApiModelProperty(value = "医院卡号类型名称")
+    private String patCardTypeName;
+
+    @ApiModelProperty(value = "默认就诊人 0-否 1-是")
+    private String isDefault;
+
+    @ApiModelProperty(value = "默认就诊人 F:女,M:男")
+    private String patientSex;
+
+    @ApiModelProperty(value = "与本人关系")
+    private String relationName;
+
+    @ApiModelProperty(value = "与本人关系 1:本人 2:配偶 3:父母 4:子女 5:他人")
+    private String relationType;
+
+    @ApiModelProperty(value = "患者类型 0:成人 1:儿童 2:妇女 3:老人")
+    private String patientType;
+
+    @ApiModelProperty(value = "患者类型名称")
+    private String patientTypeName;
+
+    @ApiModelProperty(value = "电子健康卡标识 0:无需绑定 1:需要升级 2:已有健康卡")
+    private String healthCardFlag;
+
+    @ApiModelProperty(value = "扩展字段保存的值 json格式")
+    private String extFields;
+    
+
+    @ApiModelProperty(value = "openid")
+    private String openId;
+
+    @ApiModelProperty(value = "unionid")
+    private String unionid;
+
+    // 创建时间
+    @ApiModelProperty(value = "创建时间")
+    private String createDate;
+
+    // 更新时间
+    @ApiModelProperty(value = "更新时间")
+    private String updateDate;
+    
+    // 0 无效 1 有效
+    @ApiModelProperty(value = "0 无效 1 有效")
+    private String enable;
+}

+ 22 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/WbmdOaModel.java

@@ -0,0 +1,22 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Data;
+
+@Data
+public class WbmdOaModel {
+
+    private String code;
+
+    private String type;
+
+    private String message;
+
+    private WbmdOaResult result;
+
+    private String extras;
+
+    private String time;
+
+    private Integer count;
+
+}

+ 16 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/his/model/WbmdOaResult.java

@@ -0,0 +1,16 @@
+package com.xxh.cloud.frontend.common.modules.his.model;
+
+import lombok.Data;
+
+@Data
+public class WbmdOaResult {
+
+    private String accessToken;
+
+    private String refreshToken;
+
+    private String account;
+
+    private String accountHis;
+
+}

+ 110 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/modules/Result.java

@@ -0,0 +1,110 @@
+package com.xxh.cloud.frontend.common.modules.modules;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xxh.cloud.frontend.common.modules.exception.BusinessBaseErrorEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+
+/**
+ * 响应数据
+ */
+@ApiModel(value = "响应")
+public class Result<T> implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 编码:0表示成功,其他值表示失败
+     */
+    @ApiModelProperty(value = "编码:0表示成功,其他值表示失败")
+    private int code = 0;
+    /**
+     * 消息内容
+     */
+    @ApiModelProperty(value = "消息内容")
+    private String msg = "success";
+    /**
+     * 响应数据
+     */
+    @ApiModelProperty(value = "响应数据")
+    private T data;
+
+    public Result() {
+
+    }
+
+    public Result<T> ok(T data) {
+        this.setData(data);
+        return this;
+    }
+
+//    public boolean success(){
+//        return code == Constant.ResultSuccess;
+//    }
+
+    public Result<T> success() {
+        return this;
+    }
+
+    public Result<T> error() {
+        this.code = BusinessBaseErrorEnum.INTERNAL_SERVER_ERROR.getCode();
+        this.msg = BusinessBaseErrorEnum.INTERNAL_SERVER_ERROR.getMsg();
+        return this;
+    }
+
+
+    public Result<T> error(BusinessBaseErrorEnum error) {
+        this.code = error.getCode();
+        this.msg = error.getMsg();
+        return this;
+    }
+
+
+
+    public Result<T> error(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+        return this;
+    }
+
+    public Result<T> error(String msg) {
+        this.code = BusinessBaseErrorEnum.INTERNAL_SERVER_ERROR.getCode();
+        this.msg = msg;
+        return this;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public Result(String result, Class<T> clazz) {
+        JSONObject json = JSONObject.parseObject(result);
+        this.code = (Integer)json.get("code");
+        if (json.containsKey("msg")) {
+            this.msg = json.get("msg").toString();
+        }
+        if (json.containsKey("data") && json.get("data") != null) {
+            this.data = JSONObject.parseObject(JSONObject.toJSONString(json.get("data")), clazz);
+        }
+    }
+}

+ 66 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/util/IpUtils.java

@@ -0,0 +1,66 @@
+package com.xxh.cloud.frontend.common.modules.util;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class IpUtils {
+
+   public static String getIpAddr(HttpServletRequest request) {
+      String unknown = "unknown";
+      String ip = null;
+
+      try {
+         ip = request.getHeader("x-forwarded-for");
+         if (StrUtil.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+         }
+
+         if (StrUtil.isEmpty(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+         }
+
+         if (StrUtil.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_CLIENT_IP");
+         }
+
+         if (StrUtil.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+         }
+
+         if (StrUtil.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+         }
+      } catch (Exception var4) {
+         log.error("IPUtils ERROR ", var4);
+      }
+
+      return ip;
+   }
+
+   public static String getIpAddr() {
+      if (RequestContextHolder.getRequestAttributes() != null) {
+         HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
+         return getIpAddr(request);
+      } else {
+         return getLocalIp();
+      }
+   }
+
+   public static String getLocalIp() {
+      try {
+         return InetAddress.getLocalHost().getHostAddress();
+      } catch (UnknownHostException var1) {
+         log.error("获取本机IP错误", var1);
+         return null;
+      }
+   }
+}

+ 33 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/util/IpWhite.java

@@ -0,0 +1,33 @@
+package com.xxh.cloud.frontend.common.modules.util;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+import com.xxh.cloud.frontend.common.modules.exception.BusinessException;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Configuration
+public class IpWhite {
+
+   @Value("${xxl.ip.white.enable:false}")
+   private Boolean enable;
+
+   @Value("${xxl.ip.white.list:}")
+   private List<String> whiteList;
+
+   public void validatorIpWhite() {
+      String ip = IpUtils.getIpAddr();
+      log.info("ip >>>>>> {}", ip);
+
+      if (null != enable && enable) {
+         if (StrUtil.isBlank(ip) || !whiteList.contains(ip)) {
+            throw new BusinessException("无访问权限");
+         }
+      }
+   }
+}

+ 63 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinAccessTokenService.java

@@ -0,0 +1,63 @@
+package com.xxh.cloud.frontend.common.modules.weixin;
+
+import com.alibaba.fastjson.JSONObject;
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import com.company.cloud.sdk.weixin.mp.WxMpApi;
+import com.company.cloud.sdk.weixin.mp.model.AccessTokenModel;
+import com.company.cloud.sdk.weixin.mp.model.AccessTokenResp;
+import com.company.cloud.sdk.weixin.mp.model.JsapiTicketModel;
+import com.company.cloud.sdk.weixin.mp.model.JsapiTicketResp;
+import com.xxh.cloud.frontend.common.modules.exception.BusinessBaseErrorEnum;
+import com.xxh.cloud.frontend.common.modules.exception.BusinessException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+/**
+ * 微信公众号和小程序 :全局唯一接口调用凭据 AccessToken
+ * 公众号: 全局 jsapi_ticket的有效期为7200秒
+ * */
+@Slf4j
+@Service
+@CacheConfig(cacheNames = "{CATEGORY}")
+public class ThirdWeixinAccessTokenService {
+
+    @Cacheable(key = "#config.appid")
+    public String getAccessToken(WxApiConfig config){
+        log.info("---getAccessToken(WxApiConfig config):" + JSONObject.toJSONString(config));
+        AccessTokenResp accessTokenResp=this._getAccessToken(config);
+        if(accessTokenResp==null){
+            throw new BusinessException(BusinessBaseErrorEnum.PARAMS_GET_ERROR);
+        }
+        log.info(JSONObject.toJSONString(accessTokenResp));
+        String accessToken = accessTokenResp.getAccess_token();
+        return accessToken;
+    }
+
+    public JsapiTicketResp getJsapiToken(String accessToken){
+        log.info("---getJsapiToken(String accessToken)" + accessToken);
+        JsapiTicketResp jsapiTicketResp=this._getJsapiToken(accessToken);
+        if(jsapiTicketResp==null){
+            throw new BusinessException(BusinessBaseErrorEnum.PARAMS_GET_ERROR);
+        }
+        log.info(JSONObject.toJSONString(jsapiTicketResp));
+        return jsapiTicketResp;
+    }
+
+    private AccessTokenResp _getAccessToken(WxApiConfig config){
+        AccessTokenModel param=new AccessTokenModel();
+        param.setAppid(config.getAppid());
+        param.setSecret(config.getSecret());
+        AccessTokenResp resp= WxMpApi.accessToken(param);
+        return resp;
+    }
+
+    private JsapiTicketResp _getJsapiToken(String accessToken){
+        JsapiTicketModel wxReq=new JsapiTicketModel();
+        wxReq.setAccess_token(accessToken);
+        JsapiTicketResp resp= WxMpApi.jsapiTicket(wxReq);
+        return resp;
+    }
+
+}

+ 45 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinLoginMiniService.java

@@ -0,0 +1,45 @@
+package com.xxh.cloud.frontend.common.modules.weixin;
+
+import cn.hutool.json.JSONUtil;
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import com.company.cloud.sdk.weixin.mini.WxMiniApi;
+import com.company.cloud.sdk.weixin.mini.model.Code2SessionModel;
+import com.company.cloud.sdk.weixin.mini.model.Code2SessionResp;
+import com.company.cloud.sdk.weixin.mini.model.DecryptDataModel;
+import com.xxh.cloud.frontend.common.modules.weixin.dto.BindMobileByWxDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * 微信小程序
+ * */
+@Slf4j
+@Service
+public class ThirdWeixinLoginMiniService {
+
+
+    public Code2SessionResp getLoginAuthToken(WxApiConfig config, String jscode){
+        log.info("---getLoginAuthToken(WxApiConfig config, String jscode)");
+        Code2SessionModel param=new Code2SessionModel();
+        param.setAppid(config.getAppid());
+        param.setSecret(config.getSecret());
+        param.setJs_code(jscode);
+        Code2SessionResp resp= WxMiniApi.code2Session(param);
+        log.info(JSONUtil.toJsonStr(resp));
+        return resp;
+    }
+
+    public String getMobileByOpenId(BindMobileByWxDTO param) {
+        log.info("---getMobileByOpenId(BindMobileByWxDTO param)");
+        DecryptDataModel decryptData = new DecryptDataModel();
+        decryptData.setEncryptedData(param.getEncryptedData());
+        decryptData.setIv(param.getIv());
+        String result = WxMiniApi.decryptData(decryptData);
+        log.error("微信解密信息:" + result);
+        return result;
+    }
+
+
+
+
+}

+ 81 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinLoginMpService.java

@@ -0,0 +1,81 @@
+package com.xxh.cloud.frontend.common.modules.weixin;
+
+import com.alibaba.fastjson.JSONObject;
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import com.company.cloud.sdk.weixin.mp.WxMpApi;
+import com.company.cloud.sdk.weixin.mp.WxMpUserManageApi;
+import com.company.cloud.sdk.weixin.mp.model.Code2AccessTokenModel;
+import com.company.cloud.sdk.weixin.mp.model.Code2AccessTokenResp;
+import com.company.cloud.sdk.weixin.mp.model.usermanage.UserBasicInfoReqModel;
+import com.company.cloud.sdk.weixin.mp.model.usermanage.UserBasicInfoResp;
+import com.xxh.cloud.frontend.common.modules.exception.BusinessException;
+import com.xxh.cloud.frontend.common.modules.weixin.constant.XXWeiXinErrorEnum;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Log4j2
+@Service
+public class ThirdWeixinLoginMpService {
+
+
+    @Autowired
+    private ThirdWeixinPageAccessTokenService thirdWeixinPageAccessTokenService;
+    @Autowired
+    private ThirdWeixinAccessTokenService thirdWeixinAccessTokenService;
+
+
+    /**
+     * openId 和 网页授权access_token
+     * */
+    public Code2AccessTokenResp getLoginAuthToken(WxApiConfig config, String jscode){
+        // 调用api获取openid
+        Code2AccessTokenModel code2AccessTokenModel = new Code2AccessTokenModel();
+        code2AccessTokenModel.setAppid(config.getAppid());
+        code2AccessTokenModel.setSecret(config.getSecret());
+        code2AccessTokenModel.setCode(jscode);
+        Code2AccessTokenResp resp = WxMpApi.code2Ticket(code2AccessTokenModel);
+        if (resp == null) {
+            throw new BusinessException(XXWeiXinErrorEnum.WX_MP_OpenId);
+        }
+        return resp;
+    }
+
+    /**
+     * 获取unionid
+     * */
+    public UserBasicInfoResp getUnionid(String openId, String accessToken){
+        log.info("---getUnionid()" + openId + "---" + accessToken);
+        UserBasicInfoReqModel userBasicInfoReqModel = new UserBasicInfoReqModel();
+        userBasicInfoReqModel.setAccess_token(accessToken);
+        userBasicInfoReqModel.setOpenid(openId);
+        UserBasicInfoResp userBasicInfoResp = WxMpUserManageApi.getUserInfo(userBasicInfoReqModel);
+        log.debug(JSONObject.toJSONString(userBasicInfoResp));
+        return userBasicInfoResp;
+    }
+
+
+
+//    /**
+//     * 微信js签名
+//     * */
+//    public WxJSSDKSignModel wxSign(WxApiConfig config, String url){
+//        String jsApiTicket=thirdWeixinAccessTokenService.getJsapiToken(config);
+//        if(StrUtil.isEmpty(jsApiTicket)){
+//            throw new BusinessException(XXWeiXinErrorEnum.WX_MP_JsApiTicket);
+//        }
+//        WxJSSDKSignModel wxResp= WxJSSDKSignUtils.sign(config.getAppid(),url,jsApiTicket);
+//        return wxResp;
+//    }
+
+
+
+
+
+
+
+
+
+
+
+}

+ 24 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinPageAccessTokenService.java

@@ -0,0 +1,24 @@
+package com.xxh.cloud.frontend.common.modules.weixin;
+
+import com.company.cloud.sdk.weixin.mp.WxMpApi;
+import com.company.cloud.sdk.weixin.mp.model.RefreshTokenModel;
+import com.company.cloud.sdk.weixin.mp.model.RefreshTokenResp;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.stereotype.Service;
+
+/**
+ *  微信公众号,授权后 网页授权接口调用凭证
+ * */
+@Log4j2
+@Service
+public class ThirdWeixinPageAccessTokenService {
+
+    public RefreshTokenResp refresh(String appId,String refresh_token){
+        log.info("---refresh()" + appId + "---" + refresh_token);
+        RefreshTokenModel param=new RefreshTokenModel();
+        param.setAppid(appId);
+        param.setRefresh_token(refresh_token);
+        RefreshTokenResp resp= WxMpApi.token2RefreshToken(param);
+        return resp;
+    }
+}

+ 88 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/ThirdWeixinSendTempMsgService.java

@@ -0,0 +1,88 @@
+package com.xxh.cloud.frontend.common.modules.weixin;
+
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+
+import com.alibaba.fastjson.JSONObject;
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import com.company.cloud.sdk.weixin.mp.WxMpMsgManageApi;
+import com.company.cloud.sdk.weixin.mp.model.msgmanage.SendTempMsgDataModel;
+import com.company.cloud.sdk.weixin.mp.model.msgmanage.SendTempMsgModel;
+import com.company.cloud.sdk.weixin.mp.model.msgmanage.SendTempMsgResp;
+import com.xxh.cloud.frontend.common.modules.exception.BusinessException;
+import com.xxh.cloud.frontend.common.modules.exception.WechatBaseErrorEnum;
+import com.xxh.cloud.frontend.common.modules.his.HisApiHelper;
+import com.xxh.cloud.frontend.common.modules.his.config.SysProjectConfig;
+import com.xxh.cloud.frontend.common.modules.his.model.HisAccessTokenModel;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.weixin.dto.SendTempMsgDTO;
+
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *  微信公众号,提送消息
+ * */
+@Log4j2
+@Service
+public class ThirdWeixinSendTempMsgService {
+
+    @Autowired
+    private SysProjectConfig sysProjectConfig;
+    @Autowired
+    private ThirdWeixinAccessTokenService thirdWeixinAccessTokenService;
+
+    public SendTempMsgResp sendTempMsg(SendTempMsgDTO params){
+        if (StrUtil.isBlank(params.getAccessToken())) {
+            // TODO mj-li 临时方案,从新获取token
+            if ("his".equals(sysProjectConfig.getAccess())) { //调用his获取
+                Result<HisAccessTokenModel> resp = HisApiHelper.getAccessToken(sysProjectConfig);
+                if (resp.getCode() != 0) {
+                    log.error("----获取AccessToken失败----");
+                }
+                params.setAccessToken(resp.getData().getAccToken());
+            } else { //调用微信获取
+                WxApiConfig wxApiConfig = new WxApiConfig();
+                wxApiConfig.setAppid(sysProjectConfig.getAppid());
+                wxApiConfig.setSecret(sysProjectConfig.getSecret());
+                String accessToken = thirdWeixinAccessTokenService.getAccessToken(wxApiConfig);
+                params.setAccessToken(accessToken);
+            }
+        }
+        // 发送规则的校验
+        tempMsgCheck(params);
+        // 发送
+        SendTempMsgModel model = new SendTempMsgModel();
+        model.setTouser(params.getOpenid());
+        model.setTemplate_id(params.getTemplateId());
+        model.setUrl(params.getUrl());
+
+        if (MapUtil.isNotEmpty(params.getTempData())) {
+            Map<String, SendTempMsgDataModel> data = new HashMap<>();
+            Map<String, String> map = params.getTempData();
+            map.forEach((k, v) -> {
+                SendTempMsgDataModel sendTempMsgDataModel = new SendTempMsgDataModel(v);
+                data.put(k, sendTempMsgDataModel);
+            });
+            model.setData(data);
+        }
+
+        log.info("wechat mp request send template message >>> : {}", JSONObject.toJSONString(model));
+        SendTempMsgResp resp = WxMpMsgManageApi.sendTempMsg(params.getAccessToken(), model);
+        log.info("wechat mp response send template message <<< : {}", JSONObject.toJSONString(resp));
+        return resp;
+    }
+
+    private void tempMsgCheck(SendTempMsgDTO params) {
+        if (sysProjectConfig.isCheckEnable()) {
+            if (!sysProjectConfig.whiteList().contains(params.getOpenid())) {
+                log.info("白名单校验-白名单中不存在openid:{}", params.getOpenid());
+                throw new BusinessException(WechatBaseErrorEnum.TEMP_MSG_WHITE_NONE);
+            }
+        }
+    }
+}

+ 29 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/bos/ThirdUnifyUserLoginBO.java

@@ -0,0 +1,29 @@
+package com.xxh.cloud.frontend.common.modules.weixin.bos;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ThirdUnifyUserLoginBO {
+
+
+
+    @ApiModelProperty("用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID")
+    private String openid;
+
+    @ApiModelProperty("用户授权的作用域,使用逗号(,)分隔")
+    private String scope;
+
+    @ApiModelProperty("用户在开放平台的唯一标识符")
+    private String unionid;
+
+//    @ApiModelProperty("会话密钥")
+//    private String sessionKey;
+
+
+
+
+
+}

+ 36 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/constant/XXWeiXinErrorEnum.java

@@ -0,0 +1,36 @@
+package com.xxh.cloud.frontend.common.modules.weixin.constant;
+
+import com.xxh.cloud.frontend.common.modules.exception.IErrorCodeEnum;
+
+public enum XXWeiXinErrorEnum implements IErrorCodeEnum {
+
+
+    WX_MP_OpenId(13001,"微信公众号获取openId和AccessToken错误"),
+
+
+    WX_MP_JsApiTicket(13002,"微信公众号获取JsApiTicket错误"),
+
+
+
+    ;
+    private int code;
+    private String msg;
+
+    private XXWeiXinErrorEnum() {
+    }
+
+    XXWeiXinErrorEnum(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    @Override
+    public int getCode() {
+        return code;
+    }
+
+    @Override
+    public String getMsg() {
+        return msg;
+    }
+}

+ 12 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/AccessTokenDTO.java

@@ -0,0 +1,12 @@
+package com.xxh.cloud.frontend.common.modules.weixin.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class AccessTokenDTO {
+
+    @ApiModelProperty(value = "AccessToken")
+    private String accessToken;
+
+}

+ 22 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/BindMobileByWxDTO.java

@@ -0,0 +1,22 @@
+package com.xxh.cloud.frontend.common.modules.weixin.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+
+@Data
+public class BindMobileByWxDTO {
+
+    @ApiModelProperty(value = "三方openId")
+    private String openId;
+
+    @ApiModelProperty(value = "加密字符串", required = true)
+    @NotEmpty(message = "加密字符串不能为空")
+    private String encryptedData;
+
+    @ApiModelProperty("偏移量")
+    private String iv;
+
+
+}

+ 13 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/LoginAuthTokenDTO.java

@@ -0,0 +1,13 @@
+package com.xxh.cloud.frontend.common.modules.weixin.dto;
+
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import lombok.Data;
+
+@Data
+public class LoginAuthTokenDTO extends WxApiConfig {
+
+    private String code;
+
+    private String grant_type = "authorization_code";
+
+}

+ 12 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/RefreshTokenDTO.java

@@ -0,0 +1,12 @@
+package com.xxh.cloud.frontend.common.modules.weixin.dto;
+
+import lombok.Data;
+
+@Data
+public class RefreshTokenDTO {
+
+    private String appId;
+
+    private String refresh_token;
+
+}

+ 26 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/SendTempMsgDTO.java

@@ -0,0 +1,26 @@
+package com.xxh.cloud.frontend.common.modules.weixin.dto;
+
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class SendTempMsgDTO extends WxApiConfig {
+
+    @ApiModelProperty(value = "accessToken")
+    private String accessToken;
+
+    @ApiModelProperty(value = "用户openId")
+    private String openid;
+
+    @ApiModelProperty(value = "推送模板ID")
+    private String templateId;
+
+    @ApiModelProperty(value = "跳转连接")
+    private String url;
+
+    @ApiModelProperty(value = "模板数据")
+    private Map<String, String> tempData;
+}

+ 28 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/SendWxWorkMsgDTO.java

@@ -0,0 +1,28 @@
+package com.xxh.cloud.frontend.common.modules.weixin.dto;
+
+import java.util.Map;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class SendWxWorkMsgDTO {
+    
+    @ApiModelProperty(value = "accessToken")
+    private String accessToken;
+
+    @ApiModelProperty(value = "用户openId")
+    private String openid;
+
+    @ApiModelProperty(value = "消息类型")
+    private String msgtype;
+
+    @ApiModelProperty(value = "企业应用的id,整型")
+    private Long agentid;
+
+    @ApiModelProperty(value = "消息数据")
+    private Map<String, String> data;
+
+}

+ 37 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/ThirdUnifyUserLoginDTO.java

@@ -0,0 +1,37 @@
+package com.xxh.cloud.frontend.common.modules.weixin.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotEmpty;
+
+@Getter
+@Setter
+public class ThirdUnifyUserLoginDTO {
+
+
+
+    @ApiModelProperty(value = "第三方参数配置ID",required = true)
+    @NotEmpty(message = "不能为空")
+    private String paramsId;
+
+
+    @ApiModelProperty(value = "CODE",required = true)
+    @NotEmpty(message = "不能为空")
+    private String code;
+
+
+    public ThirdUnifyUserLoginDTO(String paramsId,String code){
+        this.paramsId=paramsId;
+        this.code=code;
+    }
+
+
+    public ThirdUnifyUserLoginDTO(){
+
+    }
+
+
+
+}

+ 11 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/dto/UnionIdDTO.java

@@ -0,0 +1,11 @@
+package com.xxh.cloud.frontend.common.modules.weixin.dto;
+
+import lombok.Data;
+
+@Data
+public class UnionIdDTO {
+
+    private String openid;
+
+    private String access_token;
+}

+ 40 - 0
healthy-frontend-common/src/main/java/com/xxh/cloud/frontend/common/modules/weixin/helper/ThirdUserLoginWeixinConvert.java

@@ -0,0 +1,40 @@
+package com.xxh.cloud.frontend.common.modules.weixin.helper;
+
+import com.company.cloud.sdk.weixin.mini.model.Code2SessionResp;
+import com.company.cloud.sdk.weixin.mp.model.Code2AccessTokenResp;
+import com.company.cloud.sdk.weixin.mp.model.usermanage.UserBasicInfoResp;
+import com.xxh.cloud.frontend.common.modules.weixin.bos.ThirdUnifyUserLoginBO;
+
+public class ThirdUserLoginWeixinConvert {
+
+    public static ThirdUnifyUserLoginBO getThirdUnifyUserLoginBO(Code2SessionResp entity){
+        ThirdUnifyUserLoginBO data=new ThirdUnifyUserLoginBO();
+        data.setOpenid(entity.getOpenid());
+        data.setUnionid(entity.getUnionid());
+//        data.setSessionKey(entity.getSession_key());
+        return data;
+    }
+
+
+    public static ThirdUnifyUserLoginBO getThirdUnifyUserLoginBO(Code2AccessTokenResp entity, UserBasicInfoResp userBasicInfoResp){
+        ThirdUnifyUserLoginBO data=new ThirdUnifyUserLoginBO();
+        data.setOpenid(entity.getOpenid());
+        data.setScope(entity.getScope());
+        data.setUnionid(userBasicInfoResp.getUnionid());
+        return data;
+    }
+    //
+
+
+    public static void main(String[] args) {
+
+
+//        Code2AccessTokenModel code2AccessTokenModel = new Code2AccessTokenModel();
+//        code2AccessTokenModel.setAppid("wxbe14c70a4dcb3a0c");
+//        code2AccessTokenModel.setSecret("a46036cbb80c1c5d7ce21a98b1041969");
+//        code2AccessTokenModel.setCode("031YPxGa1vpq3G0IJ8Ia1kVLCU2YPxGW");
+//        Code2AccessTokenResp resp = WxMpApi.code2Ticket(code2AccessTokenModel);
+    }
+
+
+}

+ 26 - 0
healthy-frontend-custuser/pom.xml

@@ -0,0 +1,26 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>healthy-frontend-java</artifactId>
+        <groupId>com.xxh.cloud.frontend</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>healthy-frontend-custuser</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.xxh.cloud.frontend</groupId>
+            <artifactId>healthy-frontend-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+
+</project>

+ 34 - 0
healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/AnalysisController.java

@@ -0,0 +1,34 @@
+package com.xxh.cloud.frontend.custuser.web.controller;
+
+import com.xxh.cloud.frontend.common.modules.his.AnalysisApiHelper;
+import com.xxh.cloud.frontend.common.modules.his.dto.AnalysisDataDTO;
+import com.xxh.cloud.frontend.common.modules.his.model.AnalysisDataModel;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.util.IpWhite;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@Slf4j
+@RestController
+@RequestMapping("/consultation/advice")
+@Api(tags="会诊结论目标解析")
+public class AnalysisController {
+
+    @Autowired
+    private IpWhite ipWhite;
+
+    @PostMapping("/getAnalysisData")
+    @ApiOperation("获取会诊结论解析数据")
+    public Result<AnalysisDataModel> getPatientByThirdId(@RequestBody AnalysisDataDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        AnalysisDataModel resp = AnalysisApiHelper.getAnalysisData(params.getContent());
+        
+        return new Result<AnalysisDataModel>().ok(resp);
+    }
+}

+ 123 - 0
healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/CustUserWxLoginController.java

@@ -0,0 +1,123 @@
+package com.xxh.cloud.frontend.custuser.web.controller;
+
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import com.company.cloud.sdk.weixin.mini.model.Code2SessionResp;
+import com.company.cloud.sdk.weixin.mp.model.Code2AccessTokenResp;
+import com.company.cloud.sdk.weixin.mp.model.JsapiTicketResp;
+import com.company.cloud.sdk.weixin.mp.model.RefreshTokenResp;
+import com.company.cloud.sdk.weixin.mp.model.usermanage.UserBasicInfoResp;
+import com.xxh.cloud.frontend.common.modules.his.config.SysProjectConfig;
+import com.xxh.cloud.frontend.common.modules.his.model.HisAccessTokenModel;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.util.IpWhite;
+import com.xxh.cloud.frontend.common.modules.weixin.ThirdWeixinAccessTokenService;
+import com.xxh.cloud.frontend.common.modules.weixin.ThirdWeixinLoginMiniService;
+import com.xxh.cloud.frontend.common.modules.weixin.ThirdWeixinLoginMpService;
+import com.xxh.cloud.frontend.common.modules.weixin.ThirdWeixinPageAccessTokenService;
+import com.xxh.cloud.frontend.common.modules.weixin.dto.*;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@Slf4j
+@RestController
+@RequestMapping("/api/weixin")
+@Api(tags = "调用微信服务接口")
+public class CustUserWxLoginController {
+
+    @Autowired
+    private SysProjectConfig hisconfig;
+    @Autowired
+    private ThirdWeixinAccessTokenService thirdWeixinAccessTokenService;
+    @Autowired
+    private ThirdWeixinLoginMiniService thirdWeixinLoginMiniService;
+    @Autowired
+    private ThirdWeixinLoginMpService thirdWeixinLoginMpService;
+    @Autowired
+    private ThirdWeixinPageAccessTokenService thirdWeixinPageAccessTokenService;
+    @Autowired
+    private IpWhite ipWhite;
+
+    // 不使用此接口,调用HIS那边的统一接口获取AccessToken
+    @PostMapping("/getAccessToken")
+    @ApiOperation(value = "获取微信的AccessToken", response = Result.class)
+    public Result<HisAccessTokenModel> getAccessToken(@RequestBody WxApiConfig config) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        String accessToken = thirdWeixinAccessTokenService.getAccessToken(config);
+        HisAccessTokenModel model = new HisAccessTokenModel();
+        model.setAccToken(accessToken);
+        return new Result<HisAccessTokenModel>().ok(model);
+    }
+
+    @PostMapping("/jsapiTicket")
+    @ApiOperation(value = "用AccessToken查询JsapiTicket", response = Result.class)
+    public Result<JsapiTicketResp> jsapiTicket(@RequestBody AccessTokenDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        return new Result<JsapiTicketResp>().ok(thirdWeixinAccessTokenService.getJsapiToken(params.getAccessToken()));
+    }
+
+    @PostMapping("/mini/getLoginAuthToken")
+    @ApiOperation(value = "小程序端-获取登录信息", response = Result.class)
+    public Result<Code2SessionResp> getMiniLoginAuthToken(@RequestBody LoginAuthTokenDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        return new Result<Code2SessionResp>().ok(
+                thirdWeixinLoginMiniService.getLoginAuthToken(params, params.getCode()));
+    }
+
+    @PostMapping("/mini/getMobileByOpenId")
+    @ApiOperation(value = "小程序端-获取手机号", response = Result.class)
+    public Result<String> getMobileByOpenId(@RequestBody BindMobileByWxDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        return new Result<String>().ok(thirdWeixinLoginMiniService.getMobileByOpenId(params));
+    }
+
+    @PostMapping("/mp/getLoginAuthToken")
+    @ApiOperation(value = "公众号-获取登录信息", response = Result.class)
+    public Result<Code2AccessTokenResp> getMpLoginAuthToken(@RequestBody LoginAuthTokenDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        return new Result<Code2AccessTokenResp>().ok(
+                thirdWeixinLoginMpService.getLoginAuthToken(params, params.getCode()));
+    }
+
+    @PostMapping("/getUnionid")
+    @ApiOperation(value = "获取Unionid", response = Result.class)
+    public Result<UserBasicInfoResp> getUnionid(@RequestBody UnionIdDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        return new Result<UserBasicInfoResp>().ok(
+                thirdWeixinLoginMpService.getUnionid(params.getOpenid(), params.getAccess_token()));
+    }
+
+    @PostMapping("/page/refreshToken")
+    @ApiOperation(value = "刷新网页授权调用凭证", response = Result.class)
+    public Result<RefreshTokenResp> refreshToken(@RequestBody RefreshTokenDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        return new Result<RefreshTokenResp>().ok(
+                thirdWeixinPageAccessTokenService.refresh(params.getAppId(), params.getRefresh_token()));
+    }
+
+    @GetMapping("/getUnionidTest")
+    @ApiOperation(value = "获取Unionid", response = Result.class)
+    public Result<UserBasicInfoResp> getUnionidTest(@RequestParam("accToken") String accToken) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        return new Result<UserBasicInfoResp>().ok(
+                thirdWeixinLoginMpService.getUnionid("o6jK352u-eNoiEeQb2KsUKwAF8_c", accToken));
+    }
+}

+ 36 - 0
healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/CustUserWxSendTempMsgController.java

@@ -0,0 +1,36 @@
+package com.xxh.cloud.frontend.custuser.web.controller;
+
+import com.company.cloud.sdk.weixin.mp.model.msgmanage.SendTempMsgResp;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.util.IpWhite;
+import com.xxh.cloud.frontend.common.modules.weixin.ThirdWeixinLoginMpService;
+import com.xxh.cloud.frontend.common.modules.weixin.ThirdWeixinSendTempMsgService;
+import com.xxh.cloud.frontend.common.modules.weixin.dto.SendTempMsgDTO;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/api/weixin")
+@Api(tags = "调用微信推送接口")
+public class CustUserWxSendTempMsgController {
+
+    @Autowired
+    private ThirdWeixinSendTempMsgService thirdWeixinSendTempMsgService;
+    @Autowired
+    private ThirdWeixinLoginMpService thirdWeixinLoginMpService;
+    @Autowired
+    private IpWhite ipWhite;
+
+    @PostMapping("/sendTempMsg")
+    @ApiOperation(value = "发送模板消息", response = Result.class)
+    public Result<SendTempMsgResp> sendTempMsg(@RequestBody SendTempMsgDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        SendTempMsgResp resp = thirdWeixinSendTempMsgService.sendTempMsg(params);
+        return new Result<SendTempMsgResp>().ok(resp);
+    }
+}

+ 81 - 0
healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/CustomerApiController.java

@@ -0,0 +1,81 @@
+package com.xxh.cloud.frontend.custuser.web.controller;
+
+
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import com.xxh.cloud.frontend.common.modules.his.HisApiHelper;
+import com.xxh.cloud.frontend.common.modules.his.config.SysProjectConfig;
+import com.xxh.cloud.frontend.common.modules.his.dto.GenerateSchemeDTO;
+import com.xxh.cloud.frontend.common.modules.his.model.GenerateSchemeModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisAccessTokenModel;
+import com.xxh.cloud.frontend.common.modules.his.model.PatBindModel;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.util.IpWhite;
+import com.xxh.cloud.frontend.common.modules.weixin.ThirdWeixinAccessTokenService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@Slf4j
+@RestController
+@RequestMapping("/api/customize")
+@Api(tags="调用第三方客户服务接口")
+public class CustomerApiController {
+
+    @Autowired
+    private SysProjectConfig config;
+    @Autowired
+    private ThirdWeixinAccessTokenService thirdWeixinAccessTokenService;
+    @Autowired
+    private IpWhite ipWhite;
+
+    @GetMapping("/getAccessToken")
+    @ApiOperation("获取accessToken")
+    public Result<HisAccessTokenModel> getAccessToken() {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        if ("his".equals(config.getAccess())) { //调用his获取
+            Result<HisAccessTokenModel> resp = HisApiHelper.getAccessToken(config);
+            if (resp.getCode() != 0) {
+                log.error("----获取AccessToken失败----");
+            }
+            return resp;
+        } else { //调用微信获取
+            WxApiConfig wxApiConfig = new WxApiConfig();
+            wxApiConfig.setAppid(config.getAppid());
+            wxApiConfig.setSecret(config.getSecret());
+            String accessToken = thirdWeixinAccessTokenService.getAccessToken(wxApiConfig);
+            HisAccessTokenModel model = new HisAccessTokenModel();
+            model.setAccToken(accessToken);
+            return new Result<HisAccessTokenModel>().ok(model);
+        }
+    }
+
+    @GetMapping("/getPatInfoByOpenId")
+    @ApiOperation("获取关联就诊卡号列表")
+    public Result<PatBindModel> getPatInfoByOpenId(@RequestParam("userId") String userId) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        PatBindModel resp = HisApiHelper.getPatBind(config, userId);
+        if (resp.getCode() != 0) {
+            log.error("----获取关联就诊卡号列表----");
+        }
+        return new Result<PatBindModel>().ok(resp);
+    }
+
+    @PostMapping("/generatescheme")
+    @ApiOperation("获取schemeurl")
+    public Result<GenerateSchemeModel> getPatInfoByOpenId(@RequestBody GenerateSchemeDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        Result<GenerateSchemeModel> resp = HisApiHelper.generateScheme(config, params);
+        if (resp.getCode() != 0) {
+            log.error("----获取schemeurl----");
+        }
+        return resp;
+    }
+}

+ 127 - 0
healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/HisApiController.java

@@ -0,0 +1,127 @@
+package com.xxh.cloud.frontend.custuser.web.controller;
+
+import com.xxh.cloud.frontend.common.modules.his.HisWebApiHelper;
+import com.xxh.cloud.frontend.common.modules.his.config.HisWebConfig;
+import com.xxh.cloud.frontend.common.modules.his.dto.HisGenerateSchemeDTO;
+import com.xxh.cloud.frontend.common.modules.his.dto.HisPatientDTO;
+import com.xxh.cloud.frontend.common.modules.his.dto.HisPromotionCodeDTO;
+import com.xxh.cloud.frontend.common.modules.his.model.HisDeptListModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisDoctorListModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisPatientListModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisPromotionCodeModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisSchemeUrlModel;
+import com.xxh.cloud.frontend.common.modules.his.model.HisWxTokenModel;
+import com.xxh.cloud.frontend.common.modules.his.model.PatBindModel;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.util.IpWhite;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@Slf4j
+@RestController
+@RequestMapping("/api/his")
+@Api(tags="调用His互联网医院第三方客户服务接口")
+public class HisApiController {
+
+    @Autowired
+    private HisWebConfig config;
+    @Autowired
+    private IpWhite ipWhite;
+
+    /**
+     * 暂时使用海慈提供的accessToken
+     */
+    @GetMapping("/getAccessToken")
+    @ApiOperation("获取微信accessToken")
+    public Result<HisWxTokenModel> getAccessToken(@RequestParam("type") String type) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        HisWxTokenModel resp = HisWebApiHelper.getAccessToken(config, type);
+        
+        return new Result<HisWxTokenModel>().ok(resp);
+    }
+
+    @GetMapping("/getPatientByUnionId")
+    @ApiOperation("获取就诊人信息")
+    public Result<PatBindModel> getPatientByUnionId(@RequestParam("unionid") String unionid) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        PatBindModel resp = HisWebApiHelper.getPatientByUnionId(config, unionid);
+        
+        return new Result<PatBindModel>().ok(resp);
+    }
+
+    @PostMapping("/getPatientByThirdId")
+    @ApiOperation("获取就诊人信息")
+    public Result<PatBindModel> getPatientByThirdId(@RequestBody HisPatientDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        PatBindModel resp = HisWebApiHelper.getPatientByThirdId(config, params);
+        
+        return new Result<PatBindModel>().ok(resp);
+    }
+
+    @PostMapping("/getPatientByTimestamp")
+    @ApiOperation("批量获取就诊人信息")
+    public Result<HisPatientListModel> getPatientByTimestamp(@RequestBody HisPatientDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        HisPatientListModel resp = HisWebApiHelper.getPatientByTimestamp(config, params);
+        
+        return new Result<HisPatientListModel>().ok(resp);
+    }
+
+    @GetMapping("/getDeptsInfo")
+    @ApiOperation("获取科室信息")
+    public Result<HisDeptListModel> getDeptsInfo() {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        HisDeptListModel resp = HisWebApiHelper.getDeptsInfo(config);
+        
+        return new Result<HisDeptListModel>().ok(resp);
+    }
+
+    @GetMapping("/getDoctorsInfo")
+    @ApiOperation("获取医生信息")
+    public Result<HisDoctorListModel> getDoctorsInfo(@RequestParam(value = "showModel", required = false) String showModel) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        HisDoctorListModel resp = HisWebApiHelper.getDoctorsInfo(config, showModel);
+        
+        return new Result<HisDoctorListModel>().ok(resp);
+    }
+
+    @PostMapping("/getWxMiniSchemeUrl")
+    @ApiOperation("获取schemeurl")
+    public Result<HisSchemeUrlModel> getWxMiniSchemeUrl(@RequestBody HisGenerateSchemeDTO queryParam) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        HisSchemeUrlModel resp = HisWebApiHelper.getWxMiniSchemeUrl(config, queryParam);
+        
+        return new Result<HisSchemeUrlModel>().ok(resp);
+    }
+
+    @PostMapping("/getAndSavePromotionCodeUrl")
+    @ApiOperation("获取并保存推广码")
+    public Result<HisPromotionCodeModel> getAndSavePromotionCodeUrl(@RequestBody HisPromotionCodeDTO queryParam) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        // 获取推广码
+        HisPromotionCodeModel resp = HisWebApiHelper.getPromotionCodeUrl(config, queryParam);
+
+        return new Result<HisPromotionCodeModel>().ok(resp);
+    }
+
+}

+ 39 - 0
healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/WbmdOaController.java

@@ -0,0 +1,39 @@
+package com.xxh.cloud.frontend.custuser.web.controller;
+
+import com.xxh.cloud.frontend.common.modules.his.WbmdOaApiHelper;
+import com.xxh.cloud.frontend.common.modules.his.config.HisWebConfig;
+import com.xxh.cloud.frontend.common.modules.his.model.WbmdOaModel;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.util.IpWhite;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+@Slf4j
+@RestController
+@RequestMapping("/wbmd/oa")
+@Api(tags="WBMD内部OA系统的接口")
+public class WbmdOaController {
+
+    @Autowired
+    private HisWebConfig config;
+    @Autowired
+    private IpWhite ipWhite;
+
+    @PostMapping("/wecom/author")
+    @ApiOperation("调用内部OA企业微信授权登陆")
+    public Result<WbmdOaModel> wecomAuthor(@RequestBody Map<String, String> params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        WbmdOaModel model = WbmdOaApiHelper.wecomAuthor(params.get("code"));
+        return new Result<WbmdOaModel>().ok(model);
+    }
+
+}

+ 640 - 0
healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/WechatController.java

@@ -0,0 +1,640 @@
+package com.xxh.cloud.frontend.custuser.web.controller;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import com.company.cloud.sdk.weixin.common.utils.AesUtils;
+import com.company.cloud.sdk.weixin.common.utils.WxVerificationUtils;
+import com.company.cloud.sdk.weixin.common.utils.XmlUtils;
+import com.company.cloud.sdk.weixin.mp.WxMpMsgManageApi;
+import com.company.cloud.sdk.weixin.mp.WxMpUserManageApi;
+import com.company.cloud.sdk.weixin.mp.model.QRcodeWithParamsResp;
+import com.company.cloud.sdk.weixin.mp.model.msgmanage.ReceiveEventFullModel;
+import com.company.cloud.sdk.weixin.mp.model.usermanage.UserBasicInfoBatchReqModel;
+import com.company.cloud.sdk.weixin.mp.model.usermanage.UserBasicInfoBatchResp;
+import com.company.cloud.sdk.weixin.mp.model.usermanage.UserBasicInfoReqModel;
+import com.company.cloud.sdk.weixin.mp.model.usermanage.UserOpenidListModel;
+import com.company.cloud.sdk.weixin.mp.model.usermanage.UserOpenidListResp;
+import com.xxh.cloud.frontend.common.modules.his.HisApiHelper;
+import com.xxh.cloud.frontend.common.modules.his.config.SysProjectConfig;
+import com.xxh.cloud.frontend.common.modules.his.dto.WechatQrCodeDTO;
+import com.xxh.cloud.frontend.common.modules.his.model.HisAccessTokenModel;
+import com.xxh.cloud.frontend.common.modules.his.model.PatBindModel;
+import com.xxh.cloud.frontend.common.modules.his.model.PatInfoModel;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.util.IpWhite;
+import com.xxh.cloud.frontend.common.modules.weixin.ThirdWeixinAccessTokenService;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@RestController
+@RequestMapping("/sys/healthy/wechat")
+@Api(tags = "微信相关")
+public class WechatController {
+
+    @Autowired
+    private SysProjectConfig sysProjectConfig;
+    @Autowired
+    private ThirdWeixinAccessTokenService thirdWeixinAccessTokenService;
+    @Autowired
+    private IpWhite ipWhite;
+
+    @Value("${wechat.mp.token}")
+    private String token;
+    @Value("${wechat.mp.encodingAesKey:}")
+    private String encodingAesKey;
+
+
+    // 事件处理url
+    @Value("${wechat.mp.eventDealUrl:}")
+    private String eventDealUrl;
+
+    // 开放平台事件处理url
+    @Value("${wechat.open.componentEventDealUrl:}")
+    private String componentEventDealUrl;
+
+    // 开放平台component_verify_ticket事件处理url
+    @Value("${wechat.open.componentVerifyTicketUrl:}")
+    private String componentVerifyTicketUrl;
+
+
+    // 生产带参数的二维码
+    // @PostMapping("/qrcodewithparams")
+    // @ApiOperation(value = "生成带参数的二维码", response = QRcodeWithParamsResp.class)
+    // public QRcodeWithParamsResp createQRCode(@RequestBody String params) {
+    //     // ip白名单限制
+    //     ipWhite.validatorIpWhite();
+
+    //     log.info("/sys/healthy/wechat/msg/qrcodewithparams:params >>>>>> {}", params);
+
+    //     // 获取accessToken
+    //     String accessToken = "";
+    //     if ("his".equals(sysProjectConfig.getAccess())) { //调用his获取
+    //         log.info("从第三方获取acessToken >>>>>>>");
+    //         Result<HisAccessTokenModel> resp = HisApiHelper.getAccessToken(sysProjectConfig);
+
+    //         if (resp.getCode() != 0) {
+    //             log.error("----获取AccessToken失败----");
+    //         }
+    //         accessToken = resp.getData().getAccToken();
+    //     } else { //调用微信获取
+    //         log.info("直接从微信获取acessToken >>>>>>>");
+    //         WxApiConfig wxApiConfig = new WxApiConfig();
+    //         wxApiConfig.setAppid(sysProjectConfig.getAppid());
+    //         wxApiConfig.setSecret(sysProjectConfig.getSecret());
+    //         accessToken = thirdWeixinAccessTokenService.getAccessToken(wxApiConfig);
+    //     }
+    //     log.info("获取accessToken >>>>>> {}", accessToken);
+
+    //     // 请求二维码
+    //     log.info("查询二维码参数 >>>>>> {}", params);
+    //     QRcodeWithParamsResp resp = WxMpMsgManageApi.createQRCode(accessToken, params);
+    //     log.info("返回的二维码数据 >>>>>> {}", JSON.toJSONString(resp));
+    //     return resp;
+    // }
+
+    // 生产带参数的二维码
+    @PostMapping("/qrcodewithparams")
+    @ApiOperation(value = "生成带参数的二维码", response = QRcodeWithParamsResp.class)
+    public QRcodeWithParamsResp createQRCode(@RequestBody WechatQrCodeDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        log.info("/sys/healthy/wechat/msg/qrcodewithparams:params >>>>>> {}", JSON.toJSONString(params));
+
+        // 请求二维码
+        QRcodeWithParamsResp resp = WxMpMsgManageApi.createQRCode(params.getAccessToken(), params.getQrcodeParams());
+        log.info("返回的二维码数据 >>>>>> {}", JSON.toJSONString(resp));
+        return resp;
+    }
+
+    // 验证消息事件token,配置服务地址
+    @GetMapping("/passivemsg")
+    @ApiOperation(value = "被动回复消息验证", response = String.class)
+    public String passiveMsgToken(HttpServletRequest request, HttpServletResponse response) {
+        String echostr = null;
+        try {
+            String signature = request.getParameter("signature");
+            if (StrUtil.isNotBlank(signature)) {
+                String timestamp = request.getParameter("timestamp");
+                String nonce = request.getParameter("nonce");
+                echostr = request.getParameter("echostr");
+                log.info("/sys/healthy/wechat/msg/passivemsg:params >>>>>> signature={}, echostr={}, timestamp={}, nonce={}", signature, echostr, timestamp, nonce);
+                if (WxVerificationUtils.checkSignature(token, signature, timestamp, nonce)) {
+                    log.info("验证通过");
+                    return echostr;
+                }
+            }
+        } catch (Exception e) {
+            log.error("校验异常>>>>>> {}", e.getMessage());
+            e.printStackTrace();
+        }
+        log.info("验证失败");
+        return "error";
+    }
+
+    // 获取消息事件并回复消息
+    @PostMapping(value = "/passivemsg", produces = MediaType.APPLICATION_XML_VALUE)
+    @ApiOperation(value = "被动回复消息", response = String.class)
+    public String passiveMsg(HttpServletRequest request, HttpServletResponse response, @RequestBody String passiveReplyMsg) {
+        log.info("/sys/healthy/wechat/msg/passivemsg:passiveReplyMsg >>>>>> {}", passiveReplyMsg);
+
+        String msgSignature = request.getParameter("msg_signature");
+        String timestamp = request.getParameter("timestamp");
+        String nonce = request.getParameter("nonce");
+        log.info("url参数>>>>>> msgSignature={}, timestamp={}, nonce={}", msgSignature, timestamp, nonce);
+
+        // 数据解密
+        if (StrUtil.isNotBlank(encodingAesKey)) {
+            try {
+                passiveReplyMsg = AesUtils.decryptMsg(token, sysProjectConfig.getAppid(), encodingAesKey, passiveReplyMsg, msgSignature, timestamp, nonce);
+            } catch (Exception e) {
+                log.error("消息解密异常>>>>>> ", e.getMessage());
+                e.printStackTrace();
+            }
+        }
+
+        log.info("解密后数据>>>>>>> {}", passiveReplyMsg);
+        // 数据字符串转对象
+        ReceiveEventFullModel receiveEventFullModel = (ReceiveEventFullModel) XmlUtils.convertXmlStrToObject(ReceiveEventFullModel.class, passiveReplyMsg);
+        log.info("字符串参数转对象>>>>>> {}", JSON.toJSONString(receiveEventFullModel));
+
+        String resp = null;
+
+        // 请求处理事件,并返回消息数据
+        try {
+            log.info("请求处理被动消息>>>>>> eventDealUrl={} : receiveEventFullModel={}", eventDealUrl, JSON.toJSONString(receiveEventFullModel));
+            // String replyMsgData = HttpUtil.post(eventDealUrl, JSON.toJSONString(receiveEventFullModel)); // 直接返回字符串有乱码问题
+            String replyMsgData = this.loopPostHttp(eventDealUrl, JSON.toJSONString(receiveEventFullModel), 0); // 直接返回字符串有乱码问题
+            log.info("接受处理过的被动消息<<<<<< receiveEventFullModel={}", JSON.toJSONString(replyMsgData));
+            Result<String> msgData = JSONObject.parseObject(replyMsgData, new TypeReference<Result<String>>(){});
+            resp = msgData.getData();
+        } catch (Exception e) {
+            log.info("请求处理事件异常");
+            e.printStackTrace();
+            return "";
+        }
+        log.info("返回数据>>>>>> resp={}", JSON.toJSONString(resp));
+
+        if (StrUtil.isBlank(resp)) {
+            return "";
+        }
+
+        log.info("返回数据>>>>>> resp={}", JSON.toJSONString(resp));
+
+        // 推送数据加密
+        if (StrUtil.isNotBlank(encodingAesKey)) {
+            try {
+                resp = AesUtils.encryptMsg(token, sysProjectConfig.getAppid(), encodingAesKey, resp);
+            } catch (Exception e) {
+                log.error("消息加密异常>>>>>> ", e.getMessage());
+                e.printStackTrace();
+            }
+        }
+
+        return resp;
+    }
+    
+    // 调用失败则暂停5秒重新请求,最多重调5次
+    private String loopPostHttp(String url, String body, Integer loopNum) {
+        try {
+            return HttpRequest.post(url).body(body).execute().body();
+        } catch (Exception e) {
+            log.info("POST调用异常: {} ", url);
+            e.printStackTrace();
+            
+            // 最多循环5次
+            if (loopNum < 5) {
+                // 先暂停
+                log.info("休眠1000ms");
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e1) {
+                    e1.printStackTrace();
+                }
+                // 出现异常再次调用
+                return loopPostHttp(url, body, loopNum + 1);
+            }
+        }
+        return null;
+    }
+
+    // 拉取微信用户列表
+    @PostMapping("/pull/userInfo")
+    @ApiOperation(value = "拉取公众号关注用户信息", response = Void.class)
+    public void pullLUserInfo() {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        // 获取accessToken
+        String accessToken = "";
+        if ("his".equals(sysProjectConfig.getAccess())) { //调用his获取
+            log.info("从第三方获取acessToken >>>>>>>");
+            Result<HisAccessTokenModel> resp = HisApiHelper.getAccessToken(sysProjectConfig);
+
+            if (resp.getCode() != 0) {
+                log.error("----获取AccessToken失败----");
+            }
+            accessToken = resp.getData().getAccToken();
+        } else { //调用微信获取
+            log.info("直接从微信获取acessToken >>>>>>>");
+            WxApiConfig wxApiConfig = new WxApiConfig();
+            wxApiConfig.setAppid(sysProjectConfig.getAppid());
+            wxApiConfig.setSecret(sysProjectConfig.getSecret());
+            accessToken = thirdWeixinAccessTokenService.getAccessToken(wxApiConfig);
+        }
+        log.info("获取accessToken >>>>>> {}", accessToken);
+
+        queryOpenidList(accessToken, null); // TODO 指定要拉取的nextopenid
+    }
+
+    // 查询openid列表,并根据openid列表查询用户信息
+    private void queryOpenidList(String accessToken, String nextOpenid) {
+        
+        UserOpenidListModel userOpenidListModel = new UserOpenidListModel();
+        userOpenidListModel.setAccess_token(accessToken);
+        if (StrUtil.isNotBlank(nextOpenid)) {
+            userOpenidListModel.setNext_openid(nextOpenid);
+        }
+        log.info("查询用户openid参数 >>>>>>");
+        UserOpenidListResp resp = null; 
+        try {
+            resp = WxMpUserManageApi.listUserOpenid(userOpenidListModel);
+        } catch (Exception e) {
+            // 重新获取token再执行一次,以防因为token过期导致的问题
+            if ("his".equals(sysProjectConfig.getAccess())) { //调用his获取
+                log.info("从第三方获取acessToken >>>>>>>");
+                Result<HisAccessTokenModel> tokenResult = HisApiHelper.getAccessToken(sysProjectConfig);
+
+                if (tokenResult.getCode() != 0) {
+                    log.error("----获取AccessToken失败----");
+                }
+                accessToken = tokenResult.getData().getAccToken();
+            } else { //调用微信获取
+                log.info("直接从微信获取acessToken >>>>>>>");
+                WxApiConfig wxApiConfig = new WxApiConfig();
+                wxApiConfig.setAppid(sysProjectConfig.getAppid());
+                wxApiConfig.setSecret(sysProjectConfig.getSecret());
+                accessToken = thirdWeixinAccessTokenService.getAccessToken(wxApiConfig);
+            }
+            log.info("重新获取accessToken >>>>>> {}", accessToken);
+
+            userOpenidListModel.setAccess_token(accessToken);
+            resp = WxMpUserManageApi.listUserOpenid(userOpenidListModel);
+        }
+        if (null == resp || null == resp.getData() || CollUtil.isEmpty(resp.getData().getOpenid())) {
+            return;
+        }
+        log.info("返回用户openid列表及最后openid数据 <<<<<< {} : {}", resp.getData().getOpenid().size(), resp.getNext_openid());
+        
+        // 根据openid获取用户信息
+        queryUserInfo(accessToken, resp.getData().getOpenid());
+
+        queryOpenidList(accessToken, resp.getNext_openid());
+    }
+
+    // 根据openid列表查询用户信息
+    private void queryUserInfo(String accessToken, List<String> openids) {
+        if (CollUtil.isEmpty(openids)) {
+            return;
+        }
+
+        int maxNum = Math.round(openids.size() / 100); // 最大循环次数
+        for (int i = 0; i < maxNum; i++) {
+            List<UserBasicInfoReqModel> userBasicInfoReqModels = new ArrayList<>();
+
+            int start = i * 100; // 每次循环的起始数据
+            int length = i == Math.round(openids.size() / 100) ? Math.round(openids.size() % 100) : 100; // 每次循环的数据个数,默认100,最后一次循环特殊处理
+            for (int j = start; j < (start + length); j++) {
+                UserBasicInfoReqModel userBasicInfoReqModel = new UserBasicInfoReqModel();
+                userBasicInfoReqModel.setOpenid(openids.get(j));
+                userBasicInfoReqModel.setLang("zh_CN");
+                userBasicInfoReqModels.add(userBasicInfoReqModel);
+            }
+
+            UserBasicInfoBatchReqModel userBasicInfoBatchReqModel = new UserBasicInfoBatchReqModel();
+            userBasicInfoBatchReqModel.setAccess_token(accessToken);
+            userBasicInfoBatchReqModel.setUser_list(userBasicInfoReqModels);
+            log.info("查询用户信息 >>>>>>");
+            UserBasicInfoBatchResp resp = null;
+            try {
+                resp = WxMpUserManageApi.batchGetUserInfo(userBasicInfoBatchReqModel);
+            } catch (Exception e) {
+                // 重新获取token再执行一次,以防因为token过期导致的问题
+                if ("his".equals(sysProjectConfig.getAccess())) { //调用his获取
+                    log.info("从第三方获取acessToken >>>>>>>");
+                    Result<HisAccessTokenModel> tokenResult = HisApiHelper.getAccessToken(sysProjectConfig);
+
+                    if (tokenResult.getCode() != 0) {
+                        log.error("----获取AccessToken失败----");
+                    }
+                    accessToken = tokenResult.getData().getAccToken();
+                } else { //调用微信获取
+                    log.info("直接从微信获取acessToken >>>>>>>");
+                    WxApiConfig wxApiConfig = new WxApiConfig();
+                    wxApiConfig.setAppid(sysProjectConfig.getAppid());
+                    wxApiConfig.setSecret(sysProjectConfig.getSecret());
+                    accessToken = thirdWeixinAccessTokenService.getAccessToken(wxApiConfig);
+                }
+                log.info("重新获取accessToken >>>>>> {}", accessToken);
+
+                userBasicInfoBatchReqModel.setAccess_token(accessToken);
+                resp = WxMpUserManageApi.batchGetUserInfo(userBasicInfoBatchReqModel);
+            }
+            if (null == resp || CollectionUtil.isEmpty(resp.getUser_info_list())) {
+                continue;
+            }
+            log.info("返回用户信息列表 <<<<<< {}", resp.getUser_info_list().size());
+
+            List<Map<String, String>> requestParams = new ArrayList<>();
+            resp.getUser_info_list().forEach(user -> {
+                Map<String, String> map = new HashMap<>();
+                map.put("openId", user.getOpenid());
+                map.put("unionId", user.getUnionid());
+                map.put("isSync", "N");
+                requestParams.add(map);
+            });
+
+            // TODO 调用health接口保存用户信息(openid与unionid)
+            try {
+                log.info("保存用户信息>>>>>> {}", JSON.toJSONString(requestParams));
+                HttpUtil.post("http://172.18.84.102:8080/api/wbmd3h/sys/healthy/wechat/saveWechatUserInfoBatch", JSON.toJSONString(requestParams));
+            } catch (Exception e) {
+                log.info("请求处理事件异常");
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+
+    // 注意:递归会导致栈溢出,可以改为while/for循环方式
+    @Deprecated
+    @PostMapping("/pull/userInfo/save")
+    @ApiOperation(value = "测试拉取微信用户及海鹚用户数据")
+    public void saveUserInfoBatch() {
+        // ip白名单限制
+        // ipWhite.validatorIpWhite();
+
+        // TODO 据观察,前960页没有数据,可以直接跳过
+        queryWechatUserInfo(960);
+    }
+
+    private void queryWechatUserInfo(Integer page) {
+        // 调用health接口保存用户信息(openid与unionid)
+        List<Map<String, String>> data = this.queryWeixinUser(page, 0);
+        if (CollectionUtil.isEmpty(data)) {
+            return;
+        }
+
+        List<Map<String, Object>> list = new ArrayList<>();
+        data.forEach(i -> {
+            String id = i.get("id");
+            String openId = i.get("openId");
+            String unionId = i.get("unionId");
+            if (StrUtil.isBlank(unionId)) {
+                return;
+            }
+
+            log.info("unionId >>>>>> {}", unionId);
+            PatBindModel resp = HisApiHelper.getPatBind(sysProjectConfig, unionId);
+            if (resp.getCode() != 0 || CollUtil.isEmpty(resp.getData())) {
+                return;
+            }
+
+            for (PatInfoModel patInfo : resp.getData()) {
+                Map<String, Object> entity = new HashMap<>();
+                entity.put("wxUserId", id);
+                entity.put("wxOpenId", openId);
+                entity.put("wxUnionId", unionId);
+
+                entity.put("birthday", patInfo.getBirthday());
+                entity.put("patientId", patInfo.getPatientId());
+                entity.put("patientName", patInfo.getPatientName());
+                entity.put("patientMobile", patInfo.getPatientMobile());
+                entity.put("patientSex", patInfo.getPatientSex());
+                entity.put("idNo", patInfo.getIdNo());
+                entity.put("idType", patInfo.getIdType());
+                entity.put("patHisNo", patInfo.getPatHisNo());
+                entity.put("patCardNo", patInfo.getPatCardNo());
+                entity.put("patCardType", patInfo.getPatCardType());
+                entity.put("patCardTypeName", patInfo.getPatCardTypeName());
+                entity.put("isDefault", patInfo.getIsDefault());
+                entity.put("relationName", patInfo.getRelationName());
+                entity.put("relationType", patInfo.getRelationType());
+                entity.put("patientType", patInfo.getPatientType());
+                entity.put("patientTypeName", patInfo.getPatientTypeName());
+                entity.put("healthCardFlag", patInfo.getHealthCardFlag());
+                entity.put("extFields", patInfo.getExtFields());
+
+                list.add(entity);
+            }
+
+        });
+
+        if (CollectionUtil.isNotEmpty(list)) {
+            saveWeixinUser(list, 0);
+        } else {
+            page = page + 1;
+        }
+
+        queryWechatUserInfo(page); // 更新状态会使下一页查询的结果出现问题,所以只有当本页没有需要保存的数据更新才查询下一页,否则继续查询当前页,防止数据遗漏
+    }
+
+    // 查询需要同步的用户,出现异常再次调用
+    private List<Map<String, String>> queryWeixinUser(Integer page, Integer loopNum) {
+        // 调用health接口保存用户信息(openid与unionid)
+        List<Map<String, String>> data = null;
+        try {
+            Map<String, Integer> pageParams = new HashMap<>();
+            pageParams.put("page", page);
+            pageParams.put("rows", 100);
+
+            log.info("查询微信用户信息>>>>>> {}", JSON.toJSONString(pageParams));
+            String resp = HttpUtil.post("http://172.18.84.102:8080/api/wbmd3h/sys/healthy/wechat/queryWechatUserInfo", JSON.toJSONString(pageParams));
+            log.info("查询微信用户信息<<<<<< {}", resp);
+            data = JSONObject.parseObject(resp, new TypeReference<List<Map<String, String>>>(){});
+            if (CollUtil.isEmpty(data)) {
+                return null;
+            }
+        } catch (Exception e) {
+            log.info("请求处理事件异常");
+            e.printStackTrace();
+
+            // 最多循环5次
+            if (loopNum < 5) {
+                // 先暂停
+                log.info("休眠5000ms");
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e1) {
+                    e1.printStackTrace();
+                }
+                // 出现异常再次调用
+                data = queryWeixinUser(page, loopNum + 1);
+            }
+        }
+
+        return data;
+    }
+
+    // 保存需要同步的用户,出现异常再次调用
+    private void saveWeixinUser(List<Map<String, Object>> list, Integer loopNum) {
+        try {
+            log.info("保存用户信息>>>>>> {}", JSON.toJSONString(list));
+            HttpUtil.post("http://172.18.84.102:8080/api/wbmd3h/sys/healthy/wechat/saveUserInfoBatch", JSON.toJSONString(list));
+        } catch (Exception e) {
+            log.info("请求处理事件异常");
+            e.printStackTrace();
+            
+            // 最多循环5次
+            if (loopNum < 5) {
+                // 先暂停
+                log.info("休眠5000ms");
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e1) {
+                    e1.printStackTrace();
+                }
+                // 出现异常再次调用
+                saveWeixinUser(list, loopNum + 1);
+            }
+        }
+    }
+
+    @PostMapping("/pull/userInfo/saveBatch")
+    @ApiOperation(value = "测试拉取微信用户及海鹚用户数据")
+    public void syncSaveUserInfoBatch() {
+        // ip白名单限制
+        // ipWhite.validatorIpWhite();
+
+        int page = 0;
+        while (true) {
+            if (page == -1) {
+                return;
+            }
+            page = queryWechatUserInfo2(page);
+        }
+    }
+
+    private Integer queryWechatUserInfo2(int page) {
+        // 调用health接口保存用户信息(openid与unionid)
+        List<Map<String, String>> data = this.queryWeixinUser(page, 0);
+        if (CollectionUtil.isEmpty(data)) {
+            return -1;
+        }
+
+        List<String> wxUserList = new ArrayList<>(); // 用于更新已同步状态
+        List<Map<String, Object>> list = new ArrayList<>(); // 保存同步数据
+        data.forEach(i -> {
+            String id = i.get("id");
+
+            wxUserList.add(id);
+            
+            String openId = i.get("openId");
+            String unionId = i.get("unionId");
+
+            if (StrUtil.isBlank(unionId)) {
+                return;
+            }
+
+            log.info("unionId >>>>>> {}", unionId);
+            PatBindModel resp = HisApiHelper.getPatBind(sysProjectConfig, unionId);
+            if (resp.getCode() != 0 || CollUtil.isEmpty(resp.getData())) {
+                return;
+            }
+
+            for (PatInfoModel patInfo : resp.getData()) {
+                Map<String, Object> entity = new HashMap<>();
+                entity.put("wxUserId", id);
+                entity.put("wxOpenId", openId);
+                entity.put("wxUnionId", unionId);
+
+                entity.put("birthday", patInfo.getBirthday());
+                entity.put("patientId", patInfo.getPatientId());
+                entity.put("patientName", patInfo.getPatientName());
+                entity.put("patientMobile", patInfo.getPatientMobile());
+                entity.put("patientSex", patInfo.getPatientSex());
+                entity.put("idNo", patInfo.getIdNo());
+                entity.put("idType", patInfo.getIdType());
+                entity.put("patHisNo", patInfo.getPatHisNo());
+                entity.put("patCardNo", patInfo.getPatCardNo());
+                entity.put("patCardType", patInfo.getPatCardType());
+                entity.put("patCardTypeName", patInfo.getPatCardTypeName());
+                entity.put("isDefault", patInfo.getIsDefault());
+                entity.put("relationName", patInfo.getRelationName());
+                entity.put("relationType", patInfo.getRelationType());
+                entity.put("patientType", patInfo.getPatientType());
+                entity.put("patientTypeName", patInfo.getPatientTypeName());
+                entity.put("healthCardFlag", patInfo.getHealthCardFlag());
+                entity.put("extFields", patInfo.getExtFields());
+
+                list.add(entity);
+            }
+
+        });
+
+        if (CollectionUtil.isNotEmpty(list)) {
+            saveWeixinUser2(wxUserList, list, 0);
+        } else {
+            page = page + 1;
+        }
+
+        return page; // 更新状态会使下一页查询的结果出现问题,所以只有当本页没有需要保存的数据更新才查询下一页,否则继续查询当前页,防止数据遗漏
+    }
+
+    // 保存需要同步的用户,出现异常再次调用
+    private void saveWeixinUser2(List<String> wxUserList, List<Map<String, Object>> list, Integer loopNum) {
+        try {
+            Map<String, Object> map = new HashMap<>();
+            map.put("updateList", wxUserList);
+            map.put("saveList", list);
+            log.info("保存用户信息>>>>>> {}", JSON.toJSONString(map));
+            HttpUtil.post("http://172.18.84.102:8080/api/wbmd3h/sys/healthy/wechat/saveUserInfoBatch2", JSON.toJSONString(map));
+        } catch (Exception e) {
+            log.info("请求处理事件异常");
+            e.printStackTrace();
+            
+            // 最多循环5次
+            if (loopNum < 5) {
+                // 先暂停
+                log.info("休眠5000ms");
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e1) {
+                    e1.printStackTrace();
+                }
+                // 出现异常再次调用
+                saveWeixinUser2(wxUserList, list, loopNum + 1);
+            }
+        }
+    }
+
+}

+ 204 - 0
healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/WechatThirdController.java

@@ -0,0 +1,204 @@
+package com.xxh.cloud.frontend.custuser.web.controller;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+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 com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.company.cloud.sdk.weixin.common.utils.AesUtils;
+import com.company.cloud.sdk.weixin.common.utils.XmlUtils;
+import com.company.cloud.sdk.weixin.open.model.ComponentReceiveEventFullModel;
+import com.company.cloud.sdk.weixin.open.model.ComponentVerifyTicketModel;
+import com.xxh.cloud.frontend.common.modules.his.config.SysProjectConfig;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.util.IpWhite;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@RestController
+@RequestMapping("/sys/healthy/wechat/third")
+@Api(tags = "微信相关")
+public class WechatThirdController {
+
+    @Autowired
+    private IpWhite ipWhite;
+    @Autowired
+    private SysProjectConfig sysProjectConfig;
+
+    @Value("${wechat.open.appid}")
+    private String appid;
+    @Value("${wechat.open.token}")
+    private String token;
+    @Value("${wechat.open.encodingAesKey:}")
+    private String encodingAesKey;
+
+    // 开放平台事件处理url
+    @Value("${wechat.open.componentEventDealUrl:}")
+    private String componentEventDealUrl;
+    // 开放平台component_verify_ticket事件处理url
+    @Value("${wechat.open.componentVerifyTicketUrl:}")
+    private String componentVerifyTicketUrl;
+
+
+    @PostMapping("/componentVerifyTicket")
+    @ApiOperation(value = "第三方开放平台获取验证票据", response = String.class)
+    public String componentVerifyTicket(HttpServletRequest request, HttpServletResponse response, @RequestBody String componentVerifyTicketMsg) {
+        String msgSignature = request.getParameter("msg_signature");
+        String timestamp = request.getParameter("timestamp");
+        String nonce = request.getParameter("nonce");
+        String encryptType = request.getParameter("encrypt_type");
+        log.info("url参数>>>>>> msgSignature={}, timestamp={}, nonce={}, encryptType={}", msgSignature, timestamp, nonce, encryptType);
+
+        // 数据解密
+        if (StrUtil.isNotBlank(encodingAesKey)) {
+            try {
+                componentVerifyTicketMsg = AesUtils.decryptMsg(token, appid, encodingAesKey, componentVerifyTicketMsg, msgSignature, timestamp, nonce);
+            } catch (Exception e) {
+                log.error("消息解密异常>>>>>> ", e.getMessage());
+                e.printStackTrace();
+            }
+        }
+
+        log.info("解密后数据>>>>>>> {}", componentVerifyTicketMsg);
+        // 数据字符串转对象
+        ComponentVerifyTicketModel componentVerifyTicketModel = (ComponentVerifyTicketModel) XmlUtils.convertXmlStrToObject(ComponentVerifyTicketModel.class, componentVerifyTicketMsg);
+        log.info("字符串参数转对象>>>>>> {}", JSON.toJSONString(componentVerifyTicketModel));
+
+        // TODO 保存componentVerifyTicket,并判断component_access_token是否过期,过期则重新获取
+        // try {
+        //     HttpUtil.post(componentVerifyTicketUrl, JSON.toJSONString(componentVerifyTicketModel));
+        // } catch (Exception e) {
+        //     log.info("保存componentVerifyTicket error >>>>>>", e.getMessage());
+        //     e.printStackTrace();
+        // }
+
+        return "success";
+    }
+
+    // 第三方验证消息事件token,配置服务地址
+    // @GetMapping("/third/passivemsg")
+    // @ApiOperation(value = "被动回复消息验证", response = String.class)
+    // public String thirdPassiveMsgToken(HttpServletRequest request, HttpServletResponse response) {
+    //     String echostr = null;
+    //     try {
+    //         String signature = request.getParameter("signature");
+    //         if (StrUtil.isNotBlank(signature)) {
+    //             String timestamp = request.getParameter("timestamp");
+    //             String nonce = request.getParameter("nonce");
+    //             String encryptType = request.getParameter("encrypt_type");
+    //             echostr = request.getParameter("echostr");
+    //             log.info("/sys/healthy/wechat/msg/third/passivemsg:params >>>>>> signature={}, echostr={}, timestamp={}, nonce={}, encryptType={}", signature, echostr, timestamp, nonce, encryptType);
+    //             if (WxVerificationUtils.checkSignature(token, signature, timestamp, nonce)) {
+    //                 log.info("验证通过");
+    //                 return echostr;
+    //             }
+    //         }
+    //     } catch (Exception e) {
+    //         log.error("校验异常>>>>>> {}", e.getMessage());
+    //         e.printStackTrace();
+    //     }
+    //     log.info("验证失败");
+    //     return "error";
+    // }
+
+    // 第三方授权事件接收,配置服务地址
+    @PostMapping("/{appid}/passivemsg")
+    @ApiOperation(value = "第三方授权事件接收", response = String.class)
+    public String thirdPassiveMsgToken(HttpServletRequest request, HttpServletResponse response, @PathVariable("appid") String mpAppid, @RequestBody String passiveReplyMsg) {
+        log.info("/sys/healthy/wechat/msg/third/passivemsg:passiveReplyMsg >>>>>> {}, {}", mpAppid, passiveReplyMsg);
+
+        String timestamp = request.getParameter("timestamp");
+        String nonce = request.getParameter("nonce");
+        String encryptType = request.getParameter("encrypt_type");
+        String msgSignature = request.getParameter("msg_signature");
+        log.info("url参数>>>>>> msgSignature={}, timestamp={}, nonce={}, encryptType={}", msgSignature, timestamp, nonce, encryptType);
+
+        // 数据解密
+        if (StrUtil.isNotBlank(encodingAesKey)) {
+            try {
+                passiveReplyMsg = AesUtils.decryptMsg(token, appid, encodingAesKey, passiveReplyMsg, msgSignature, timestamp, nonce);
+            } catch (Exception e) {
+                log.error("消息解密异常>>>>>> ", e.getMessage());
+                e.printStackTrace();
+            }
+        }
+
+        log.info("解密后数据>>>>>>> {}", passiveReplyMsg);
+
+        // 数据字符串转对象
+        ComponentReceiveEventFullModel componentReceiveEventFullModel = (ComponentReceiveEventFullModel) XmlUtils.convertXmlStrToObject(ComponentReceiveEventFullModel.class, passiveReplyMsg);
+        log.info("字符串参数转对象>>>>>> {}", JSON.toJSONString(componentReceiveEventFullModel));
+
+        // 请求处理事件,并返回消息数据
+        String resp = "success";
+
+        // toUserName和appId不会同时存在
+        // 微信推送关注用户触发的事件消息,可以进行回复
+        // 请求处理事件,并返回消息数据
+        try {
+            log.info("请求处理被动消息>>>>>> componentEventDealUrl={} : componentReceiveEventFullModel={}", componentEventDealUrl, JSON.toJSONString(componentReceiveEventFullModel));
+            String replyMsgData = HttpUtil.post(componentEventDealUrl, JSON.toJSONString(componentReceiveEventFullModel)); // 直接返回字符串有乱码问题
+            log.info("接受处理过的被动消息<<<<<< componentReceiveEventFullModel={}", JSON.toJSONString(replyMsgData));
+            Result<String> msgData = JSONObject.parseObject(replyMsgData, new TypeReference<Result<String>>(){});
+            resp = msgData.getData();
+        } catch (Exception e) {
+            log.info("请求处理事件异常");
+            e.printStackTrace();
+            return "";
+        }
+        log.info("返回数据>>>>>> resp={}", JSON.toJSONString(resp));
+
+        if (StrUtil.isBlank(resp)) {
+            return "";
+        }
+
+        // 推送数据加密
+        if (StrUtil.isNotBlank(encodingAesKey)) {
+            try {
+                resp = AesUtils.encryptMsg(token, appid, encodingAesKey, resp);
+            } catch (Exception e) {
+                log.error("消息加密异常>>>>>> ", e.getMessage());
+                e.printStackTrace();
+            }
+        }
+        return resp;
+    }
+
+
+    @GetMapping("/empower")
+    @ApiOperation(value = "授权接口", response = String.class)
+    public void empower(HttpServletResponse response) {
+        log.info("/sys/healthy/wechat/msg/third/empower >>>>>>");
+        try {
+            response.sendRedirect("https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=wxb044d310a603d404&pre_auth_code=preauthcode@@@zPVJDrHpEpd2ZMVEh8l8a23PMw4K_5uIpJIH_Y6ugdadTmBzJcz8ZADiPnLZggMI2uKvsZLuxmMLm29ePVjLFQ&redirect_uri=https://dev1.cloud-seal.com/healthy-frontend/sys/healthy/wechat/third/componentloginpage&auth_type=1");
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+    @GetMapping("/componentloginpage")
+    @ApiOperation(value = "授权回调接口", response = String.class)
+    public String componentloginpage(@RequestParam("auth_code") String authCode, @RequestParam("expires_in") Integer expiresIn) {
+        log.info("/sys/healthy/wechat/msg/third/componentloginpage >>>>>> authCode={}, expiresIn={}", authCode, expiresIn);
+        return "success";
+    }
+}

+ 127 - 0
healthy-frontend-custuser/src/main/java/com/xxh/cloud/frontend/custuser/web/controller/WechatWorkController.java

@@ -0,0 +1,127 @@
+package com.xxh.cloud.frontend.custuser.web.controller;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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.alibaba.fastjson.JSONObject;
+import com.company.cloud.sdk.weixin.common.config.WxApiConfig;
+import com.company.cloud.wx.sdk.work.inner.WxWorkInnerApi;
+import com.company.cloud.wx.sdk.work.inner.model.Code2TicketModel;
+import com.company.cloud.wx.sdk.work.inner.model.Code2TicketResp;
+import com.company.cloud.wx.sdk.work.inner.model.MessageSendResp;
+import com.company.cloud.wx.sdk.work.inner.model.MessageSendTextCardModel;
+import com.company.cloud.wx.sdk.work.inner.model.MessageSendTextCardModel.TextCard;
+import com.company.cloud.wx.sdk.work.intra.WxWorkCommonApi;
+import com.company.cloud.wx.sdk.work.model.common.AccessTokenModel;
+import com.company.cloud.wx.sdk.work.model.common.AccessTokenResp;
+import com.xxh.cloud.frontend.common.modules.exception.BusinessException;
+import com.xxh.cloud.frontend.common.modules.modules.Result;
+import com.xxh.cloud.frontend.common.modules.util.IpWhite;
+import com.xxh.cloud.frontend.common.modules.weixin.dto.SendWxWorkMsgDTO;
+
+import cn.hutool.core.util.StrUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@RestController
+@RequestMapping("/sys/healthy/wechat/third/work")
+@Api(tags = "企业微信相关")
+public class WechatWorkController {
+
+    @Autowired
+    private IpWhite ipWhite;
+
+    @PostMapping("/getAccessToken")
+    @ApiOperation(value = "企业微信-获取AccessToken", response = Result.class)
+    public Result<AccessTokenResp> getWorkAccessToken(@RequestBody WxApiConfig config) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        // 获取accessToken
+        AccessTokenModel accessTokenModel = new AccessTokenModel();
+        accessTokenModel.setCorpid(config.getAppid());
+        accessTokenModel.setCorpsecret(config.getSecret());
+        AccessTokenResp accessTokenResp = WxWorkCommonApi.accessToken(accessTokenModel);
+        if (accessTokenResp.getErrcode() != 0 || StrUtil.isBlank(accessTokenResp.getAccess_token())) {
+            throw new BusinessException("获取token失败");
+        }
+
+        return new Result<AccessTokenResp>().ok(accessTokenResp);
+    }
+
+    // 在xx-user中:/app/sys/userlogin/oauth2
+    // @GetMapping("/empower")
+    // @ApiOperation(value = "企业微信授权接口", response = String.class)
+    // public void workEmpower(HttpServletResponse response) {
+    //     log.info("/sys/healthy/wechat/msg/third/work/empower >>>>>>");
+    //     try {
+    //         Authorize2CodeModel authorize2CodeModel = new Authorize2CodeModel();
+    //         authorize2CodeModel.setAppId(corpid);
+    //         authorize2CodeModel.setRedirectUri(redirectUri);
+    //         authorize2CodeModel.setResponseType("code");
+    //         authorize2CodeModel.setScope(scope);
+    //         authorize2CodeModel.setState(state);
+    //         authorize2CodeModel.setAgentId(agentid);
+    //         response.sendRedirect(WxWorkInnerApi.authorize2Code(authorize2CodeModel));
+    //     } catch (IOException e) {
+    //         // TODO Auto-generated catch block
+    //         e.printStackTrace();
+    //     }
+    // }
+
+    @PostMapping("/getUserInfo")
+    @ApiOperation(value = "企业微信-获取用户身份", response = Result.class)
+    public Result<Code2TicketResp> getWorkUserInfo(@RequestBody Code2TicketModel params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+        
+        return new Result<Code2TicketResp>().ok(WxWorkInnerApi.getUserInfo(params));
+    }
+
+    @PostMapping("/sendAgentMsg")
+    @ApiOperation(value = "企业微信-发送应用消息", response = Result.class)
+    public Result<MessageSendResp> sendAgentMsg(@RequestBody SendWxWorkMsgDTO params) {
+        // ip白名单限制
+        ipWhite.validatorIpWhite();
+
+        MessageSendResp resp = null;
+        if ("textcard".equals(params.getMsgtype())) {
+            resp = this.sendTextCardMsg(params);
+        }
+
+        return new Result<MessageSendResp>().ok(resp);
+    }
+
+    // 文本卡片消息
+    private MessageSendResp sendTextCardMsg(SendWxWorkMsgDTO params) {
+        
+        MessageSendTextCardModel model = new MessageSendTextCardModel();
+        model.setAccess_token(params.getAccessToken());
+        model.setAgentid(params.getAgentid());
+        model.setTouser(params.getOpenid());
+        model.setMsgtype("textcard");
+
+        Map<String, String> paramMap = params.getData();
+        TextCard textCard = new TextCard();
+        textCard.setTitle(paramMap.get("title"));
+        textCard.setDescription(paramMap.get("description"));
+        textCard.setUrl(paramMap.get("url"));
+        textCard.setBtntxt(paramMap.get("btntxt"));
+        model.setTextcard(textCard);
+
+        // 发送
+        log.info("wechat work request send textcard message >>> : {}", JSONObject.toJSONString(model));
+        MessageSendResp resp = WxWorkInnerApi.messageSendTextcard(model);
+        log.info("wechat work response send textcard message <<< : {}", JSONObject.toJSONString(resp));
+        
+        return resp;
+    }
+
+}

+ 99 - 0
healthy-frontend-mq/pom.xml

@@ -0,0 +1,99 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>healthy-frontend-java</artifactId>
+        <groupId>com.xxh.cloud.frontend</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>healthy-frontend-mq</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+
+        <!-- Swagger -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>${swagger2bootstrap2ui.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.5.22</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.5.22</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>${fastjson.version}</version>
+        </dependency>
+
+        <!--ActiveMq-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-activemq</artifactId>
+        </dependency>
+
+        <!--消息队列连接池-->
+        <dependency>
+            <groupId>org.apache.activemq</groupId>
+            <artifactId>activemq-pool</artifactId>
+            <version>5.16.5</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.messaginghub</groupId>
+            <artifactId>pooled-jms</artifactId>
+            <version>1.0.4</version>
+        </dependency>
+
+    </dependencies>
+
+
+</project>

+ 37 - 0
healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/controller/FrontendDemoController.java

@@ -0,0 +1,37 @@
+package com.xxh.cloud.frontend.mq.controller;
+
+
+import cn.hutool.json.JSONUtil;
+import com.xxh.cloud.frontend.mq.model.MqMessageModel;
+import com.xxh.cloud.frontend.mq.model.MqSendDelayModel;
+import com.xxh.cloud.frontend.mq.service.ActiveMqService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Slf4j
+@RestController
+@RequestMapping("/mq/demo")
+@Api(tags="MQ的测试接口")
+public class FrontendDemoController {
+
+    @Autowired
+    private ActiveMqService activeMqService;
+
+    @RequestMapping(value = "/delay", method = RequestMethod.GET)
+    @ApiOperation(value = "延时队列")
+    public String delay(HttpServletRequest request) {
+        MqMessageModel mqMessageModel =
+                new MqMessageModel("tag001", JSONUtil.toJsonStr("10000"));
+        MqSendDelayModel mqSendModel = new MqSendDelayModel("queue", "20231111_topic", mqMessageModel, 5);
+        activeMqService.delay(mqSendModel);
+        return "OK";
+    }
+
+}

+ 18 - 0
healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/listener/FrontendDemoListener.java

@@ -0,0 +1,18 @@
+package com.xxh.cloud.frontend.mq.listener;
+
+import cn.hutool.json.JSONUtil;
+import com.xxh.cloud.frontend.mq.model.MqMessageModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jms.annotation.JmsListener;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class FrontendDemoListener {
+
+    @JmsListener(destination="20231111_topic")
+    public void onMessage(String message) {
+        log.info("售后订单MQ消费:" + message);
+        MqMessageModel messageExt = JSONUtil.toBean(message, MqMessageModel.class);
+    }
+}

+ 23 - 0
healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/model/ActiveMqTypeEnum.java

@@ -0,0 +1,23 @@
+package com.xxh.cloud.frontend.mq.model;
+
+public enum ActiveMqTypeEnum {
+
+    QUEUE("queue","queue模式"),
+    TOPIC("topic","topic模式"),
+
+    ;
+    private String code;
+    private String msg;
+    private ActiveMqTypeEnum(String code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+}

+ 21 - 0
healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/model/MqMessageModel.java

@@ -0,0 +1,21 @@
+package com.xxh.cloud.frontend.mq.model;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class MqMessageModel {
+
+    @ApiModelProperty(value = "tags")
+    private String tags;
+
+    @ApiModelProperty(value = "body")
+    private String body;
+
+}
+

+ 44 - 0
healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/model/MqSendDelayModel.java

@@ -0,0 +1,44 @@
+package com.xxh.cloud.frontend.mq.model;
+
+
+import cn.hutool.json.JSONUtil;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 如果用自定义bean作为activemq的参数,则必须实现序列化
+ */
+@Data
+public class MqSendDelayModel {
+
+    @ApiModelProperty(value = "队列/广播 [ActiveMqTypeEnum] queue/topic")
+    private String sendModel;
+
+    @ApiModelProperty(value = "队列/广播目标")
+    private String target;
+
+    @ApiModelProperty(value = "消息内容")
+    private String content;
+
+    @ApiModelProperty(value = "延迟(s)")
+    private Integer delay;
+
+    public MqSendDelayModel() {
+
+    }
+    public MqSendDelayModel(String sendModel, String target, String content, Integer delay) {
+        this.sendModel = sendModel;
+        this.target = target;
+        this.content = content;
+        this.delay = delay;
+    }
+
+    public MqSendDelayModel(String sendModel, String target, MqMessageModel content, Integer delay) {
+        this.sendModel = sendModel;
+        this.target = target;
+        this.content = JSONUtil.toJsonStr(content);
+        this.delay = delay;
+    }
+
+}
+

+ 39 - 0
healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/model/MqSendModel.java

@@ -0,0 +1,39 @@
+package com.xxh.cloud.frontend.mq.model;
+
+
+import cn.hutool.json.JSONUtil;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 如果用自定义bean作为activemq的参数,则必须实现序列化
+ */
+@Data
+public class MqSendModel {
+
+    @ApiModelProperty(value = "队列/广播 [ActiveMqTypeEnum] queue/topic")
+    private String sendModel;
+
+    @ApiModelProperty(value = "队列/广播目标")
+    private String target;
+
+    @ApiModelProperty(value = "消息内容")
+    private String content;
+
+    public MqSendModel() {
+
+    }
+
+    public MqSendModel(String sendModel, String target, String content) {
+        this.sendModel = sendModel;
+        this.target = target;
+        this.content = content;
+    }
+
+    public MqSendModel(String sendModel, String target, MqMessageModel content) {
+        this.sendModel = sendModel;
+        this.target = target;
+        this.content = JSONUtil.toJsonStr(content);
+    }
+}
+

+ 16 - 0
healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/service/ActiveMqService.java

@@ -0,0 +1,16 @@
+package com.xxh.cloud.frontend.mq.service;
+
+import com.xxh.cloud.frontend.mq.model.MqSendDelayModel;
+import com.xxh.cloud.frontend.mq.model.MqSendModel;
+
+public interface ActiveMqService {
+
+    public void send(MqSendModel model);
+
+    public void delay(MqSendDelayModel model);
+
+    public void send(String sendModel, String target, String tag, Object content);
+
+    public void delay(String sendModel, String target, String tag, Object content, Integer delay);
+
+}

+ 86 - 0
healthy-frontend-mq/src/main/java/com/xxh/cloud/frontend/mq/service/impl/ActiveMqServiceImpl.java

@@ -0,0 +1,86 @@
+package com.xxh.cloud.frontend.mq.service.impl;
+
+import cn.hutool.json.JSONUtil;
+import com.xxh.cloud.frontend.mq.model.ActiveMqTypeEnum;
+import com.xxh.cloud.frontend.mq.model.MqMessageModel;
+import com.xxh.cloud.frontend.mq.model.MqSendDelayModel;
+import com.xxh.cloud.frontend.mq.model.MqSendModel;
+import com.xxh.cloud.frontend.mq.service.ActiveMqService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.activemq.ScheduledMessage;
+import org.apache.activemq.command.ActiveMQQueue;
+import org.apache.activemq.command.ActiveMQTopic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jms.core.JmsMessagingTemplate;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.jms.Destination;
+import javax.jms.Queue;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+
+@Slf4j
+@Service
+public class ActiveMqServiceImpl implements ActiveMqService {
+
+    @Autowired
+    private JmsMessagingTemplate jmsMessagingTemplate;
+
+    @Override
+    public void send(MqSendModel model) {
+        if (ActiveMqTypeEnum.QUEUE.getCode().equals(model.getSendModel())) {
+            Queue queue = new ActiveMQQueue(model.getTarget());
+            sendMessage(queue, model.getContent());
+        } else if (ActiveMqTypeEnum.TOPIC.getCode().equals(model.getSendModel())) {
+            Topic topic = new ActiveMQTopic(model.getTarget());
+            sendMessage(topic, model.getContent());
+        } else {
+            log.error("MQ队列类型错误");
+        }
+    }
+
+    @Override
+    public void delay(MqSendDelayModel model) {
+        if (ActiveMqTypeEnum.QUEUE.getCode().equals(model.getSendModel())) {
+            Queue queue = new ActiveMQQueue(model.getTarget());
+            sendMessageDelay(queue, model.getContent(), model.getDelay());
+        } else if (ActiveMqTypeEnum.TOPIC.getCode().equals(model.getSendModel())) {
+            Topic topic = new ActiveMQTopic(model.getTarget());
+            sendMessageDelay(topic, model.getContent(), model.getDelay());
+        } else {
+            log.error("MQ队列类型错误");
+        }
+    }
+
+    @Override
+    public void send(String sendModel, String target, String tag, Object content) {
+        MqMessageModel mqMessageModel = new MqMessageModel(tag, JSONUtil.toJsonStr(content));
+        MqSendModel mqSendModel = new MqSendModel(sendModel, target, mqMessageModel);
+        this.send(mqSendModel);
+    }
+
+    @Override
+    public void delay(String sendModel, String target, String tag, Object content, Integer delay) {
+
+        MqMessageModel mqMessageModel = new MqMessageModel(tag, JSONUtil.toJsonStr(content));
+        MqSendDelayModel mqSendDelayModel = new MqSendDelayModel(sendModel, target, mqMessageModel , delay);
+        this.delay(mqSendDelayModel);
+    }
+
+    // 发送消息,destination是发送到的队列,message是待发送的消息
+    private void sendMessage(Destination destination, String content){
+        jmsMessagingTemplate.convertAndSend(destination, content);
+    }
+
+    // 发送延迟消息,destination是发送到的队列,message是待发送的消息
+    private void sendMessageDelay(Destination destination, String content, Integer delay){
+        JmsTemplate jmsTemplate = jmsMessagingTemplate.getJmsTemplate();
+        assert jmsTemplate != null;
+        jmsTemplate.send(destination, session -> {
+            TextMessage message = session.createTextMessage(content);
+            message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, delay * 1000);
+            return message;
+        });
+    }
+}

+ 34 - 0
pom.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.7.5</version>
+	</parent>
+
+	<groupId>com.xxh.cloud.frontend</groupId>
+	<artifactId>healthy-frontend-java</artifactId>
+	<version>1.0.0</version>
+	<packaging>pom</packaging>
+
+	<properties>
+		<java.version>1.8</java.version>
+		<spring-boot-version>2.1.3.RELEASE</spring-boot-version>
+		<fastjson.version>1.2.73</fastjson.version>
+		<hutool.version>5.4.1</hutool.version>
+		<swagger.version>2.9.2</swagger.version>
+		<swagger2markup.version>1.2.0</swagger2markup.version>
+		<swagger2bootstrap2ui.version>1.9.6</swagger2bootstrap2ui.version>
+	</properties>
+
+	<modules>
+		<module>healthy-frontend-app</module>
+		<module>healthy-frontend-custuser</module>
+		<module>healthy-frontend-common</module>
+		<module>healthy-frontend-mq</module>
+	</modules>
+
+</project>