Преглед изворни кода

tsl_data v1 数据生成部分1.0版本完成

lifuquan пре 2 година
родитељ
комит
1a6f506ef1
21 измењених фајлова са 647 додато и 163 уклоњено
  1. 0 23
      doc/开发文档/tsl_data/接口测试.md
  2. 42 0
      doc/开发文档/tsl_data/本地环境接口测试.md
  3. 51 0
      doc/开发文档/tsl_data/部署环境接口测试.md
  4. 2 0
      doc/开发文档/开发文档.md
  5. 18 1
      doc/开发文档/数据库文档/一些语句.sql
  6. 44 0
      tsl_data/src/main/java/com/nokia/common/spring/SpringContextHolder.java
  7. 2 0
      tsl_data/src/main/java/com/nokia/tsl_data/TslDataApplication.java
  8. 22 0
      tsl_data/src/main/java/com/nokia/tsl_data/config/BeanConfig.java
  9. 37 0
      tsl_data/src/main/java/com/nokia/tsl_data/config/TaskRunner.java
  10. 128 0
      tsl_data/src/main/java/com/nokia/tsl_data/controller/TslTaskConroller.java
  11. 0 34
      tsl_data/src/main/java/com/nokia/tsl_data/controller/TslWaraHouseConroller.java
  12. 16 0
      tsl_data/src/main/java/com/nokia/tsl_data/dao/TslDao.java
  13. 70 0
      tsl_data/src/main/java/com/nokia/tsl_data/service/TslCronTaskService.java
  14. 58 86
      tsl_data/src/main/java/com/nokia/tsl_data/service/TslReportService.java
  15. 101 0
      tsl_data/src/main/java/com/nokia/tsl_data/service/TslTaskService.java
  16. 15 14
      tsl_data/src/main/java/com/nokia/tsl_data/service/TslWaraHouseService.java
  17. 8 0
      tsl_data/src/main/java/com/nokia/tsl_data/service/exception/TslTaskException.java
  18. 3 0
      tsl_data/src/main/resources/application-dev.properties
  19. 9 1
      tsl_data/src/main/resources/application.properties
  20. 6 0
      tsl_data/src/main/resources/mapper/TslDao.xml
  21. 15 4
      tsl_data/src/test/java/com/nokia/tsl_data/TslDataApplicationTest.java

+ 0 - 23
doc/开发文档/tsl_data/接口测试.md

@@ -1,23 +0,0 @@
-# 接口测试
-
-## 数据手动入库
-
-```http
-POST http://192.168.10.7:29100/tsl/warahouse/manually HTTP/1.1
-Content-Type:application/json
-
-{
-    "type":"MOBILE_COMP",
-    "day":"20230421"
-}
-```
-
-```http
-POST http://192.168.10.7:29100/tsl/warahouse/manually HTTP/1.1
-Content-Type:application/json
-
-{
-    "type":"HIGH_QUALITY",
-    "day":"20230421"
-}
-```

+ 42 - 0
doc/开发文档/tsl_data/本地环境接口测试.md

@@ -0,0 +1,42 @@
+# 接口测试
+
+## 数据手动入库
+
+```http
+POST http://127.0.0.1:29100/tsl/task/warahouse/manually HTTP/1.1
+Content-Type:application/json
+
+20230425
+```
+
+## 定时任务
+
+### 查询定时任务
+
+```http
+POST http://127.0.0.1:29100/tsl/task/cron/status HTTP/1.1
+Content-Type:application/json
+```
+
+### 停止定时任务
+
+```http
+POST http://127.0.0.1:29100/tsl/task/cron/stop HTTP/1.1
+Content-Type:application/json
+```
+
+### 启动定时任务
+
+```http
+POST http://127.0.0.1:29100/tsl/task/cron/start HTTP/1.1
+Content-Type:application/json
+```
+
+### 修改定时表达式
+
+```http
+POST http://127.0.0.1:29100/tsl/task/cron/expression HTTP/1.1
+Content-Type:application/json
+
+0/25 * * * 
+```

+ 51 - 0
doc/开发文档/tsl_data/部署环境接口测试.md

@@ -0,0 +1,51 @@
+# 接口测试
+
+## 数据手动入库
+
+```http
+POST http://192.168.10.7:29100/tsl/task/warhouse HTTP/1.1
+Content-Type:application/json
+
+20230425
+```
+
+## 手动生成报表
+
+```http
+POST http://192.168.10.7:29100/tsl/task/report/generate HTTP/1.1
+Content-Type:application/json
+
+20230425
+```
+
+## 定时任务
+
+### 查询定时任务
+
+```http
+POST http://127.0.0.1:29100/tsl/task/cron/status HTTP/1.1
+Content-Type:application/json
+```
+
+### 停止定时任务
+
+```http
+POST http://127.0.0.1:29100/tsl/task/cron/stop HTTP/1.1
+Content-Type:application/json
+```
+
+### 启动定时任务
+
+```http
+POST http://127.0.0.1:29100/tsl/task/cron/start HTTP/1.1
+Content-Type:application/json
+```
+
+### 修改定时表达式
+
+```http
+POST http://127.0.0.1:29100/tsl/task/cron/expression HTTP/1.1
+Content-Type:application/json
+
+0/25 * * * 
+```

