15810770710@163.com 4 lat temu
rodzic
commit
34a0becf73
38 zmienionych plików z 2105 dodań i 0 usunięć
  1. 51 0
      deploy/config-map.yaml
  2. 82 0
      deploy/deploy.yaml
  3. 156 0
      pom.xml
  4. 24 0
      src/main/java/info/aspirecn/cloud/yysj/Application.java
  5. 79 0
      src/main/java/info/aspirecn/cloud/yysj/config/ElasticSearchConfig.java
  6. 22 0
      src/main/java/info/aspirecn/cloud/yysj/config/IndexConfig.java
  7. 24 0
      src/main/java/info/aspirecn/cloud/yysj/config/JsonConfig.java
  8. 48 0
      src/main/java/info/aspirecn/cloud/yysj/config/SwaggerConfig.java
  9. 82 0
      src/main/java/info/aspirecn/cloud/yysj/controller/AnalysisController.java
  10. 77 0
      src/main/java/info/aspirecn/cloud/yysj/controller/StatisticsController.java
  11. 101 0
      src/main/java/info/aspirecn/cloud/yysj/controller/handler/GlobalExceptionHandler.java
  12. 12 0
      src/main/java/info/aspirecn/cloud/yysj/dao/db/ProduceMapper.java
  13. 12 0
      src/main/java/info/aspirecn/cloud/yysj/dao/db/ProduceRelevanceMapper.java
  14. 12 0
      src/main/java/info/aspirecn/cloud/yysj/dao/db/UserMapper.java
  15. 12 0
      src/main/java/info/aspirecn/cloud/yysj/dao/db/UserProduceMapper.java
  16. 125 0
      src/main/java/info/aspirecn/cloud/yysj/dao/es/YysjGatewayFirstIndex.java
  17. 265 0
      src/main/java/info/aspirecn/cloud/yysj/dao/es/YysjGatewaySecondIndex.java
  18. 26 0
      src/main/java/info/aspirecn/cloud/yysj/exception/UserNotFountException.java
  19. 18 0
      src/main/java/info/aspirecn/cloud/yysj/model/ResponseInfo.java
  20. 49 0
      src/main/java/info/aspirecn/cloud/yysj/model/entity/Produce.java
  21. 44 0
      src/main/java/info/aspirecn/cloud/yysj/model/entity/ProduceRelevance.java
  22. 57 0
      src/main/java/info/aspirecn/cloud/yysj/model/entity/User.java
  23. 33 0
      src/main/java/info/aspirecn/cloud/yysj/model/entity/UserProduce.java
  24. 34 0
      src/main/java/info/aspirecn/cloud/yysj/model/remote/SjjhAccountInfo.java
  25. 26 0
      src/main/java/info/aspirecn/cloud/yysj/model/response/AccountInfo.java
  26. 31 0
      src/main/java/info/aspirecn/cloud/yysj/model/response/ConsumptionInfo.java
  27. 26 0
      src/main/java/info/aspirecn/cloud/yysj/model/response/ExceptionStatistics.java
  28. 37 0
      src/main/java/info/aspirecn/cloud/yysj/model/response/OrderStatistics.java
  29. 29 0
      src/main/java/info/aspirecn/cloud/yysj/model/response/Statistics.java
  30. 23 0
      src/main/java/info/aspirecn/cloud/yysj/remote/FindUserInfoFeign.java
  31. 38 0
      src/main/java/info/aspirecn/cloud/yysj/service/AnalysisService.java
  32. 56 0
      src/main/java/info/aspirecn/cloud/yysj/service/DbService.java
  33. 32 0
      src/main/java/info/aspirecn/cloud/yysj/service/StatisticsService.java
  34. 135 0
      src/main/java/info/aspirecn/cloud/yysj/service/impl/AnalysisServiceImpl.java
  35. 110 0
      src/main/java/info/aspirecn/cloud/yysj/service/impl/DbServiceImpl.java
  36. 32 0
      src/main/java/info/aspirecn/cloud/yysj/service/impl/StatisticsServiceImpl.java
  37. 46 0
      src/main/resources/application.yml
  38. 39 0
      src/main/resources/bootstrap.yml

+ 51 - 0
deploy/config-map.yaml

@@ -0,0 +1,51 @@
+kind: ConfigMap
+apiVersion: v1
+metadata:
+  name: cloud-yysj-analysis-info
+data:
+  application.yaml: |-
+    spring:
+      datasource:
+        url: jdbc:mysql://10.8.17.119:32196/cloud-yysj?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
+        username: root
+        driver-class-name: com.mysql.cj.jdbc.Driver
+        type: com.zaxxer.hikari.HikariDataSource
+        hikari:
+          minimum-idle: 5
+          maximum-pool-size: 15
+          auto-commit: true
+          idle-timeout: 30000
+          pool-name: DatebookHikariCP
+          max-lifetime: 1800000
+          connection-timeout: 30000
+          password: 123456
+
+    mybatis-plus:
+      configuration:
+        # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
+        #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+        # 驼峰下划线转换
+        map-underscore-to-camel-case: false
+        # 配置的缓存的全局开关
+        cache-enabled: true
+        # 延时加载的开关
+        lazy-loading-enabled: true
+        # 开启的话,延时加载一个属性时会加载该对象全部属性,否则按需加载属性
+        multiple-result-sets-enabled: true
+        use-generated-keys: true
+        default-statement-timeout: 60
+        default-fetch-size: 100
+
+    elasticsearch:
+      schema: http
+      address: 10.8.17.118:9200
+      #address: 192.168.16.41:30002,192.168.16.41:31821,192.168.16.41:30097
+      connectTimeout: 5000
+      socketTimeout: 5000
+      connectionRequestTimeout: 5000
+      maxConnectNum: 100
+      maxConnectPerRoute: 100
+      index:
+        yysjFirst: access-yysj-gateway-first-log-cloud-yysj*
+        yysjSecond: access-yysj-gateway-second-log-cloud-yysj*
+        sjjh: iov_sjjh_access_test1*

+ 82 - 0
deploy/deploy.yaml

@@ -0,0 +1,82 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: cloud-yysj-analysis-info
+  labels:
+    app: cloud-yysj-analysis-info
+    svcEndpoints: actuator
+spec:
+  type: NodePort
+  ports:
+    - name: server
+      port: 8080
+      targetPort: 8080
+    - name: management
+      port: 8081
+      targetPort: 8081
+  selector:
+    app: cloud-yysj-analysis-info
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: cloud-yysj-analysis-info
+  labels:
+    app: cloud-yysj-analysis-info
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: cloud-yysj-analysis-info
+  template:
+    metadata:
+      name: cloud-yysj-analysis-info
+      labels:
+        app: cloud-yysj-analysis-info
+    spec:
+      restartPolicy: Always
+      containers:
+      - name: service-provider
+        image: hub.i139.cn/cloud-yysj/cloud-yysj-analysis-info:1.0.0
+        imagePullPolicy: IfNotPresent
+        ports:
+        - name: server
+          containerPort: 8080
+        - name: management
+          containerPort: 8081
+        env:
+        - name: KUBERNETES_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        - name: POD_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.name
+        - name: JAVA_OPTS
+          value: ""
+        - name: APP_OPTS
+          value: ""
+        resources:
+          limits:
+            memory: 1000Mi
+            cpu: 2000m
+          requests:
+            memory: 256Mi
+            cpu: 1000m
+        readinessProbe:
+          initialDelaySeconds: 20
+          periodSeconds: 5
+          timeoutSeconds: 10
+          failureThreshold: 5
+          httpGet:
+            path: /actuator/health
+            port: 8081
+        livenessProbe:
+          initialDelaySeconds: 60
+          periodSeconds: 5
+          timeoutSeconds: 5
+          failureThreshold: 3
+          httpGet:
+            path: /actuator/health
+            port: 8081

+ 156 - 0
pom.xml

