weijianghai 2 жил өмнө
parent
commit
5028cb1af4
54 өөрчлөгдсөн 2716 нэмэгдсэн , 1234 устгасан
  1. 55 5
      pom.xml
  2. 90 0
      src/main/java/com/nokia/common/R.java
  3. 10 0
      src/main/java/com/nokia/common/exception/BizException.java
  4. 22 0
      src/main/java/com/nokia/common/exception/MyRuntimeException.java
  5. 3 8
      src/main/java/com/nokia/hb/HbApplication.java
  6. 22 0
      src/main/java/com/nokia/hb/config/MybatisPlusConfig.java
  7. 25 0
      src/main/java/com/nokia/hb/config/ValidatorConfig.java
  8. 85 0
      src/main/java/com/nokia/hb/config/web/ControllerExceptionHandler.java
  9. 2 1
      src/main/java/com/nokia/hb/config/web/LoginHandlerInterceptor.java
  10. 3 3
      src/main/java/com/nokia/hb/config/web/MyWebMvcConfigurer.java
  11. 30 0
      src/main/java/com/nokia/hb/controller/AreaController.java
  12. 33 0
      src/main/java/com/nokia/hb/controller/AuthController.java
  13. 30 0
      src/main/java/com/nokia/hb/controller/IndicatorController.java
  14. 53 0
      src/main/java/com/nokia/hb/controller/IndicatorTemplateController.java
  15. 31 0
      src/main/java/com/nokia/hb/controller/PmController.java
  16. 90 90
      src/main/java/com/nokia/hb/controller/TemplateController.java
  17. 45 0
      src/main/java/com/nokia/hb/dao/entity/IndicatorTemplate.java
  18. 35 0
      src/main/java/com/nokia/hb/dao/entity/IndicatorTemplateItem.java
  19. 31 0
      src/main/java/com/nokia/hb/dao/entity/PerCfgArea.java
  20. 43 0
      src/main/java/com/nokia/hb/dao/entity/PerCfgCell.java
  21. 38 0
      src/main/java/com/nokia/hb/dao/entity/PerCfgIndicator.java
  22. 38 0
      src/main/java/com/nokia/hb/dao/entity/User.java
  23. 34 0
      src/main/java/com/nokia/hb/dao/entity/UserArea.java
  24. 69 0
      src/main/java/com/nokia/hb/dao/mapper/IndicatorTemplateItemMapper.java
  25. 64 0
      src/main/java/com/nokia/hb/dao/mapper/IndicatorTemplateMapper.java
  26. 27 0
      src/main/java/com/nokia/hb/dao/mapper/PerCfgAreaMapper.java
  27. 83 0
      src/main/java/com/nokia/hb/dao/mapper/PerCfgCellMapper.java
  28. 28 0
      src/main/java/com/nokia/hb/dao/mapper/PerCfgIndicatorMapper.java
  29. 28 0
      src/main/java/com/nokia/hb/dao/mapper/UserAreaMapper.java
  30. 27 0
      src/main/java/com/nokia/hb/dao/mapper/UserMapper.java
  31. 8 52
      src/main/java/com/nokia/hb/pojo/RetData.java
  32. 11 0
      src/main/java/com/nokia/hb/pojo/bo/IndicatorTemplateItemBo.java
  33. 22 0
      src/main/java/com/nokia/hb/pojo/dto/AddTemplateDto.java
  34. 18 0
      src/main/java/com/nokia/hb/pojo/dto/DeleteTemplateDto.java
  35. 20 0
      src/main/java/com/nokia/hb/pojo/dto/LoginDto.java
  36. 44 0
      src/main/java/com/nokia/hb/pojo/dto/RenderTableDto.java
  37. 15 0
      src/main/java/com/nokia/hb/pojo/enums/SearchTypeEnum.java
  38. 16 0
      src/main/java/com/nokia/hb/pojo/enums/TimeTypeEnum.java
  39. 14 0
      src/main/java/com/nokia/hb/pojo/vo/LoginVo.java
  40. 42 0
      src/main/java/com/nokia/hb/service/AreaService.java
  41. 52 0
      src/main/java/com/nokia/hb/service/AuthService.java
  42. 0 0
      src/main/java/com/nokia/hb/service/DataViewDao.java
  43. 42 0
      src/main/java/com/nokia/hb/service/IndicatorService.java
  44. 96 0
      src/main/java/com/nokia/hb/service/IndicatorTemplateService.java
  45. 88 0
      src/main/java/com/nokia/hb/service/PmService.java
  46. 815 815
      src/main/java/com/nokia/hb/utils/DbUtil.java
  47. 18 0
      src/main/java/com/nokia/hb/utils/SessionUtil.java
  48. 3 0
      src/main/resources/application-dev.yml
  49. 8 0
      src/main/resources/application-prod.yml
  50. 7 3
      src/main/resources/application.yml
  51. 1 1
      src/main/resources/logback-spring.xml
  52. 12 13
      src/main/resources/templates/login.html
  53. 117 243
      src/main/resources/templates/template.html
  54. 73 0
      src/test/java/com/nokia/hb/MybatisPlusGenerator.java

+ 55 - 5
pom.xml

@@ -5,7 +5,7 @@
 	<parent>
 		<groupId>org.springframework.boot</groupId>
 		<artifactId>spring-boot-starter-parent</artifactId>
-		<version>2.6.9</version>
+		<version>2.6.14</version>
 		<relativePath/> <!-- lookup parent from repository -->
 	</parent>
 	<groupId>com.nokia</groupId>
@@ -19,14 +19,32 @@
 		<maven.compiler.target>${java.version}</maven.compiler.target>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 		<project.reporting.outputEncoding>${project.build.sourceEncoding}</project.reporting.outputEncoding>
+		<mybatis-plus.version>3.5.3.1</mybatis-plus.version>
 		<skipTests>true</skipTests>
 	</properties>
 
+	<dependencyManagement>
+		<dependencies>
+			<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui -->
+			<dependency>
+				<groupId>org.springdoc</groupId>
+				<artifactId>springdoc-openapi-ui</artifactId>
+				<version>1.6.9</version>
+			</dependency>
+			<dependency>
+				<groupId>io.swagger.core.v3</groupId>
+				<artifactId>swagger-annotations</artifactId>
+				<version>2.2.2</version>
+			</dependency>
+			<dependency>
+				<groupId>io.swagger.core.v3</groupId>
+				<artifactId>swagger-models</artifactId>
+				<version>2.2.2</version>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
 	<dependencies>
-		<dependency>
-			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-jdbc</artifactId>
-		</dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-thymeleaf</artifactId>
@@ -51,6 +69,10 @@
 			<artifactId>spring-boot-starter-test</artifactId>
 			<scope>test</scope>
 		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-validation</artifactId>
+		</dependency>
 		<dependency>
 			<groupId>org.postgresql</groupId>
 			<artifactId>postgresql</artifactId>
@@ -73,6 +95,34 @@
 			<artifactId>commons-lang3</artifactId>
 			<version>3.12.0</version>
 		</dependency>
+		<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
+		<dependency>
+			<groupId>com.baomidou</groupId>
+			<artifactId>mybatis-plus-boot-starter</artifactId>
+			<version>${mybatis-plus.version}</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generator -->
+		<dependency>
+			<groupId>com.baomidou</groupId>
+			<artifactId>mybatis-plus-generator</artifactId>
+			<version>${mybatis-plus.version}</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity-engine-core -->
+		<dependency>
+			<groupId>org.apache.velocity</groupId>
+			<artifactId>velocity-engine-core</artifactId>
+			<version>2.3</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-openapi3-spring-boot-starter -->
+		<dependency>
+			<groupId>com.github.xiaoymin</groupId>
+			<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
+			<version>4.0.0</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springdoc</groupId>
+			<artifactId>springdoc-openapi-ui</artifactId>
+		</dependency>
 	</dependencies>
 
 	<build>

+ 90 - 0
src/main/java/com/nokia/common/R.java

@@ -0,0 +1,90 @@
+package com.nokia.common;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.slf4j.MDC;
+
+/**
+ * 返回值的统一包装
+ */
+@Data
+public class R<T> {
+    @Schema(description = "是否成功")
+    private Boolean success;
+    @Schema(description = "业务码")
+    private Integer code;
+    @Schema(description = "提示信息", example = "成功")
+    private String message;
+    @Schema(description = "数据")
+    private T data = null;
+
+    /**
+     * 私有化构造方法,不允许在外部实例化
+     */
+    private R() {
+    }
+
+    /**
+     * 成功的静态方法
+     *
+     * @return R实例
+     */
+    public static <T> R<T> ok() {
+        R<T> r = new R<>();
+        r.setSuccess(true);
+        r.setCode(1);
+        r.setMessage("成功");
+        return r;
+    }
+
+    public static <T> R<T> ok(T data) {
+        R<T> r = new R<>();
+        r.setSuccess(true);
+        r.setCode(1);
+        r.setMessage("成功");
+        r.setData(data);
+        return r;
+    }
+
+    /**
+     * 失败的静态方法
+     *
+     * @return R实例
+     */
+    public static <T> R<T> error() {
+        R<T> r = new R<>();
+        r.setSuccess(false);
+        r.setCode(0);
+        r.setMessage("失败" + MDC.get("traceId"));
+        return r;
+    }
+
+    public static <T> R<T> error(String message) {
+        R<T> r = new R<>();
+        r.setSuccess(false);
+        r.setCode(0);
+        r.setMessage(message);
+        return r;
+    }
+
+    public R<T> success(Boolean success) {
+        this.setSuccess(success);
+        return this;
+    }
+
+
+    public R<T> code(Integer code) {
+        this.setCode(code);
+        return this;
+    }
+
+    public R<T> data(T object) {
+        this.setData(object);
+        return this;
+    }
+
+    public R<T> message(String message) {
+        this.setMessage(message);
+        return this;
+    }
+}

+ 10 - 0
src/main/java/com/nokia/common/exception/BizException.java

@@ -0,0 +1,10 @@
+package com.nokia.common.exception;
+
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+public class BizException extends RuntimeException{
+    public BizException(String message) {
+        super(message);
+    }
+}

+ 22 - 0
src/main/java/com/nokia/common/exception/MyRuntimeException.java

@@ -0,0 +1,22 @@
+package com.nokia.common.exception;
+
+public class MyRuntimeException extends RuntimeException{
+    public MyRuntimeException() {
+    }
+
+    public MyRuntimeException(String message) {
+        super(message);
+    }
+
+    public MyRuntimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public MyRuntimeException(Throwable cause) {
+        super(cause);
+    }
+
+    public MyRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

+ 3 - 8
src/main/java/com/nokia/hb/HbApplication.java

@@ -1,16 +1,11 @@
 package com.nokia.hb;
 
 import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 
 @SpringBootApplication
-@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
 public class HbApplication {
-
-	public static void main(String[] args) {
-		SpringApplication.run(HbApplication.class, args);
-	}
-
+    public static void main(String[] args) {
+        SpringApplication.run(HbApplication.class, args);
+    }
 }

+ 22 - 0
src/main/java/com/nokia/hb/config/MybatisPlusConfig.java

@@ -0,0 +1,22 @@
+package com.nokia.hb.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * mybatis +配置
+ *
+ */
+@Configuration
+public class MybatisPlusConfig {
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        // 添加分页拦截器
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
+        return interceptor;
+    }
+}

+ 25 - 0
src/main/java/com/nokia/hb/config/ValidatorConfig.java

@@ -0,0 +1,25 @@
+package com.nokia.hb.config;
+
+import org.hibernate.validator.HibernateValidator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+/**
+ * 校验配置
+ */
+@Configuration
+public class ValidatorConfig
+{
+    @Bean
+    public Validator validator()
+    {
+        try (ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class).configure()
+                .failFast(true).buildValidatorFactory()) {
+            return validatorFactory.getValidator();
+        }
+    }
+}

+ 85 - 0
src/main/java/com/nokia/hb/config/web/ControllerExceptionHandler.java

@@ -0,0 +1,85 @@
+package com.nokia.hb.config.web;
+
+import com.nokia.common.R;
+import com.nokia.common.exception.BizException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.TypeMismatchException;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageConversionException;
+import org.springframework.validation.BindException;
+import org.springframework.validation.FieldError;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MissingRequestValueException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.validation.ValidationException;
+
+/**
+ * 请求异常处理
+ */
+@Slf4j
+@RestControllerAdvice
+public class ControllerExceptionHandler
+{
+    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+    public ResponseEntity<Object> httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e)
+    {
+        log.warn(e.getMessage());
+        return ResponseEntity.ok().body(R.error().message(e.getMessage()));
+    }
+
+    @ExceptionHandler(MissingRequestValueException.class)
+    public ResponseEntity<Object> missingRequestValueExceptionHandler(MissingRequestValueException e)
+    {
+        log.warn(e.getMessage());
+        return ResponseEntity.ok().body(R.error().message(e.getMessage()));
+    }
+
+    @ExceptionHandler(HttpMessageConversionException.class)
+    public ResponseEntity<Object> httpMessageConversionExceptionHandler(HttpMessageConversionException e)
+    {
+        log.warn(e.getMessage());
+        return ResponseEntity.ok().body(R.error().message(e.getMessage()));
+    }
+
+    @ExceptionHandler(TypeMismatchException.class)
+    public ResponseEntity<Object> typeMismatchExceptionHandler(TypeMismatchException e)
+    {
+        log.warn(e.getMessage());
+        return ResponseEntity.ok().body(R.error().message(e.getMessage()));
+    }
+
+    @ExceptionHandler(BindException.class)
+    public ResponseEntity<Object> bindExceptionHandler(BindException e)
+    {
+        FieldError fieldError = e.getBindingResult().getFieldError();
+        String message = "";
+        if (fieldError != null)
+        {
+            message = fieldError.getDefaultMessage();
+        }
+        log.warn(message);
+        return ResponseEntity.ok().body(R.error().message(message));
+    }
+
+    @ExceptionHandler(ValidationException.class)
+    public ResponseEntity<Object> validationExceptionHandler(ValidationException e)
+    {
+        log.warn(e.getMessage());
+        return ResponseEntity.ok().body(R.error().message(e.getMessage()));
+    }
+
+    @ExceptionHandler(BizException.class)
+    public ResponseEntity<Object> bizExceptionHandler(BizException e)
+    {
+        return ResponseEntity.ok().body(R.error(e.getMessage()));
+    }
+
+    @ExceptionHandler(Exception.class)
+    public ResponseEntity<Object> exceptionHandler(Exception e)
+    {
+        log.error("╭( ′• o •′ )╭☞ 发生错误了 {}", e.getMessage(), e);
+        return ResponseEntity.ok().body(R.error());
+    }
+}

+ 2 - 1
src/main/java/com/nokia/hb/config/web/LoginHandlerInterceptor.java

@@ -1,5 +1,6 @@
 package com.nokia.hb.config.web;
 