+ 2 - 0
doc/开发文档/开发文档.md

@@ -1,5 +1,7 @@
 # 开发文档
 
+nohup java -jar tsl_data-1.0-exec.jar >output.log 2>&1 &
+
 ## 钉钉API相关汇总
 
 [钉钉api地址](https://open.dingtalk.com/document/orgapp/api-overview)

+ 18 - 1
doc/开发文档/数据库文档/一些语句.sql

@@ -22,4 +22,21 @@ select t4.compl_area_local, t4.total_num, t9.timeout_num, t9.timeout_num/t4.tota
 with t1 as (select compl_area_local, case when proce_time != '' then (extract('epoch' from to_timestamp(proce_time, 'YYYY-MM-DD HH24:MI:SS')) - extract('epoch' from to_timestamp(accept_time, 'YYYY-MM-DD HH24:MI:SS')))/3600 when is_online_complete = '是' then 0
 else (extract('epoch' from to_timestamp(end_time, 'YYYY-MM-DD HH24:MI:SS')) - extract('epoch' from to_timestamp(accept_time, 'YYYY-MM-DD HH24:MI:SS')))/3600 end as duration
 from report_auto.he_d_mobile_comp hdmc where month_id = substring('20230420' from 1 for 6) and day_id <= substring('20230420' from 7 for 2))
-select compl_area_local, avg(duration) as avg_duration from t1 group by compl_area_local
+select compl_area_local, avg(duration) as avg_duration from t1 group by compl_area_local
+
+-- 客户端统计
+with t1 as (select businoareaname, complaint_satisfied_list::numeric, complaint_satisfied_count::numeric,
+complaint_resolution_list::numeric, complaint_resolution_count::numeric,
+complaint_response_list::numeric, complaint_response_count::numeric from report_auto.he_d_high_quality hdhq 
+where acct_date = '2023-04-20'
+and profes_dep = '网络质量'
+and big_type_name = '移网网络体验'
+and small_type_name = '--')
+select '全省' as businoareaname, 
+sum(complaint_satisfied_list) / sum(complaint_satisfied_count) as complaint_satisfied,
+sum(complaint_resolution_list) / sum(complaint_resolution_count) as complaint_resolution,
+sum(complaint_response_list) / sum(complaint_response_count) as complaint_response from t1 union
+select businoareaname, 
+complaint_satisfied_list / complaint_satisfied_count as complaint_satisfied, 
+complaint_resolution_list / complaint_resolution_count as complaint_resolution, 
+complaint_response_list / complaint_response_count as complaint_response from t1

+ 44 - 0
tsl_data/src/main/java/com/nokia/common/spring/SpringContextHolder.java

@@ -0,0 +1,44 @@
+package com.nokia.common.spring;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ConfigurableApplicationContext;
+
+/*
+ * 自动注入springboot项目,可用于获取spring容器的上下文信息
+ */
+public class SpringContextHolder implements ApplicationContextAware {
+
+    private static ApplicationContext applicationContext;
+
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        SpringContextHolder.applicationContext = applicationContext;
+    }
+
+    public static ApplicationContext getContext() {
+        assertApplicationContext();
+        return applicationContext;
+    }
+
+    public static void close() {
+        ((ConfigurableApplicationContext) applicationContext).close();
+    }
+
+    public static <T> T getBean(Class<T> requiredType) {
+        assertApplicationContext();
+        return applicationContext.getBean(requiredType);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String beanName) {
+        assertApplicationContext();
+        return (T) applicationContext.getBean(beanName);
+    }
+
+    private static void assertApplicationContext() {
+        if (SpringContextHolder.applicationContext == null) {
+            throw new RuntimeException("applicationContext属性为null,请检查是否正常注入了SpringContextHolder!");
+        }
+    }
+}

+ 2 - 0
tsl_data/src/main/java/com/nokia/tsl_data/TslDataApplication.java

@@ -2,8 +2,10 @@ package com.nokia.tsl_data;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
 
 @SpringBootApplication