@@ -0,0 +1,156 @@
+<?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 https://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.2.2.RELEASE</version>
+    </parent>
+
+    <groupId>info.aspirecn.cloud.yysj</groupId>
+    <artifactId>cloud-yysj-analysis-info</artifactId>
+    <version>1.0.0</version>
+    <name>cloud-yysj-analysis-info</name>
+    <description>cloud yysj platform analysis information</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
+    </properties>
+
+    <dependencies>
+        <!--web-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <!--actuator-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <!--springcloud-kubernetes-config-->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-kubernetes-config</artifactId>
+        </dependency>
+        <!--lombok-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <!--swagger-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+        <!--elasticsearch-->
+        <dependency>
+            <groupId>org.elasticsearch.client</groupId>
+            <artifactId>elasticsearch-rest-high-level-client</artifactId>
+            <version>6.6.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.elasticsearch</groupId>
+            <artifactId>elasticsearch</artifactId>
+            <version>6.6.2</version>
+        </dependency>
+        <!--commons-->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.8.1</version>
+        </dependency>
+        <!--mybatis plus-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.3.0</version>
+        </dependency>
+        <!--feign-->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+        <!--mysql-->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+    </dependencies>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring-cloud.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <plugins>
+            <!--设置应用 Main 参数启动依赖查找的地址指向外部 lib 文件夹-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>lib/</classpathPrefix>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <!--设置 SpringBoot 打包插件不包含任何 Jar 依赖包-->
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <includes>
+                        <include>
+                            <groupId>nothing</groupId>
+                            <artifactId>nothing</artifactId>
+                        </include>
+                    </includes>
+                </configuration>
+            </plugin>
+            <!--设置将 lib 拷贝到应用 Jar 外面-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 24 - 0
src/main/java/info/aspirecn/cloud/yysj/Application.java

@@ -0,0 +1,24 @@
+package info.aspirecn.cloud.yysj;
+
+import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * @author dingliqiang
+ */
+@EnableSwagger2
+@EnableKnife4j
+@EnableFeignClients
+@SpringBootApplication
+@MapperScan("info.aspirecn.cloud.yysj.dao")
+public class Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+
+}

+ 79 - 0
src/main/java/info/aspirecn/cloud/yysj/config/ElasticSearchConfig.java

@@ -0,0 +1,79 @@
+package info.aspirecn.cloud.yysj.config;
+
+import org.apache.http.HttpHost;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.client.RestClientBuilder;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * ElasticSearch 配置
+ *
+ * @author dingliqiang
+ */
+@Configuration
+public class ElasticSearchConfig {
+
+    /** 协议 */
+    @Value("${elasticsearch.schema}")
+    private String schema = "http";
+
+    /** 集群地址,如果有多个用“,”隔开 */
+    @Value("${elasticsearch.address}")
+    private String address;
+
+    /** 连接超时时间 */
+    @Value("${elasticsearch.connectTimeout:5000}")
+    private int connectTimeout;
+
+    /** Socket 连接超时时间 */
+    @Value("${elasticsearch.socketTimeout:10000}")
+    private int socketTimeout;
+
+    /** 获取连接的超时时间 */
+    @Value("${elasticsearch.connectionRequestTimeout:5000}")
+    private int connectionRequestTimeout;
+
+    /** 最大连接数 */
+    @Value("${elasticsearch.maxConnectNum:100}")
+    private int maxConnectNum;
+
+    /** 最大路由连接数 */
+    @Value("${elasticsearch.maxConnectPerRoute:100}")
+    private int maxConnectPerRoute;
+
+    @Bean
+    public RestHighLevelClient restHighLevelClient() {
+        // 拆分地址
+        List<HttpHost> hostLists = new ArrayList<>();
+        String[] hostList = address.split(",");
+        for (String addr : hostList) {
+            String host = addr.split(":")[0];
+            String port = addr.split(":")[1];
+            hostLists.add(new HttpHost(host, Integer.parseInt(port), schema));
+        }
+        // 转换成 HttpHost 数组
+        HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{});
+        // 构建连接对象
+        RestClientBuilder builder = RestClient.builder(httpHost);
+        // 异步连接延时配置
+        builder.setRequestConfigCallback(requestConfigBuilder -> {
+            requestConfigBuilder.setConnectTimeout(connectTimeout);
+            requestConfigBuilder.setSocketTimeout(socketTimeout);
+            requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
+            return requestConfigBuilder;
+        });
+        // 异步连接数配置
+        builder.setHttpClientConfigCallback(httpClientBuilder -> {
+            httpClientBuilder.setMaxConnTotal(maxConnectNum);
+            httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
+            return httpClientBuilder;
+        });
+        return new RestHighLevelClient(builder);
+    }
+
+}

+ 22 - 0
src/main/java/info/aspirecn/cloud/yysj/config/IndexConfig.java

@@ -0,0 +1,22 @@
+package info.aspirecn.cloud.yysj.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author dingliqiang
+ */
+@Data
+@Configuration
+public class IndexConfig {
+
+    /** 云验数据平台一级网关索引*/
+    @Value("${elasticsearch.index.yysjFirst}")
+    private String indexYysjFirst;
+
+    /** 云验数据平台二级网关索引*/
+    @Value("${elasticsearch.index.yysjSecond}")
+    private String indexYysjSecond;
+
+}

+ 24 - 0
src/main/java/info/aspirecn/cloud/yysj/config/JsonConfig.java

@@ -0,0 +1,24 @@
+package info.aspirecn.cloud.yysj.config;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Json 配置
+ *
+ * @author mydlq
+ */
+@Configuration
+public class JsonConfig {
+
+    @Bean
+    public ObjectMapper objectMapper() {
+        ObjectMapper objectMapper = new ObjectMapper();
+        // 不转换值null的字段
+        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        return objectMapper;
+    }
+
+}

+ 48 - 0
src/main/java/info/aspirecn/cloud/yysj/config/SwaggerConfig.java

@@ -0,0 +1,48 @@
+package info.aspirecn.cloud.yysj.config;
+
+import com.google.common.base.Predicates;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+
+/**
+ * Swagger 配置
+ *
+ * @author dingliqiang
+ */
+@Configuration
+public class SwaggerConfig {
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                // 项目组名
+                .apiInfo(apiInfo())
+                // 选择那些路径和api会生成document
+                .select()
+                // 对所有api进行监控
+                .apis(RequestHandlerSelectors.any())
+                // 对所有路径进行监控
+                .paths(PathSelectors.any())
+                //错误路径不监控
+                .paths(Predicates.not(PathSelectors.regex("/error.*")))
+                //actuator路径跳过
+                .paths(Predicates.not(PathSelectors.regex("/actuator.*")))
+                .build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                // 文档标题
+                .title("账户产品数据分析服务接口项目")
+                // 文档描述
+                .description("账户产品数据分析服务接口项目接口文档。")
+                // 文档版本
+                .version("1.0.0")
+                .build();
+    }
+}

+ 82 - 0
src/main/java/info/aspirecn/cloud/yysj/controller/AnalysisController.java

@@ -0,0 +1,82 @@
+package info.aspirecn.cloud.yysj.controller;
+
+import info.aspirecn.cloud.yysj.model.ResponseInfo;
+import info.aspirecn.cloud.yysj.model.response.AccountInfo;
+import info.aspirecn.cloud.yysj.model.response.ConsumptionInfo;
+import info.aspirecn.cloud.yysj.model.response.OrderStatistics;
+import info.aspirecn.cloud.yysj.service.AnalysisService;
+import io.swagger.annotations.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RestController;
+import java.util.List;
+
+/**
+ * 用户订单统计、消费信息、余额、产品消费比例等信息查询,适用于首页
+ *
+ * @author dingliqiang
+ */
+@Api(tags = "账户产品数据分析服务接口(适用于首页)")
+@ApiResponses({
+        @ApiResponse(code = 200, message = "成功处理请求"),
+        @ApiResponse(code = 400, message = "没有找到该用户信息"),
+        @ApiResponse(code = 401, message = "没有权限访问该服务"),
+        @ApiResponse(code = 403, message = "权限不足无法访问该服务"),
+        @ApiResponse(code = 404, message = "未发现该微服务"),
+        @ApiResponse(code = 500, message = "服务器内部错误")
+})
+@Slf4j
+@RestController
+public class AnalysisController {
+
+    @Autowired
+    private AnalysisService analysisService;
+
+    /**
+     * 主订单统计信息接口
+     * @param userId 用户ID
+     * @return 主订单统计信息
+     */
+    @ApiOperation(value = "主订单统计信息", notes = "获取账户最新 15 天订单统计信息。")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "string", required = false, paramType = "header")
+    })
+    @GetMapping("/statisticsInfo")
+    public ResponseInfo getOrderStatistics(@RequestHeader(required = true) String userId) {
+        List<OrderStatistics> statisticsList = analysisService.getOrderStatistics(userId);
+        return new ResponseInfo().setData(statisticsList).setMessage("请求成功");
+    }
+
+    /**
+     * 产品消费信息接口
+     * @param userId 用户ID
+     * @return 产品消费信息
+     */
+    @ApiOperation(value = "产品消费信息", notes = "获取账户当月订购产品的消费及占比信息。")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "string", required = true, paramType = "header")
+    })
+    @GetMapping("/consumptionInfo")
+    public ResponseInfo getConsumptionInfo(@RequestHeader(required = true) String userId) {
+        List<ConsumptionInfo> consumptionList = analysisService.getConsumptionInfo(userId);
+        return new ResponseInfo().setData(consumptionList).setMessage("请求成功");
+    }
+
+    /**
+     * 账户信息接口
+     * @param userId 用户ID
+     * @return 账户信息
+     */
+    @ApiOperation(value = "账户信息", notes = "获取用户当日消费金额和账户余额。")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "string", required = true, paramType = "header")
+    })
+    @GetMapping("/accountInfo")
+    public ResponseInfo getAccountInfo(@RequestHeader(required = true) String userId) {
+        AccountInfo accountInfo = analysisService.getAccountInfo(userId);
+        return new ResponseInfo().setData(accountInfo).setMessage("请求成功");
+    }
+
+}