+import com.nokia.hb.utils.SessionUtil;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.servlet.HandlerInterceptor;
@@ -26,7 +27,7 @@ public class LoginHandlerInterceptor implements HandlerInterceptor {
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         HttpSession session = request.getSession();
-        Object username = session.getAttribute("username");
+        Object username = SessionUtil.getUsername(session);
         log.debug("username: {}", username);
         // 用户名为空重定向登录页面
         if (username == null) {

+ 3 - 3
src/main/java/com/nokia/hb/config/web/MyWebMvcConfigurer.java

@@ -21,12 +21,12 @@ public class MyWebMvcConfigurer implements WebMvcConfigurer {
     public void addInterceptors(InterceptorRegistry registry) {
         // 添加请求日志拦截
         registry.addInterceptor(new RequestLogHandlerInterceptor())
-                .addPathPatterns("/**")
-                .excludePathPatterns("/", "/login", "/template", "/error", "/js/**", "/html/**", "/image/**", "/css/**");
+                .addPathPatterns("/api/**");
         // 添加登录拦截
         registry.addInterceptor(new LoginHandlerInterceptor(timeoutSeconds))
                 .addPathPatterns("/**")
-                .excludePathPatterns("/login", "/error", "/userLogin", "/js/**", "/html/**", "/image/**", "/css/**");
+                .excludePathPatterns("/login", "/error", "/api/userLogin", "/js/**", "/html/**", "/image/**", "/css/**",
+                        "/swagger-ui/**", "/v3/**", "/webjars/**", "/doc**");
     }
 
     /**

+ 30 - 0
src/main/java/com/nokia/hb/controller/AreaController.java

@@ -0,0 +1,30 @@
+package com.nokia.hb.controller;
+
+import com.nokia.common.R;
+import com.nokia.hb.pojo.TreeNode;
+import com.nokia.hb.service.AreaService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@Tag(name = "地区")
+@RestController
+public class AreaController {
+    private final AreaService areaService;
+
+    public AreaController(AreaService areaService) {
+        this.areaService = areaService;
+    }
+
+    /**
+     * 查询地市树形结构
+     */
+    @Operation(summary = "查询地市树形结构")
+    @PostMapping("/api/initTreeCitys")
+    public R<List<TreeNode>> initTreeCitys() {
+        return areaService.initTreeCitys();
+    }
+}

+ 33 - 0
src/main/java/com/nokia/hb/controller/AuthController.java

@@ -0,0 +1,33 @@
+package com.nokia.hb.controller;
+
+import com.nokia.common.R;
+import com.nokia.hb.pojo.dto.LoginDto;
+import com.nokia.hb.pojo.vo.LoginVo;
+import com.nokia.hb.service.AuthService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpSession;
+import javax.validation.Valid;
+
+@Tag(name = "授权")
+@RestController
+public class AuthController {
+    private final AuthService authService;
+
+    public AuthController(AuthService authService) {
+        this.authService = authService;
+    }
+
+    /**
+     * 用户登录
+     */
+    @Operation(summary = "登录")
+    @PostMapping("/api/userLogin")
+    public R<LoginVo> userLogin(@Valid @RequestBody LoginDto dto, HttpSession session) {
+        return authService.userLogin(dto, session);
+    }
+}

+ 30 - 0
src/main/java/com/nokia/hb/controller/IndicatorController.java

@@ -0,0 +1,30 @@
+package com.nokia.hb.controller;
+
+import com.nokia.common.R;
+import com.nokia.hb.pojo.TreeNode;
+import com.nokia.hb.service.IndicatorService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@Tag(name = "指标")
+@RestController
+public class IndicatorController {
+    private final IndicatorService indicatorService;
+
+    public IndicatorController(IndicatorService indicatorService) {
+        this.indicatorService = indicatorService;
+    }
+
+    /**
+     * 查询指标树形结构
+     */
+    @Operation(summary = "查询指标树形结构")
+    @PostMapping("/api/initTreeIndicator")
+    public R<List<TreeNode>> initTreeIndicator() {
+        return indicatorService.initTreeIndicator();
+    }
+}

+ 53 - 0
src/main/java/com/nokia/hb/controller/IndicatorTemplateController.java

@@ -0,0 +1,53 @@
+package com.nokia.hb.controller;
+
+import com.nokia.common.R;
+import com.nokia.hb.pojo.TreeNode;
+import com.nokia.hb.pojo.dto.AddTemplateDto;
+import com.nokia.hb.pojo.dto.DeleteTemplateDto;
+import com.nokia.hb.service.IndicatorTemplateService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpSession;
+import javax.validation.Valid;
+import java.util.List;
+
+@Tag(name = "指标模板")
+@RestController
+public class IndicatorTemplateController {
+    private final IndicatorTemplateService indicatorTemplateService;
+
+    public IndicatorTemplateController(IndicatorTemplateService indicatorTemplateService) {
+        this.indicatorTemplateService = indicatorTemplateService;
+    }
+
+    /**
+     * 获取指标模板
+     */
+    @Operation(summary = "获取指标模板")
+    @PostMapping("/api/initTreeIndicatorTemplate")
+    public R<List<TreeNode>> initTreeIndicatorTemplate(HttpSession session) {
+        return indicatorTemplateService.initTreeIndicatorTemplate(session);
+    }
+
+    /**
+     * 添加指标模板
+     */
+    @Operation(summary = "添加指标模板")
+    @PostMapping("/api/addTemplate")
+    public R<Object> addTemplate(@Valid @RequestBody AddTemplateDto dto, HttpSession session) {
+        return indicatorTemplateService.addTemplate(dto, session);
+    }
+
+    /**
+     * 删除指标模板
+     */
+    @Operation(summary = "删除指标模板")
+    @PostMapping("/api/deleteTemplate")
+    public R<Object> deleteTemplate(@Valid @RequestBody DeleteTemplateDto dto, HttpSession session) {
+        return indicatorTemplateService.deleteTemplate(dto, session);
+    }
+}

+ 31 - 0
src/main/java/com/nokia/hb/controller/PmController.java

@@ -0,0 +1,31 @@
+package com.nokia.hb.controller;
+
+import com.nokia.common.R;
+import com.nokia.hb.pojo.RetData;
+import com.nokia.hb.pojo.dto.RenderTableDto;
+import com.nokia.hb.service.PmService;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpSession;
+import javax.validation.Valid;
+
+@Tag(name = "pm数据")
+@RestController
+public class PmController {
+    private final PmService pmService;
+
+    public PmController(PmService pmService) {
+        this.pmService = pmService;
+    }
+
+    /**
+     * 查询pm数据
+     */
+    @PostMapping("/api/renderTable")
+    public R<RetData> renderTable(@Valid @RequestBody RenderTableDto dto, HttpSession session) {
+        return pmService.renderTable(dto, session);
+    }
+}

+ 90 - 90
src/main/java/com/nokia/hb/controller/TemplateController.java

@@ -1,90 +1,90 @@
-package com.nokia.hb.controller;
-
-import com.nokia.hb.pojo.RetData;
-import com.nokia.hb.pojo.TreeNode;
-import com.nokia.hb.utils.DbUtil;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpSession;
-import java.util.List;
-
-@RestController
-public class TemplateController {
-    /**
-     * 用户登录
-     */
-    @PostMapping("userLogin")
-    public Object userLogin(String username, String password, HttpSession session) {
-        return DbUtil.userLogin(username, password, session);
-    }
-
-    /**
-     * 查询地市树形结构
-     *
-     * @return {@link List}<{@link TreeNode}>
-     */
-    @GetMapping("initTreeCitys")
-    public List<TreeNode> initTreeCitys() {
-        return DbUtil.initTreeCitys();
-    }
-
-    /**
-     * 查询指标树形结构
-     *
-     * @return {@link List}<{@link TreeNode}>
-     */
-    @GetMapping("initTreeIndicator")
-    public List<TreeNode> initTreeIndicator() {
-        return DbUtil.initTreeIndicator();
-    }
-
-    /**
-     * 查询pm数据
-     *
-     * @param citys      地市
-     * @param quxians    区县
-     * @param indicators 指标
-     * @param ttype      时间单位
-     * @param sdate      时间范围
-     * @param condition  条件
-     * @param searchType 搜索类型
-     * @param session    会话
-     * @return {@link RetData}
-     */
-    @PostMapping("renderTable")
-    public RetData renderTable(String citys, String quxians, String indicators, String ttype, String sdate,
-                               String condition, String searchType, HttpSession session) {
-        return DbUtil.renderTable(citys, quxians, indicators, ttype, sdate, condition, searchType, session);
-    }
-
-    /**
-     * 添加指标模板
-     *
-     * @param templateName 指标模板名称
-     * @param indicators   指标
-     */
-    @PostMapping("addTemplate")
-    public Object addTemplate(String templateName, String indicators, HttpSession session) {
-        return DbUtil.addTemplate(templateName, indicators, session);
-    }
-
-    /**
-     * 获取指标模板
-     */
-    @GetMapping("initTreeIndicatorTemplate")
-    public List<TreeNode> initTreeIndicatorTemplate(HttpSession session) {
-        return DbUtil.initTreeIndicatorTemplate(session);
-    }
-
-    /**
-     * 删除指标模板
-     *
-     * @param ids 模板id
-     */
-    @PostMapping("deleteTemplate")
-    public Object deleteTemplate(String ids) {
-        return DbUtil.deleteTemplate(ids);
-    }
-}
+//package com.nokia.hb.controller;
+//
+//import com.nokia.hb.pojo.RetData;
+//import com.nokia.hb.pojo.TreeNode;
+//import com.nokia.hb.utils.DbUtil;
+//import org.springframework.web.bind.annotation.GetMapping;
+//import org.springframework.web.bind.annotation.PostMapping;
+//import org.springframework.web.bind.annotation.RestController;
+//
+//import javax.servlet.http.HttpSession;
+//import java.util.List;
+//
+//@RestController
+//public class TemplateController {
+//    /**
+//     * 用户登录
+//     */
+//    @PostMapping("userLogin")
+//    public Object userLogin(String username, String password, HttpSession session) {
+//        return DbUtil.userLogin(username, password, session);
+//    }
+//
+//    /**
+//     * 查询地市树形结构
+//     *
+//     * @return {@link List}<{@link TreeNode}>
+//     */
+//    @GetMapping("initTreeCitys")
+//    public List<TreeNode> initTreeCitys() {
+//        return DbUtil.initTreeCitys();
+//    }
+//
+//    /**
+//     * 查询指标树形结构
+//     *
+//     * @return {@link List}<{@link TreeNode}>
+//     */
+//    @GetMapping("initTreeIndicator")
+//    public List<TreeNode> initTreeIndicator() {
+//        return DbUtil.initTreeIndicator();
+//    }
+//
+//    /**
+//     * 查询pm数据
+//     *
+//     * @param citys      地市
+//     * @param quxians    区县
+//     * @param indicators 指标
+//     * @param ttype      时间单位
+//     * @param sdate      时间范围
+//     * @param condition  条件
+//     * @param searchType 搜索类型
+//     * @param session    会话
+//     * @return {@link RetData}
+//     */
+//    @PostMapping("renderTable")
+//    public RetData renderTable(String citys, String quxians, String indicators, String ttype, String sdate,
+//                               String condition, String searchType, HttpSession session) {
+//        return DbUtil.renderTable(citys, quxians, indicators, ttype, sdate, condition, searchType, session);
+//    }
+//
+//    /**
+//     * 添加指标模板
+//     *
+//     * @param templateName 指标模板名称
+//     * @param indicators   指标
+//     */
+//    @PostMapping("addTemplate")
+//    public Object addTemplate(String templateName, String indicators, HttpSession session) {
+//        return DbUtil.addTemplate(templateName, indicators, session);
+//    }
+//
+//    /**
+//     * 获取指标模板
+//     */
+//    @GetMapping("initTreeIndicatorTemplate")
+//    public List<TreeNode> initTreeIndicatorTemplate(HttpSession session) {
+//        return DbUtil.initTreeIndicatorTemplate(session);
+//    }
+//
+//    /**
+//     * 删除指标模板
+//     *
+//     * @param ids 模板id
+//     */
+//    @PostMapping("deleteTemplate")
+//    public Object deleteTemplate(String ids) {
+//        return DbUtil.deleteTemplate(ids);
+//    }
+//}

+ 45 - 0
src/main/java/com/nokia/hb/dao/entity/IndicatorTemplate.java

@@ -0,0 +1,45 @@
+package com.nokia.hb.dao.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 指标模板
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-28
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+@TableName("pm_parse.indicator_template")
+public class IndicatorTemplate implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 指标模板主键
+     */
+    @TableId("id")
+    private Long id;
+
+    /**
+     * 模板名称
+     */
+    @TableField("template_name")
+    private String templateName;
+
+    /**
+     * 用户名
+     */
+    @TableField("username")
+    private String username;
+}

+ 35 - 0
src/main/java/com/nokia/hb/dao/entity/IndicatorTemplateItem.java

@@ -0,0 +1,35 @@
+package com.nokia.hb.dao.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 指标模板关联表
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-28
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+@TableName("pm_parse.indicator_template_item")
+public class IndicatorTemplateItem implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 指标模板编号
+     */
+    private Long templateId;
+
+    /**
+     * 指标编号
+     */
+    private Integer indicatorId;
+}

+ 31 - 0
src/main/java/com/nokia/hb/dao/entity/PerCfgArea.java

@@ -0,0 +1,31 @@
+package com.nokia.hb.dao.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-28
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+@TableName("pm_parse.per_cfg_area")
+public class PerCfgArea implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableField("city")
+    private String city;
+
+    @TableField("quxian")
+    private String quxian;
+}

+ 43 - 0
src/main/java/com/nokia/hb/dao/entity/PerCfgCell.java

@@ -0,0 +1,43 @@
+package com.nokia.hb.dao.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-28
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+@TableName("pm_parse.per_cfg_cell")
+public class PerCfgCell implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableField("eci")
+    private String eci;
+
+    @TableField("cellname")
+    private String cellname;
+
+    @TableField("province")
+    private String province;
+
+    @TableField("city")
+    private String city;
+
+    @TableField("quxian")
+    private String quxian;
+
+    @TableField("vendor")
+    private String vendor;
+}

+ 38 - 0
src/main/java/com/nokia/hb/dao/entity/PerCfgIndicator.java

@@ -0,0 +1,38 @@
+package com.nokia.hb.dao.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-28
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+@TableName("pm_parse.per_cfg_indicator")
+public class PerCfgIndicator implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableField("indicator_id")
+    private Integer indicatorId;
+
+    @TableField("indicator_cn")
+    private String indicatorCn;
+
+    @TableField("indicator_en")
+    private String indicatorEn;
+
+    @TableField("indicator_type")
+    private String indicatorType;
+}

+ 38 - 0
src/main/java/com/nokia/hb/dao/entity/User.java

@@ -0,0 +1,38 @@
+package com.nokia.hb.dao.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 用户表
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-28
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+@TableName("pm_parse.user")
+public class User implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户名
+     */
+    @TableId("username")
+    private String username;
+
+    /**
+     * 密码
+     */
+    @TableField("password")
+    private String password;
+}

+ 34 - 0
src/main/java/com/nokia/hb/dao/entity/UserArea.java

@@ -0,0 +1,34 @@
+package com.nokia.hb.dao.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 用户地区关联表
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-28
+ */
+@Getter
+@Setter
+@Accessors(chain = true)
+@TableName("pm_parse.user_area")
+public class UserArea implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 城市
+     */
+    private String area;
+}

+ 69 - 0
src/main/java/com/nokia/hb/dao/mapper/IndicatorTemplateItemMapper.java

@@ -0,0 +1,69 @@
+package com.nokia.hb.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.nokia.hb.dao.entity.IndicatorTemplateItem;
+import com.nokia.hb.pojo.bo.IndicatorTemplateItemBo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 指标模板关联表 Mapper 接口
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-27
+ */
+@Mapper
+public interface IndicatorTemplateItemMapper extends BaseMapper<IndicatorTemplateItem> {
+    /**
+     * 插入批
+     *
+     * @param list 列表
+     * @return int
+     */
+    @Update("<script>"
+            + " insert into pm_parse.indicator_template_item (template_id, indicator_id) values"
+            + "     <foreach collection=\"list\" item=\"item\" index=\"index\" separator=\",\">"
+            + "       (#{item.templateId}, #{item.indicatorId})"
+            + "     </foreach>"
+            + " </script>")
+    int insertBatch(List<IndicatorTemplateItem> list);
+
+    /**
+     * 通过模板id查询列表
+     *
+     * @param list 模板id列表
+     * @return {@link List}<{@link IndicatorTemplateItemBo}>
+     */
+    @Select("<script>"
+            + " select iti.template_id, iti.indicator_id, pci.indicator_cn, pci.indicator_en"
+            + " from pm_parse.indicator_template_item iti"
+            + " inner join pm_parse.per_cfg_indicator pci on iti.indicator_id = pci.indicator_id"
+            + " where iti.template_id in"
+            + " <foreach open=\"(\" close=\")\" collection=\"list\" item=\"item\" separator=\",\">"
+            + "   #{item}"
+            + " </foreach>"
+            + " order by iti.template_id, iti.indicator_id"
+            + " </script>")
+    List<IndicatorTemplateItemBo> listByTemplateIds(@Param("list") List<Long> list);
+
+    /**
+     * 删除批处理
+     *
+     * @param list 模板id列表
+     * @return int
+     */
+    @Update("<script>"
+            + "delete from pm_parse.indicator_template_item"
+            + " where template_id in"
+            + " <foreach open=\"(\" close=\")\" collection=\"list\" item=\"item\" separator=\",\">"
+            + "   #{item}"
+            + " </foreach>"
+            + " </script>")
+    int deleteBatch(@Param("list") List<Long> list);
+}

+ 64 - 0
src/main/java/com/nokia/hb/dao/mapper/IndicatorTemplateMapper.java

@@ -0,0 +1,64 @@
+package com.nokia.hb.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.nokia.hb.dao.entity.IndicatorTemplate;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * <p>
+ * 指标模板 Mapper 接口
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-27
+ */
+@Mapper
+public interface IndicatorTemplateMapper extends BaseMapper<IndicatorTemplate> {
+    /**
+     * 根据用户名查询指标模板
+     *
+     * @param username 用户名
+     * @return {@link List}<{@link IndicatorTemplate}>
+     */
+    @Select("select * from pm_parse.indicator_template where username = #{username} order by id")
+    List<IndicatorTemplate> listByUsername(String username);
+
+    /**
+     * 过滤不属于该用户的模板id
+     *
+     * @param username 用户名
+     * @param list     模板id列表
+     * @return {@link List}<{@link Long}>
+     */
+    @Select("<script>"
+            + "select id from pm_parse.indicator_template"
+            + " where username = #{username}"
+            + " and id in"
+            + " <foreach open=\"(\" close=\")\" collection=\"list\" item=\"item\" separator=\",\">"
+            + "   #{item}"
+            + " </foreach>"
+            + " order by id"
+            + " </script>")
+    List<Long> getIds(@Param("username") String username, @Param("list") Set<Long> list);
+
+    /**
+     * 删除批处理
+     *
+     * @param list 模板id列表
+     * @return int
+     */
+    @Update("<script>"
+            + "delete from pm_parse.indicator_template"
+            + " where id in"
+            + " <foreach open=\"(\" close=\")\" collection=\"list\" item=\"item\" separator=\",\">"
+            + "   #{item}"
+            + " </foreach>"
+            + " </script>")
+    int deleteBatch(@Param("list") List<Long> list);
+}

+ 27 - 0
src/main/java/com/nokia/hb/dao/mapper/PerCfgAreaMapper.java

@@ -0,0 +1,27 @@
+package com.nokia.hb.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.nokia.hb.dao.entity.PerCfgArea;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-27
+ */
+@Mapper
+public interface PerCfgAreaMapper extends BaseMapper<PerCfgArea> {
+    /**
+     * 所有地区
+     *
+     * @return {@link List}<{@link PerCfgArea}>
+     */
+    @Select("select distinct * from pm_parse.per_cfg_area order by city, quxian")
+    List<PerCfgArea> all();
+}

+ 83 - 0
src/main/java/com/nokia/hb/dao/mapper/PerCfgCellMapper.java

@@ -0,0 +1,83 @@
+package com.nokia.hb.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.nokia.hb.dao.entity.PerCfgCell;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-27
+ */
+@Mapper
+public interface PerCfgCellMapper extends BaseMapper<PerCfgCell> {
+    /**
+     * 按地区查询
+     *
+     * @param citys      地市
+     * @param quxians    区县
+     * @param indicators 指标
+     * @param timeType   时间单位
+     * @param startTime  开始时间
+     * @param endTime    结束时间
+     * @return {@link List}<{@link Map}<{@link String}, {@link Object}>>
+     */
+    @Select("<script>"
+            + "select a.cellname, a.city, a.quxian, a.vendor, b.*"
+            + " from (select eci, cellname, city, quxian, vendor from pm_parse.per_cfg_cell"
+                + " where city in"
+                + " <foreach open=\"(\" close=\")\" collection=\"citys\" item=\"item\" separator=\",\">"
+                + "   #{item}"
+                + " </foreach>"
+                + " and quxian in"
+                + " <foreach open=\"(\" close=\")\" collection=\"quxians\" item=\"item\" separator=\",\">"
+                + "   #{item}"
+                + " </foreach> ) a"
+            + " inner join (select ${indicators} from pm_parse.pm_4g_${timeType}"
+            + " where sdate <![CDATA[ >= ]]> #{startTime}"
+            + " and sdate <![CDATA[ <= ]]> #{endTime}) b"
+            + " on a.eci = b.eci"
+            + " order by b.sdate desc"
+            + " </script>")
+    List<Map<String, Object>> searchByCity(@Param("citys") Set<String> citys, @Param("quxians") Set<String> quxians,
+                                           @Param("indicators") String indicators, @Param("timeType") String timeType,
+                                           @Param("startTime") LocalDateTime startTime,
+                                           @Param("endTime") LocalDateTime endTime);
+
+    /**
+     * 按eci查询
+     *
+     * @param ecis       eci列表
+     * @param indicators 指标
+     * @param timeType   时间单位
+     * @param startTime  开始时间
+     * @param endTime    结束时间
+     * @return {@link List}<{@link Map}<{@link String}, {@link Object}>>
+     */
+    @Select("<script>"
+            + "select a.cellname, a.city, a.quxian, a.vendor, b.*"
+            + " from (select eci, cellname, city, quxian, vendor from pm_parse.per_cfg_cell"
+                + " where eci in"
+                + " <foreach open=\"(\" close=\")\" collection=\"ecis\" item=\"item\" separator=\",\">"
+                + "   #{item}"
+                + " </foreach> ) a"
+            + " inner join (select ${indicators} from pm_parse.pm_4g_${timeType}"
+            + " where sdate <![CDATA[ >= ]]> #{startTime}"
+            + " and sdate <![CDATA[ <= ]]> #{endTime}) b"
+            + " on a.eci = b.eci"
+            + " order by b.sdate desc"
+            + " </script>")
+    List<Map<String, Object>> searchByEci(@Param("ecis") Set<String> ecis, @Param("indicators") String indicators,
+                                          @Param("timeType") String timeType, @Param("startTime") LocalDateTime startTime,
+                                          @Param("endTime") LocalDateTime endTime);
+}