+@EnableTransactionManagement
 public class TslDataApplication {
 
     public static void main(String[] args) {

+ 22 - 0
tsl_data/src/main/java/com/nokia/tsl_data/config/BeanConfig.java

@@ -0,0 +1,22 @@
+package com.nokia.tsl_data.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+
+@Configuration
+public class BeanConfig {
+
+    private int poolSize = 1;
+
+    @Bean
+    public ThreadPoolTaskScheduler taskScheduler() {
+        // 使用最常用的ThreadPoolTaskScheduler
+        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
+        // 线程数
+        taskScheduler.setPoolSize(poolSize);
+        taskScheduler.setRemoveOnCancelPolicy(true);
+        taskScheduler.setThreadNamePrefix("taskSchedulerThreadPool-");
+        return taskScheduler;
+    }
+}

+ 37 - 0
tsl_data/src/main/java/com/nokia/tsl_data/config/TaskRunner.java

@@ -0,0 +1,37 @@
+package com.nokia.tsl_data.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+import com.nokia.tsl_data.service.TslCronTaskService;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 在项目启动时根据配置启动任务
+ */
+@Slf4j
+@Component
+public class TaskRunner implements CommandLineRunner {
+
+    @Value("${tslTask.isStarted}")
+    private boolean isStarted;
+
+    @Value("${tslTask.cronExpression}")
+    private String cronExpression;
+
+    @Autowired
+    private TslCronTaskService cronTaskService;
+
+    @Override
+    public void run(String... args) throws Exception {
+        cronTaskService.updateCronExpression(cronExpression);
+        if (isStarted) {
+            cronTaskService.startCronTask();
+        }
+        log.info("已启动定时任务");
+    }
+
+}

+ 128 - 0
tsl_data/src/main/java/com/nokia/tsl_data/controller/TslTaskConroller.java

@@ -0,0 +1,128 @@
+package com.nokia.tsl_data.controller;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import org.springframework.scheduling.support.CronExpression;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.nokia.common.http.R;
+import com.nokia.tsl_data.service.TslCronTaskService;
+import com.nokia.tsl_data.service.TslTaskService;
+
+/**
+ * 投诉率相关数据源入库
+ * 
+ * 1. 支持定时任务状态查询、修改定时任务表达式、启动或停止定时任务
+ * 支持手动重新生成某天的报告或入库
+ */
+@RequestMapping("/tsl/task")
+@RestController
+public class TslTaskConroller {
+
+    private final TslTaskService taskService;
+    private final TslCronTaskService cronTaskService;
+
+    public TslTaskConroller(TslTaskService taskService, TslCronTaskService cronTaskService) {
+        this.taskService = taskService;
+        this.cronTaskService = cronTaskService;
+    }
+
+    /**
+     * 手动入库
+     * 
+     * @param day
+     * @return
+     */
+    @PostMapping("/warahouse")
+    public R warahouseManually(@RequestBody String day) {
+        try {
+            taskService.dataWaraHouseTask(day);
+            return R.ok().message("入库成功");
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+            return R.error().message(String.format("文件缺失--%s", e.getMessage()));
+        } catch (IOException e) {
+            e.printStackTrace();
+            return R.error().message(String.format("文件IO错误--%s", e.getMessage()));
+        } catch (Exception e) {
+            e.printStackTrace();
+            return R.error().message(String.format("发生错误--%s", e.getMessage()));
+        }
+    }
+
+    /**
+     * 手动生成报告
+     * 
+     * @param day
+     * @return
+     */
+    @PostMapping("/report/generate")
+    public R reportGenrateManully(@RequestBody String day) {
+        try {
+            taskService.reportGenerateTask(day);
+            return R.ok().message("报告生成成功");
+        } catch (NullPointerException e) {
+            e.printStackTrace();
+            return R.error().message(String.format("数据不全, 请检查数据库"));
+        } catch (Exception e) {
+            e.printStackTrace();
+            return R.error().message(String.format("发生未知错误--%s", e.getMessage()));
+        }
+    }
+
+    /**
+     * 启动定时任务
+     * 
+     * @return
+     */
+    @PostMapping("/cron/start")
+    public R startCronTask() {
+        cronTaskService.startCronTask();
+        return R.ok().message("任务启动成功");
+    }
+
+    /**
+     * 停止定时任务
+     * 
+     * @return
+     */
+    @PostMapping("/cron/stop")
+    public R stopCronTask() {
+        cronTaskService.stopCronTask();
+        return R.ok().message("任务已停止");
+    }
+
+    /**
+     * 查询定时任务状态
+     * 
+     * @return
+     */
+    @PostMapping("/cron/status")
+    public R getCronTaskStatus() {
+        String cronExpression = cronTaskService.getCronExpression();
+        boolean started = cronTaskService.isStarted();
+        String status = started ? "启动中" : "已停止";
+        return R.ok().message(String.format("任务状态:%s, 定时表达式:%s", status, cronExpression));
+    }
+
+    /**
+     * 修改定时任务定时表达式
+     * 
+     * @return
+     */
+    @PostMapping("/cron/expression")
+    public R updateCronTaskExpression(@RequestBody String cronExpression) {
+        try {
+            CronExpression.parse(cronExpression);
+        } catch (IllegalArgumentException e) {
+            return R.error().message(String.format("输入的表达式有误, 任务状态不变:%s", e.getMessage()));
+        }
+        String oldCronExpression = cronTaskService.getCronExpression();
+        cronTaskService.updateCronExpression(cronExpression);
+        return R.ok().message(String.format("定时表达式更新成功, 新表达式:%s, 原表达式:%s", cronExpression, oldCronExpression));
+    }
+}

+ 0 - 34
tsl_data/src/main/java/com/nokia/tsl_data/controller/TslWaraHouseConroller.java

@@ -1,34 +0,0 @@
-package com.nokia.tsl_data.controller;
-
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.nokia.common.http.R;
-import com.nokia.tsl_data.service.TslWaraHouseService;
-import com.nokia.tsl_data.vo.WarahouseManuallyRequest;
-
-/**
- * 投诉率相关数据源入库
- */
-@RequestMapping("/tsl/warahouse")
-@RestController
-public class TslWaraHouseConroller {
-
-    private final TslWaraHouseService tslWaraHouseService;
-
-    public TslWaraHouseConroller(TslWaraHouseService tslWaraHouseService) {
-        this.tslWaraHouseService = tslWaraHouseService;
-    }
-
-    @PostMapping("/manually")
-    public R warahouseManually(@RequestBody WarahouseManuallyRequest request) {
-        if (request.getType().equalsIgnoreCase("MOBILE_COMP")) {
-            tslWaraHouseService.waraHouseMobileComp(request.getDay());
-        } else if (request.getType().equalsIgnoreCase("HIGH_QUALITY")) {
-            tslWaraHouseService.waraHouseHighQuality(request.getDay());
-        }
-        return R.ok().message("入库成功");
-    }
-}

+ 16 - 0
tsl_data/src/main/java/com/nokia/tsl_data/dao/TslDao.java

@@ -9,6 +9,22 @@ import org.apache.ibatis.annotations.Param;
 @Mapper
 public interface TslDao {
 
+    /**
+     * 查询某天的河北_CEM移网质量投诉明细数据量
+     * 
+     * @param day
+     * @return
+     */
+    int selectCompCountForDay(String day);
+
+    /**
+     * 查询河北_CEM高品质2日统计数据量
+     * 
+     * @param day
+     * @return
+     */
+    int selectQualityCountForDay(String day);
+
     /**
      * 客户端-投诉问题解决满意度
      * 客户端-投诉问题解决率

+ 70 - 0
tsl_data/src/main/java/com/nokia/tsl_data/service/TslCronTaskService.java

@@ -0,0 +1,70 @@
+package com.nokia.tsl_data.service;
+
+import java.util.concurrent.ScheduledFuture;
+
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.scheduling.support.CronTrigger;
+import org.springframework.stereotype.Service;
+
+import lombok.Getter;
+
+/**
+ * 定时任务相关逻辑
+ * 
+ * 支持查询任务状态、启动任务、停止任务、修改任务定时表达式
+ */
+@Service
+public class TslCronTaskService {
+
+    @Getter
+    private String cronExpression;
+    @Getter
+    private boolean isStarted = false;
+    private ScheduledFuture<?> future = null;
+
+    private final ThreadPoolTaskScheduler taskScheduler;
+    private final TslTaskService tslTaskService;
+
+    public TslCronTaskService(ThreadPoolTaskScheduler taskScheduler, TslTaskService tslTaskService) {
+        this.taskScheduler = taskScheduler;
+        this.tslTaskService = tslTaskService;
+    }
+
+    /**
+     * 启动任务
+     */
+    public void startCronTask() {
+        if (!isStarted) {
+            future = taskScheduler.schedule(tslTaskService.cronTask(), new CronTrigger(cronExpression));
+            isStarted = true;
+        }
+    }
+
+    /**
+     * 停止任务
+     */
+    public void stopCronTask() {
+        if (isStarted) {
+            if (future != null) {
+                // 如果有正在执行的任务,需要执行完
+                future.cancel(false);
+            }
+            isStarted = false;
+        }
+    }
+
+    /**
+     * 修改任务定时表达式
+     * 
+     * @param cronExpression
+     */
+    public void updateCronExpression(String newCronExpression) {
+        cronExpression = newCronExpression;
+        if (isStarted) {
+            // 如果任务在启动状态,需要停止任务并重新启动
+            startCronTask();
+            startCronTask();
+        }
+    }
+
+}

+ 58 - 86
tsl_data/src/main/java/com/nokia/tsl_data/service/TslReportService.java

@@ -43,13 +43,6 @@ public class TslReportService {
 
     private XSSFWorkbook workbook = null;
 
-    // 等线 9号字 普通单元格 带边框
-    private XSSFCellStyle cellStyle1 = null;
-    // 等线 9号字 加粗 标题栏 带边框
-    private XSSFCellStyle cellStyle2 = null;
-    // 等线 9号字 带边框 小数 保留2位
-    private XSSFCellStyle cellStyle3 = null;
-
     private static final DateFormat DAY_FORMAT = new SimpleDateFormat("yyyyMMdd");
 
     public TslReportService(TslDataService tslDataService) {
@@ -66,7 +59,7 @@ public class TslReportService {
             workbook.close();
             workbook = null;
         } catch (Exception e) {
-            log.info("写入失败。。。");
+            log.error("写入失败。。。");
         }
     }
 
@@ -597,10 +590,42 @@ public class TslReportService {
         Row row;
         Cell cell;
 
+        XSSFCellStyle cellStyle1 = getWorkbook().createCellStyle();
+        cellStyle1.setAlignment(HorizontalAlignment.CENTER);
+        XSSFFont font = getWorkbook().createFont();
+        font.setFontName("等线");
+        font.setBold(false);
+        font.setFontHeightInPoints((short) 9);
+        cellStyle1.setFont(font);
+        cellStyle1.setBorderBottom(BorderStyle.THIN);
+        cellStyle1.setBorderTop(BorderStyle.THIN);
+        cellStyle1.setBorderLeft(BorderStyle.THIN);
+        cellStyle1.setBorderRight(BorderStyle.THIN);
+        XSSFCellStyle cellStyle3 = getWorkbook().createCellStyle();
+        cellStyle3.setAlignment(HorizontalAlignment.CENTER);
+        cellStyle3.setFont(font);
+        cellStyle3.setBorderBottom(BorderStyle.THIN);
+        cellStyle3.setBorderTop(BorderStyle.THIN);
+        cellStyle3.setBorderLeft(BorderStyle.THIN);
+        cellStyle3.setBorderRight(BorderStyle.THIN);
+        XSSFDataFormat format = getWorkbook().createDataFormat();
+        cellStyle3.setDataFormat(format.getFormat("0.00"));
+        XSSFCellStyle cellStyle2 = getWorkbook().createCellStyle();
+        cellStyle2.setAlignment(HorizontalAlignment.CENTER);
+        font = getWorkbook().createFont();
+        font.setFontName("等线");
+        font.setBold(true);
+        font.setFontHeightInPoints((short) 9);
+        cellStyle2.setFont(font);
+        cellStyle2.setBorderBottom(BorderStyle.THIN);
+        cellStyle2.setBorderTop(BorderStyle.THIN);
+        cellStyle2.setBorderLeft(BorderStyle.THIN);
+        cellStyle2.setBorderRight(BorderStyle.THIN);
+
         // 第一行 标题栏
         cell = sheet.createRow(0).createCell(0);
         cell.setCellValue("2023年客服投诉清单各地市投诉率情况(管理端-移网质量类)");
-        cell.setCellStyle(getCellStyle2());
+        cell.setCellStyle(cellStyle2);
         // 合并单元格
         CellRangeAddress range = new CellRangeAddress(0, 0, 0, dayOfMonth + 7);
         sheet.addMergedRegion(range);
@@ -614,33 +639,33 @@ public class TslReportService {
         row = sheet.createRow(1);
         cell = row.createCell(0);
         cell.setCellValue("地市");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
         for (int i = 1; i <= dayOfMonth; i++) {
             cell = row.createCell(i);
             cell.setCellValue(i + "日");
-            cell.setCellStyle(getCellStyle1());
+            cell.setCellStyle(cellStyle1);
         }
         cell = row.createCell(dayOfMonth + 1);
         cell.setCellValue("投诉总量");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
         cell = row.createCell(dayOfMonth + 2);
         cell.setCellValue("用户数");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
         cell = row.createCell(dayOfMonth + 3);
         cell.setCellValue("目前万投率");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
         cell = row.createCell(dayOfMonth + 4);
         cell.setCellValue("本月预测");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
         cell = row.createCell(dayOfMonth + 5);
         cell.setCellValue("目标值");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
         cell = row.createCell(dayOfMonth + 6);
         cell.setCellValue("与目标差距");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
         cell = row.createCell(dayOfMonth + 7);
         cell.setCellValue("地市");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
 
         // 获取数据
         Map<String, List<Object>> seet1Data = tslDataService.getSeet1Data(day);
@@ -653,16 +678,16 @@ public class TslReportService {
             // 写入A列的地市
             cell = row.createCell(cellNum++);
             cell.setCellValue(area);
-            cell.setCellStyle(getCellStyle1());
+            cell.setCellStyle(cellStyle1);
             for (Object obj : seet1Data.get(area)) {
                 cell = row.createCell(cellNum++);
                 cell.setCellValue(Double.parseDouble(obj.toString()));
-                cell.setCellStyle(getCellStyle1());
+                cell.setCellStyle(cellStyle1);
             }
-            // 写入AC列的地市
+            // 写入最后一列的地市
             cell = row.createCell(cellNum++);
             cell.setCellValue(area);
-            cell.setCellStyle(getCellStyle1());
+            cell.setCellStyle(cellStyle1);
             // cellNum复位
             cellNum = 0;
         }
@@ -671,37 +696,37 @@ public class TslReportService {
         // 写入A列的地市
         cell = row.createCell(cellNum++);
         cell.setCellValue("全省");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
         for (Object obj : seet1Data.get("全省")) {
             cell = row.createCell(cellNum++);
             cell.setCellValue(Double.parseDouble(obj.toString()));
-            cell.setCellStyle(getCellStyle1());
+            cell.setCellStyle(cellStyle1);
         }
-        // 写入AC列的地市
+        // 写入最后一列的地市
         cell = row.createCell(cellNum++);
         cell.setCellValue("全省");
-        cell.setCellStyle(getCellStyle1());
+        cell.setCellStyle(cellStyle1);
 
-        // 3-15行(2-14)X列到AB列 (23-27)是浮点数,设置为显示小数点后2位
+        // 3-15行(2-14)dayOfMonth+2 - dayofMonth+6是浮点数,设置为显示小数点后2位
         for (int i = 2; i <= 14; i++) {
             row = sheet.getRow(i);
-            for (int j = 23; j <= 27; j++) {
+            for (int j = dayOfMonth + 2; j <= dayOfMonth + 6; j++) {
                 cell = row.getCell(j);
-                cell.setCellStyle(getCellStyle3());
+                cell.setCellStyle(cellStyle3);
             }
         }
 
         // 添加条件格式B15-V15
         CellRangeAddress rangeAddress = new CellRangeAddress(rowNum, rowNum, 1, dayOfMonth);
         setConditionalFormatting(sheet, rangeAddress);
-        // 添加条件格式Y3-Y14
-        rangeAddress = new CellRangeAddress(2, 13, 24, 24);
+        // 添加条件格式(dayOfMonth+3)(3-14)
+        rangeAddress = new CellRangeAddress(2, 13, dayOfMonth + 3, dayOfMonth + 3);
         setConditionalFormatting(sheet, rangeAddress);
         // 添加条件格式Z3-Z14
-        rangeAddress = new CellRangeAddress(2, 13, 25, 25);
+        rangeAddress = new CellRangeAddress(2, 13, dayOfMonth + 4, dayOfMonth + 4);
         setConditionalFormatting(sheet, rangeAddress);
         // 添加条件格式AB3-AB14
-        rangeAddress = new CellRangeAddress(2, 13, 27, 27);
+        rangeAddress = new CellRangeAddress(2, 13, dayOfMonth + 6, dayOfMonth + 6);
         setConditionalFormatting(sheet, rangeAddress);
 
         // 设置sheet的列宽 1409, 876, 876, ..., 876, 1792, 1665, 2177, 2844, 1409, 2177, 1409
@@ -730,59 +755,6 @@ public class TslReportService {
         return this.workbook;
     }
 
-    private XSSFCellStyle getCellStyle1() {
-        if (cellStyle1 == null) {
-            cellStyle1 = getWorkbook().createCellStyle();
-            cellStyle1.setAlignment(HorizontalAlignment.CENTER);
-            XSSFFont font = getWorkbook().createFont();
-            font.setFontName("等线");
-            font.setBold(false);
-            font.setFontHeightInPoints((short) 9);
-            cellStyle1.setFont(font);
-            cellStyle1.setBorderBottom(BorderStyle.THIN);
-            cellStyle1.setBorderTop(BorderStyle.THIN);
-            cellStyle1.setBorderLeft(BorderStyle.THIN);
-            cellStyle1.setBorderRight(BorderStyle.THIN);
-        }
-        return this.cellStyle1;
-    }
-
-    private XSSFCellStyle getCellStyle2() {
-        if (cellStyle2 == null) {
-            cellStyle2 = getWorkbook().createCellStyle();
-            cellStyle2.setAlignment(HorizontalAlignment.CENTER);
-            XSSFFont font = getWorkbook().createFont();
-            font.setFontName("等线");
-            font.setBold(true);
-            font.setFontHeightInPoints((short) 9);
-            cellStyle2.setFont(font);
-            cellStyle2.setBorderBottom(BorderStyle.THIN);
-            cellStyle2.setBorderTop(BorderStyle.THIN);
-            cellStyle2.setBorderLeft(BorderStyle.THIN);
-            cellStyle2.setBorderRight(BorderStyle.THIN);
-        }
-        return this.cellStyle2;
-    }
-
-    private XSSFCellStyle getCellStyle3() {
-        if (cellStyle3 == null) {
-            cellStyle3 = getWorkbook().createCellStyle();
-            cellStyle3.setAlignment(HorizontalAlignment.CENTER);
-            XSSFFont font = getWorkbook().createFont();
-            font.setFontName("等线");
-            font.setBold(false);
-            font.setFontHeightInPoints((short) 9);
-            cellStyle3.setFont(font);
-            cellStyle3.setBorderBottom(BorderStyle.THIN);
-            cellStyle3.setBorderTop(BorderStyle.THIN);
-            cellStyle3.setBorderLeft(BorderStyle.THIN);
-            cellStyle3.setBorderRight(BorderStyle.THIN);
-            XSSFDataFormat format = getWorkbook().createDataFormat();
-            cellStyle3.setDataFormat(format.getFormat("0.00"));
-        }
-        return this.cellStyle3;
-    }
-
     /**
      * 添加合并单元格并添加边框
      * 

+ 101 - 0
tsl_data/src/main/java/com/nokia/tsl_data/service/TslTaskService.java

@@ -0,0 +1,101 @@
+package com.nokia.tsl_data.service;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.nokia.tsl_data.dao.TslDao;
+import com.nokia.tsl_data.service.exception.TslTaskException;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 任务
+ */
+@Slf4j
+@Service
+public class TslTaskService {
+
+    private final TslReportService tslReportService;
+    private final TslWaraHouseService tslWaraHouseService;
+    private final TslDao tslDao;
+
+    @Value("${tslTask.outputPath}")
+    private String outputPath;
+
+    private String outputFileName = "投诉清单各地市投诉率";
+
+    public TslTaskService(TslReportService tslReportService, TslWaraHouseService tslWaraHouseService, TslDao tslDao) {
+        this.tslReportService = tslReportService;
+        this.tslWaraHouseService = tslWaraHouseService;
+        this.tslDao = tslDao;
+    }
+
+    /**
+     * 定时任务
+     * 
+     * @return
+     */
+    public Runnable cronTask() {
+        return new Runnable() {
+
+            @Override
+            public void run() {
+                // 获取入参 day
+                String day = new SimpleDateFormat("yyyyMMdd")
+                        .format(new Date(System.currentTimeMillis() - 1000L * 3600 * 24));
+
+                try {
+                    dataWaraHouseTask(day);
+                    reportGenerateTask(day);
+                } catch (Exception e) {
+                    log.error("定时任务出错--{}", e.getMessage());
+                    e.printStackTrace();
+                }
+            }
+
+        };
+    }
+
+    /**
+     * 报表生成任务
+     * 
+     * @param day
+     * @throws TslTaskException
+     */
+    public void reportGenerateTask(String day) throws TslTaskException {
+        File file = new File(outputPath + day);
+        if (!file.exists()) {
+            file.mkdirs();
+        }
+        String dayId = day.substring(0, 4) + "-" + day.substring(4, 6) + "-" + day.substring(6);
+        int qualityCountForDay = tslDao.selectQualityCountForDay(dayId);
+        if (qualityCountForDay == 0) {
+            throw new TslTaskException("he_d_high_quality表缺少数据");
+        }
+        int compCountForDay = tslDao.selectCompCountForDay(day);
+        if (compCountForDay == 0) {
+            throw new TslTaskException("he_d_mobile_comp表缺少数据");
+        }
+        tslReportService.workbookToFile(day, file.getAbsolutePath() + "/" + outputFileName + day + ".xlsx");
+    }
+
+    /**
+     * 数据入库任务
+     * 
+     * @param day
+     * @throws IOException
+     * @throws FileNotFoundException
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void dataWaraHouseTask(String day) throws FileNotFoundException, IOException {
+        tslWaraHouseService.waraHouseHighQuality(day);
+        tslWaraHouseService.waraHouseMobileComp(day);
+    }
+}

+ 15 - 14
tsl_data/src/main/java/com/nokia/tsl_data/service/TslWaraHouseService.java

@@ -1,6 +1,7 @@
 package com.nokia.tsl_data.service;
 
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
@@ -16,12 +17,9 @@ import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import lombok.extern.slf4j.Slf4j;
-
 /**
  * 原始数据入库
  */
-@Slf4j
 @Service
 public class TslWaraHouseService {
 
@@ -51,12 +49,17 @@ public class TslWaraHouseService {
         this.jdbcTemplate = jdbcTemplate;
     }
 
+    
+
     /**
      * 河北_CEM移网质量投诉明细 数据入库
      * report_auto.he_d_mobile_comp
+     * 
+     * @throws IOException
+     * @throws FileNotFoundException
      */
-    @Transactional
-    public void waraHouseMobileComp(String day) {
+    @Transactional(rollbackFor = Exception.class)
+    public void waraHouseMobileComp(String day) throws FileNotFoundException, IOException {
         String filePath = MOBILE_COMP_DIR + MOBILE_COMP_PREFIX + day + ".csv";
         try (Reader reader = new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8)) {
             CSVParser parser = CSVFormat.DEFAULT.builder()
@@ -75,19 +78,19 @@ public class TslWaraHouseService {
                     ps[i] = record.get(i);
                 }
             }
-
             jdbcTemplate.batchUpdate(MOBILE_COMP_SQL, list);
-        } catch (IOException e) {
-            log.info("csv文件读取错误--{}", filePath);
-            e.printStackTrace();
         }
     }
 
     /**
      * 河北_CEM高品质2日统计 数据入库
      * report_auto.he_d_high_quality
+     * 
+     * @throws IOException
+     * @throws FileNotFoundException
      */
-    public void waraHouseHighQuality(String day) {
+    @Transactional(rollbackFor = Exception.class)
+    public void waraHouseHighQuality(String day) throws FileNotFoundException, IOException {
         String filePath = HIGH_QUALITY_DIR + HIGH_QUALITY_PREFIX + day + ".csv";
         try (Reader reader = new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8)) {
             CSVParser parser = CSVFormat.DEFAULT.builder()
@@ -106,11 +109,9 @@ public class TslWaraHouseService {
                     ps[i] = record.get(i);
                 }
             }
-
+            // 出发exception
+            // System.out.println(10 / 0);
             jdbcTemplate.batchUpdate(HIGH_QUALITY_SQL, list);
-        } catch (IOException e) {
-            log.info("csv文件读取错误--{}", filePath);
-            e.printStackTrace();
         }
     }
 }

+ 8 - 0
tsl_data/src/main/java/com/nokia/tsl_data/service/exception/TslTaskException.java

@@ -0,0 +1,8 @@
+package com.nokia.tsl_data.service.exception;
+
+public class TslTaskException extends Exception {
+    
+    public TslTaskException(String msg) {
+        super(msg);
+    }
+}

+ 3 - 0
tsl_data/src/main/resources/application-dev.properties

@@ -13,3 +13,6 @@ spring.datasource.password=Richr00t!
 # 测试环境路径配置--本地PC
 tslTask.source.MOBILE_COMP_DIR=D:/src/
 tslTask.source.HIGH_QUALITY_DIR=D:/src/
+
+# 生成文件的输出路径,末尾带/
+tslTask.outputPath=D:/src/

+ 9 - 1
tsl_data/src/main/resources/application.properties

@@ -20,4 +20,12 @@ tslTask.source.HIGH_QUALITY_FIELD_NUM=33
 # 达标值 满意率92%,解决率85%,响应率99%
 tslTask.compliance.satisfied=0.92
 tslTask.compliance.resolution=0.85
-tslTask.compliance.response=0.99
+tslTask.compliance.response=0.99
+
+# 生成文件的输出路径,末尾带/
+tslTask.outputPath=/data/report_auto/output/
+
+# 定时任务
+tslTask.isStarted=true
+# 定时任务表达式每天应只执行1次,默认每天14点10分执行
+tslTask.cronExpression=0 10 14 * * *

+ 6 - 0
tsl_data/src/main/resources/mapper/TslDao.xml

@@ -3,6 +3,12 @@
 
 <mapper namespace="com.nokia.tsl_data.dao.TslDao">
 
+    <select id="selectCompCountForDay" resultType="int"> select count(1) from
+        report_auto.he_d_mobile_comp where acct_date = #{day} </select>
+
+    <select id="selectQualityCountForDay" resultType="int"> select count(1) from
+        report_auto.he_d_high_quality where acct_date = #{day} </select>
+
     <select id="selectClientRatioForDay" resultType="Map">with t1 as (select businoareaname,
         complaint_satisfied_list::numeric, complaint_satisfied_count::numeric,
         complaint_resolution_list::numeric, complaint_resolution_count::numeric,

+ 15 - 4
tsl_data/src/test/java/com/nokia/tsl_data/TslDataApplicationTest.java

@@ -5,16 +5,27 @@ import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
-import com.nokia.tsl_data.service.TslReportService;
+import com.nokia.tsl_data.dao.TslDao;
+import com.nokia.tsl_data.service.TslTaskService;
+import com.nokia.tsl_data.service.exception.TslTaskException;
 
 @SpringBootTest
 public class TslDataApplicationTest {
 
     @Autowired
-    private TslReportService tslReportService;
+    private TslTaskService taskService;
 
     @Test
-    void test() throws IOException {
-        tslReportService.workbookToFile("20230421", "D:/src/dddddd.xlsx");
+    void test() throws IOException, TslTaskException {
+        taskService.reportGenerateTask("20230425");
+    }
+
+    @Autowired
+    private TslDao tslDao;
+
+    @Test
+    void test1() {
+        System.out.println(tslDao.selectCompCountForDay("20230420"));
+        System.out.println(tslDao.selectQualityCountForDay("2023-04-20"));
     }
 }