+ 77 - 0
src/main/java/info/aspirecn/cloud/yysj/controller/StatisticsController.java

@@ -0,0 +1,77 @@
+package info.aspirecn.cloud.yysj.controller;
+
+import info.aspirecn.cloud.yysj.model.ResponseInfo;
+import info.aspirecn.cloud.yysj.model.response.ExceptionStatistics;
+import info.aspirecn.cloud.yysj.model.response.Statistics;
+import info.aspirecn.cloud.yysj.service.StatisticsService;
+import io.swagger.annotations.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import java.util.List;
+
+/**
+ * 统计结果信息,用于统计分析页面
+ *
+ * @author dingliqiang
+ */
+@Api(tags = "统计结果信息接口(适用于统计分析页面)")
+@ApiResponses({
+        @ApiResponse(code = 200, message = "成功处理请求"),
+        @ApiResponse(code = 400, message = "没有找到该用户信息"),
+        @ApiResponse(code = 401, message = "没有权限访问该服务"),
+        @ApiResponse(code = 403, message = "权限不足无法访问该服务"),
+        @ApiResponse(code = 404, message = "未发现该微服务"),
+        @ApiResponse(code = 500, message = "服务器内部错误")
+})
+@RestController
+public class StatisticsController {
+
+    @Autowired
+    private StatisticsService statisticsService;
+
+    /**
+     * 总订单统计信息接口
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param userId 用户ID
+     * @return 总订单统计信息
+     */
+    @ApiOperation(value = "总订单统计信息", notes = "获取指定日期内,总订单统计结果信息和一致的结果。")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "endTime", value = "结束时间", dataType = "string", required = true, paramType = "query"),
+            @ApiImplicitParam(name = "startTime", value = "开始时间", dataType = "string", required = true, paramType = "query"),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "string", required = true, paramType = "header")
+    })
+    @GetMapping("/countStatisticsInfo")
+    public ResponseInfo getCountStatistics(@RequestParam(required = true) String startTime,
+                                            @RequestParam(required = true) String endTime,
+                                            @RequestHeader(required = true) String userId) {
+        List<Statistics> statisticsList = statisticsService.getCountStatistics(startTime, endTime, userId);
+        return new ResponseInfo().setData(statisticsList).setMessage("请求成功");
+    }
+
+    /**
+     * 异常效验统计信息
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param userId 用户ID
+     * @return
+     */
+    @ApiOperation(value = "异常效验统计信息", notes = "获取指定日期内,不一致订单统计结果信息。")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "startTime", value = "开始时间", dataType = "string", required = true, paramType = "query"),
+            @ApiImplicitParam(name = "endTime", value = "结束时间", dataType = "string", required = true, paramType = "query"),
+            @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "string", required = true, paramType = "header")
+    })
+    @GetMapping("/exceptionStatisticsInfo")
+    public ResponseInfo getErrorStatistics(@RequestParam(required = true) String startTime,
+                                            @RequestParam(required = true) String endTime,
+                                            @RequestHeader(required = true) String userId) {
+        List<ExceptionStatistics> exceptionStatisticsList = statisticsService.getErrorStatistics(startTime, endTime, userId);
+        return new ResponseInfo().setData(exceptionStatisticsList).setMessage("请求成功");
+    }
+
+}

+ 101 - 0
src/main/java/info/aspirecn/cloud/yysj/controller/handler/GlobalExceptionHandler.java

@@ -0,0 +1,101 @@
+package info.aspirecn.cloud.yysj.controller.handler;
+
+import info.aspirecn.cloud.yysj.exception.UserNotFountException;
+import info.aspirecn.cloud.yysj.model.ResponseInfo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.FieldError;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingRequestHeaderException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 全局异常处理器
+ *
+ * @author dingliqiang
+ */
+@Slf4j
+@ControllerAdvice
+public class GlobalExceptionHandler {
+
+    /**
+     * 全局异常处理器
+     *
+     * @param e 异常信息
+     */
+    @ResponseBody
+    @ExceptionHandler(Exception.class)
+    public ResponseInfo exceptionHandler(Exception e, HttpServletResponse response) {
+        log.error("", e);
+        if (e instanceof UserNotFountException) {
+            response.setStatus(400);
+            return new ResponseInfo().setMessage("系统无此用户信息").setData("");
+        } else if (e instanceof MissingRequestHeaderException) {
+            return new ResponseInfo().setMessage("Header 参数 token 不能为空").setData("");
+        } else if (e instanceof MissingServletRequestParameterException){
+            return new ResponseInfo().setMessage("Header 参数 token 不能为空").setData("");
+        }
+        response.setStatus(503);
+        return new ResponseInfo().setMessage("系统繁忙,请稍后再试").setData("");
+    }
+
+    /**
+     * 忽略参数异常处理器
+     *
+     * @param e 忽略参数异常
+     * @return ResponseResult
+     */
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(MissingServletRequestParameterException.class)
+    public ResponseInfo parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
+        log.error("", e);
+        return new ResponseInfo().setMessage("请求参数 " + e.getParameterName() + " 不能为空").setData("");
+    }
+
+    /**
+     * 缺少请求体异常处理器
+     *
+     * @param e 缺少请求体异常
+     * @return ResponseResult
+     */
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(HttpMessageNotReadableException.class)
+    public ResponseInfo parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
+        log.error("", e);
+        return new ResponseInfo().setMessage("参数体不能为空").setData("");
+    }
+
+    /**
+     * 参数效验异常处理器
+     *
+     * @param e 参数验证异常
+     * @return ResponseInfo
+     */
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public ResponseInfo parameterExceptionHandler(MethodArgumentNotValidException e) {
+        log.error("", e);
+        // 获取异常信息
+        BindingResult exceptions = e.getBindingResult();
+        // 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
+        if (exceptions.hasErrors()) {
+            List<ObjectError> errors = exceptions.getAllErrors();
+            if (!errors.isEmpty()) {
+                // 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可
+                FieldError fieldError = (FieldError) errors.get(0);
+                return new ResponseInfo().setMessage(fieldError.getDefaultMessage()).setData("");
+            }
+        }
+        return new ResponseInfo().setMessage("请求参数错误").setData("");
+    }
+
+}

+ 12 - 0
src/main/java/info/aspirecn/cloud/yysj/dao/db/ProduceMapper.java

@@ -0,0 +1,12 @@
+package info.aspirecn.cloud.yysj.dao.db;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import info.aspirecn.cloud.yysj.model.entity.Produce;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author dingliqiang
+ */
+@Repository
+public interface ProduceMapper extends BaseMapper<Produce> {
+}

+ 12 - 0
src/main/java/info/aspirecn/cloud/yysj/dao/db/ProduceRelevanceMapper.java

@@ -0,0 +1,12 @@
+package info.aspirecn.cloud.yysj.dao.db;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import info.aspirecn.cloud.yysj.model.entity.ProduceRelevance;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author dingliqiang
+ */
+@Repository
+public interface ProduceRelevanceMapper extends BaseMapper<ProduceRelevance> {
+}

+ 12 - 0
src/main/java/info/aspirecn/cloud/yysj/dao/db/UserMapper.java

@@ -0,0 +1,12 @@
+package info.aspirecn.cloud.yysj.dao.db;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import info.aspirecn.cloud.yysj.model.entity.User;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author dingliqiang
+ */
+@Repository
+public interface UserMapper extends BaseMapper<User> {
+}

+ 12 - 0
src/main/java/info/aspirecn/cloud/yysj/dao/db/UserProduceMapper.java

@@ -0,0 +1,12 @@
+package info.aspirecn.cloud.yysj.dao.db;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import info.aspirecn.cloud.yysj.model.entity.UserProduce;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author dingliqiang
+ */
+@Repository
+public interface UserProduceMapper extends BaseMapper<UserProduce> {
+}

+ 125 - 0
src/main/java/info/aspirecn/cloud/yysj/dao/es/YysjGatewayFirstIndex.java