+ 28 - 0
src/main/java/com/nokia/hb/dao/mapper/PerCfgIndicatorMapper.java

@@ -0,0 +1,28 @@
+package com.nokia.hb.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.nokia.hb.dao.entity.PerCfgIndicator;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * <p>
+ * Mapper 接口
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-27
+ */
+@Mapper
+public interface PerCfgIndicatorMapper extends BaseMapper<PerCfgIndicator> {
+    /**
+     * 所有指标
+     *
+     * @return {@link List}<{@link PerCfgIndicator}>
+     */
+    @Select("select * from pm_parse.per_cfg_indicator"
+            + " order by indicator_id, indicator_type, indicator_cn, indicator_en")
+    List<PerCfgIndicator> all();
+}

+ 28 - 0
src/main/java/com/nokia/hb/dao/mapper/UserAreaMapper.java

@@ -0,0 +1,28 @@
+package com.nokia.hb.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.nokia.hb.dao.entity.UserArea;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 用户地区关联表 Mapper 接口
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-27
+ */
+@Mapper
+public interface UserAreaMapper extends BaseMapper<UserArea> {
+    /**
+     * 根据用户名查询拥有的地区权限
+     *
+     * @param username 用户名
+     * @return {@link List}<{@link String}>
+     */
+    @Select("select distinct area from pm_parse.user_area where username = #{username} order by area")
+    List<String> listByUsername(String username);
+}

+ 27 - 0
src/main/java/com/nokia/hb/dao/mapper/UserMapper.java

@@ -0,0 +1,27 @@
+package com.nokia.hb.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.nokia.hb.dao.entity.User;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+/**
+ * <p>
+ * 用户表 Mapper 接口
+ * </p>
+ *
+ * @author baomidou
+ * @since 2023-02-27
+ */
+@Mapper
+public interface UserMapper extends BaseMapper<User> {
+    /**
+     * 根据用户名查询
+     *
+     * @param username 用户名
+     * @return {@link User}
+     */
+    @Select("select * from pm_parse.user where username = #{username}")
+    User getByUsername(@Param("username") String username);
+}

+ 8 - 52
src/main/java/com/nokia/hb/pojo/RetData.java

@@ -1,60 +1,16 @@
 package com.nokia.hb.pojo;
 
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
 import java.util.List;
 import java.util.Map;
 
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
 public class RetData {
-    /**
-     * 错误信息
-     */
-    String msg;
     List<Col> cols;
-    List<Map<String,String>> datas;
-
-    public RetData() {
-    }
-
-    public RetData(List<Col> cols, List<Map<String, String>> datas) {
-        this.cols = cols;
-        this.datas = datas;
-    }
-
-    public RetData(List<Col> cols, List<Map<String, String>> datas, String msg) {
-        this.cols = cols;
-        this.datas = datas;
-        this.msg = msg;
-    }
-
-    public List<Col> getCols() {
-        return cols;
-    }
-
-    public void setCols(List<Col> cols) {
-        this.cols = cols;
-    }
-
-    public List<Map<String, String>> getDatas() {
-        return datas;
-    }
-
-    public void setDatas(List<Map<String, String>> datas) {
-        this.datas = datas;
-    }
-
-    public String getMsg() {
-        return msg;
-    }
-
-    public void setMsg(String msg) {
-        this.msg = msg;
-    }
-
-    @Override
-    public String toString() {
-        return "RetData{" +
-                "msg='" + msg + '\'' +
-                ", cols=" + cols +
-                ", datas=" + datas +
-                '}';
-    }
+    List<Map<String,Object>> datas;
 }

+ 11 - 0
src/main/java/com/nokia/hb/pojo/bo/IndicatorTemplateItemBo.java

@@ -0,0 +1,11 @@
+package com.nokia.hb.pojo.bo;
+
+import lombok.Data;
+
+@Data
+public class IndicatorTemplateItemBo {
+    private Long templateId;
+    private Integer indicatorId;
+    private String indicatorCn;
+    private String indicatorEn;
+}

+ 22 - 0
src/main/java/com/nokia/hb/pojo/dto/AddTemplateDto.java

@@ -0,0 +1,22 @@
+package com.nokia.hb.pojo.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import java.util.Set;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class AddTemplateDto {
+    @Schema(description = "模板名称", required = true)
+    @NotBlank(message = "templateName不能为空")
+    private String templateName;
+    @Schema(description = "指标", required = true)
+    @NotEmpty(message = "indicators不能为空")
+    private Set<Integer> indicators;
+}

+ 18 - 0
src/main/java/com/nokia/hb/pojo/dto/DeleteTemplateDto.java

@@ -0,0 +1,18 @@
+package com.nokia.hb.pojo.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.Set;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class DeleteTemplateDto {
+    @Schema(description = "指标模板id列表", required = true)
+    @NotEmpty(message = "ids不能为空")
+    private Set<Long> ids;
+}

+ 20 - 0
src/main/java/com/nokia/hb/pojo/dto/LoginDto.java

@@ -0,0 +1,20 @@
+package com.nokia.hb.pojo.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class LoginDto {
+    @Schema(description = "用户名", required = true)
+    @NotBlank(message = "username不能为空")
+    private String username;
+    @Schema(description = "密码", required = true)
+    @NotBlank(message = "password不能为空")
+    private String password;
+}

+ 44 - 0
src/main/java/com/nokia/hb/pojo/dto/RenderTableDto.java

@@ -0,0 +1,44 @@
+package com.nokia.hb.pojo.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.nokia.hb.pojo.enums.SearchTypeEnum;
+import com.nokia.hb.pojo.enums.TimeTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.*;
+import java.time.LocalDateTime;
+import java.util.Set;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class RenderTableDto {
+    @Schema(description = "地市列表")
+    private Set<String> citys;
+    @Schema(description = "区县列表")
+    private Set<String> quxians;
+    @Schema(description = "时间单位")
+    @NotNull(message = "timeType不能为空")
+    private TimeTypeEnum timeType;
+    @Schema(description = "指标")
+    @NotEmpty(message = "indicators不能为空")
+    private Set<String> indicators;
+    @Schema(description = "起始时间", example = "2022-11-01 13:00:00", required = true)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Past(message = "startTime不能大于当前时间")
+    @NotNull(message = "startTime不能为空")
+    private LocalDateTime startTime;
+    @Schema(description = "截至时间", example = "2022-11-02 13:00:00", required = true)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @PastOrPresent(message = "endTime不能大于当前时间")
+    @NotNull(message = "endTime不能为空")
+    private LocalDateTime endTime;
+    @Schema(description = "条件")
+    private String condition;
+    @Schema(description = "搜索类型")
+    @NotNull(message = "searchType不能为空")
+    private SearchTypeEnum searchType;
+}

+ 15 - 0
src/main/java/com/nokia/hb/pojo/enums/SearchTypeEnum.java

@@ -0,0 +1,15 @@
+package com.nokia.hb.pojo.enums;
+
+/**
+ * 搜索类型枚举
+ */
+public enum SearchTypeEnum {
+    /**
+     * 地区
+     */
+    AREA,
+    /**
+     * eci
+     */
+    ECI;
+}

+ 16 - 0
src/main/java/com/nokia/hb/pojo/enums/TimeTypeEnum.java

@@ -0,0 +1,16 @@
+package com.nokia.hb.pojo.enums;
+
+public enum TimeTypeEnum {
+    /**
+     * 15分钟
+     */
+    QUATER,
+    /**
+     * 小时
+     */
+    HOUR,
+    /**
+     * 天
+     */
+    DAY;
+}

+ 14 - 0
src/main/java/com/nokia/hb/pojo/vo/LoginVo.java

@@ -0,0 +1,14 @@
+package com.nokia.hb.pojo.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class LoginVo {
+    @Schema(description = "用户名")
+    private String username;
+}

+ 42 - 0
src/main/java/com/nokia/hb/service/AreaService.java

@@ -0,0 +1,42 @@
+package com.nokia.hb.service;
+
+import com.nokia.common.R;
+import com.nokia.hb.dao.entity.PerCfgArea;
+import com.nokia.hb.dao.mapper.PerCfgAreaMapper;
+import com.nokia.hb.pojo.TreeNode;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class AreaService {
+    private final PerCfgAreaMapper perCfgAreaMapper;
+
+    public AreaService(PerCfgAreaMapper perCfgAreaMapper) {
+        this.perCfgAreaMapper = perCfgAreaMapper;
+    }
+
+    public R<List<TreeNode>> initTreeCitys() {
+        List<PerCfgArea> areas = perCfgAreaMapper.all();
+        Map<String, List<TreeNode>> m = new HashMap<>();
+        TreeNode allTree = new TreeNode("地市选择", "地市选择", new ArrayList<>());
+        allTree.setSpread(true);
+        List<TreeNode> res = new ArrayList<>();
+        res.add(allTree);
+        areas.forEach(a -> {
+            String city = a.getCity();
+            String quxian = a.getQuxian();
+            String id = city + quxian;
+            TreeNode t = new TreeNode(quxian, id, null);
+            m.putIfAbsent(city, new ArrayList<>());
+            m.get(city).add(t);
+        });
+        m.forEach((key, value) -> allTree.getChildren().add(new TreeNode(key, key, value)));
+        return R.ok(res);
+    }
+}

+ 52 - 0
src/main/java/com/nokia/hb/service/AuthService.java

@@ -0,0 +1,52 @@
+package com.nokia.hb.service;
+
+import com.alibaba.fastjson2.JSON;
+import com.nokia.common.R;
+import com.nokia.hb.dao.entity.User;
+import com.nokia.hb.dao.mapper.UserAreaMapper;
+import com.nokia.hb.dao.mapper.UserMapper;
+import com.nokia.hb.pojo.dto.LoginDto;
+import com.nokia.hb.pojo.vo.LoginVo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpSession;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class AuthService {
+    /**
+     * session过期时间(秒)
+     */
+    @Value("${session.timeout}")
+    private Integer timeoutSeconds;
+
+    private final UserMapper userMapper;
+    private final UserAreaMapper userAreaMapper;
+
+    public AuthService(UserMapper userMapper, UserAreaMapper userAreaMapper) {
+        this.userMapper = userMapper;
+        this.userAreaMapper = userAreaMapper;
+    }
+
+    public R<LoginVo> userLogin(LoginDto dto, HttpSession session) {
+        User user = userMapper.getByUsername(dto.getUsername());
+        if (user == null || !dto.getPassword().equals(user.getPassword())) {
+            return R.error("用户名或密码错误!");
+        }
+        // 查询用户地区权限
+        List<String> areas = userAreaMapper.listByUsername(dto.getUsername());
+        Map<String, String> map = new HashMap<>();
+        areas.forEach(t -> map.put(t, ""));
+        log.debug("areas: {}", JSON.toJSONString(map.keySet()));
+        // 保存session
+        session.setMaxInactiveInterval(timeoutSeconds);
+        session.setAttribute("username", dto.getUsername());
+        session.setAttribute("areas", map);
+        return R.ok(new LoginVo(dto.getUsername()));
+    }
+}

+ 0 - 0
src/main/java/com/nokia/hb/dao/DataViewDao.java → src/main/java/com/nokia/hb/service/DataViewDao.java


+ 42 - 0
src/main/java/com/nokia/hb/service/IndicatorService.java

@@ -0,0 +1,42 @@
+package com.nokia.hb.service;
+
+import com.nokia.common.R;
+import com.nokia.hb.dao.entity.PerCfgIndicator;
+import com.nokia.hb.dao.mapper.PerCfgIndicatorMapper;
+import com.nokia.hb.pojo.TreeNode;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class IndicatorService {
+    private final PerCfgIndicatorMapper perCfgIndicatorMapper;
+
+    public IndicatorService(PerCfgIndicatorMapper perCfgIndicatorMapper) {
+        this.perCfgIndicatorMapper = perCfgIndicatorMapper;
+    }
+
+    public R<List<TreeNode>> initTreeIndicator() {
+        List<PerCfgIndicator> indicators = perCfgIndicatorMapper.all();
+        Map<String, List<TreeNode>> m = new HashMap<>();
+        TreeNode allTree = new TreeNode("指标选择", "指标选择", new ArrayList<>());
+        allTree.setSpread(true);
+        List<TreeNode> res = new ArrayList<>();
+        res.add(allTree);
+        indicators.forEach(i -> {
+            String indicatorType = i.getIndicatorType();
+            String indicatorCn = i.getIndicatorCn();
+            String indicatorId = String.valueOf(i.getIndicatorId());
+            TreeNode t = new TreeNode(indicatorCn, indicatorId, null);
+            m.putIfAbsent(indicatorType, new ArrayList<>());
+            m.get(indicatorType).add(t);
+        });
+        m.forEach((k, v) -> allTree.getChildren().add(new TreeNode(k, k, v)));
+        return R.ok(res);
+    }
+}

+ 96 - 0
src/main/java/com/nokia/hb/service/IndicatorTemplateService.java