@@ -0,0 +1,125 @@
+package info.aspirecn.cloud.yysj.dao.es;
+
+import info.aspirecn.cloud.yysj.config.IndexConfig;
+import info.aspirecn.cloud.yysj.model.response.OrderStatistics;
+import lombok.SneakyThrows;
+import org.apache.commons.lang3.StringUtils;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
+import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
+import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
+import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * ElasticSearch 云验数据平台子订单索引查询
+ *
+ * @author dingliqiang
+ */
+@Repository
+public class YysjGatewayFirstIndex {
+
+    /**
+     * 车辆查询
+     */
+    private static final String QUERY_CAR_INFO = "/info_check/carInfo.do";
+
+    /**
+     * 驾驶员查询
+     */
+    private static final String QUERY_DRIVER_INFO = "/info_check/driverInfo.do";
+    /**
+     * 运单查询
+     */
+    private static final String QUERY_WAYBILL_INFO = "/info_check/waybill.do";
+
+    /**
+     * 查询产品类型
+     */
+    private static final String[] QUERY_TYPE = {QUERY_CAR_INFO, QUERY_DRIVER_INFO, QUERY_WAYBILL_INFO};
+
+    @Autowired
+    private RestHighLevelClient restHighLevelClient;
+
+    @Autowired
+    private IndexConfig indexConfig;
+
+    /**
+     * 统计云验平台用户调用总量、车辆、运单、司机信息
+     *
+     * @param userId 云验平台用户ID
+     * @return 用户调用总量、车辆、运单、司机统计信息
+     */
+    @SneakyThrows(IOException.class)
+    public List<OrderStatistics> getTotalConsumptionAmount(String userId) {
+        // 设置云验平台用户当日总量、车辆、运单、司机接口调用量集合
+        List<OrderStatistics> orderStatisticsList = new ArrayList<>();
+        // 构建查询源构建器
+        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
+        searchSourceBuilder.size(0);
+        searchSourceBuilder.query(QueryBuilders.boolQuery()
+                .filter(QueryBuilders.rangeQuery("DateTime").gte("now-15d"))
+                .must(QueryBuilders.termQuery("MG-UserId", userId))
+                .must(QueryBuilders.termsQuery("URI.keyword", QUERY_TYPE)));
+        searchSourceBuilder.aggregation(AggregationBuilders.dateHistogram("daily_count")
+                .field("DateTime").format("yyyy-MM-dd").dateHistogramInterval(DateHistogramInterval.DAY)
+                .subAggregation(AggregationBuilders.terms("orders_received_statistics").field("URI.keyword")));
+        // 创建查询请求对象,将查询对象配置到其中
+        SearchRequest request = new SearchRequest(indexConfig.getIndexYysjFirst()).source(searchSourceBuilder);
+        // 执行查询请求,获取响应信息
+        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
+        if (!RestStatus.OK.equals(response.status()) || response.getAggregations() == null) {
+            return orderStatisticsList;
+        }
+        // 获取响应中的聚合信息
+        ParsedDateHistogram parsedDateHistogram = response.getAggregations().get("daily_count");
+        // 获取分桶信息
+        List<? extends Histogram.Bucket> buckets = parsedDateHistogram.getBuckets();
+        for (Histogram.Bucket bucket : buckets) {
+            // 创建 OrderStatistics 对象,并设置车辆、运单、司机信息
+            OrderStatistics orderStatistics = getCarDriverWaybill(bucket);
+            // 设置日期
+            orderStatistics.setDate(bucket.getKeyAsString());
+            // 设置总数
+            orderStatistics.setSum(bucket.getDocCount());
+            // 加入到集合
+            orderStatisticsList.add(orderStatistics);
+        }
+        return orderStatisticsList;
+    }
+
+    /**
+     * 获取车辆、运单、司机产品的调用统计信息
+     *
+     * @param bucket 分桶信息
+     * @return 车辆、运单、司机调用统计信息
+     */
+    private OrderStatistics getCarDriverWaybill(Histogram.Bucket bucket) {
+        OrderStatistics orderStatistics = new OrderStatistics();
+        ParsedTerms termsAggregations = bucket.getAggregations().get("orders_received_statistics");
+        List<? extends Terms.Bucket> termsBuckets = termsAggregations.getBuckets();
+        for (Terms.Bucket termsBucket : termsBuckets) {
+            if (StringUtils.equalsIgnoreCase(QUERY_CAR_INFO, termsBucket.getKeyAsString())) {
+                orderStatistics.setVehicle(termsBucket.getDocCount());
+            } else if (StringUtils.equalsIgnoreCase(QUERY_DRIVER_INFO, termsBucket.getKeyAsString())) {
+                orderStatistics.setDriver(termsBucket.getDocCount());
+            } else if (StringUtils.equalsIgnoreCase(QUERY_WAYBILL_INFO, termsBucket.getKeyAsString())) {
+                orderStatistics.setWaybill(termsBucket.getDocCount());
+            }
+        }
+        return orderStatistics;
+    }
+
+}

+ 265 - 0
src/main/java/info/aspirecn/cloud/yysj/dao/es/YysjGatewaySecondIndex.java

@@ -0,0 +1,265 @@
+package info.aspirecn.cloud.yysj.dao.es;
+
+import info.aspirecn.cloud.yysj.config.IndexConfig;
+import info.aspirecn.cloud.yysj.model.entity.UserProduce;
+import info.aspirecn.cloud.yysj.model.response.ConsumptionInfo;
+import info.aspirecn.cloud.yysj.model.response.ExceptionStatistics;
+import info.aspirecn.cloud.yysj.model.response.Statistics;
+import lombok.SneakyThrows;
+import org.apache.commons.lang3.StringUtils;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.Aggregations;
+import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
+import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
+import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
+import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.elasticsearch.search.aggregations.metrics.sum.ParsedSum;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ElasticSearch 云验数据平台子订单索引查询
+ *
+ * @author dingliqiang
+ */
+@Repository
+public class YysjGatewaySecondIndex {
+
+    /**
+     * 是否计费(0:不计费,1:计费)
+     */
+    private static final int IS_CHARGE = 1;
+
+    /**
+     * 一致
+     */
+    private static final int QUERY_RESULT_COINCIDE = 1;
+
+    /**
+     * 不一致
+     */
+    private static final int QUERY_RESULT_NOT_COINCIDE = 0;
+
+    /**
+     * 查询产品类型
+     */
+    private static final int[] QUERY_RESULT = {QUERY_RESULT_COINCIDE, QUERY_RESULT_NOT_COINCIDE};
+
+    @Autowired
+    private IndexConfig indexConfig;
+
+    @Autowired
+    private RestHighLevelClient restHighLevelClient;
+
+    /**
+     * 获取一定时间内异常效验统计结果(获取不一致结果的统计信息)
+     *
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     * @param userId    云验数据平台用户ID
+     * @return 异常效验统计结果
+     */
+    @SneakyThrows(IOException.class)
+    public List<Statistics> getCountStatistics(String startTime, String endTime, String userId) {
+        // 设置返回结果
+        List<Statistics> exceptionStatisticsList = new ArrayList<>();
+        // 创建 Bool 查询构建器
+        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
+        searchSourceBuilder.size(0);
+        searchSourceBuilder.query(QueryBuilders.boolQuery()
+                .filter(QueryBuilders.rangeQuery("DateTime").gte(startTime).lte(endTime).format("yyyy-MM-dd"))
+                .must(QueryBuilders.termQuery("MG-UserId", userId))
+                .must(QueryBuilders.termsQuery("MG-Result", QUERY_RESULT)));
+        searchSourceBuilder.aggregation(AggregationBuilders.dateHistogram("daily_count")
+                .field("DateTime").format("yyyy-MM-dd").dateHistogramInterval(DateHistogramInterval.DAY)
+                .subAggregation(AggregationBuilders.terms("normal_num").field("MG-Result"))
+        );
+        // 创建查询请求对象,将查询对象配置到其中
+        SearchRequest request = new SearchRequest(indexConfig.getIndexYysjSecond()).source(searchSourceBuilder);
+        // 执行请求
+        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
+        if (!RestStatus.OK.equals(response.status()) || response.getAggregations() == null) {
+            return exceptionStatisticsList;
+        }
+        // 获取响应中的聚合信息
+        Aggregations aggregations = response.getAggregations();
+        // 转换为 DateHistogram 对象
+        ParsedDateHistogram aggregation = aggregations.get("daily_count");
+        List<? extends Histogram.Bucket> buckets = aggregation.getBuckets();
+        for (Histogram.Bucket bucket : buckets) {
+            Statistics statistics = new Statistics();
+            // 设置日期
+            statistics.setDate(bucket.getKeyAsString());
+            // 设置总数
+            statistics.setSum(bucket.getDocCount());
+            // 设置一致结果统计数
+            ParsedTerms termsAggregations = bucket.getAggregations().get("normal_num");
+            List<? extends Terms.Bucket> termsBuckets = termsAggregations.getBuckets();
+            for (Terms.Bucket buck : termsBuckets) {
+                if (StringUtils.equalsIgnoreCase(String.valueOf(QUERY_RESULT_COINCIDE), buck.getKeyAsString())) {
+                    statistics.setNormalNum(buck.getDocCount());
+                }
+            }
+            // 加入到集合
+            exceptionStatisticsList.add(statistics);
+        }
+        return exceptionStatisticsList;
+    }
+
+    /**
+     * 获取一定时间内总量与正常验统计结果(获取总数和一致结果的统计信息)
+     *
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     * @param userId    云验数据平台用户ID
+     * @return 总量与正常验统计结果
+     */
+    @SneakyThrows(IOException.class)
+    public List<ExceptionStatistics> getErrorStatistics(String startTime, String endTime, String userId) {
+        // 设置返回结果
+        List<ExceptionStatistics> exceptionStatisticsList = new ArrayList<>();
+        // 创建 Bool 查询构建器
+        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
+        searchSourceBuilder.size(0);
+        searchSourceBuilder.query(QueryBuilders.boolQuery()
+                .filter(QueryBuilders.rangeQuery("DateTime").gte(startTime).lte(endTime).format("yyyy-MM-dd"))
+                .must(QueryBuilders.termQuery("MG-UserId", userId))
+                .must(QueryBuilders.termQuery("MG-Result", QUERY_RESULT_NOT_COINCIDE)));
+        searchSourceBuilder.aggregation(AggregationBuilders.dateHistogram("daily_count")
+                .field("DateTime").dateHistogramInterval(DateHistogramInterval.DAY).format("yyyy-MM-dd"));
+        // 创建查询请求对象,将查询对象配置到其中
+        SearchRequest request = new SearchRequest(indexConfig.getIndexYysjSecond()).source(searchSourceBuilder);
+        // 执行请求
+        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
+        if (!RestStatus.OK.equals(response.status()) || response.getAggregations() == null) {
+            return exceptionStatisticsList;
+        }
+        // 获取响应中的聚合信息
+        Aggregations aggregations = response.getAggregations();
+        // 转换为 DateHistogram 对象
+        ParsedDateHistogram aggregation = aggregations.get("daily_count");
+        List<? extends Histogram.Bucket> buckets = aggregation.getBuckets();
+        for (Histogram.Bucket bucket : buckets) {
+            ExceptionStatistics orderStatistics = new ExceptionStatistics();
+            // 设置日期
+            orderStatistics.setDate(bucket.getKeyAsString());
+            // 设置总数
+            orderStatistics.setNum(bucket.getDocCount());
+            // 加入到集合
+            exceptionStatisticsList.add(orderStatistics);
+        }
+        return exceptionStatisticsList;
+    }
+
+    /**
+     * 获取用户当日消费金额
+     *
+     * @param userId 云验平台用户ID
+     * @return 当日消费金额
+     */
+    @SneakyThrows(IOException.class)
+    public Long getAccountConsumptionAmount(String userId) {
+        // 构建查询源构建器
+        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
+        searchSourceBuilder.size(0);
+        searchSourceBuilder.query(QueryBuilders.boolQuery()
+                .filter(QueryBuilders.rangeQuery("DateTime").gte("now/d").lte("now"))
+                .must(QueryBuilders.termQuery("MG-UserId", userId))
+                .must(QueryBuilders.termQuery("MG-IsCharge", IS_CHARGE)));
+        searchSourceBuilder.aggregation(AggregationBuilders.sum("product_price_sum").field("MG-Money"));
+        // 创建查询请求对象,将查询对象配置到其中
+        SearchRequest request = new SearchRequest(indexConfig.getIndexYysjSecond()).source(searchSourceBuilder);
+        // 执行请求
+        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
+        if (!RestStatus.OK.equals(response.status()) || response.getAggregations() == null) {
+            return 0L;
+        }
+        // 获取响应中的聚合信息
+        Aggregations aggregations = response.getAggregations();
+        ParsedSum aggregation = aggregations.get("product_price_sum");
+        return Math.round(aggregation.getValue());
+    }
+
+    /**
+     * 获取云验平台用户当月订购产品的消费及占比信息
+     *
+     * @param userId         云验平台用户ID
+     * @param produceIds 产品ID列表
+     * @return 用户当月订购产品的消费及占比信息
+     */
+    @SneakyThrows(IOException.class)
+    public Map<Integer, ConsumptionInfo> getConsumptionInfo(String userId, List<UserProduce> userProduceList, Integer[] produceIds) {
+        Map<Integer, ConsumptionInfo> consumptionInfoMap = new HashMap<>();
+        // 构建查询源构建器
+        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
+        searchSourceBuilder.size(0);
+        searchSourceBuilder.query(QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery("DateTime").gte("now/M"))
+                .must(QueryBuilders.termQuery("MG-UserId", userId))
+                .must(QueryBuilders.termQuery("MG-IsCharge", IS_CHARGE))
+                .must(QueryBuilders.termsQuery("MG-ProductId", produceIds)));
+        searchSourceBuilder.aggregation(AggregationBuilders.terms("product_usage_analysis").field("MG-ProductId")
+                .subAggregation(AggregationBuilders.sum("price_sum").field("MG-Money")));
+        // 创建查询请求对象,将查询对象配置到其中
+        SearchRequest request = new SearchRequest(indexConfig.getIndexYysjSecond()).source(searchSourceBuilder);
+        // 执行查询请求,获取响应信息
+        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
+        if (!RestStatus.OK.equals(response.status()) || response.getAggregations() == null) {
+            return consumptionInfoMap;
+        }
+        // 获取响应中的聚合信息
+        Aggregations aggregations = response.getAggregations();
+        // 转换为 Terms 对象
+        ParsedTerms aggregation = aggregations.get("product_usage_analysis");
+        List<? extends Terms.Bucket> buckets = aggregation.getBuckets();
+        // 合并各个产品信息,然后返回数据
+        consumptionInfoMap.putAll(getCarDriverWaybill(buckets, userProduceList));
+        return consumptionInfoMap;
+    }
+
+    /**
+     * 获取数据交互中各个产品信息,如果数据交互多个产品同属于云验平台,则将这些产品汇总
+     *
+     * @param buckets 分桶信息
+     */
+    private Map<Integer, ConsumptionInfo> getCarDriverWaybill(List<? extends Terms.Bucket> buckets, List<UserProduce> userProduceList) {
+        Map<Integer, Long> produceMap = new HashMap<>(50);
+        for (UserProduce userProduce : userProduceList) {
+            for (Terms.Bucket bucket : buckets) {
+                if (StringUtils.equalsIgnoreCase(String.valueOf(userProduce.getProduceId()), bucket.getKeyAsString())) {
+                    ParsedSum parsedSum = bucket.getAggregations().get("price_sum");
+                    long value;
+                    if (produceMap.containsKey(userProduce.getProduceId())) {
+                        value = produceMap.get(userProduce.getProduceId()) + Math.round(parsedSum.getValue());
+                    } else {
+                        value = Math.round(parsedSum.getValue());
+                    }
+                    produceMap.put(userProduce.getProduceId(), value);
+                }
+            }
+        }
+        Map<Integer, ConsumptionInfo> consumptionInfoMap = new HashMap<>(50);
+        // 设置各个产品的金额比例
+        for (Map.Entry<Integer, Long> entry : produceMap.entrySet()) {
+            // 设置产品消费信息
+            consumptionInfoMap.put(entry.getKey(), new ConsumptionInfo()
+                    .setProductId(entry.getKey())
+                    .setConsumptionAmount(String.valueOf(entry.getValue())));
+        }
+        return consumptionInfoMap;
+    }
+
+}

+ 26 - 0
src/main/java/info/aspirecn/cloud/yysj/exception/UserNotFountException.java

@@ -0,0 +1,26 @@
+package info.aspirecn.cloud.yysj.exception;
+
+/**
+ * 无法发现用户信息异常
+ *
+ * @author dingliqiang
+ */
+public class UserNotFountException extends RuntimeException {
+
+    public UserNotFountException() {
+        super();
+    }
+
+    public UserNotFountException(String message) {
+        super(message);
+    }
+
+    public UserNotFountException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public UserNotFountException(Throwable cause) {
+        super(cause);
+    }
+
+}