@@ -0,0 +1,96 @@
+package com.nokia.hb.service;
+
+import com.nokia.common.R;
+import com.nokia.hb.dao.entity.IndicatorTemplate;
+import com.nokia.hb.dao.entity.IndicatorTemplateItem;
+import com.nokia.hb.dao.mapper.IndicatorTemplateItemMapper;
+import com.nokia.hb.dao.mapper.IndicatorTemplateMapper;
+import com.nokia.hb.pojo.TreeNode;
+import com.nokia.hb.pojo.bo.IndicatorTemplateItemBo;
+import com.nokia.hb.pojo.dto.AddTemplateDto;
+import com.nokia.hb.pojo.dto.DeleteTemplateDto;
+import com.nokia.hb.utils.SessionUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import javax.servlet.http.HttpSession;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class IndicatorTemplateService {
+    private final IndicatorTemplateMapper indicatorTemplateMapper;
+    private final IndicatorTemplateItemMapper indicatorTemplateItemMapper;
+
+    public IndicatorTemplateService(IndicatorTemplateMapper indicatorTemplateMapper,
+                                    IndicatorTemplateItemMapper indicatorTemplateItemMapper) {
+        this.indicatorTemplateMapper = indicatorTemplateMapper;
+        this.indicatorTemplateItemMapper = indicatorTemplateItemMapper;
+    }
+
+    public R<List<TreeNode>> initTreeIndicatorTemplate(HttpSession session) {
+        String username = SessionUtil.getUsername(session);
+        List<IndicatorTemplate> indicatorTemplates = indicatorTemplateMapper.listByUsername(username);
+        TreeNode allTree = new TreeNode("指标模板选择", "指标模板选择", true, new ArrayList<>());
+        List<TreeNode> res = new ArrayList<>();
+        res.add(allTree);
+        if (CollectionUtils.isEmpty(indicatorTemplates)) {
+            return R.ok(res);
+        }
+        List<Long> templateIds = indicatorTemplates.stream().map(IndicatorTemplate::getId).collect(Collectors.toList());
+        List<IndicatorTemplateItemBo> indicatorTemplateItemBos = indicatorTemplateItemMapper.listByTemplateIds(templateIds);
+        if (CollectionUtils.isEmpty(indicatorTemplateItemBos)) {
+            return R.ok(res);
+        }
+        // 按templateId分组
+        Map<Long, List<IndicatorTemplateItemBo>> map = indicatorTemplateItemBos.stream()
+                .collect(Collectors.groupingBy(IndicatorTemplateItemBo::getTemplateId,
+                        LinkedHashMap::new, Collectors.toList()));
+        // 生成指标模板节点
+        indicatorTemplates.forEach(i -> {
+            Long id = i.getId();
+            String templateName = i.getTemplateName();
+            TreeNode t = new TreeNode(templateName, String.valueOf(id), new ArrayList<>());
+            allTree.getChildren().add(t);
+            List<IndicatorTemplateItemBo> bos = map.get(id);
+            bos.forEach(b -> t.getChildren().add(new TreeNode(b.getIndicatorCn(), b.getIndicatorEn())));
+        });
+        return R.ok(res);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public R<Object> addTemplate(AddTemplateDto dto, HttpSession session) {
+        String username = SessionUtil.getUsername(session);
+        IndicatorTemplate indicatorTemplate = new IndicatorTemplate();
+        indicatorTemplate.setTemplateName(dto.getTemplateName());
+        indicatorTemplate.setUsername(username);
+        indicatorTemplateMapper.insert(indicatorTemplate);
+        List<IndicatorTemplateItem> indicatorTemplateItems = new ArrayList<>();
+        dto.getIndicators().forEach(t -> {
+            IndicatorTemplateItem tt = new IndicatorTemplateItem();
+            tt.setTemplateId(indicatorTemplate.getId());
+            tt.setIndicatorId(t);
+            indicatorTemplateItems.add(tt);
+        });
+        indicatorTemplateItemMapper.insertBatch(indicatorTemplateItems);
+        return R.ok();
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public R<Object> deleteTemplate(DeleteTemplateDto dto, HttpSession session) {
+        String username = SessionUtil.getUsername(session);
+        List<Long> ids = indicatorTemplateMapper.getIds(username, dto.getIds());
+        if (CollectionUtils.isEmpty(ids)) {
+            return R.ok();
+        }
+        indicatorTemplateMapper.deleteBatch(ids);
+        indicatorTemplateItemMapper.deleteBatch(ids);
+        return R.ok();
+    }
+}

+ 88 - 0
src/main/java/com/nokia/hb/service/PmService.java

@@ -0,0 +1,88 @@
+package com.nokia.hb.service;
+
+import com.nokia.common.R;
+import com.nokia.hb.dao.entity.PerCfgIndicator;
+import com.nokia.hb.dao.mapper.PerCfgCellMapper;
+import com.nokia.hb.dao.mapper.PerCfgIndicatorMapper;
+import com.nokia.hb.pojo.Col;
+import com.nokia.hb.pojo.RetData;
+import com.nokia.hb.pojo.dto.RenderTableDto;
+import com.nokia.hb.pojo.enums.SearchTypeEnum;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.HttpSession;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Slf4j
+@Service
+public class PmService {
+    private final PerCfgIndicatorMapper perCfgIndicatorMapper;
+    private final PerCfgCellMapper perCfgCellMapper;
+
+    public PmService(PerCfgIndicatorMapper perCfgIndicatorMapper, PerCfgCellMapper perCfgCellMapper) {
+        this.perCfgIndicatorMapper = perCfgIndicatorMapper;
+        this.perCfgCellMapper = perCfgCellMapper;
+    }
+
+    public R<RetData> renderTable(RenderTableDto dto, HttpSession session) {
+        List<Map<String, Object>> list = new ArrayList<>();
+        String indicators = String.join(",", dto.getIndicators());
+        // 按地市查询
+        if (SearchTypeEnum.AREA.equals(dto.getSearchType())) {
+            // 获取拥有的城市权限
+            Map<String, String> areas = (Map<String, String>) session.getAttribute("areas");
+            // 地区权限校验
+            for (String t : dto.getCitys()) {
+                if (!areas.containsKey(t)) {
+                    log.debug("没有权限的city: {}", t);
+                    return R.error("没有" + t + "的权限");
+                }
+            }
+            list = perCfgCellMapper.searchByCity(dto.getCitys(), dto.getQuxians(), indicators,
+                    dto.getTimeType().name().toLowerCase(), dto.getStartTime(), dto.getEndTime());
+        }
+        // 按eci查询
+        if (SearchTypeEnum.ECI.equals(dto.getSearchType())) {
+            String[] conditionArray = StringUtils.split(dto.getCondition(), ",");
+            if (conditionArray == null) {
+                conditionArray = new String[]{dto.getCondition()};
+            }
+            Set<String> conditions = Stream.of(conditionArray).collect(Collectors.toSet());
+            list = perCfgCellMapper.searchByEci(conditions, indicators, dto.getTimeType().name().toLowerCase(),
+                    dto.getStartTime(), dto.getEndTime());
+        }
+        if (CollectionUtils.isEmpty(list)) {
+            return R.ok(new RetData(new ArrayList<>(), new ArrayList<>()));
+        }
+        Map<String, String> ezMap = initZnEnMap();
+        List<Col> cols = new ArrayList<>();
+        Set<String> headers = list.get(0).keySet();
+        ezMap.forEach((k, v) -> {
+            if (headers.contains(k)) {
+                cols.add(new Col(k, v));
+            }
+        });
+        return R.ok(new RetData(cols, list));
+    }
+
+    /**
+     * 指标字段中英文map
+     *
+     * @return {@link Map}<{@link String}, {@link String}>
+     */
+    public Map<String, String> initZnEnMap() {
+        Map<String, String> m = new LinkedHashMap<>();
+        m.put("cellname", "小区中文名");
+        m.put("city", "地市");
+        m.put("quxian", "区县");
+        m.put("vendor", "厂家");
+        List<PerCfgIndicator> indicators = perCfgIndicatorMapper.all();
+        indicators.forEach(t -> m.put(t.getIndicatorEn(), t.getIndicatorCn()));
+        return m;
+    }
+}

+ 815 - 815
src/main/java/com/nokia/hb/utils/DbUtil.java

@@ -1,98 +1,173 @@
-package com.nokia.hb.utils;
-
-import com.nokia.hb.pojo.Col;
-import com.nokia.hb.pojo.RetData;
-import com.nokia.hb.pojo.TreeNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.util.StringUtils;
-
-import javax.servlet.http.HttpSession;
-import java.sql.*;
-import java.util.*;
-
-@SuppressWarnings("unchecked")
-public class DbUtil {
-    private static final Logger log = LoggerFactory.getLogger(DbUtil.class);
-    private static Connection conn = null;
-
-    // private static final String URL =
-    // "jdbc:postgresql://127.0.0.1:5432/postgres";
-    // private static final String USER = "postgres";
-    // private static final String PASSWORD = "ava1234";
-
-    private static final String URL = "jdbc:postgresql://10.100.68.195:5432/sqmmt";
-    private static final String USER = "pmparse";
-    private static final String PASSWORD = "abc123!";
-
-    static {
-        try {
-            conn = DriverManager.getConnection(URL, USER, PASSWORD);
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-    }
-
-    public static Map<String, String> initZnEnMap() {
-        String sql = "select distinct indicator_en,indicator_cn from pm_parse.per_cfg_indicator;";
-        Map<String, String> m = new HashMap<>();
-        m.put("cellname", "小区中文名");
-        m.put("city", "地市");
-        m.put("quxian", "区县");
-        m.put("vendor", "厂家");
-        try {
-            PreparedStatement psmt = null;
-            psmt = conn.prepareStatement(sql);
-            psmt.setQueryTimeout(600);
-            ResultSet rs = psmt.executeQuery();
-            while (rs.next()) {
-                m.put(rs.getString("indicator_en"), rs.getString("indicator_cn"));
-            }
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-        return m;
-    }
-
-//    public static RetData conditionRenderTable(String condition, String searchType, String indicators, String ttype,
-//            String sdate) {
+//package com.nokia.hb.utils;
+//
+//import com.nokia.hb.pojo.Col;
+//import com.nokia.hb.pojo.RetData;
+//import com.nokia.hb.pojo.TreeNode;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//import org.springframework.util.StringUtils;
+//
+//import javax.servlet.http.HttpSession;
+//import java.sql.*;
+//import java.util.*;
+//
+//@SuppressWarnings("unchecked")
+//public class DbUtil {
+//    private static final Logger log = LoggerFactory.getLogger(DbUtil.class);
+//    private static Connection conn = null;
+//
+//    // private static final String URL =
+//    // "jdbc:postgresql://127.0.0.1:5432/postgres";
+//    // private static final String USER = "postgres";
+//    // private static final String PASSWORD = "ava1234";
+//
+//    private static final String URL = "jdbc:postgresql://10.100.68.195:5432/sqmmt";
+//    private static final String USER = "pmparse";
+//    private static final String PASSWORD = "abc123!";
+//
+//    static {
+//        try {
+//            conn = DriverManager.getConnection(URL, USER, PASSWORD);
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//        }
+//    }
+//
+//    public static Map<String, String> initZnEnMap() {
+//        String sql = "select distinct indicator_en,indicator_cn from pm_parse.per_cfg_indicator;";
+//        Map<String, String> m = new HashMap<>();
+//        m.put("cellname", "小区中文名");
+//        m.put("city", "地市");
+//        m.put("quxian", "区县");
+//        m.put("vendor", "厂家");
+//        try {
+//            PreparedStatement psmt = null;
+//            psmt = conn.prepareStatement(sql);
+//            psmt.setQueryTimeout(600);
+//            ResultSet rs = psmt.executeQuery();
+//            while (rs.next()) {
+//                m.put(rs.getString("indicator_en"), rs.getString("indicator_cn"));
+//            }
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//        }
+//        return m;
+//    }
+//
+////    public static RetData conditionRenderTable(String condition, String searchType, String indicators, String ttype,
+////            String sdate) {
+////        Map<String, String> ezMap = initZnEnMap();
+////        String[] timeArray = sdate.split(" - ");
+////        String startTime = timeArray[0];
+////        String endTime = timeArray[1];
+////        condition = condition.replace(",", "','");
+////        log.debug("condition: {}", condition);
+////        // eci
+////        String sql = "select a.cellname,a.city,a.quxian,a.vendor,b.*"
+////                + " from (select eci, cellname, city, quxian, vendor"
+////                    + " from pm_parse.per_cfg_cell"
+////                    + " where eci in (" + condition + ")) a"
+////                + " inner join (select " + indicators + " from pm_parse.pm_4g_" + ttype
+////                    + " where sdate >= '" + startTime
+////                    + "' and sdate <= '" + endTime + "') b"
+////                + " on a.eci = b.eci";
+////        // 全网
+////        if ("all".equals(searchType)) {
+////            sql = "select a.cellname, a.city, a.quxian, a.vendor, b.* from pm_parse.per_cfg_cell a"
+////                    + " inner join (select " + indicators + " from pm_parse.pm_4g_" + ttype
+////                        + " where sdate >= '" + startTime
+////                        + "' and sdate <= '" + endTime + "') b"
+////                    + " on a.eci = b.eci";
+////        }
+////
+////        log.debug("sql: {}", sql);
+////        List<Map<String, String>> datas = new ArrayList<>();
+////        List<Col> cols = new ArrayList<>();
+////        try {
+////            PreparedStatement psmt = null;
+////            psmt = conn.prepareStatement(sql);
+////            psmt.setQueryTimeout(600);
+////            ResultSet rs = psmt.executeQuery();
+////            ResultSetMetaData rsmd = rs.getMetaData();
+////            List<String> heads = new ArrayList<>();
+////            String columnName;
+////            for (int i = 1; i <= rsmd.getColumnCount(); i++) {
+////                columnName = rsmd.getColumnName(i);
+////                heads.add(columnName);
+////                cols.add(new Col(columnName, ezMap.get(columnName)));
+////            }
+////            while (rs.next()) {
+////                Map<String, String> m = new HashMap<>();
+////                for (String head : heads) {
+////                    String string = rs.getString(head);
+////                    m.put(head, string);
+////                }
+////                datas.add(m);
+////            }
+////        } catch (SQLException e) {
+////            e.printStackTrace();
+////        }
+////        return new RetData(cols, datas);
+////    }
+//
+//    public static RetData renderTable(String citys, String quxians, String indicators, String ttype, String sdate,
+//                                      String condition, String searchType, HttpSession session) {
 //        Map<String, String> ezMap = initZnEnMap();
 //        String[] timeArray = sdate.split(" - ");
 //        String startTime = timeArray[0];
 //        String endTime = timeArray[1];
-//        condition = condition.replace(",", "','");
-//        log.debug("condition: {}", condition);
-//        // eci
-//        String sql = "select a.cellname,a.city,a.quxian,a.vendor,b.*"
-//                + " from (select eci, cellname, city, quxian, vendor"
+//        String sql = null;
+//        // 按地市查询
+//        if ("area".equals(searchType)) {
+//            // 获取城市数组
+//            String[] cityArray = StringUtils.delete(citys, "'").split(",");
+//            // 获取拥有的城市权限
+//            Map<String, String> areas = (Map<String, String>) session.getAttribute("areas");
+//            log.debug("{} areas: {}", areas.keySet().size(), areas.keySet());
+//            log.debug("{} cityArray: {}", cityArray.length, Arrays.toString(cityArray));
+//            // 地区权限校验
+//            for (String t : cityArray) {
+//                if (!areas.containsKey(t)) {
+//                    log.debug("没有权限的city: {}", t);
+//                    return new RetData(null, null, "没有" + t + "的权限");
+//                }
+//            }
+//            sql = "select a.cellname, a.city, a.quxian, a.vendor, b.*"
+//                    + " from (select eci, cellname, city, quxian, vendor from pm_parse.per_cfg_cell"
+//                    + " where city in (" + citys + ") and quxian in (" + quxians + ")) a"
+//                    + " inner join (select " + indicators + " from pm_parse.pm_4g_" + ttype
+//                    + " where sdate >= '" + startTime
+//                    + "' and sdate <= '" + endTime + "') b"
+//                    + " on a.eci = b.eci"
+//                    + " order by b.sdate desc";
+//        }
+//        // 按eci查询
+//        if ("eci".equals(searchType)) {
+//            condition = "'" + condition.replace(",", "','") + "'";
+//            log.debug("condition: {}", condition);
+//            sql = "select a.cellname,a.city,a.quxian,a.vendor,b.*"
+//                    + " from (select eci, cellname, city, quxian, vendor"
 //                    + " from pm_parse.per_cfg_cell"
 //                    + " where eci in (" + condition + ")) a"
-//                + " inner join (select " + indicators + " from pm_parse.pm_4g_" + ttype
+//                    + " inner join (select " + indicators + " from pm_parse.pm_4g_" + ttype
 //                    + " where sdate >= '" + startTime
 //                    + "' and sdate <= '" + endTime + "') b"
-//                + " on a.eci = b.eci";
-//        // 全网
-//        if ("all".equals(searchType)) {
-//            sql = "select a.cellname, a.city, a.quxian, a.vendor, b.* from pm_parse.per_cfg_cell a"
-//                    + " inner join (select " + indicators + " from pm_parse.pm_4g_" + ttype
-//                        + " where sdate >= '" + startTime
-//                        + "' and sdate <= '" + endTime + "') b"
-//                    + " on a.eci = b.eci";
+//                    + " on a.eci = b.eci"
+//                    + " order by b.sdate desc";
 //        }
-//
 //        log.debug("sql: {}", sql);
 //        List<Map<String, String>> datas = new ArrayList<>();
 //        List<Col> cols = new ArrayList<>();
 //        try {
 //            PreparedStatement psmt = null;
 //            psmt = conn.prepareStatement(sql);
-//            psmt.setQueryTimeout(600);
+//            psmt.setQueryTimeout(60 * 10);
 //            ResultSet rs = psmt.executeQuery();
 //            ResultSetMetaData rsmd = rs.getMetaData();
 //            List<String> heads = new ArrayList<>();
-//            String columnName;
+//
 //            for (int i = 1; i <= rsmd.getColumnCount(); i++) {
-//                columnName = rsmd.getColumnName(i);
+//                String columnName = rsmd.getColumnName(i);
 //                heads.add(columnName);
 //                cols.add(new Col(columnName, ezMap.get(columnName)));
 //            }
@@ -109,742 +184,667 @@ public class DbUtil {
 //        }
 //        return new RetData(cols, datas);
 //    }
-
-    public static RetData renderTable(String citys, String quxians, String indicators, String ttype, String sdate,
-                                      String condition, String searchType, HttpSession session) {
-        Map<String, String> ezMap = initZnEnMap();
-        String[] timeArray = sdate.split(" - ");
-        String startTime = timeArray[0];
-        String endTime = timeArray[1];
-        String sql = null;
-        // 按地市查询
-        if ("area".equals(searchType)) {
-            // 获取城市数组
-            String[] cityArray = StringUtils.delete(citys, "'").split(",");
-            // 获取拥有的城市权限
-            Map<String, String> areas = (Map<String, String>) session.getAttribute("areas");
-            log.debug("{} areas: {}", areas.keySet().size(), areas.keySet());
-            log.debug("{} cityArray: {}", cityArray.length, Arrays.toString(cityArray));
-            // 地区权限校验
-            for (String t : cityArray) {
-                if (!areas.containsKey(t)) {
-                    log.debug("没有权限的city: {}", t);
-                    return new RetData(null, null, "没有" + t + "的权限");
-                }
-            }
-            sql = "select a.cellname, a.city, a.quxian, a.vendor, b.*"
-                    + " from (select eci, cellname, city, quxian, vendor from pm_parse.per_cfg_cell"
-                    + " where city in (" + citys + ") and quxian in (" + quxians + ")) a"
-                    + " inner join (select " + indicators + " from pm_parse.pm_4g_" + ttype
-                    + " where sdate >= '" + startTime
-                    + "' and sdate <= '" + endTime + "') b"
-                    + " on a.eci = b.eci"
-                    + " order by b.sdate desc";
-        }
-        // 按eci查询
-        if ("eci".equals(searchType)) {
-            condition = "'" + condition.replace(",", "','") + "'";
-            log.debug("condition: {}", condition);
-            sql = "select a.cellname,a.city,a.quxian,a.vendor,b.*"
-                    + " from (select eci, cellname, city, quxian, vendor"
-                    + " from pm_parse.per_cfg_cell"
-                    + " where eci in (" + condition + ")) a"
-                    + " inner join (select " + indicators + " from pm_parse.pm_4g_" + ttype
-                    + " where sdate >= '" + startTime
-                    + "' and sdate <= '" + endTime + "') b"
-                    + " on a.eci = b.eci"
-                    + " order by b.sdate desc";
-        }
-        log.debug("sql: {}", sql);
-        List<Map<String, String>> datas = new ArrayList<>();
-        List<Col> cols = new ArrayList<>();
-        try {
-            PreparedStatement psmt = null;
-            psmt = conn.prepareStatement(sql);
-            psmt.setQueryTimeout(60 * 10);
-            ResultSet rs = psmt.executeQuery();
-            ResultSetMetaData rsmd = rs.getMetaData();
-            List<String> heads = new ArrayList<>();
-
-            for (int i = 1; i <= rsmd.getColumnCount(); i++) {
-                String columnName = rsmd.getColumnName(i);
-                heads.add(columnName);
-                cols.add(new Col(columnName, ezMap.get(columnName)));
-            }
-            while (rs.next()) {
-                Map<String, String> m = new HashMap<>();
-                for (String head : heads) {
-                    String string = rs.getString(head);
-                    m.put(head, string);
-                }
-                datas.add(m);
-            }
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-        return new RetData(cols, datas);
-    }
-
-    public static List<TreeNode> initTreeCitys() {
-        String sql = "select distinct * from pm_parse.per_cfg_area order by city,quxian";
-        PreparedStatement psmt = null;
-        TreeNode allTree = new TreeNode("地市选择", "地市选择", new ArrayList<>());
-        // int i = 0;
-        try {
-            psmt = conn.prepareStatement(sql);
-            psmt.setQueryTimeout(60 * 10);
-            ResultSet rs = psmt.executeQuery();
-            Map<String, List<TreeNode>> m = new HashMap<>();
-
-            while (rs.next()) {
-                String city = rs.getString("city");
-                String quxian = rs.getString("quxian");
-                String id = city + quxian;
-                TreeNode t = new TreeNode(quxian, id, null);
-                if (m.keySet().contains(city)) {
-                    m.get(city).add(t);
-                } else {
-                    List<TreeNode> l = new ArrayList<>();
-                    l.add(t);
-                    m.put(city, l);
-                }
-
-            }
-
-            for (String s : m.keySet()) {
-                allTree.getChildren().add(new TreeNode(s, s, m.get(s)));
-            }
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-        List<TreeNode> res = new ArrayList<>();
-        allTree.setSpread(true);
-        res.add(allTree);
-        log.debug("initTreeCitys: {}", res);
-        return res;
-    }
-
-    public static List<TreeNode> initTreeIndicator() {
-        // String sql = "select distinct * from pm_parse.per_cfg_indicator order by
-        // indicator_type,indicator_cn,indicator_en";
-        String sql = "select distinct * from pm_parse.per_cfg_indicator order by indicator_id,indicator_type,indicator_cn,indicator_en";
-        PreparedStatement psmt = null;
-        TreeNode allTree = new TreeNode("指标选择", "指标选择", new ArrayList<>());
-        try {
-            psmt = conn.prepareStatement(sql);
-            psmt.setQueryTimeout(60 * 10);
-            ResultSet rs = psmt.executeQuery();
-            Map<String, List<TreeNode>> m = new HashMap<>();
-
-            while (rs.next()) {
-                String indicator_type = rs.getString("indicator_type");
-                String indicator_cn = rs.getString("indicator_cn");
-                String indicator_id = rs.getString("indicator_id");
-                TreeNode t = new TreeNode(indicator_cn, indicator_id, null);
-                if (m.keySet().contains(indicator_type)) {
-                    m.get(indicator_type).add(t);
-                } else {
-                    List<TreeNode> l = new ArrayList<>();
-                    l.add(t);
-                    m.put(indicator_type, l);
-                }
-
-            }
-            // int i = 0;
-            for (String s : m.keySet()) {
-                allTree.getChildren().add(new TreeNode(s, s, m.get(s)));
-            }
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-        List<TreeNode> res = new ArrayList<>();
-        allTree.setSpread(true);
-        res.add(allTree);
-        log.debug("initTreeIndicator: {}", res);
-        return res;
-    }
-
-    // public static Map<String, List<Object>> searchRate(String from, String t1,
-    // String t2, String ttype, String provinces, String citys) {
-    //
-    //
-    // HashMap<String, List<Object>> res = new HashMap<>();
-    // PreparedStatement psmt = null;
-    // String pn = "province_name";
-    // String cn = "city_name";
-    // if ("roaming".equals(from)) {
-    // pn = "roaming_province_name";
-    // cn = "roaming_city_name";
-    // }
-    // String sql = "select a.sdate as dt,round(a.openusers/b.users,4) as num from
-    // \n" +
-    // "(select sdate,sum(user_count) as openusers from
-    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
-    // stype='打开5G开关用户数' and size_type='" + ttype + "天' and " + pn + " in (" +
-    // provinces + ") and " + cn + " in (" + citys + ") group by sdate ) a\n" +
-    // "inner join\n" +
-    // "(select sdate,sum(user_count) as users from
-    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
-    // stype='5G终端用户数' and size_type='" + ttype + "天' and " + pn + " in (" +
-    // provinces + ") and " + cn + " in (" + citys + ") group by sdate) b\n" +
-    // "on a.sdate=b.sdate\n" +
-    // "order by a.sdate";
-    // if ("".equals(citys)) {
-    // sql = "select a.sdate as dt,round(a.openusers/b.users,4) as num from \n" +
-    // "(select sdate,sum(user_count) as openusers from
-    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
-    // stype='打开5G开关用户数' and size_type='" + ttype + "天' and " + pn + " in (" +
-    // provinces + ") group by sdate ) a\n" +
-    // "inner join\n" +
-    // "(select sdate,sum(user_count) as users from
-    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
-    // stype='5G终端用户数' and size_type='" + ttype + "天' and " + pn + " in (" +
-    // provinces + ") group by sdate) b\n" +
-    // "on a.sdate=b.sdate\n" +
-    // "order by a.sdate";
-    // }
-    //
-    // List<Object> dtList = new ArrayList<>();
-    // List<Object> numList = new ArrayList<>();
-    // try {
-    // psmt = conn.prepareStatement(sql);
-    //
-    // psmt.setQueryTimeout(60 * 10);
-    // psmt.setLong(1, Integer.valueOf(t1));
-    // psmt.setLong(2, Integer.valueOf(t2));
-    // psmt.setLong(3, Integer.valueOf(t1));
-    // psmt.setLong(4, Integer.valueOf(t2));
-    //
-    //// psmt.setString(5,provinces);
-    //// psmt.setString(6,citys);
-    // ResultSet rs = psmt.executeQuery();
-    // while (rs.next()) {
-    // String dt = rs.getString("dt");
-    // Long num = rs.getLong("num");
-    // dtList.add(dt);
-    // numList.add(num);
-    // }
-    // res.put("dt", dtList);
-    // res.put("num", numList);
-    // } catch (SQLException e) {
-    // e.printStackTrace();
-    // }
-    // return res;
-    // }
-
-    // public static HashMap<String, List<Object>> search(String from, String t1,
-    // String t2, String stype, String ttype, String provinces, String citys) {
-    // HashMap<String, List<Object>> res = new HashMap<>();
-    // PreparedStatement psmt = null;
-    // String pn = "province_name";
-    // String cn = "city_name";
-    // if ("roaming".equals(from)) {
-    // pn = "roaming_province_name";
-    // cn = "roaming_city_name";
-    // }
-    //// String sql = "select sdate,sum(user_count) from
-    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between '20210720' and
-    // '20210727' and stype='5G终端用户数' and size_type='7天' and province_name in ('河北')
-    // and city_name in ('石家庄','唐山') group by sdate;";
-    // String sql = "select sdate as dt ,sum(user_count) as num from
-    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
-    // stype=? and size_type=? and " + pn + " in (" + provinces + ") and " + cn + "
-    // in (" + citys + ") group by sdate order by sdate;";
-    // if ("".equals(citys)) {
-    // sql = "select sdate as dt ,sum(user_count) as num from
-    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
-    // stype=? and size_type=? and " + pn + " in (" + provinces + ") group by sdate
-    // order by sdate;";
-    // }
-    //
-    // List<Object> dtList = new ArrayList<>();
-    // List<Object> numList = new ArrayList<>();
-    // try {
-    // psmt = conn.prepareStatement(sql);
-    //
-    // psmt.setQueryTimeout(60 * 10);
-    // psmt.setLong(1, Integer.valueOf(t1));
-    // psmt.setLong(2, Integer.valueOf(t2));
-    // psmt.setString(3, stype);
-    // psmt.setString(4, ttype + "天");
-    //// psmt.setString(5,provinces);
-    //// psmt.setString(6,citys);
-    // ResultSet rs = psmt.executeQuery();
-    // while (rs.next()) {
-    // String dt = rs.getString("dt");
-    // Long num = rs.getLong("num");
-    // dtList.add(dt);
-    // numList.add(num);
-    // }
-    // res.put("dt", dtList);
-    // res.put("num", numList);
-    // } catch (SQLException e) {
-    // e.printStackTrace();
-    // }
-    // return res;
-    // }
-
-    // public static String typeExport(String from, String provinces, String citys,
-    // String ttype, String t1, String t2) {
-    // String res = "";
-    // String pn = "province_name";
-    // String cn = "city_name";
-    // String guishu = "归属地";
-    // String area = citys;
-    // if ("roaming".equals(from)) {
-    // pn = "roaming_province_name";
-    // cn = "roaming_city_name";
-    // guishu = "拜访地";
-    // }
-    // String sql = "with tab as (\n" +
-    // "select distinct\n" +
-    // "stype,\n" +
-    // "'" + guishu + "' as 维度, \n" +
-    // "size_type as 粒度,\n" +
-    // "'" + area + "' as 区域, \n" +
-    // "sdate as 日期,\n" +
-    // "sum(user_count) over(partition by stype,sdate,size_type) as user_count\n" +
-    // "from sqmdb_5g.user_terminal_status_5g_abstract\n" +
-    // "where sdate between ? and ? \n" +
-    // "and " + pn + " in ('" + provinces + "') and " + cn + " in ('" + citys + "')
-    // \n" +
-    // "and size_type = '" + ttype + "天'\n" +
-    // ") \n" +
-    // "\n" +
-    // "select \n" +
-    // "a.维度,\n" +
-    // "a.粒度,\n" +
-    // "a.区域,\n" +
-    // "a.日期,\n" +
-    // "sum(a.user_count) as 终端用户数,\n" +
-    // "sum(b.user_count) as 打开5G开关用户数,\n" +
-    // "sum(c.user_count) as 关闭5G开关用户数,\n" +
-    // "round(sum(b.user_count)/sum(a.user_count),4) as 开关打开率\n" +
-    // "from tab a\n" +
-    // "join tab b on b.日期=a.日期 and b.stype = '打开5G开关用户数'\n" +
-    // "join tab c on c.日期=a.日期 and c.stype = '关闭5G开关用户数'\n" +
-    // "where a.stype = '5G终端用户数'\n" +
-    // "group by \n" +
-    // "a.维度,\n" +
-    // "a.粒度,\n" +
-    // "a.区域,\n" +
-    // "a.日期\n" +
-    // "order by 日期";
-    //
-    // if ("".equals(citys)) {
-    // area = provinces;
-    // sql = "with tab as (\n" +
-    // "select distinct\n" +
-    // "stype,\n" +
-    // "'" + guishu + "' as 维度, \n" +
-    // "size_type as 粒度,\n" +
-    // "'" + area + "' as 区域, \n" +
-    // "sdate as 日期,\n" +
-    // "sum(user_count) over(partition by stype,sdate,size_type) as user_count\n" +
-    // "from sqmdb_5g.user_terminal_status_5g_abstract\n" +
-    // "where sdate between ? and ? \n" +
-    // "and " + pn + " in ('" + provinces + "') \n" +
-    // "and size_type = '" + ttype + "天'\n" +
-    // ") \n" +
-    // "\n" +
-    // "select \n" +
-    // "a.维度,\n" +
-    // "a.粒度,\n" +
-    // "a.区域,\n" +
-    // "a.日期,\n" +
-    // "sum(a.user_count) as 终端用户数,\n" +
-    // "sum(b.user_count) as 打开5G开关用户数,\n" +
-    // "sum(c.user_count) as 关闭5G开关用户数,\n" +
-    // "round(sum(b.user_count)/sum(a.user_count),4) as 开关打开率\n" +
-    // "from tab a\n" +
-    // "join tab b on b.日期=a.日期 and b.stype = '打开5G开关用户数'\n" +
-    // "join tab c on c.日期=a.日期 and c.stype = '关闭5G开关用户数'\n" +
-    // "where a.stype = '5G终端用户数'\n" +
-    // "group by \n" +
-    // "a.维度,\n" +
-    // "a.粒度,\n" +
-    // "a.区域,\n" +
-    // "a.日期\n" +
-    // "order by 日期";
-    // }
-    //
-    //
-    // PreparedStatement psmt = null;
-    //
-    //
-    // try {
-    // psmt = conn.prepareStatement(sql);
-    // psmt.setQueryTimeout(60 * 10);
-    //
-    // psmt.setLong(1, Integer.valueOf(t1));
-    // psmt.setLong(2, Integer.valueOf(t2));
-    // ResultSet rs = psmt.executeQuery();
-    // res = rsprocess(rs);
-    // } catch (SQLException e) {
-    // e.printStackTrace();
-    // }
-    // return res;
-    // }
-
-    // public static String exportAll(String ttype, String sts, String ets, String
-    // smts, String emts) {
-    // String res = "";
-    // String range = smts + "-" + ets;
-    // PreparedStatement psmt = null;
-    // String sql = "select '" + ttype + "天' as \"粒度\",\n" +
-    // "'" + range + "' as \"开始(结束)时间\",\n" +
-    // "msisdn as \"号码\",\n" +
-    // "province_name as \"归属省\",\n" +
-    // "city_name as \"归属地市\",\n" +
-    // "roaming_province_name as \"拜访省\",\n" +
-    // "roaming_city_name as \"拜访地市\",\n" +
-    // "tml_brand as \"终端品牌\",\n" +
-    // "tml_name as \"终端型号\",\n" +
-    // "case when last_open_date >= ? then 1 else 0 end as \"开关是否打开\" \n" +
-    // "from sqmdb_5g.user_terminal_status_5g_agg\n" +
-    // "where sdate=? \n" +
-    // "and last_chg_date >= ? ";
-    //
-    // try {
-    // psmt = conn.prepareStatement(sql);
-    // psmt.setQueryTimeout(60 * 10);
-    //
-    // psmt.setLong(1, Integer.valueOf(emts));
-    // psmt.setLong(2, Integer.valueOf(ets));
-    // psmt.setLong(3, Integer.valueOf(emts));
-    //
-    // ResultSet rs = psmt.executeQuery();
-    // res = rsprocess(rs);
-    // } catch (SQLException e) {
-    // e.printStackTrace();
-    // }
-    // return res;
-    // }
-
-    // public static String exportClose(String ttype, String sts, String ets, String
-    // smts, String emts) {
-    // String res = "";
-    // String range = smts + "-" + ets;
-    // PreparedStatement psmt = null;
-    // String sql = "select '" + ttype + "天' as \"粒度\",\n" +
-    // "'" + range + "' as \"开始(结束)时间\",\n" +
-    // "msisdn as \"号码\",\n" +
-    // "province_name as \"归属省\",\n" +
-    // "city_name as \"归属地市\",\n" +
-    // "roaming_province_name as \"拜访省\",\n" +
-    // "roaming_city_name as \"拜访地市\",\n" +
-    // "tml_brand as \"终端品牌\",\n" +
-    // "tml_name as \"终端型号\",\n" +
-    // "0 as \"开关是否打开\"\n" +
-    // "from sqmdb_5g.user_terminal_status_5g_agg\n" +
-    // "where sdate=? \n" +
-    // "and last_chg_date >= ? \n" +
-    // "and (last_open_date < ? or last_open_date is null) ";
-    //
-    // try {
-    // psmt = conn.prepareStatement(sql);
-    // psmt.setQueryTimeout(60 * 10);
-    //
-    // psmt.setLong(1, Integer.valueOf(ets));
-    // psmt.setLong(2, Integer.valueOf(emts));
-    // psmt.setLong(3, Integer.valueOf(emts));
-    //
-    // ResultSet rs = psmt.executeQuery();
-    // res = rsprocess(rs);
-    // } catch (SQLException e) {
-    // e.printStackTrace();
-    // }
-    // return res;
-    // }
-
-    // public static String rsprocess(ResultSet rs) {
-    // List<String> heads = new ArrayList<>();
-    // String headStr = "";
-    // StringBuffer sb = new StringBuffer();
-    // try {
-    // ResultSetMetaData rsmd = rs.getMetaData();
-    // for (int i = 1; i <= rsmd.getColumnCount(); i++) {
-    // String columnName = rsmd.getColumnName(i);
-    // heads.add(columnName);
-    // headStr += columnName + ",";
-    //
-    // }
-    //
-    // headStr = headStr.substring(0, headStr.length() - 1);
-    // sb.append(headStr + "\n");
-    // while (rs.next()) {
-    // String line = "";
-    // for (String head : heads) {
-    // line += rs.getString(head) + ",";
-    //
-    // }
-    // line = line.substring(0, line.length() - 1);
-    // sb.append(line + "\n");
-    // }
-    //
-    // } catch (SQLException throwables) {
-    // throwables.printStackTrace();
-    // }
-    // return sb.toString();
-    // }
-
-    public static Object userLogin(String username, String password, HttpSession session) {
-        log.debug("username: {}, password: {}", username, password);
-        // 查询用户信息
-        String sql = "select * from pm_parse.user where username='" + username + "'";
-        PreparedStatement psmt;
-        try {
-            psmt = conn.prepareStatement(sql);
-            psmt.setQueryTimeout(60 * 10);
-            ResultSet rs = psmt.executeQuery();
-            // 没有查到数据
-            if (!rs.next()) {
-                return "用户名或密码错误!";
-            }
-
-            String passwordStore = rs.getString("password");
-            log.debug("passwordStore: {}", passwordStore);
-            // 密码错误
-            if (!password.equals(passwordStore)) {
-                return "用户名或密码错误!";
-            }
-
-            // 查询地区权限
-            sql = "select area from pm_parse.user_area where username='" + username + "'";
-            psmt = conn.prepareStatement(sql);
-            psmt.setQueryTimeout(60 * 10);
-            rs = psmt.executeQuery();
-            Map<String, String> map = new HashMap<>();
-            while (rs.next()) {
-                String area = rs.getString("area");
-                map.put(area, "");
-            }
-
-            log.debug("areas: {}", map.keySet());
-            // 保存session
-            session.setMaxInactiveInterval(30 * 60);
-            session.setAttribute("username", username);
-            session.setAttribute("areas", map);
-            return null;
-        } catch (SQLException e) {
-            e.printStackTrace();
-            return "数据库异常!";
-        }
-    }
-
-    public static Object addTemplate(String templateName, String indicators, HttpSession session) {
-        log.debug("templateName: {}", templateName);
-        log.debug("indicators: {}", indicators);
-        String username = (String) session.getAttribute("username");
-        long id = System.currentTimeMillis();
-        String sql = "insert into pm_parse.indicator_template (id, template_name, username) values (?, ?, ?)";
-        PreparedStatement psmt;
-        try {
-            conn.setAutoCommit(false);
-            psmt = conn.prepareStatement(sql);
-            psmt.setObject(1, id);
-            psmt.setObject(2, templateName);
-            psmt.setObject(3, username);
-            int rs = psmt.executeUpdate();
-            if (rs < 1) {
-                conn.rollback();
-                return "添加失败";
-            }
-
-            String[] indicatorArray = StringUtils.delete(indicators, "'").split(",");
-            sql = "insert into pm_parse.indicator_template_item (template_id, indicator_id) values (?, ?)";
-            psmt = conn.prepareStatement(sql);
-            for (String s : indicatorArray) {
-                psmt.setObject(1, id);
-                psmt.setObject(2, Integer.valueOf(s));
-                rs = psmt.executeUpdate();
-                if (rs < 1) {
-                    conn.rollback();
-                    return "添加失败";
-                }
-            }
-
-            conn.commit();
-        } catch (SQLException e) {
-            e.printStackTrace();
-            try {
-                conn.rollback();
-            } catch (SQLException ex) {
-                e.printStackTrace();
-                return "添加失败";
-            }
-            return "添加失败";
-        }
-
-        return null;
-    }
-
-    public static List<TreeNode> initTreeIndicatorTemplate(HttpSession session) {
-        // 查询用户指标模板
-        String username = (String) session.getAttribute("username");
-        String sql = "select id, template_name from pm_parse.indicator_template where username = ?";
-        PreparedStatement psmt = null;
-        TreeNode allTree = new TreeNode("指标模板选择", "指标模板选择", true, new ArrayList<>());
-        try {
-            psmt = conn.prepareStatement(sql);
-            psmt.setQueryTimeout(60 * 10);
-            psmt.setObject(1, username);
-            ResultSet rs = psmt.executeQuery();
-            while (rs.next()) {
-                String id = rs.getString("id");
-                String templateName = rs.getString("template_name");
-                TreeNode t = new TreeNode(templateName, id, new ArrayList<>());
-                allTree.getChildren().add(t);
-                // 查询模板下的指标
-                sql = "select x.indicator_cn, x.indicator_en from pm_parse.per_cfg_indicator x where x.indicator_id " +
-                        "in (select indicator_id from pm_parse.indicator_template_item where template_id = ?)";
-                psmt = conn.prepareStatement(sql);
-                psmt.setQueryTimeout(60 * 10);
-                psmt.setObject(1, Long.valueOf(id));
-                ResultSet r = psmt.executeQuery();
-                while (r.next()) {
-                    String indicatorCn = r.getString("indicator_cn");
-                    String indicatorEn = r.getString("indicator_en");
-                    t.getChildren().add(new TreeNode(indicatorCn, indicatorEn));
-                }
-            }
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-        List<TreeNode> res = new ArrayList<>();
-        res.add(allTree);
-        log.debug("initTreeIndicatorTemplate: {}", res);
-        return res;
-    }
-
-    public static Object deleteTemplate(String ids) {
-        log.debug("ids: {}", ids);
-        String sql = "delete from pm_parse.indicator_template where id in (" + ids + ")";
-        PreparedStatement psmt;
-        try {
-            conn.setAutoCommit(false);
-            psmt = conn.prepareStatement(sql);
-            int rs = psmt.executeUpdate();
-            if (rs < 1) {
-                conn.rollback();
-                return "删除失败";
-            }
-
-            sql = "delete from pm_parse.indicator_template_item where template_id in (" + ids + ")";
-            psmt = conn.prepareStatement(sql);
-            rs = psmt.executeUpdate();
-            if (rs < 1) {
-                conn.rollback();
-                return "删除失败";
-            }
-
-            conn.commit();
-        } catch (SQLException e) {
-            e.printStackTrace();
-            try {
-                conn.rollback();
-            } catch (SQLException ex) {
-                e.printStackTrace();
-                return "删除失败";
-            }
-            return "删除失败";
-        }
-
-        return null;
-    }
-
-    // public static List<String> initCitys(String type, String province) {
-    // PreparedStatement psmt = null;
-    // if (type == null) {
-    // type = "roaming";
-    // }
-    //
-    // String sql = "select distinct roaming_city_name as city from
-    // sqmdb_5g.user_terminal_status_5g_abstract where roaming_province_name=? and
-    // roaming_city_name!='null' order by roaming_city_name";
-    //// Map<String,List<String>>res = new HashMap<>();
-    // List<String> res = new ArrayList<>();
-    // if ("roaming".equals(type)) {
-    // sql = "select distinct roaming_city_name as city from
-    // sqmdb_5g.user_terminal_status_5g_abstract where roaming_province_name=? and
-    // roaming_city_name!='null' order by roaming_city_name";
-    //// sql = "select distinct city from sqmdb_5g.roaming_area where province = ?
-    // order by city";
-    //
-    // } else {
-    // sql = "select distinct city_name as city from
-    // sqmdb_5g.user_terminal_status_5g_abstract where province_name=? and
-    // roaming_city_name!='null' order by city_name";
-    //// sql = "select distinct city from sqmdb_5g.local_area where province = ?
-    // order by city";
-    // }
-    // try {
-    // psmt = conn.prepareStatement(sql);
-    // psmt.setQueryTimeout(60 * 10);
-    // psmt.setString(1, province);
-    //
-    // ResultSet rs = psmt.executeQuery();
-    // while (rs.next()) {
-    // String city = rs.getString("city");
-    // res.add(city);
-    //// if(res.keySet().contains(province)){
-    //// List<String> ls = res.get(province);
-    //// ls.add(city);
-    //// }else {
-    //// List<String>as = new ArrayList<>();
-    //// as.add(city);
-    //// res.put(province,as);
-    //// }
-    // }
-    // } catch (SQLException e) {
-    // e.printStackTrace();
-    // }
-    // return res;
-    // }
-
-    // public static List<String> initProvince(String type) {
-    // PreparedStatement psmt = null;
-    // if (type == null) {
-    // type = "roaming";
-    // }
-    // String sql = "";
-    //// String sql = "select distinct roaming_province_name as province from
-    // sqmdb_5g.user_terminal_status_5g_abstract order by roaming_province_name";
-    ////// Map<String,List<String>>res = new HashMap<>();
-    // List<String> res = new ArrayList<>();
-    // if ("roaming".equals(type)) {
-    // sql = "select distinct roaming_province_name as province from
-    // sqmdb_5g.user_terminal_status_5g_abstract order by roaming_province_name";
-    //// sql = "select distinct province from sqmdb_5g.roaming_area order by
-    // province";
-    //
-    // } else {
-    // sql = "select distinct province_name as province from
-    // sqmdb_5g.user_terminal_status_5g_abstract order by province_name";
-    //// sql = "select distinct province from sqmdb_5g.local_area order by
-    // province";
-    // }
-    // try {
-    // psmt = conn.prepareStatement(sql);
-    // psmt.setQueryTimeout(60 * 10);
-    //
-    // ResultSet rs = psmt.executeQuery();
-    // while (rs.next()) {
-    // String province = rs.getString("province");
-    // res.add(province);
-    //// if(res.keySet().contains(province)){
-    //// List<String> ls = res.get(province);
-    //// ls.add(city);
-    //// }else {
-    //// List<String>as = new ArrayList<>();
-    //// as.add(city);
-    //// res.put(province,as);
-    //// }
-    // }
-    // } catch (SQLException e) {
-    // e.printStackTrace();
-    // }
-    // return res;
-    // }
-
-}
+//
+//    public static List<TreeNode> initTreeCitys() {
+//        String sql = "select distinct * from pm_parse.per_cfg_area order by city,quxian";
+//        PreparedStatement psmt = null;
+//        TreeNode allTree = new TreeNode("地市选择", "地市选择", new ArrayList<>());
+//        // int i = 0;
+//        try {
+//            psmt = conn.prepareStatement(sql);
+//            psmt.setQueryTimeout(60 * 10);
+//            ResultSet rs = psmt.executeQuery();
+//            Map<String, List<TreeNode>> m = new HashMap<>();
+//
+//            while (rs.next()) {
+//                String city = rs.getString("city");
+//                String quxian = rs.getString("quxian");
+//                String id = city + quxian;
+//                TreeNode t = new TreeNode(quxian, id, null);
+//                if (m.keySet().contains(city)) {
+//                    m.get(city).add(t);
+//                } else {
+//                    List<TreeNode> l = new ArrayList<>();
+//                    l.add(t);
+//                    m.put(city, l);
+//                }
+//
+//            }
+//
+//            for (String s : m.keySet()) {
+//                allTree.getChildren().add(new TreeNode(s, s, m.get(s)));
+//            }
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//        }
+//        List<TreeNode> res = new ArrayList<>();
+//        allTree.setSpread(true);
+//        res.add(allTree);
+//        log.debug("initTreeCitys: {}", res);
+//        return res;
+//    }
+//
+//    public static List<TreeNode> initTreeIndicator() {
+//        // String sql = "select distinct * from pm_parse.per_cfg_indicator order by
+//        // indicator_type,indicator_cn,indicator_en";
+//        String sql = "select distinct * from pm_parse.per_cfg_indicator order by indicator_id,indicator_type,indicator_cn,indicator_en";
+//        PreparedStatement psmt = null;
+//        TreeNode allTree = new TreeNode("指标选择", "指标选择", new ArrayList<>());
+//        try {
+//            psmt = conn.prepareStatement(sql);
+//            psmt.setQueryTimeout(60 * 10);
+//            ResultSet rs = psmt.executeQuery();
+//            Map<String, List<TreeNode>> m = new HashMap<>();
+//
+//            while (rs.next()) {
+//                String indicator_type = rs.getString("indicator_type");
+//                String indicator_cn = rs.getString("indicator_cn");
+//                String indicator_id = rs.getString("indicator_id");
+//                TreeNode t = new TreeNode(indicator_cn, indicator_id, null);
+//                if (m.keySet().contains(indicator_type)) {
+//                    m.get(indicator_type).add(t);
+//                } else {
+//                    List<TreeNode> l = new ArrayList<>();
+//                    l.add(t);
+//                    m.put(indicator_type, l);
+//                }
+//
+//            }
+//            // int i = 0;
+//            for (String s : m.keySet()) {
+//                allTree.getChildren().add(new TreeNode(s, s, m.get(s)));
+//            }
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//        }
+//        List<TreeNode> res = new ArrayList<>();
+//        allTree.setSpread(true);
+//        res.add(allTree);
+//        log.debug("initTreeIndicator: {}", res);
+//        return res;
+//    }
+//
+//    // public static Map<String, List<Object>> searchRate(String from, String t1,
+//    // String t2, String ttype, String provinces, String citys) {
+//    //
+//    //
+//    // HashMap<String, List<Object>> res = new HashMap<>();
+//    // PreparedStatement psmt = null;
+//    // String pn = "province_name";
+//    // String cn = "city_name";
+//    // if ("roaming".equals(from)) {
+//    // pn = "roaming_province_name";
+//    // cn = "roaming_city_name";
+//    // }
+//    // String sql = "select a.sdate as dt,round(a.openusers/b.users,4) as num from
+//    // \n" +
+//    // "(select sdate,sum(user_count) as openusers from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
+//    // stype='打开5G开关用户数' and size_type='" + ttype + "天' and " + pn + " in (" +
+//    // provinces + ") and " + cn + " in (" + citys + ") group by sdate ) a\n" +
+//    // "inner join\n" +
+//    // "(select sdate,sum(user_count) as users from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
+//    // stype='5G终端用户数' and size_type='" + ttype + "天' and " + pn + " in (" +
+//    // provinces + ") and " + cn + " in (" + citys + ") group by sdate) b\n" +
+//    // "on a.sdate=b.sdate\n" +
+//    // "order by a.sdate";
+//    // if ("".equals(citys)) {
+//    // sql = "select a.sdate as dt,round(a.openusers/b.users,4) as num from \n" +
+//    // "(select sdate,sum(user_count) as openusers from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
+//    // stype='打开5G开关用户数' and size_type='" + ttype + "天' and " + pn + " in (" +
+//    // provinces + ") group by sdate ) a\n" +
+//    // "inner join\n" +
+//    // "(select sdate,sum(user_count) as users from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
+//    // stype='5G终端用户数' and size_type='" + ttype + "天' and " + pn + " in (" +
+//    // provinces + ") group by sdate) b\n" +
+//    // "on a.sdate=b.sdate\n" +
+//    // "order by a.sdate";
+//    // }
+//    //
+//    // List<Object> dtList = new ArrayList<>();
+//    // List<Object> numList = new ArrayList<>();
+//    // try {
+//    // psmt = conn.prepareStatement(sql);
+//    //
+//    // psmt.setQueryTimeout(60 * 10);
+//    // psmt.setLong(1, Integer.valueOf(t1));
+//    // psmt.setLong(2, Integer.valueOf(t2));
+//    // psmt.setLong(3, Integer.valueOf(t1));
+//    // psmt.setLong(4, Integer.valueOf(t2));
+//    //
+//    //// psmt.setString(5,provinces);
+//    //// psmt.setString(6,citys);
+//    // ResultSet rs = psmt.executeQuery();
+//    // while (rs.next()) {
+//    // String dt = rs.getString("dt");
+//    // Long num = rs.getLong("num");
+//    // dtList.add(dt);
+//    // numList.add(num);
+//    // }
+//    // res.put("dt", dtList);
+//    // res.put("num", numList);
+//    // } catch (SQLException e) {
+//    // e.printStackTrace();
+//    // }
+//    // return res;
+//    // }
+//
+//    // public static HashMap<String, List<Object>> search(String from, String t1,
+//    // String t2, String stype, String ttype, String provinces, String citys) {
+//    // HashMap<String, List<Object>> res = new HashMap<>();
+//    // PreparedStatement psmt = null;
+//    // String pn = "province_name";
+//    // String cn = "city_name";
+//    // if ("roaming".equals(from)) {
+//    // pn = "roaming_province_name";
+//    // cn = "roaming_city_name";
+//    // }
+//    //// String sql = "select sdate,sum(user_count) from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between '20210720' and
+//    // '20210727' and stype='5G终端用户数' and size_type='7天' and province_name in ('河北')
+//    // and city_name in ('石家庄','唐山') group by sdate;";
+//    // String sql = "select sdate as dt ,sum(user_count) as num from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
+//    // stype=? and size_type=? and " + pn + " in (" + provinces + ") and " + cn + "
+//    // in (" + citys + ") group by sdate order by sdate;";
+//    // if ("".equals(citys)) {
+//    // sql = "select sdate as dt ,sum(user_count) as num from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where sdate between ? and ? and
+//    // stype=? and size_type=? and " + pn + " in (" + provinces + ") group by sdate
+//    // order by sdate;";
+//    // }
+//    //
+//    // List<Object> dtList = new ArrayList<>();
+//    // List<Object> numList = new ArrayList<>();
+//    // try {
+//    // psmt = conn.prepareStatement(sql);
+//    //
+//    // psmt.setQueryTimeout(60 * 10);
+//    // psmt.setLong(1, Integer.valueOf(t1));
+//    // psmt.setLong(2, Integer.valueOf(t2));
+//    // psmt.setString(3, stype);
+//    // psmt.setString(4, ttype + "天");
+//    //// psmt.setString(5,provinces);
+//    //// psmt.setString(6,citys);
+//    // ResultSet rs = psmt.executeQuery();
+//    // while (rs.next()) {
+//    // String dt = rs.getString("dt");
+//    // Long num = rs.getLong("num");
+//    // dtList.add(dt);
+//    // numList.add(num);
+//    // }
+//    // res.put("dt", dtList);
+//    // res.put("num", numList);
+//    // } catch (SQLException e) {
+//    // e.printStackTrace();
+//    // }
+//    // return res;
+//    // }
+//
+//    // public static String typeExport(String from, String provinces, String citys,
+//    // String ttype, String t1, String t2) {
+//    // String res = "";
+//    // String pn = "province_name";
+//    // String cn = "city_name";
+//    // String guishu = "归属地";
+//    // String area = citys;
+//    // if ("roaming".equals(from)) {
+//    // pn = "roaming_province_name";
+//    // cn = "roaming_city_name";
+//    // guishu = "拜访地";
+//    // }
+//    // String sql = "with tab as (\n" +
+//    // "select distinct\n" +
+//    // "stype,\n" +
+//    // "'" + guishu + "' as 维度, \n" +
+//    // "size_type as 粒度,\n" +
+//    // "'" + area + "' as 区域, \n" +
+//    // "sdate as 日期,\n" +
+//    // "sum(user_count) over(partition by stype,sdate,size_type) as user_count\n" +
+//    // "from sqmdb_5g.user_terminal_status_5g_abstract\n" +
+//    // "where sdate between ? and ? \n" +
+//    // "and " + pn + " in ('" + provinces + "') and " + cn + " in ('" + citys + "')
+//    // \n" +
+//    // "and size_type = '" + ttype + "天'\n" +
+//    // ") \n" +
+//    // "\n" +
+//    // "select \n" +
+//    // "a.维度,\n" +
+//    // "a.粒度,\n" +
+//    // "a.区域,\n" +
+//    // "a.日期,\n" +
+//    // "sum(a.user_count) as 终端用户数,\n" +
+//    // "sum(b.user_count) as 打开5G开关用户数,\n" +
+//    // "sum(c.user_count) as 关闭5G开关用户数,\n" +
+//    // "round(sum(b.user_count)/sum(a.user_count),4) as 开关打开率\n" +
+//    // "from tab a\n" +
+//    // "join tab b on b.日期=a.日期 and b.stype = '打开5G开关用户数'\n" +
+//    // "join tab c on c.日期=a.日期 and c.stype = '关闭5G开关用户数'\n" +
+//    // "where a.stype = '5G终端用户数'\n" +
+//    // "group by \n" +
+//    // "a.维度,\n" +
+//    // "a.粒度,\n" +
+//    // "a.区域,\n" +
+//    // "a.日期\n" +
+//    // "order by 日期";
+//    //
+//    // if ("".equals(citys)) {
+//    // area = provinces;
+//    // sql = "with tab as (\n" +
+//    // "select distinct\n" +
+//    // "stype,\n" +
+//    // "'" + guishu + "' as 维度, \n" +
+//    // "size_type as 粒度,\n" +
+//    // "'" + area + "' as 区域, \n" +
+//    // "sdate as 日期,\n" +
+//    // "sum(user_count) over(partition by stype,sdate,size_type) as user_count\n" +
+//    // "from sqmdb_5g.user_terminal_status_5g_abstract\n" +
+//    // "where sdate between ? and ? \n" +
+//    // "and " + pn + " in ('" + provinces + "') \n" +
+//    // "and size_type = '" + ttype + "天'\n" +
+//    // ") \n" +
+//    // "\n" +
+//    // "select \n" +
+//    // "a.维度,\n" +
+//    // "a.粒度,\n" +
+//    // "a.区域,\n" +
+//    // "a.日期,\n" +
+//    // "sum(a.user_count) as 终端用户数,\n" +
+//    // "sum(b.user_count) as 打开5G开关用户数,\n" +
+//    // "sum(c.user_count) as 关闭5G开关用户数,\n" +
+//    // "round(sum(b.user_count)/sum(a.user_count),4) as 开关打开率\n" +
+//    // "from tab a\n" +
+//    // "join tab b on b.日期=a.日期 and b.stype = '打开5G开关用户数'\n" +
+//    // "join tab c on c.日期=a.日期 and c.stype = '关闭5G开关用户数'\n" +
+//    // "where a.stype = '5G终端用户数'\n" +
+//    // "group by \n" +
+//    // "a.维度,\n" +
+//    // "a.粒度,\n" +
+//    // "a.区域,\n" +
+//    // "a.日期\n" +
+//    // "order by 日期";
+//    // }
+//    //
+//    //
+//    // PreparedStatement psmt = null;
+//    //
+//    //
+//    // try {
+//    // psmt = conn.prepareStatement(sql);
+//    // psmt.setQueryTimeout(60 * 10);
+//    //
+//    // psmt.setLong(1, Integer.valueOf(t1));
+//    // psmt.setLong(2, Integer.valueOf(t2));
+//    // ResultSet rs = psmt.executeQuery();
+//    // res = rsprocess(rs);
+//    // } catch (SQLException e) {
+//    // e.printStackTrace();
+//    // }
+//    // return res;
+//    // }
+//
+//    // public static String exportAll(String ttype, String sts, String ets, String
+//    // smts, String emts) {
+//    // String res = "";
+//    // String range = smts + "-" + ets;
+//    // PreparedStatement psmt = null;
+//    // String sql = "select '" + ttype + "天' as \"粒度\",\n" +
+//    // "'" + range + "' as \"开始(结束)时间\",\n" +
+//    // "msisdn as \"号码\",\n" +
+//    // "province_name as \"归属省\",\n" +
+//    // "city_name as \"归属地市\",\n" +
+//    // "roaming_province_name as \"拜访省\",\n" +
+//    // "roaming_city_name as \"拜访地市\",\n" +
+//    // "tml_brand as \"终端品牌\",\n" +
+//    // "tml_name as \"终端型号\",\n" +
+//    // "case when last_open_date >= ? then 1 else 0 end as \"开关是否打开\" \n" +
+//    // "from sqmdb_5g.user_terminal_status_5g_agg\n" +
+//    // "where sdate=? \n" +
+//    // "and last_chg_date >= ? ";
+//    //
+//    // try {
+//    // psmt = conn.prepareStatement(sql);
+//    // psmt.setQueryTimeout(60 * 10);
+//    //
+//    // psmt.setLong(1, Integer.valueOf(emts));
+//    // psmt.setLong(2, Integer.valueOf(ets));
+//    // psmt.setLong(3, Integer.valueOf(emts));
+//    //
+//    // ResultSet rs = psmt.executeQuery();
+//    // res = rsprocess(rs);
+//    // } catch (SQLException e) {
+//    // e.printStackTrace();
+//    // }
+//    // return res;
+//    // }
+//
+//    // public static String exportClose(String ttype, String sts, String ets, String
+//    // smts, String emts) {
+//    // String res = "";
+//    // String range = smts + "-" + ets;
+//    // PreparedStatement psmt = null;
+//    // String sql = "select '" + ttype + "天' as \"粒度\",\n" +
+//    // "'" + range + "' as \"开始(结束)时间\",\n" +
+//    // "msisdn as \"号码\",\n" +
+//    // "province_name as \"归属省\",\n" +
+//    // "city_name as \"归属地市\",\n" +
+//    // "roaming_province_name as \"拜访省\",\n" +
+//    // "roaming_city_name as \"拜访地市\",\n" +
+//    // "tml_brand as \"终端品牌\",\n" +
+//    // "tml_name as \"终端型号\",\n" +
+//    // "0 as \"开关是否打开\"\n" +
+//    // "from sqmdb_5g.user_terminal_status_5g_agg\n" +
+//    // "where sdate=? \n" +
+//    // "and last_chg_date >= ? \n" +
+//    // "and (last_open_date < ? or last_open_date is null) ";
+//    //
+//    // try {
+//    // psmt = conn.prepareStatement(sql);
+//    // psmt.setQueryTimeout(60 * 10);
+//    //
+//    // psmt.setLong(1, Integer.valueOf(ets));
+//    // psmt.setLong(2, Integer.valueOf(emts));
+//    // psmt.setLong(3, Integer.valueOf(emts));
+//    //
+//    // ResultSet rs = psmt.executeQuery();
+//    // res = rsprocess(rs);
+//    // } catch (SQLException e) {
+//    // e.printStackTrace();
+//    // }
+//    // return res;
+//    // }
+//
+//    // public static String rsprocess(ResultSet rs) {
+//    // List<String> heads = new ArrayList<>();
+//    // String headStr = "";
+//    // StringBuffer sb = new StringBuffer();
+//    // try {
+//    // ResultSetMetaData rsmd = rs.getMetaData();
+//    // for (int i = 1; i <= rsmd.getColumnCount(); i++) {
+//    // String columnName = rsmd.getColumnName(i);
+//    // heads.add(columnName);
+//    // headStr += columnName + ",";
+//    //
+//    // }
+//    //
+//    // headStr = headStr.substring(0, headStr.length() - 1);
+//    // sb.append(headStr + "\n");
+//    // while (rs.next()) {
+//    // String line = "";
+//    // for (String head : heads) {
+//    // line += rs.getString(head) + ",";
+//    //
+//    // }
+//    // line = line.substring(0, line.length() - 1);
+//    // sb.append(line + "\n");
+//    // }
+//    //
+//    // } catch (SQLException throwables) {
+//    // throwables.printStackTrace();
+//    // }
+//    // return sb.toString();
+//    // }
+//
+//    public static Object userLogin(String username, String password, HttpSession session) {
+//        log.debug("username: {}, password: {}", username, password);
+//        // 查询用户信息
+//        String sql = "select * from pm_parse.user where username='" + username + "'";
+//        PreparedStatement psmt;
+//        try {
+//            psmt = conn.prepareStatement(sql);
+//            psmt.setQueryTimeout(60 * 10);
+//            ResultSet rs = psmt.executeQuery();
+//            // 没有查到数据
+//            if (!rs.next()) {
+//                return "用户名或密码错误!";
+//            }
+//
+//            String passwordStore = rs.getString("password");
+//            log.debug("passwordStore: {}", passwordStore);
+//            // 密码错误
+//            if (!password.equals(passwordStore)) {
+//                return "用户名或密码错误!";
+//            }
+//
+//            // 查询地区权限
+//            sql = "select area from pm_parse.user_area where username='" + username + "'";
+//            psmt = conn.prepareStatement(sql);
+//            psmt.setQueryTimeout(60 * 10);
+//            rs = psmt.executeQuery();
+//            Map<String, String> map = new HashMap<>();
+//            while (rs.next()) {
+//                String area = rs.getString("area");
+//                map.put(area, "");
+//            }
+//
+//            log.debug("areas: {}", map.keySet());
+//            // 保存session
+//            session.setMaxInactiveInterval(30 * 60);
+//            session.setAttribute("username", username);
+//            session.setAttribute("areas", map);
+//            return null;
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//            return "数据库异常!";
+//        }
+//    }
+//
+//    public static Object addTemplate(String templateName, String indicators, HttpSession session) {
+//        log.debug("templateName: {}", templateName);
+//        log.debug("indicators: {}", indicators);
+//        String username = (String) session.getAttribute("username");
+//        long id = System.currentTimeMillis();
+//        String sql = "insert into pm_parse.indicator_template (id, template_name, username) values (?, ?, ?)";
+//        PreparedStatement psmt;
+//        try {
+//            conn.setAutoCommit(false);
+//            psmt = conn.prepareStatement(sql);
+//            psmt.setObject(1, id);
+//            psmt.setObject(2, templateName);
+//            psmt.setObject(3, username);
+//            int rs = psmt.executeUpdate();
+//            if (rs < 1) {
+//                conn.rollback();
+//                return "添加失败";
+//            }
+//
+//            String[] indicatorArray = StringUtils.delete(indicators, "'").split(",");
+//            sql = "insert into pm_parse.indicator_template_item (template_id, indicator_id) values (?, ?)";
+//            psmt = conn.prepareStatement(sql);
+//            for (String s : indicatorArray) {
+//                psmt.setObject(1, id);
+//                psmt.setObject(2, Integer.valueOf(s));
+//                rs = psmt.executeUpdate();
+//                if (rs < 1) {
+//                    conn.rollback();
+//                    return "添加失败";
+//                }
+//            }
+//
+//            conn.commit();
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//            try {
+//                conn.rollback();
+//            } catch (SQLException ex) {
+//                e.printStackTrace();
+//                return "添加失败";
+//            }
+//            return "添加失败";
+//        }
+//
+//        return null;
+//    }
+//
+//    public static List<TreeNode> initTreeIndicatorTemplate(HttpSession session) {
+//        // 查询用户指标模板
+//        String username = (String) session.getAttribute("username");
+//        String sql = "select id, template_name from pm_parse.indicator_template where username = ?";
+//        PreparedStatement psmt = null;
+//        TreeNode allTree = new TreeNode("指标模板选择", "指标模板选择", true, new ArrayList<>());
+//        try {
+//            psmt = conn.prepareStatement(sql);
+//            psmt.setQueryTimeout(60 * 10);
+//            psmt.setObject(1, username);
+//            ResultSet rs = psmt.executeQuery();
+//            while (rs.next()) {
+//                String id = rs.getString("id");
+//                String templateName = rs.getString("template_name");
+//                TreeNode t = new TreeNode(templateName, id, new ArrayList<>());
+//                allTree.getChildren().add(t);
+//                // 查询模板下的指标
+//                sql = "select x.indicator_cn, x.indicator_en from pm_parse.per_cfg_indicator x where x.indicator_id " +
+//                        "in (select indicator_id from pm_parse.indicator_template_item where template_id = ?)";
+//                psmt = conn.prepareStatement(sql);
+//                psmt.setQueryTimeout(60 * 10);
+//                psmt.setObject(1, Long.valueOf(id));
+//                ResultSet r = psmt.executeQuery();
+//                while (r.next()) {
+//                    String indicatorCn = r.getString("indicator_cn");
+//                    String indicatorEn = r.getString("indicator_en");
+//                    t.getChildren().add(new TreeNode(indicatorCn, indicatorEn));
+//                }
+//            }
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//        }
+//        List<TreeNode> res = new ArrayList<>();
+//        res.add(allTree);
+//        log.debug("initTreeIndicatorTemplate: {}", res);
+//        return res;
+//    }
+//
+//    public static Object deleteTemplate(String ids) {
+//        log.debug("ids: {}", ids);
+//        String sql = "delete from pm_parse.indicator_template where id in (" + ids + ")";
+//        PreparedStatement psmt;
+//        try {
+//            conn.setAutoCommit(false);
+//            psmt = conn.prepareStatement(sql);
+//            int rs = psmt.executeUpdate();
+//            if (rs < 1) {
+//                conn.rollback();
+//                return "删除失败";
+//            }
+//
+//            sql = "delete from pm_parse.indicator_template_item where template_id in (" + ids + ")";
+//            psmt = conn.prepareStatement(sql);
+//            rs = psmt.executeUpdate();
+//            if (rs < 1) {
+//                conn.rollback();
+//                return "删除失败";
+//            }
+//
+//            conn.commit();
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//            try {
+//                conn.rollback();
+//            } catch (SQLException ex) {
+//                e.printStackTrace();
+//                return "删除失败";
+//            }
+//            return "删除失败";
+//        }
+//
+//        return null;
+//    }
+//
+//    // public static List<String> initCitys(String type, String province) {
+//    // PreparedStatement psmt = null;
+//    // if (type == null) {
+//    // type = "roaming";
+//    // }
+//    //
+//    // String sql = "select distinct roaming_city_name as city from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where roaming_province_name=? and
+//    // roaming_city_name!='null' order by roaming_city_name";
+//    //// Map<String,List<String>>res = new HashMap<>();
+//    // List<String> res = new ArrayList<>();
+//    // if ("roaming".equals(type)) {
+//    // sql = "select distinct roaming_city_name as city from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where roaming_province_name=? and
+//    // roaming_city_name!='null' order by roaming_city_name";
+//    //// sql = "select distinct city from sqmdb_5g.roaming_area where province = ?
+//    // order by city";
+//    //
+//    // } else {
+//    // sql = "select distinct city_name as city from
+//    // sqmdb_5g.user_terminal_status_5g_abstract where province_name=? and
+//    // roaming_city_name!='null' order by city_name";
+//    //// sql = "select distinct city from sqmdb_5g.local_area where province = ?
+//    // order by city";
+//    // }
+//    // try {
+//    // psmt = conn.prepareStatement(sql);
+//    // psmt.setQueryTimeout(60 * 10);
+//    // psmt.setString(1, province);
+//    //
+//    // ResultSet rs = psmt.executeQuery();
+//    // while (rs.next()) {
+//    // String city = rs.getString("city");
+//    // res.add(city);
+//    //// if(res.keySet().contains(province)){
+//    //// List<String> ls = res.get(province);
+//    //// ls.add(city);
+//    //// }else {
+//    //// List<String>as = new ArrayList<>();
+//    //// as.add(city);
+//    //// res.put(province,as);
+//    //// }
+//    // }
+//    // } catch (SQLException e) {
+//    // e.printStackTrace();
+//    // }
+//    // return res;
+//    // }
+//
+//    // public static List<String> initProvince(String type) {
+//    // PreparedStatement psmt = null;
+//    // if (type == null) {
+//    // type = "roaming";
+//    // }
+//    // String sql = "";
+//    //// String sql = "select distinct roaming_province_name as province from
+//    // sqmdb_5g.user_terminal_status_5g_abstract order by roaming_province_name";
+//    ////// Map<String,List<String>>res = new HashMap<>();
+//    // List<String> res = new ArrayList<>();
+//    // if ("roaming".equals(type)) {
+//    // sql = "select distinct roaming_province_name as province from
+//    // sqmdb_5g.user_terminal_status_5g_abstract order by roaming_province_name";
+//    //// sql = "select distinct province from sqmdb_5g.roaming_area order by
+//    // province";
+//    //
+//    // } else {
+//    // sql = "select distinct province_name as province from
+//    // sqmdb_5g.user_terminal_status_5g_abstract order by province_name";
+//    //// sql = "select distinct province from sqmdb_5g.local_area order by
+//    // province";
+//    // }
+//    // try {
+//    // psmt = conn.prepareStatement(sql);
+//    // psmt.setQueryTimeout(60 * 10);
+//    //
+//    // ResultSet rs = psmt.executeQuery();
+//    // while (rs.next()) {
+//    // String province = rs.getString("province");
+//    // res.add(province);
+//    //// if(res.keySet().contains(province)){
+//    //// List<String> ls = res.get(province);
+//    //// ls.add(city);
+//    //// }else {
+//    //// List<String>as = new ArrayList<>();
+//    //// as.add(city);
+//    //// res.put(province,as);
+//    //// }
+//    // }
+//    // } catch (SQLException e) {
+//    // e.printStackTrace();
+//    // }
+//    // return res;
+//    // }
+//
+//}

+ 18 - 0
src/main/java/com/nokia/hb/utils/SessionUtil.java

@@ -0,0 +1,18 @@
+package com.nokia.hb.utils;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * session工具
+ */
+public class SessionUtil {
+    /**
+     * 获得用户名
+     *
+     * @param session 会话
+     * @return {@link String}
+     */
+    public static String getUsername(HttpSession session) {
+        return (String) session.getAttribute("username");
+    }
+}

+ 3 - 0
src/main/resources/application-dev.yml

@@ -0,0 +1,3 @@
+logging:
+  level:
+    com.nokia.hb: debug

+ 8 - 0
src/main/resources/application-prod.yml

@@ -0,0 +1,8 @@
+# 关闭接口文档
+knife4j:
+  production: true
+springdoc:
+  api-docs:
+    enabled: false
+  swagger-ui:
+    enabled: false

+ 7 - 3
src/main/resources/application.yml

@@ -7,6 +7,8 @@ server:
     max-threads: 800
     min-spare-threads: 30
 spring:
+  profiles:
+    active: dev
   thymeleaf:
     prefix: classpath:/templates/
     mode: HTML
@@ -14,8 +16,10 @@ spring:
     encoding: UTF-8
     servlet:
       content-type: text/html
-logging:
-  level:
-    com.nokia.hb: debug
+  datasource:
+    driver-class-name: org.postgresql.Driver
+    url: jdbc:postgresql://10.100.68.195:5432/sqmmt?currentSchema=pm_parse
+    username: pmparse
+    password: abc123!
 session:
   timeout: 1800

+ 1 - 1
src/main/resources/logback-spring.xml

@@ -18,7 +18,7 @@
             <totalSizeCap>20GB</totalSizeCap>
         </rollingPolicy>
         <encoder>
-            <Pattern>%d %highlight(%-5level) %yellow(%X{traceId}) %magenta([%thread]) %cyan(%logger:%line) %msg%n</Pattern>
+            <Pattern>%d %-5level %X{traceId} [%thread] %logger:%line %msg%n</Pattern>
             <charset>UTF-8</charset>
         </encoder>
     </appender>

+ 12 - 13
src/main/resources/templates/login.html

@@ -58,23 +58,22 @@
         form.on('submit(formData)', function (data) {
             const username = data.field.username;
             const password = data.field.password;
+            const dataJson = JSON.stringify({
+                "username": username,
+                "password": password,
+            })
             $.ajax({
                 type: "POST",
-                url: './userLogin',
-                async: false,
-                data: {
-                    "username": username,
-                    "password": password,
-                },
+                contentType: "application/json;charset=UTF-8",
+                url: '/api/userLogin',
+                data: dataJson,
                 success: function (r) {
-                    if (r) {
-                        alert(r)
-                        return false
+                    if (r?.success) {
+                        layer.msg('登录成功');
+                        setTimeout(() => window.location.href = '/template', 1500)
+                        return
                     }
-
-                    layer.msg('登录成功');
-                    window.location.href = '/template'
-                    return true
+                    alert(r?.message ?? '发生错误了');
                 }
             });
             return false

+ 117 - 243
src/main/resources/templates/template.html

@@ -124,9 +124,9 @@
         
                     <div class="timeTypeDiv c1" style="width: 10%;">
                         <select name="timeType" id="timeType">
-                            <option value="quater">15分钟</option>
-                            <option value="hour">小时</option>
-                            <option value="day">天</option>
+                            <option value="QUATER">15分钟</option>
+                            <option value="HOUR">小时</option>
+                            <option value="DAY">天</option>
                             <!--<option value="week">星期</option>-->
                             <!--<option value="month">月</option>-->
                         </select>
@@ -140,8 +140,8 @@
             </br>
                 <div style="width:100%;float: left;">
                     <div class="column" id="searchType" style="width:auto;float: left;">
-                        <input type="radio" name="where" value="area" title="按地市查询" lay-filter="where" checked>
-                        <input type="radio" name="where" value="eci" title="按eci查询" lay-filter="where" >
+                        <input type="radio" name="where" value="AREA" title="按地市查询" lay-filter="where" checked>
+                        <input type="radio" name="where" value="ECI" title="按eci查询" lay-filter="where" >
                     </div>
                     <div style="width:70%;float: left;">
                         <input id="condition" class="layui-input" placeholder="如多个eci查询请用英文逗号隔开"
@@ -196,7 +196,6 @@
                     // layer.alert('Hi,头部工具栏扩展的右侧图标。');
                     var tableData = table.cache['demo']
                     obj.config.title = "地市指标"
-                    // console.log(JSON.stringify(dataA))
                     table.exportFile(obj.config.id, dataA.datas, 'csv')
                 }
             });
@@ -212,29 +211,22 @@
 
         var treeCity;
         function initTreeCity(tree) {
-            console.log('initTreeCity')
             $.ajax({
-                type: "GET",
-                // url: './json/citys.json',
-                url: './initTreeCitys',
-                data: {
-                    "spread": false
-                },
+                type: "POST",
+                // url: '/api/json/citys.json',
+                url: '/api/initTreeCitys',
                 success: function (r) {
-
-                    // console.log(r)
-                    let o = r instanceof Object
-                    if (!o) {
-                        r = JSON.parse(r)
+                    if (r?.success) {
+                        treeCity = tree.render({
+                            elem: '#allArea',
+                            showCheckbox: true,
+                            accordion: true,
+                            id: 'Id1',
+                            data: r?.data
+                        });
+                        return
                     }
-                    treeCity = tree.render({
-                        elem: '#allArea',
-                        showCheckbox: true,
-                        accordion: true,
-                        id: 'Id1',
-                        data: r
-                    });
-                    return false;
+                    alert(r?.message ?? '发生错误了');
                 }
             });
         }
@@ -242,115 +234,95 @@
         var treeIn;
         // 渲染指标模板
         function initTreeIndicatorTemplate(tree) {
-            console.log('initTreeIndicatorTemplate')
             $.ajax({
-                type: "GET",
-                url: './initTreeIndicatorTemplate',
-                data: {
-                    "spread": false
-                },
+                type: "POST",
+                url: '/api/initTreeIndicatorTemplate',
                 success: function (r) {
-                    let o = r instanceof Object
-                    if (!o) {
-                        r = JSON.parse(r)
+                    if (r?.success) {
+                        treeIn = tree.render({
+                            elem: '#indicatorTemplate',
+                            showCheckbox: true,
+                            accordion: true,
+                            id: 'Id3',
+                            data: r?.data
+                        });
+                        return
                     }
-                    treeIn = tree.render({
-                        elem: '#indicatorTemplate',
-                        showCheckbox: true,
-                        accordion: true,
-                        id: 'Id3',
-                        data: r
-                    });
-                    return false;
+                    alert(r?.message ?? '发生错误了');
                 }
             });
         }
 
         function initTreeIndicator(tree) {
-            console.log('initTreeIndicator')
             $.ajax({
-                type: "GET",
-                url: './initTreeIndicator',
-                data: {
-                    "spread": false
-                },
+                type: "POST",
+                url: '/api/initTreeIndicator',
                 success: function (r) {
-                    // console.log(r)
-                    let o = r instanceof Object
-                    if (!o) {
-                        r = JSON.parse(r)
+                    if (r?.success) {
+                        treeIn = tree.render({
+                            elem: '#allIndicator',
+                            showCheckbox: true,
+                            accordion: true,
+                            id: 'Id2',
+                            data: r?.data
+                        });
+                        return
                     }
-                    treeIn = tree.render({
-                        elem: '#allIndicator',
-                        showCheckbox: true,
-                        accordion: true,
-                        id: 'Id2',
-                        data: r
-                    });
-                    return false;
+                    alert(r?.message ?? '发生错误了');
                 }
             });
         }
 
-        function renderTable(condition, searchType, table, citys, quxians, indicators, ttype, sdate) {
-            console.log('renderTable')
-            console.log('layer.load: ', layer.load);
+        function renderTable(condition, searchType, table, citys, quxians, indicators, timeType, startTime, endTime) {
             var tishi = layer.load(1, {
                 shadeClose: false,
                 title: '加载中..',
                 shade: [0.5,'#000'] //0.1透明度的白色背景
             });
-            console.log('tishi: ', tishi);
             // setTimeout(()=>{
             //     layer.close(tishi);
             // },5000)
+            const dataJson = JSON.stringify({
+                "condition": condition,
+                "searchType": searchType,
+                "citys": [...citys],
+                "quxians": [...quxians],
+                "indicators": [...indicators],
+                "timeType": timeType,
+                "startTime": startTime,
+                "endTime": endTime
+            })
             $.ajax({
                 type: "POST",
-                url: './renderTable',
-                async: true,
-                traditional: true,
-                data: {
-                    "condition": condition,
-                    "searchType": searchType,
-                    "citys": citys,
-                    "quxians": quxians,
-                    "indicators": indicators,
-                    "ttype": ttype,
-                    "sdate": sdate
-                },
+                contentType: "application/json;charset=UTF-8",
+                url: '/api/renderTable',
+                data: dataJson,
                 success: function (r) {
                     layer.close(tishi);
-                    dataA = r;
-                    // 没有权限提示
-                    if (r?.msg && r.msg.length > 0) {
-                        alert(r.msg);
-                        return;
-                    }
-                    let o = r instanceof Object
-                    if (!o) {
-                        r = JSON.parse(r)
+                    if (r?.success) {
+                        table.render({
+                            elem: '#demo',
+                            height: 320,
+                            // url: 'https://www.layui.com/demo/table/user/' , //数据接口
+                            page: true, //开启分页
+                            toolbar: true,
+                            defaultToolbar: [{
+                                title: '提示' //标题
+                                ,
+                                layEvent: 'export' //事件名,用于 toolbar 事件中使用
+                                ,
+                                icon: 'layui-icon-export' //图标类名
+                            }],
+                            limit: 50,
+                            limits: [50, 200, 500],
+                            cols: [
+                                r?.data?.cols ?? []
+                            ],
+                            data: r?.data?.datas ?? []
+                        });
+                        return
                     }
-                    table.render({
-                        elem: '#demo',
-                        height: 320,
-                        // url: 'https://www.layui.com/demo/table/user/' , //数据接口
-                        page: true, //开启分页
-                        toolbar: true,
-                        defaultToolbar: [{
-                            title: '提示' //标题
-                            ,
-                            layEvent: 'export' //事件名,用于 toolbar 事件中使用
-                            ,
-                            icon: 'layui-icon-export' //图标类名
-                        }],
-                        limit: 50,
-                        limits: [50, 200, 500],
-                        cols: [
-                            r.cols
-                        ],
-                        data: r.datas
-                    });
-                    return false;
+                    alert(r?.message ?? '发生错误了');
                 },
                 error: function(err){
                     layer.close(tishi);
@@ -358,53 +330,7 @@
             });
         }
 
-        // function conditionRenderTable(table, condition, searchType, indicators, ttype, sdate) {
-        //     console.log('conditionRenderTable')
-        //     $.ajax({
-        //         type: "POST",
-        //         url: './conditionRenderTable',
-        //         async: false,
-        //         data: {
-        //             "condition": condition,
-        //             "searchType": searchType,
-        //             "indicators": indicators,
-        //             "ttype": ttype,
-        //             "sdate": sdate
-        //         },
-        //         success: function (r) {
-        //             dataA = r;
-        //             // console.log(r)
-        //             let o = r instanceof Object
-        //             if (!o) {
-        //                 r = JSON.parse(r)
-        //             }
-        //             table.render({
-        //                 elem: '#demo',
-        //                 height: 320,
-        //                 // url: 'https://www.layui.com/demo/table/user/' , //数据接口
-        //                 page: true, //开启分页
-        //                 toolbar: true,
-        //                 defaultToolbar: [{
-        //                     title: '提示' //标题
-        //                     ,
-        //                     layEvent: 'export' //事件名,用于 toolbar 事件中使用
-        //                     ,
-        //                     icon: 'layui-icon-export' //图标类名
-        //                 }],
-        //                 limit: 50,
-        //                 limits: [50, 200, 500],
-        //                 cols: [
-        //                     r.cols
-        //                 ],
-        //                 data: r.datas
-        //             });
-        //             return false;
-        //         }
-        //     });
-        // }
-
         function search() {
-            // form.on('submit(formDemo)', function (data) {
             if ($('#time1').val() === 0) {
                 alert('填选择时间')
                 return;
@@ -415,86 +341,41 @@
             }
             let condition = $('#condition').val();
             let searchType = $('#searchType').find('input:checked').val()
-            if (searchType === 'eci' && $('#condition').val().length === 0) {
+            if (searchType === 'ECI' && $('#condition').val().length === 0) {
                 alert('请填写eci')
                 return;
             }
-            if (searchType === 'area' && tree.getChecked('Id1').length === 0) {
+            if (searchType === 'AREA' && tree.getChecked('Id1').length === 0) {
                 alert('请选择地市')
                 return;
             }
             alert('开始查询')
             let checkData1 = tree?.getChecked('Id1')?.[0]?.children;
-            let quxians
-            let citys
+            let quxians = new Set()
+            let citys = new Set()
             if (checkData1) {
-                const quxianA = new Set();
-                const citysA = [];
                 checkData1.forEach(eee => {
-                    citysA.push("'" + eee.title + "'")
+                    citys.add(eee.title)
                     eee.children.forEach(ee => {
-                        quxianA.add("'" + ee.title + "'")
+                        quxians.add(ee.title)
                     })
                 });
-                quxians = Array.from(quxianA).join(',')
-                citys = citysA.join(',')
-                console.log(`citys: ${citys}`)
-                console.log(`quxians: ${quxians}`)
             }
             let checkData2 = tree.getChecked('Id3')[0].children;
-            const indicatorsA = new Set();
+            const indicators = new Set();
             checkData2.forEach(eee => {
                 eee.children.forEach(ee => {
-                    indicatorsA.add(ee.id)
+                    indicators.add(ee.id)
                 })
             });
-            indicatorsA.add('eci')
-            const indicators = Array.from(indicatorsA).join(',')
-            console.log(`indicators: ${JSON.stringify(indicators)}`)
-            let ttype = $('#timeType').val()
+            indicators.add('eci')
+            let timeType = $('#timeType').val()
             let sdate = $('#time1').val()
-            console.log(`sdate: ${sdate}`)
-            renderTable(condition, searchType, table, citys, quxians,indicators, ttype, sdate)
+            const [startTime, endTime] = sdate.split(' - ')
+            renderTable(condition, searchType, table, citys, quxians, indicators, timeType, startTime, endTime)
             return false;
         }
 
-        // function conditionSearch() {
-        //     let sdate = $('#time1').val()
-        //     if (sdate.length === 0) {
-        //         alert('请选择时间')
-        //         return;
-        //     }
-        //
-        //     if (tree.getChecked('Id3').length == 0) {
-        //         alert('请选择指标')
-        //         return;
-        //     }
-        //     let condition = $('#condition').val();
-        //     let ttype = $('#timeType').val()
-        //     let searchType = $('#searchType').find('input:checked').val()
-        //     if (searchType === 'eci' && $('#condition').val().length === 0) {
-        //         alert('请填写查询条件')
-        //         return;
-        //     }
-        //     console.log(`searchType: ${searchType}`)
-        //     console.log(`condition: ${condition}`)
-        //     // layer.msg(JSON.stringify(data.field));
-        //     // let checkData1 = tree.getChecked('Id1')[0].children;
-        //     let checkData2 = tree.getChecked('Id3')[0].children;
-        //     const indicatorsA = new Set();
-        //     checkData2.forEach(eee => {
-        //         eee.children.forEach(ee => {
-        //             indicatorsA.add(ee.id)
-        //         })
-        //     });
-        //     indicatorsA.add('eci')
-        //     const indicatorsB = [...indicatorsA]
-        //     const indicators = indicatorsB.join(',')
-        //     console.log(`indicators: ${indicators}`)
-        //     conditionRenderTable(table, condition, searchType, indicators, ttype, sdate)
-        //     return false;
-        // }
-
         // 添加指标模板
         function addTemplate() {
             layer.open({
@@ -515,34 +396,29 @@
                         alert('请选择指标!')
                         return
                     }
-                    console.log(`templateName: ${templateName}`)
-                    console.log(`checkedData: ${JSON.stringify(checkedData)}`)
-                    const indicatorsA = []
+                    const indicators = new Set()
                     checkedData.forEach(eee => {
                         eee.children.forEach(ee => {
-                            indicatorsA.push(ee.id)
+                            indicators.add(ee.id)
                         })
                     });
-                    const indicators = indicatorsA.join(',')
-                    console.log(`indicators: ${indicators}`)
+                    const dataJson = JSON.stringify({
+                        "templateName": templateName,
+                        "indicators": [...indicators],
+                    })
                     $.ajax({
                         type: "POST",
-                        url: './addTemplate',
-                        async: false,
-                        data: {
-                            "templateName": templateName,
-                            "indicators": indicators,
-                        },
+                        contentType: "application/json;charset=UTF-8",
+                        url: '/api/addTemplate',
+                        data: dataJson,
                         success: function (r) {
-                            console.log(`response: ${JSON.stringify(r)}`)
-
-                            if (r) {
-                                alert('添加失败!')
-                            } else {
+                            if (r?.success) {
                                 initTreeIndicatorTemplate(tree)
                                 layer.msg('添加成功')
                                 layer.close(index)
+                                return
                             }
+                            alert(r?.message ?? '发生错误了');
                         }
                     });
                 },
@@ -552,34 +428,32 @@
         // 删除指标模板
         function deleteTemplate() {
             const checkedData = tree?.getChecked('Id3')?.[0]?.children
-            const idArray = []
-            checkedData.forEach(t => {
-                idArray.push(t.id)
-            });
             if (!checkedData || checkedData.length <= 0) {
                 alert('请选择要删除的指标模板!')
                 return
             }
+            const ids = new Set()
+            checkedData.forEach(t => {
+                ids.add(t.id)
+            });
+            const dataJson = JSON.stringify({
+                "ids": [...ids],
+            })
             layer.confirm('确认删除?', {icon: 3, title:'删除模板'}, function(index){
-                const ids = idArray.join(',')
-                console.log(`deleteTemplate: ${JSON.stringify(idArray)}`)
                 $.ajax({
                     type: "POST",
-                    url: './deleteTemplate',
-                    async: false,
-                    data: {
-                        "ids": ids,
-                    },
+                    contentType: "application/json;charset=UTF-8",
+                    url: '/api/deleteTemplate',
+                    // async: false,
+                    data: dataJson,
                     success: function (r) {
-                        console.log(`response: ${JSON.stringify(r)}`)
-
-                        if (r) {
-                            alert('删除失败!')
-                        } else {
+                        if (r?.success) {
                             initTreeIndicatorTemplate(tree)
                             layer.msg('删除成功')
                             layer.close(index)
+                            return
                         }
+                        alert(r?.message ?? '发生错误了')
                     }
                 });
             });

+ 73 - 0
src/test/java/com/nokia/hb/MybatisPlusGenerator.java

@@ -0,0 +1,73 @@
+package com.nokia.hb;
+
+import com.baomidou.mybatisplus.generator.FastAutoGenerator;
+import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
+import com.baomidou.mybatisplus.generator.config.OutputFile;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.annotations.Mapper;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.Collections;
+
+/**
+ * mybatis plus生成器
+ */
+@Slf4j
+@SpringBootTest
+class MybatisPlusGenerator {
+    @Autowired
+    private DataSourceProperties dataSourceProperties;
+
+    @Test
+    void generate() {
+        log.info("dataSourceProperties: {}, {}, {}", dataSourceProperties.getUrl(), dataSourceProperties.getUsername(),
+                dataSourceProperties.getPassword());
+        FastAutoGenerator g1 = create();
+        g1.strategyConfig(builder -> {
+            builder.addInclude("user_area", "indicator_template_item")
+                    .entityBuilder()
+//                    .enableFileOverride()
+                    .enableLombok()
+                    .enableChainModel()
+                    .mapperBuilder()
+                    .mapperAnnotation(Mapper.class);
+        }).execute();
+        FastAutoGenerator g2 = create();
+        g2.strategyConfig(builder -> {
+            builder.addInclude("user", "indicator_template", "per_cfg_indicator", "per_cfg_cell", "per_cfg_area")
+                    .entityBuilder()
+//                    .enableFileOverride()
+                    .enableLombok()
+                    .enableChainModel()
+                    .enableTableFieldAnnotation()
+                    .mapperBuilder()
+                    .mapperAnnotation(Mapper.class);
+        }).execute();
+    }
+
+    FastAutoGenerator create() {
+        return FastAutoGenerator.create(new DataSourceConfig
+                        .Builder(dataSourceProperties.getUrl(), dataSourceProperties.getUsername(),
+                        dataSourceProperties.getPassword())
+                )
+                .globalConfig(builder -> {
+                    builder.disableOpenDir()
+                            .outputDir("src/main/java");
+                })
+                .packageConfig(builder -> {
+                    builder.parent("com.nokia.hb.dao")
+                            .pathInfo(Collections.singletonMap(OutputFile.xml, "src/main/resources/mapper"));
+
+                })
+                .templateConfig(builder -> {
+//                    builder.mapper("");
+                    builder.controller("");
+                    builder.xml("");
+                    builder.service("");
+                    builder.serviceImpl("");
+                });
+    }
+}