+ 18 - 0
src/main/java/info/aspirecn/cloud/yysj/model/ResponseInfo.java

@@ -0,0 +1,18 @@
+package info.aspirecn.cloud.yysj.model;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author dingliqiang
+ */
+@Data
+@Accessors(chain = true)
+public class ResponseInfo {
+
+    /** 错误信息*/
+    private String message = "";
+    /** 返回结果*/
+    private Object data = "";
+
+}

+ 49 - 0
src/main/java/info/aspirecn/cloud/yysj/model/entity/Produce.java

@@ -0,0 +1,49 @@
+package info.aspirecn.cloud.yysj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * @author dingliqiang
+ */
+@Data
+@ToString
+@Accessors(chain = true)
+@TableName("yysj_produce")
+public class Produce {
+
+    /**
+     * 主键
+     */
+    private Integer id;
+
+    /**
+     * 产品名称
+     */
+    private String produceName;
+
+    /**
+     * 产品类型
+     */
+    private Integer type;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+}

+ 44 - 0
src/main/java/info/aspirecn/cloud/yysj/model/entity/ProduceRelevance.java

@@ -0,0 +1,44 @@
+package info.aspirecn.cloud.yysj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * @author dingliqiang
+ */
+@Data
+@ToString
+@Accessors(chain = true)
+@TableName("yysj_sjjh_produce_relevance")
+public class ProduceRelevance {
+
+    /**
+     * 主键
+     */
+    private Integer id;
+
+    /**
+     * 云验数据平台产品id
+     */
+    private Integer yysjId;
+
+    /**
+     * 数据交互平台产品id
+     */
+    private Integer sjjhId;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 修改时间
+     */
+    private Date updateTime;
+
+}

+ 57 - 0
src/main/java/info/aspirecn/cloud/yysj/model/entity/User.java

@@ -0,0 +1,57 @@
+package info.aspirecn.cloud.yysj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.ToString;
+
+import java.util.Date;
+
+/**
+ * @author dingliqiang
+ */
+@Data
+@ToString
+@TableName("yysj_user")
+public class User {
+
+    /**
+     * 主键
+     */
+    private Integer id;
+
+    /**
+     * 用户id,一般是国家物流平台交换码
+     */
+    private String userId;
+
+    /**
+     * 数据交互用户id
+     */
+    private Integer sjjhUserId;
+
+    /**
+     * 访问数据交互网关的 appid
+     */
+    private String appId;
+
+    /**
+     * 访问数据交互网关的 secret
+     */
+    private String secret;
+
+    /**
+     * 国家物流平台注册时的用户名
+     */
+    private String username;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+}

+ 33 - 0
src/main/java/info/aspirecn/cloud/yysj/model/entity/UserProduce.java

@@ -0,0 +1,33 @@
+package info.aspirecn.cloud.yysj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.ToString;
+import java.util.Date;
+
+@Data
+@ToString
+@TableName("yysj_user_produce")
+public class UserProduce {
+
+    /**
+     * 主键
+     */
+    private Integer id;
+
+    /**
+     * 用户id
+     */
+    private String userId;
+
+    /**
+     * 产品id
+     */
+    private Integer produceId;
+
+    /**
+     * 产品订购时间
+     */
+    private Date createTime;
+
+}

+ 34 - 0
src/main/java/info/aspirecn/cloud/yysj/model/remote/SjjhAccountInfo.java

@@ -0,0 +1,34 @@
+package info.aspirecn.cloud.yysj.model.remote;
+
+import lombok.Data;
+import lombok.ToString;
+
+/**
+ * @author dingliqiang
+ */
+@Data
+@ToString
+public class SjjhAccountInfo {
+
+    /**
+     * ID
+     */
+    private String id;
+    /**
+     * 用户ID
+     */
+    private String userId;
+    /**
+     * 余额
+     */
+    private String balance;
+    /**
+     * 更新时间
+     */
+    private String updatetime;
+    /**
+     * 创建时间
+     */
+    private String createtime;
+
+}

+ 26 - 0
src/main/java/info/aspirecn/cloud/yysj/model/response/AccountInfo.java

@@ -0,0 +1,26 @@
+package info.aspirecn.cloud.yysj.model.response;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+/**
+ * 账户信息
+ *
+ * @author dingliqiang
+ */
+@Data
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class AccountInfo {
+
+    @ApiModelProperty(value = "账户余额")
+    private String accountBalance = "";
+
+    @ApiModelProperty(value = "当日消费金额")
+    private String dailyConsumption = "";
+
+}

+ 31 - 0
src/main/java/info/aspirecn/cloud/yysj/model/response/ConsumptionInfo.java

@@ -0,0 +1,31 @@
+package info.aspirecn.cloud.yysj.model.response;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+/**
+ * 产品消费信息(当月消费及占比)
+ *
+ * @author dingliqiang
+ */
+@Data
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class ConsumptionInfo {
+
+    @ApiModelProperty(value = "产品ID")
+    @JsonIgnore
+    private Integer productId;
+
+    @ApiModelProperty(value = "产品名称")
+    private String productName;
+
+    @ApiModelProperty(value = "消费金额")
+    private String consumptionAmount;
+
+}

+ 26 - 0
src/main/java/info/aspirecn/cloud/yysj/model/response/ExceptionStatistics.java

@@ -0,0 +1,26 @@
+package info.aspirecn.cloud.yysj.model.response;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+/**
+ * 订单统计
+ *
+ * @author dingliqiang
+ */
+@Data
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class ExceptionStatistics {
+
+    @ApiModelProperty(value = "日期")
+    private String date;
+
+    @ApiModelProperty(value = "异常订单量")
+    private Long num = 0L;
+
+}

+ 37 - 0
src/main/java/info/aspirecn/cloud/yysj/model/response/OrderStatistics.java

@@ -0,0 +1,37 @@
+package info.aspirecn.cloud.yysj.model.response;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+/**
+ * 订单统计
+ *
+ * @author dingliqiang
+ */
+@Data
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+public class OrderStatistics {
+
+    @ApiModelProperty(value = "日期")
+    private String date;
+
+    @ApiModelProperty(value = "总量")
+    private Long sum;
+
+    @ApiModelProperty(value = "运单数量")
+    private Long waybill = 0L;
+
+    @ApiModelProperty(value = "司机数量")
+    private Long driver = 0L;
+
+    @ApiModelProperty(value = "车辆数量")
+    private Long vehicle = 0L;
+
+}

+ 29 - 0
src/main/java/info/aspirecn/cloud/yysj/model/response/Statistics.java

@@ -0,0 +1,29 @@
+package info.aspirecn.cloud.yysj.model.response;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+/**
+ * 订单统计
+ *
+ * @author dingliqiang
+ */
+@Data
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class Statistics {
+
+    @ApiModelProperty(value = "日期")
+    private String date;
+
+    @ApiModelProperty(value = "总订单量")
+    private Long sum = 0L;
+
+    @ApiModelProperty(value = "正常订单量")
+    private Long normalNum = 0L;
+
+}

+ 23 - 0
src/main/java/info/aspirecn/cloud/yysj/remote/FindUserInfoFeign.java

@@ -0,0 +1,23 @@
+package info.aspirecn.cloud.yysj.remote;
+
+import info.aspirecn.cloud.yysj.model.remote.SjjhAccountInfo;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * @author dingliqiang
+ */
+@FeignClient(value = "http://iov-sjjh-servicenode-order.iov-sjjh:8080",url = "http://iov-sjjh-servicenode-order.iov-sjjh:8080")
+//@FeignClient(value = "http://10.8.18.171:20181",url = "http://10.8.18.171:20181")
+public interface FindUserInfoFeign {
+
+    /**
+     * 获取用户账户信息
+     * @param userId 数据交互用户ID
+     * @return 用户信息
+     */
+    @GetMapping("/getUserAccount.do")
+    public SjjhAccountInfo getUserAccount(@RequestParam("userId") Integer userId);
+
+}

+ 38 - 0
src/main/java/info/aspirecn/cloud/yysj/service/AnalysisService.java

@@ -0,0 +1,38 @@
+package info.aspirecn.cloud.yysj.service;
+
+import info.aspirecn.cloud.yysj.model.response.AccountInfo;
+import info.aspirecn.cloud.yysj.model.response.ConsumptionInfo;
+import info.aspirecn.cloud.yysj.model.response.OrderStatistics;
+import java.util.List;
+
+/**
+ * @author dingliqiang
+ */
+public interface AnalysisService {
+
+    /**
+     * 统计云验平台用户调用总量、车辆、运单、司机信息
+     *
+     * @param userId 云验数据平台用户ID
+     * @return 总量、车辆、运单、司机信息
+     */
+    List<OrderStatistics> getOrderStatistics(String userId);
+
+    /**
+     * 获取用户当月订购产品的消费及占比信息
+     *
+     * @param userId 云验数据平台用户ID
+     * @return 账户当月订购产品的消费及占比信息
+     */
+    List<ConsumptionInfo> getConsumptionInfo(String userId);
+
+
+    /**
+     * 获取用户当日消费金额和账户余额
+     *
+     * @param userId 云验数据平台用户ID
+     * @return 当日消费金额、用户余额
+     */
+    AccountInfo getAccountInfo(String userId);
+
+}

+ 56 - 0
src/main/java/info/aspirecn/cloud/yysj/service/DbService.java

@@ -0,0 +1,56 @@
+package info.aspirecn.cloud.yysj.service;
+
+import info.aspirecn.cloud.yysj.model.entity.Produce;
+import info.aspirecn.cloud.yysj.model.entity.ProduceRelevance;
+import info.aspirecn.cloud.yysj.model.entity.User;
+import info.aspirecn.cloud.yysj.model.entity.UserProduce;
+import java.util.List;
+
+/**
+ * 数据库查询服务接口
+ *
+ * @author dingliqiang
+ */
+public interface DbService {
+
+
+    /**
+     * 查询用户信息
+     *
+     * @param userId 云验平台用户ID
+     * @return 云验平台用户信息
+     */
+    User getUserInfo(String userId);
+
+    /**
+     * 查询用户订购产品信息
+     * @param userId 云验平台用户ID
+     * @return 用户订购产品关联列表
+     */
+    List<UserProduce> getUserProduceList(String userId);
+
+    /**
+     * 查询用户云验平台与数据交互平台关联信息列表
+     *
+     * @param produceId 云验平台产品ID
+     * @return 关联信息列表
+     */
+    List<ProduceRelevance> getProduceRelevanceList(Integer produceId);
+
+    /**
+     * 根据多个产品ID查询对应的产品列表
+     *
+     * @param produceIdList 产品ID列表
+     * @return 云验平台产品列表
+     */
+    List<Produce> getProduceInfo(List<Integer> produceIdList);
+
+    /**
+     * 根据产品ID查询对应的产品信息
+     *
+     * @param produceId 云验数据平台产品ID
+     * @return 云验平台产品信息
+     */
+    Produce getProduceInfo(Integer produceId);
+
+}

+ 32 - 0
src/main/java/info/aspirecn/cloud/yysj/service/StatisticsService.java

@@ -0,0 +1,32 @@
+package info.aspirecn.cloud.yysj.service;
+
+import info.aspirecn.cloud.yysj.model.response.ExceptionStatistics;
+import info.aspirecn.cloud.yysj.model.response.Statistics;
+import java.util.List;
+
+/**
+ * @author dingliqiang
+ */
+public interface StatisticsService {
+
+    /**
+     * 获取一定时间内异常效验统计结果(获取不一致结果的统计信息)
+     *
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     * @param userId    云验平台用户ID
+     * @return 异常效验统计结果
+     */
+    List<ExceptionStatistics> getErrorStatistics(String startTime, String endTime, String userId);
+
+    /**
+     * 获取一定时间内总量与正常验统计结果(获取总数和一致结果的统计信息)
+     *
+     * @param startTime 开始时间
+     * @param endTime   结束时间
+     * @param userId    云验平台用户ID
+     * @return 总量与正常验统计结果
+     */
+    List<Statistics> getCountStatistics(String startTime, String endTime, String userId);
+
+}

+ 135 - 0
src/main/java/info/aspirecn/cloud/yysj/service/impl/AnalysisServiceImpl.java

@@ -0,0 +1,135 @@
+package info.aspirecn.cloud.yysj.service.impl;
+
+import info.aspirecn.cloud.yysj.dao.es.YysjGatewayFirstIndex;
+import info.aspirecn.cloud.yysj.dao.es.YysjGatewaySecondIndex;
+import info.aspirecn.cloud.yysj.exception.UserNotFountException;
+import info.aspirecn.cloud.yysj.model.entity.User;
+import info.aspirecn.cloud.yysj.model.entity.UserProduce;
+import info.aspirecn.cloud.yysj.model.remote.SjjhAccountInfo;
+import info.aspirecn.cloud.yysj.model.response.AccountInfo;
+import info.aspirecn.cloud.yysj.model.response.ConsumptionInfo;
+import info.aspirecn.cloud.yysj.model.response.OrderStatistics;
+import info.aspirecn.cloud.yysj.remote.FindUserInfoFeign;
+import info.aspirecn.cloud.yysj.service.AnalysisService;
+import info.aspirecn.cloud.yysj.service.DbService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import java.util.*;
+
+/**
+ * 数据分析,用于首页
+ *
+ * @author dingliqiang
+ */
+@Slf4j
+@Service
+public class AnalysisServiceImpl implements AnalysisService {
+
+    @Autowired
+    private FindUserInfoFeign findUserInfoFeign;
+
+    @Autowired
+    private DbService dbService;
+
+    @Autowired
+    private YysjGatewayFirstIndex yysjGatewayFirstIndex;
+
+    @Autowired
+    private YysjGatewaySecondIndex yysjGatewaySecondIndex;
+
+    /**
+     * 统计云验平台用户调用总量、车辆、运单、司机信息
+     *
+     * @param userId 云验数据平台用户ID
+     * @return 总量、车辆、运单、司机信息
+     */
+    @Override
+    public List<OrderStatistics> getOrderStatistics(String userId) {
+        return yysjGatewayFirstIndex.getTotalConsumptionAmount(userId);
+    }
+
+    /**
+     * @param userId 云验数据平台用户ID
+     * @return 账户当月订购产品的消费及占比信息
+     */
+    @Override
+    public List<ConsumptionInfo> getConsumptionInfo(String userId) {
+        List<ConsumptionInfo> consumptionList = new ArrayList<>();
+        // 获取用户信息
+        User user = dbService.getUserInfo(userId);
+        if (user == null) {
+            throw new UserNotFountException("无法查询到用户 " + userId + " 信息");
+        }
+        // 设置云验数据平台产品ID列表
+        List<Integer> yysjProduceIds = new ArrayList<>();
+        // 获取用户关联的产品信息
+        List<UserProduce> userProduceList = dbService.getUserProduceList(userId);
+        // 获取数据交互中的全部产品ID
+        for (UserProduce userProduce : userProduceList) {
+            yysjProduceIds.add(userProduce.getProduceId());
+        }
+        // 获取云验平台用户当月订购产品的消费及占比信息
+        Map<Integer, ConsumptionInfo> consumptionInfoMap = yysjGatewaySecondIndex.getConsumptionInfo(userId,
+                userProduceList, yysjProduceIds.toArray(new Integer[yysjProduceIds.size()]));
+        // 根据产品ID到产品表中查询对应的产品名称
+        for (Map.Entry<Integer, ConsumptionInfo> entry : consumptionInfoMap.entrySet()) {
+            // 从数据库中查询产品名称
+            String produceName = dbService.getProduceInfo(entry.getValue().getProductId()).getProduceName();
+            // 设置产品名称
+            entry.getValue().setProductName(produceName);
+            // 处理价格单位(从厘转换为元)
+            String price = priceProcess(entry.getValue().getConsumptionAmount());
+            entry.getValue().setConsumptionAmount(price);
+            // 添加到列表
+            consumptionList.add(entry.getValue());
+        }
+        return consumptionList;
+    }
+
+    /**
+     * 获取用户当日消费金额和账户余额
+     *
+     * @param userId 云验数据平台用户ID
+     * @return 当日消费金额、用户余额
+     */
+    @Override
+    public AccountInfo getAccountInfo(String userId) {
+        // 设置返回对象
+        AccountInfo accountInfo = new AccountInfo();
+        // 获取用户信息
+        User user = dbService.getUserInfo(userId);
+        if (user == null) {
+            throw new UserNotFountException("无法查询到用户 " + userId + " 信息");
+        }
+        // 从 ES 查询账户当日消费数据
+        Long dailyConsumption = yysjGatewaySecondIndex.getAccountConsumptionAmount(userId);
+        accountInfo.setDailyConsumption(priceProcess(String.valueOf(dailyConsumption)));
+        // 从数据库查询账户余额
+        SjjhAccountInfo sjjhAccountInfo = findUserInfoFeign.getUserAccount(user.getSjjhUserId());
+        accountInfo.setAccountBalance(priceProcess(sjjhAccountInfo.getBalance()));
+        return accountInfo;
+    }
+
+    /**
+     * 处理价格单位
+     */
+    private String priceProcess(String price) {
+        // 获取签名部分
+        if (price.length() == 1) {
+            return "0.00" + price;
+        } else if (price.length() == 2) {
+            return "0.0" + price;
+        } else if (price.length() == 3) {
+            return "0." + price;
+        }
+        // 获取签名部分
+        String pricePre = StringUtils.substring(price, 0, price.length() - 3);
+        // 获取后面部分
+        String pricePost = StringUtils.substring(price, price.length() - 3, price.length());
+        // 拼接
+        return pricePre + "." + pricePost;
+    }
+
+}

+ 110 - 0
src/main/java/info/aspirecn/cloud/yysj/service/impl/DbServiceImpl.java

@@ -0,0 +1,110 @@
+package info.aspirecn.cloud.yysj.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import info.aspirecn.cloud.yysj.dao.db.ProduceMapper;
+import info.aspirecn.cloud.yysj.dao.db.ProduceRelevanceMapper;
+import info.aspirecn.cloud.yysj.dao.db.UserMapper;
+import info.aspirecn.cloud.yysj.dao.db.UserProduceMapper;
+import info.aspirecn.cloud.yysj.exception.UserNotFountException;
+import info.aspirecn.cloud.yysj.model.entity.Produce;
+import info.aspirecn.cloud.yysj.model.entity.ProduceRelevance;
+import info.aspirecn.cloud.yysj.model.entity.User;
+import info.aspirecn.cloud.yysj.model.entity.UserProduce;
+import info.aspirecn.cloud.yysj.service.DbService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 云验平台数据库查询服务
+ *
+ * @author dingliqiang
+ */
+@Service
+public class DbServiceImpl implements DbService {
+
+    @Autowired
+    private UserProduceMapper userProduceMapper;
+
+    @Autowired
+    private ProduceRelevanceMapper produceRelevanceMapper;
+
+    @Autowired
+    private ProduceMapper produceMapper;
+
+    @Autowired
+    private UserMapper userMapper;
+
+    /**
+     * 查询用户信息
+     *
+     * @param userId 云验平台用户ID
+     * @return 云验平台用户信息
+     */
+    @Override
+    public User getUserInfo(String userId) {
+        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
+        userQueryWrapper.eq("userId", userId);
+        User user = userMapper.selectOne(userQueryWrapper);
+        if (user == null) {
+            throw new UserNotFountException("无法查找到该用户");
+        }
+        return user;
+    }
+
+    /**
+     * 查询用户订购产品信息
+     *
+     * @return 用户订购产品关联列表
+     */
+    @Override
+    public List<UserProduce> getUserProduceList(String userId) {
+        QueryWrapper<UserProduce> userProduceQueryWrapper = new QueryWrapper<>();
+        userProduceQueryWrapper.eq("userId", userId);
+        List<UserProduce> yysjProduceList = userProduceMapper.selectList(userProduceQueryWrapper);
+        return new ArrayList<>(yysjProduceList);
+    }
+
+    /**
+     * 查询用户云验平台与数据交互平台关联信息列表
+     *
+     * @return 关联信息列表
+     */
+    @Override
+    public List<ProduceRelevance> getProduceRelevanceList(Integer produceId) {
+        QueryWrapper<ProduceRelevance> produceRelevanceQueryWrapper = new QueryWrapper<>();
+        produceRelevanceQueryWrapper.eq("yysjId", produceId);
+        List<ProduceRelevance> sjjhProduceIdList = produceRelevanceMapper.selectList(produceRelevanceQueryWrapper);
+        return new ArrayList<>(sjjhProduceIdList);
+    }
+
+    /**
+     * 根据多个产品ID查询对应的产品列表
+     *
+     * @param produceIdList 产品ID列表
+     * @return 云验平台产品列表
+     */
+    @Override
+    public List<Produce> getProduceInfo(List<Integer> produceIdList) {
+        QueryWrapper<Produce> produceQueryWrapper = new QueryWrapper<>();
+        produceQueryWrapper.in("id", produceIdList);
+        List<Produce> produceList = produceMapper.selectList(produceQueryWrapper);
+        return new ArrayList<>(produceList);
+    }
+
+    /**
+     * 根据产品ID查询对应的产品信息
+     *
+     * @param produceId 云验数据平台产品ID
+     * @return 云验平台产品信息
+     */
+    @Override
+    public Produce getProduceInfo(Integer produceId) {
+        QueryWrapper<Produce> produceQueryWrapper = new QueryWrapper<>();
+        produceQueryWrapper.eq("id", produceId);
+        return produceMapper.selectOne(produceQueryWrapper);
+    }
+
+}

+ 32 - 0
src/main/java/info/aspirecn/cloud/yysj/service/impl/StatisticsServiceImpl.java

@@ -0,0 +1,32 @@
+package info.aspirecn.cloud.yysj.service.impl;
+
+import info.aspirecn.cloud.yysj.dao.es.YysjGatewaySecondIndex;
+import info.aspirecn.cloud.yysj.model.response.ExceptionStatistics;
+import info.aspirecn.cloud.yysj.model.response.Statistics;
+import info.aspirecn.cloud.yysj.service.StatisticsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import java.util.List;
+
+/**
+ * 数据分析,用于统计分析
+ *
+ * @author dingliqiang
+ */
+@Service
+public class StatisticsServiceImpl implements StatisticsService {
+
+    @Autowired
+    private YysjGatewaySecondIndex yysjGatewaySecondIndex;
+
+    @Override
+    public List<Statistics> getCountStatistics(String startTime, String endTime, String userId) {
+        return yysjGatewaySecondIndex.getCountStatistics(startTime, endTime, userId);
+    }
+
+    @Override
+    public List<ExceptionStatistics> getErrorStatistics(String startTime, String endTime, String userId) {
+        return yysjGatewaySecondIndex.getErrorStatistics(startTime, endTime, userId);
+    }
+
+}

+ 46 - 0
src/main/resources/application.yml

@@ -0,0 +1,46 @@
+#spring:
+#  datasource:
+#    url: jdbc:mysql://10.8.17.119:32196/cloud-yysj?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
+#    username: root
+#    driver-class-name: com.mysql.cj.jdbc.Driver
+#    type: com.zaxxer.hikari.HikariDataSource
+#    hikari:
+#      minimum-idle: 5
+#      maximum-pool-size: 15
+#      auto-commit: true
+#      idle-timeout: 30000
+#      pool-name: DatebookHikariCP
+#      max-lifetime: 1800000
+#      connection-timeout: 30000
+#      password: 123456
+#
+#
+#mybatis-plus:
+#  configuration:
+#    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
+#    #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+#    # 驼峰下划线转换
+#    map-underscore-to-camel-case: false
+#    # 配置的缓存的全局开关
+#    cache-enabled: true
+#    # 延时加载的开关
+#    lazy-loading-enabled: true
+#    # 开启的话,延时加载一个属性时会加载该对象全部属性,否则按需加载属性
+#    multiple-result-sets-enabled: true
+#    use-generated-keys: true
+#    default-statement-timeout: 60
+#    default-fetch-size: 100
+#
+#elasticsearch:
+#  schema: http
+#  address: 10.8.17.119:32482
+#  #address: 192.168.16.41:30002,192.168.16.41:31821,192.168.16.41:30097
+#  connectTimeout: 5000
+#  socketTimeout: 5000
+#  connectionRequestTimeout: 5000
+#  maxConnectNum: 100
+#  maxConnectPerRoute: 100
+#  index:
+#    yysjFirst: access-yysj-gateway-first-log-cloud-yysj*
+#    yysjSecond: access-yysj-gateway-second-log-cloud-yysj*
+#    sjjh: iov_sjjh_access_test1*

+ 39 - 0
src/main/resources/bootstrap.yml

@@ -0,0 +1,39 @@
+#ConfigMap 配置参数
+server:
+  port: 8080
+spring:
+  application:
+    name: cloud-yysj-analysis-info
+  cloud:
+    kubernetes:
+      reload:
+        enabled: true
+        mode: polling
+        period: 10000
+        strategy: refresh
+        monitoring-secrets: true
+      config:
+        enabled: true
+        enableApi: true
+        sources:
+          - namespace: cloud-yysj
+            name: ${spring.application.name}
+
+#监控配置参数
+management:
+  server:
+    port: 8081
+  endpoint:
+    restart:
+      enabled: true
+    health:
+      show-details: always
+  endpoints:
+    enabled-by-default: true
+    web:
+      exposure:
+        include: "*"
+
+info:
+  name: 账户数据分析服务(首页、统计分析页面)
+  version: 1.0.0