Browse Source

睿行数据迁移能力商店

weijianghai 1 month ago
parent
commit
4d86f82408
52 changed files with 5648 additions and 2681 deletions
  1. 6 0
      pom.xml
  2. 20 0
      readme.md
  3. 16 0
      src/main/java/com/nokia/finance/tasks/config/JobConfig.java
  4. 61 2
      src/main/java/com/nokia/finance/tasks/dao/car/CarProcedureDao.java
  5. 8 0
      src/main/java/com/nokia/finance/tasks/enums/JobEnum.java
  6. 4 3
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarBaoXianJob.java
  7. 4 3
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarDaWeiXiuJob.java
  8. 4 2
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarFuWuFeiJob.java
  9. 4 3
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarLuQiaoJob.java
  10. 4 3
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarNianJianFeiJob.java
  11. 4 3
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarQiTaJob.java
  12. 4 3
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarRanYouJob.java
  13. 4 2
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarSiCheGongYongJob.java
  14. 4 3
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarWeiXiuJob.java
  15. 4 2
      src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarZuLinJob.java
  16. 1 1
      src/main/java/com/nokia/finance/tasks/jobs/car/procedure/CarBaseDataMonthProcJob.java
  17. 2 1
      src/main/java/com/nokia/finance/tasks/jobs/car/procedure/CarFeeProcJob.java
  18. 1 1
      src/main/java/com/nokia/finance/tasks/jobs/car/procedure/CarLiChengMonthProcJob.java
  19. 1 1
      src/main/java/com/nokia/finance/tasks/jobs/car/procedure/CarPaiDanProcJob.java
  20. 350 350
      src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarBaoFeiJob.java
  21. 379 379
      src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarBaseDataDayJob.java
  22. 365 365
      src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarLiChengDayJob.java
  23. 368 368
      src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarLiChengMonthJob.java
  24. 354 354
      src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarWuDanYongCheJob.java
  25. 382 382
      src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarYongCheJob.java
  26. 354 354
      src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarYueJieJob.java
  27. 305 0
      src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarBaoFeiMonthTask.java
  28. 323 0
      src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarBaseDataDayTask.java
  29. 308 0
      src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarLiChengDayTask.java
  30. 310 0
      src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarLiChengMonthTask.java
  31. 305 0
      src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarWuDanYongCheDayTask.java
  32. 307 0
      src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarWuDanYongCheMonthTask.java
  33. 293 0
      src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarYongCheDayTask.java
  34. 293 0
      src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarYongCheMonthTask.java
  35. 307 0
      src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarYueJieDayTask.java
  36. 16 4
      src/main/java/com/nokia/finance/tasks/jobs/car/shujucangku/CarFeeBsJob.java
  37. 16 4
      src/main/java/com/nokia/finance/tasks/jobs/car/shujucangku/CarFeeHbJob.java
  38. 4 3
      src/main/java/com/nokia/finance/tasks/jobs/house/chengben/HouseBuildingRepairMonthJob.java
  39. 4 2
      src/main/java/com/nokia/finance/tasks/jobs/house/chengben/HouseRentInRepairMonthJob.java
  40. 27 21
      src/main/java/com/nokia/finance/tasks/service/JobService.java
  41. 19 11
      src/main/resources/application-dev.yml
  42. 16 8
      src/main/resources/application-prod.yml
  43. 3 3
      src/test/java/com/nokia/finance/tasks/car/ruixing/CarBaoFeiJobTests.java
  44. 3 3
      src/test/java/com/nokia/finance/tasks/car/ruixing/CarBaseDataDayJobTests.java
  45. 3 3
      src/test/java/com/nokia/finance/tasks/car/ruixing/CarLiChengDayJobTests.java
  46. 3 3
      src/test/java/com/nokia/finance/tasks/car/ruixing/CarLiChengMonthJobTests.java
  47. 22 0
      src/test/java/com/nokia/finance/tasks/car/ruixing/CarWuDanYongCheDayJobTests.java
  48. 3 3
      src/test/java/com/nokia/finance/tasks/car/ruixing/CarWuDanYongCheJobTests.java
  49. 22 0
      src/test/java/com/nokia/finance/tasks/car/ruixing/CarYongCheDayJobTests.java
  50. 3 3
      src/test/java/com/nokia/finance/tasks/car/ruixing/CarYongCheJobTests.java
  51. 3 3
      src/test/java/com/nokia/finance/tasks/car/ruixing/CarYueJieJobTests.java
  52. 22 22
      src/test/java/com/nokia/finance/tasks/gdc/car/CarPhpRequestLogJobTests.java

+ 6 - 0
pom.xml

@@ -130,6 +130,12 @@
             <artifactId>netty-all</artifactId>
             <version>4.2.0.Final</version>
         </dependency>
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-launcher</artifactId>
+            <version>1.8.2</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <dependencyManagement>

+ 20 - 0
readme.md

@@ -70,6 +70,26 @@ curl --location 'http://127.0.0.1:39110/jobs/runJob' \
 }'
 ```
 
+##### 睿行车辆无单用车报警日统计数据入库定时任务
+
+```shell
+curl --location 'http://127.0.0.1:39110/jobs/runJob' \
+--header 'Content-Type: application/json' \
+--data '{
+    "jobName": "CAR_WU_DAN_YONG_CHE_DAY_JOB"
+}'
+```
+
+##### 睿行车辆用车日统计数据入库定时任务
+
+```shell
+curl --location 'http://127.0.0.1:39110/jobs/runJob' \
+--header 'Content-Type: application/json' \
+--data '{
+    "jobName": "CAR_YONG_CHE_DAY_JOB"
+}'
+```
+
 ##### 睿行车辆行驶里程日数据入库定时任务
 
 ```shell

+ 16 - 0
src/main/java/com/nokia/finance/tasks/config/JobConfig.java

@@ -248,6 +248,22 @@ public class JobConfig {
      * 河北成本管理系统车辆租赁费用数据归档路径
      */
     private String carZuLinHistoryPath;
+    /**
+     * 睿行车辆无单用车报警日统计数据路径
+     */
+    private String carWuDanYongCheDaySourcePath;
+    /**
+     * 睿行车辆无单用车报警日统计数据归档路径
+     */
+    private String carWuDanYongCheDayHistoryPath;
+    /**
+     * 睿行车辆用车日统计数据路径
+     */
+    private String carYongCheDaySourcePath;
+    /**
+     * 睿行车辆用车日统计数据归档路径
+     */
+    private String carYongCheDayHistoryPath;
     /**
      * 策略输出临时路径
      */

+ 61 - 2
src/main/java/com/nokia/finance/tasks/dao/car/CarProcedureDao.java

@@ -545,8 +545,8 @@ t107 as (
 t111 as (
 select
     case
-        when (select not exists(select 1 from car.car_base_data_month b where b.che_pai_hao = a.che_pai_hao and b.year_month = a.stat_year_month)) then 0
         when (select exists(select 1 from car.car_bao_fei b where b.che_pai_hao = a.che_pai_hao and b.year_month <= a.stat_year_month)) then 0
+        when (select not exists(select 1 from car.car_base_data_month b where b.che_pai_hao = a.che_pai_hao and b.year_month = a.stat_year_month)) then 0
         when first_unit = '省公司本部' then 0
         when position('建设部' in che_liang_suo_shu_dan_wei) > 0 then 0
         when che_liang_lei_xing in ('特种车', '中型面包车(8-20座的面包车)', '大巴车') then 0
@@ -558,8 +558,8 @@ select
         else 0
     end as di_xiao_sum,
     case
-        when (select not exists(select 1 from car.car_base_data_month b where b.che_pai_hao = a.che_pai_hao and b.year_month = a.stat_year_month)) then '当月车辆基本信息不存在'
         when (select exists(select 1 from car.car_bao_fei b where b.che_pai_hao = a.che_pai_hao and b.year_month <= a.stat_year_month and b.valid = 1)) then (select max(b.year_month) from car.car_bao_fei b where b.che_pai_hao = a.che_pai_hao and b.year_month <= a.stat_year_month) || '报废'
+        when (select not exists(select 1 from car.car_base_data_month b where b.che_pai_hao = a.che_pai_hao and b.year_month = a.stat_year_month)) then '车辆基本信息已删除'
         when first_unit = '省公司本部' then '省公司本部'
         when position('建设部' in che_liang_suo_shu_dan_wei) > 0 then '建设部'
         when che_liang_lei_xing = '特种车' then '特种车'
@@ -1927,6 +1927,65 @@ where year_month = #{endYearMonth}
 """)
     int updateCarFeiYongMonthBaseInfo(@Param("endYearMonth") Integer endYearMonth);
 
+    /**
+     * 插入车辆费用不存在的基本信息
+     * @param endYearMonth 账期
+     */
+    @Update("""
+insert into car.car_fei_yong_month
+(
+year_month,
+che_pai_hao,
+che_liang_lai_yuan,
+che_liang_lei_xing,
+che_liang_shi_yong_xing_zhi,
+che_liang_suo_shu_dan_wei,
+first_unit,
+second_unit,
+third_unit,
+area_no,
+area_name,
+city_no,
+city_name,
+area_name2,
+area_no2,
+city_id,
+city,
+district_id,
+district,
+year_no,
+month_no,
+rui_xing,
+rui_xing_month
+)
+select
+year_month,
+che_pai_hao,
+che_liang_lai_yuan,
+che_liang_lei_xing,
+che_liang_shi_yong_xing_zhi,
+che_liang_suo_shu_dan_wei,
+first_unit,
+second_unit,
+third_unit,
+area_no,
+area_name,
+city_no,
+city_name,
+area_name2,
+area_no2,
+city_id,
+city,
+district_id,
+district,
+year_no,
+month_no,
+1 as rui_xing,
+1 as rui_xing_month
+from car.car_base_data_month a where year_month = #{endYearMonth} and not exists (select 1 from car.car_fei_yong_month b where a.year_month = b.year_month and a.che_pai_hao = b.che_pai_hao)
+""")
+    int insertCarFeiYongMonthBaseInfo(@Param("endYearMonth") Integer endYearMonth);
+
     /**
      * 判断是否有车辆基本信息、用车数据
      * @param endYearMonth 账期

+ 8 - 0
src/main/java/com/nokia/finance/tasks/enums/JobEnum.java

@@ -25,6 +25,14 @@ public enum JobEnum {
      * 睿行车辆用车月统计数据入库定时任务
      */
     CAR_YONG_CHE_JOB,
+    /**
+     * 睿行车辆无单用车报警日统计数据入库定时任务
+     */
+    CAR_WU_DAN_YONG_CHE_DAY_JOB,
+    /**
+     * 睿行车辆用车日统计数据入库定时任务
+     */
+    CAR_YONG_CHE_DAY_JOB,
     /**
      * 河北成本管理系统车辆燃油数据入库定时任务
      */

+ 4 - 3
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarBaoXianJob.java

@@ -69,11 +69,12 @@ public class CarBaoXianJob {
         Path dir = Paths.get(jobConfig.getCarBaoXianSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆保险数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆保险数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarBaoXianHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -114,7 +115,8 @@ public class CarBaoXianJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -237,7 +239,6 @@ public class CarBaoXianJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarBaoXianHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getCarBaoXianHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 4 - 3
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarDaWeiXiuJob.java

@@ -69,11 +69,12 @@ public class CarDaWeiXiuJob {
         Path dir = Paths.get(jobConfig.getCarDaWeiXiuSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆大额维修数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆大额维修数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarDaWeiXiuHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -114,7 +115,8 @@ public class CarDaWeiXiuJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -234,7 +236,6 @@ public class CarDaWeiXiuJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarDaWeiXiuHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getCarDaWeiXiuHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 4 - 2
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarFuWuFeiJob.java

@@ -38,11 +38,12 @@ public class CarFuWuFeiJob {
         Path dir = Paths.get(jobConfig.getCarFuWuFeiSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆服务费数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆服务费数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarFuWuFeiHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -68,7 +69,8 @@ public class CarFuWuFeiJob {
     public void singleJob(Path path) throws IOException {
         if (Files.size(path) == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         move(path);
     }

+ 4 - 3
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarLuQiaoJob.java

@@ -69,11 +69,12 @@ public class CarLuQiaoJob {
         Path dir = Paths.get(jobConfig.getCarLuQiaoSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆路桥数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆路桥数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarLuQiaoHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -114,7 +115,8 @@ public class CarLuQiaoJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -233,7 +235,6 @@ public class CarLuQiaoJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarLuQiaoHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getCarLuQiaoHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 4 - 3
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarNianJianFeiJob.java

@@ -69,11 +69,12 @@ public class CarNianJianFeiJob {
         Path dir = Paths.get(jobConfig.getCarNianJianFeiSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆年检数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆年检数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarNianJianFeiHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -114,7 +115,8 @@ public class CarNianJianFeiJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -233,7 +235,6 @@ public class CarNianJianFeiJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarNianJianFeiHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getCarNianJianFeiHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 4 - 3
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarQiTaJob.java

@@ -69,11 +69,12 @@ public class CarQiTaJob {
         Path dir = Paths.get(jobConfig.getCarQiTaSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆其他费用数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆其他费用数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarQiTaHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -114,7 +115,8 @@ public class CarQiTaJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -233,7 +235,6 @@ public class CarQiTaJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarQiTaHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getCarQiTaHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 4 - 3
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarRanYouJob.java

@@ -69,11 +69,12 @@ public class CarRanYouJob {
         Path dir = Paths.get(jobConfig.getCarRanYouSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆燃油数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆燃油数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarRanYouHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -114,7 +115,8 @@ public class CarRanYouJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -235,7 +237,6 @@ public class CarRanYouJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarRanYouHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getCarRanYouHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 4 - 2
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarSiCheGongYongJob.java

@@ -38,11 +38,12 @@ public class CarSiCheGongYongJob {
         Path dir = Paths.get(jobConfig.getCarSiCheGongYongSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆私车公用数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆私车公用数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarSiCheGongYongHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -68,7 +69,8 @@ public class CarSiCheGongYongJob {
     public void singleJob(Path path) throws IOException {
         if (Files.size(path) == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         move(path);
     }

+ 4 - 3
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarWeiXiuJob.java

@@ -69,11 +69,12 @@ public class CarWeiXiuJob {
         Path dir = Paths.get(jobConfig.getCarWeiXiuSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆普通维修数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆普通维修数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarWeiXiuHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -114,7 +115,8 @@ public class CarWeiXiuJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -234,7 +236,6 @@ public class CarWeiXiuJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarWeiXiuHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getCarWeiXiuHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 4 - 2
src/main/java/com/nokia/finance/tasks/jobs/car/chengben/CarZuLinJob.java

@@ -38,11 +38,12 @@ public class CarZuLinJob {
         Path dir = Paths.get(jobConfig.getCarZuLinSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统车辆租赁费用数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统车辆租赁费用数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarZuLinHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -68,7 +69,8 @@ public class CarZuLinJob {
     public void singleJob(Path path) throws IOException {
         if (Files.size(path) == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         move(path);
     }

+ 1 - 1
src/main/java/com/nokia/finance/tasks/jobs/car/procedure/CarBaseDataMonthProcJob.java

@@ -37,7 +37,7 @@ public class CarBaseDataMonthProcJob {
     /**
      * 执行任务
      */
-    @Scheduled(cron = "0 0 0 7 * ?")
+    @Scheduled(cron = "0 0 0 10 * ?")
     @Transactional(timeout = 60, rollbackFor = Exception.class)
     public void runJob() {
         log.info("执行车辆基本信息月数据加工定时任务");

+ 2 - 1
src/main/java/com/nokia/finance/tasks/jobs/car/procedure/CarFeeProcJob.java

@@ -59,13 +59,14 @@ public class CarFeeProcJob {
             Integer endYearMonth = Integer.valueOf(localDateEnd.format(DateTimeFormatter.ofPattern("yyyyMM")));
             // 开始年月
             Integer startYearMonth = Integer.valueOf(localDateStart.format(DateTimeFormatter.ofPattern("yyyyMM")));
+            carProcedureDao.insertCarFeiYongMonthBaseInfo(endYearMonth);
             carProcedureDao.insertCarQiTa(endYearMonth);
             carProcedureDao.insertCarNianJianFei(endYearMonth);
             carProcedureDao.insertCarBaoXian(endYearMonth);
             carProcedureDao.insertCarLuQiao(endYearMonth);
             carProcedureDao.insertCarWeiXiu(endYearMonth);
             carProcedureDao.insertCarRanYou(endYearMonth);
-            carProcedureDao.insertCarZuLin(endYearMonth);
+//            carProcedureDao.insertCarZuLin(endYearMonth);
             carProcedureDao.updateCarQiTan(endYearMonth);
             carProcedureDao.updateCarNianJianFei(endYearMonth);
             carProcedureDao.updateCarBaoXian(endYearMonth);

+ 1 - 1
src/main/java/com/nokia/finance/tasks/jobs/car/procedure/CarLiChengMonthProcJob.java

@@ -33,7 +33,7 @@ public class CarLiChengMonthProcJob {
     /**
      * 执行任务
      */
-    @Scheduled(cron = "0 2 0 7 * ?")
+    @Scheduled(cron = "0 2 0 10 * ?")
     @Transactional(timeout = 60, rollbackFor = Exception.class)
     public void runJob() {
         log.info("执行车辆行驶里程月数据加工定时任务");

+ 1 - 1
src/main/java/com/nokia/finance/tasks/jobs/car/procedure/CarPaiDanProcJob.java

@@ -37,7 +37,7 @@ public class CarPaiDanProcJob {
     /**
      * 执行任务
      */
-    @Scheduled(cron = "0 4 0 7 * ?")
+    @Scheduled(cron = "0 4 0 10 * ?")
     @Transactional(timeout = 60, rollbackFor = Exception.class)
     public void runJob() {
         log.info("执行车辆派单数据加工定时任务");

+ 350 - 350
src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarBaoFeiJob.java

@@ -1,350 +1,350 @@
-package com.nokia.finance.tasks.jobs.car.ruixing;
-
-import com.nokia.finance.tasks.common.exception.MyRuntimeException;
-import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
-import com.nokia.finance.tasks.config.JobConfig;
-import com.nokia.finance.tasks.enums.DataStageEnum;
-import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
-import com.nokia.finance.tasks.pojo.po.common.AreaPo;
-import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
-import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
-import com.nokia.finance.tasks.service.car.CarService;
-import com.nokia.finance.tasks.service.common.AreaService;
-import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
-import com.nokia.finance.tasks.service.common.OrganizationService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVPrinter;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-/**
- * 睿行车辆报废月数据入库定时任务
- */
-@Slf4j
-@Service
-public class CarBaoFeiJob {
-    private final JobConfig jobConfig;
-    private final CarService carService;
-    private final OrganizationService organizationService;
-    private final AreaService areaService;
-    private final DataLogServiceImpl dataLogService;
-
-    public CarBaoFeiJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
-                        AreaService areaService, DataLogServiceImpl dataLogService) {
-        this.jobConfig = jobConfig;
-        this.carService = carService;
-        this.organizationService = organizationService;
-        this.areaService = areaService;
-        this.dataLogService = dataLogService;
-    }
-
-    /**
-     * 执行任务
-     */
-    @Scheduled(cron = "0 0 5 1 * ?")
-    public void runJob() {
-        List<DataLogPo> dataLogPoList = new ArrayList<>();
-        // 数据目录
-        Path dir = Paths.get(jobConfig.getCarBaoFeiSourcePath());
-        try (Stream<Path> stream = Files.list(dir)) {
-            // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
-            log.info("睿行车辆报废月数据文件列表: {}", pathList);
-            if (CollectionUtils.isEmpty(pathList)) {
-                throw new MyRuntimeException("睿行车辆报废月数据没有文件");
-            }
-            for (Path path : pathList) {
-                CompletableFuture.runAsync(() -> {
-                    try {
-                        singleJob(path, dataLogPoList);
-                    } catch (Exception e) {
-                        throw new MyRuntimeException(e);
-                    }
-                }).get(1, TimeUnit.MINUTES);
-            }
-        } catch (InterruptedException e) {
-            log.error("线程中断: {}", e, e);
-            Thread.currentThread().interrupt();
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆报废月数据", DataStageEnum.CC, "入库");
-        } catch (Exception e) {
-            log.error(e.toString(), e);
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆报废月数据", DataStageEnum.CC, "入库");
-        } finally {
-            if (!CollectionUtils.isEmpty(dataLogPoList)) {
-                dataLogService.saveBatch(dataLogPoList);
-            }
-        }
-    }
-
-    /**
-     * 处理单个文件
-     *
-     * @param path          文件路径
-     * @param dataLogPoList 数据处理日志列表
-     */
-    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
-        DataLogPo dataLogPo = new DataLogPo();
-        dataLogPo.setDataName("睿行车辆报废月数据");
-        dataLogPo.setObject(path.getFileName().toString());
-        dataLogPo.setStage(DataStageEnum.CC.value);
-        dataLogPo.setOperationName("入库");
-        long fileSize = Files.size(path);
-        dataLogPo.setDataSize(fileSize);
-        dataLogPoList.add(dataLogPo);
-        if (fileSize == 0) {
-            move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
-        }
-        List<Map<String, String>> list = readFile(path);
-        List<Map<String, String>> distinctList = dataProcessing(path, list);
-        dataLogPo.setDataCount(distinctList.size());
-        Path csvPath = toCsv(path, distinctList);
-        copyCsv(csvPath);
-        move(path);
-    }
-
-    /**
-     * 读取文件
-     *
-     * @param path 文件路径
-     */
-    public List<Map<String, String>> readFile(Path path) throws IOException {
-        log.info("读取: {}", path);
-        List<String> rawHeaders = Stream.of("车牌号码", "车辆所属单位", "报废类型", "报废标准", "报废日期",
-                "行驶公里数(Km)", "备注", "资产编号", "资产名称", "规格型号", "实际使用年限", "资产原值(万元)",
-                "累计折旧值(万元)").toList();
-        List<String> headers = Stream.of("che_pai_hao", "che_liang_suo_shu_dan_wei", "bai_fei_lei_xing",
-                "bao_fei_biao_zhun", "bao_fei_ri_qi", "xing_shi_gong_li_shu", "bei_zhu", "zi_chan_bian_hao",
-                "zi_chan_ming_cheng", "gui_ge_xing_hao", "shi_ji_shi_yong_nian_xian", "zi_chan_yuan_zhi_wan_yuan",
-                "lei_ji_zhe_jiu_zhi_wan_yuan").toList();
-        try (InputStream inputStream = Files.newInputStream(path);
-             Workbook workbook = new XSSFWorkbook(inputStream)
-        ) {
-            List<Map<String, String>> resultList = new ArrayList<>();
-            // 读取第一个工作表
-            Sheet sheet = workbook.getSheetAt(0);
-            // 表头行
-            Row headerRow = sheet.getRow(0);
-            // 列数
-            int columnCount = headerRow.getPhysicalNumberOfCells();
-            log.info("columnCount: {}", columnCount);
-            // 检查表头
-            if (headers.size() != columnCount) {
-                throw new MyRuntimeException(path.getFileName() + "列数错误");
-            }
-            for (int i = 0; i < columnCount; i++) {
-                Cell cell = headerRow.getCell(i);
-                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
-                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
-                }
-            }
-            // 最后行数
-            int lastRowNum = sheet.getLastRowNum();
-            log.info("lastRowNum: {}", lastRowNum);
-            if (lastRowNum == 0) {
-                move(path);
-                throw new MyRuntimeException(path.getFileName() + " 数据0条");
-            }
-            // 遍历行
-            for (int i = 1; i <= lastRowNum; i++) {
-                log.debug("row: {}", i);
-                Row row = sheet.getRow(i);
-                if (row == null || row.getCell(0) == null) {
-                    continue;
-                }
-                Map<String, String> rowMap = new LinkedHashMap<>();
-                // 遍历列
-                for (int j = 0; j < columnCount; j++) {
-                    log.debug("column: {}", j);
-                    String cellValue = "";
-                    rowMap.put(headers.get(j), cellValue);
-                    Cell cell = row.getCell(j);
-                    if (cell == null) {
-                        continue;
-                    }
-                    switch (cell.getCellType()) {
-                        case STRING:
-                            // 删除字符串空白字符
-                            cellValue = StringUtils.trimAllWhitespace(cell.getStringCellValue());
-                            break;
-                        case NUMERIC:
-                            if (DateUtil.isCellDateFormatted(cell)) {
-                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
-                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                                break;
-                            }
-                            cellValue = String.valueOf(cell.getNumericCellValue());
-                            break;
-                        case BOOLEAN:
-                            cellValue = String.valueOf(cell.getBooleanCellValue());
-                            break;
-                        default:
-                            break;
-                    }
-                    rowMap.put(headers.get(j), cellValue);
-                }
-                resultList.add(rowMap);
-            }
-            return resultList;
-        }
-    }
-
-    /**
-     * 数据加工
-     *
-     * @param path 文件路径
-     * @param list 数据
-     */
-    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
-        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
-        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
-        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
-        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
-                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
-        List<AreaPo> cities = areaService.getCities();
-        List<AreaPo> districts = areaService.getDistricts();
-        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
-        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
-        for (Map<String, String> map : list) {
-            String baoFeiRiQi = map.get("bao_fei_ri_qi");
-            LocalDate localDate = LocalDate.parse(baoFeiRiQi, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-            String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
-            String year = String.valueOf(localDate.getYear());
-            String month = String.valueOf(localDate.getMonthValue());
-            map.put("year_month", yearMonth);
-            map.put("year_no", year);
-            map.put("month_no", month);
-            String rawChePaiHao = map.get("che_pai_hao");
-            map.put("raw_che_pai_hao", rawChePaiHao);
-            String chePaiHao = carService.getChePai(rawChePaiHao);
-            map.put("che_pai_hao", chePaiHao);
-            String chePaiFail = carService.chePaiFail(rawChePaiHao);
-            map.put("che_pai_fail", chePaiFail);
-            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
-            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
-            String firstUnit = carService.getFirstUnit(carUnitBo);
-            if (!StringUtils.hasText(firstUnit)) {
-                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
-            }
-            map.put("first_unit", firstUnit);
-            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
-            map.put("second_unit", secondUnit);
-            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
-            map.put("third_unit", thirdUnit);
-            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
-            map.put("area_no", areaNo);
-            String areaName = carService.getOrgName(orgMap, areaNo);
-            map.put("area_name", areaName);
-            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
-            map.put("city_no", cityNo);
-            String cityName = carService.getOrgName(orgMap, cityNo);
-            map.put("city_name", cityName);
-            String areaNo2 = carService.getAreaNo2(areaName, cityName);
-            map.put("area_no2", areaNo2);
-            String areaName2 = carService.getOrgName(orgMap, areaNo2);
-            map.put("area_name2", areaName2);
-            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
-            map.put("city_id", cityId);
-            String city = carService.getAreaName(areaMap, cityId);
-            map.put("city", city);
-            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
-            map.put("district_id", districtId);
-            String district = carService.getAreaName(areaMap, districtId);
-            map.put("district", district);
-            map.put("manual", "0");
-            map.put("valid", "1");
-            map.put("source", path.getFileName().toString());
-        }
-        // 去重
-        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao") + map.get("bao_fei_ri_qi"))).toList();
-    }
-
-    /**
-     * 去重
-     */
-    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
-        Set<Object> set = ConcurrentHashMap.newKeySet();
-        return t -> set.add(keyExtractor.apply(t));
-    }
-
-    /**
-     * 生成csv
-     *
-     * @param path 源文件路径
-     * @param list 数据
-     */
-    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
-        log.info("去重后条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarBaoFeiHistoryPath()));
-        Path csvPath = Paths.get(jobConfig.getCarBaoFeiHistoryPath() + path.getFileName() + ".csv");
-        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
-                StandardCharsets.UTF_8);
-             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
-            // 添加bom头避免excel乱码
-            osw.write('\ufeff');
-            Map<String, String> header = list.get(0);
-            // 表头
-            printer.printRecord(header.keySet());
-            for (Map<String, String> map : list) {
-                printer.printRecord(map.values());
-            }
-        }
-        return csvPath;
-    }
-
-    /**
-     * 导入数据库
-     *
-     * @param path 文件路径
-     */
-    public void copyCsv(Path path) {
-        String dbTable = "car.car_bao_fei";
-        String csv = path.toString();
-        String columns = "(che_pai_hao,che_liang_suo_shu_dan_wei,bai_fei_lei_xing,bao_fei_biao_zhun,bao_fei_ri_qi,xing_shi_gong_li_shu,bei_zhu,zi_chan_bian_hao,zi_chan_ming_cheng,gui_ge_xing_hao,shi_ji_shi_yong_nian_xian,zi_chan_yuan_zhi_wan_yuan,lei_ji_zhe_jiu_zhi_wan_yuan,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,manual,valid,source)";
-        Long timeout = 60000L;
-        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
-                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
-                timeout, null);
-    }
-
-    /**
-     * 移动源文件到历史文件夹
-     *
-     * @param path 源文件路径
-     */
-    public void move(Path path) throws IOException {
-        Path targetPath = Paths.get(jobConfig.getCarBaoFeiHistoryPath(), path.getFileName().toString());
-        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
-    }
-}
+//package com.nokia.finance.tasks.jobs.car.ruixing;
+//
+//import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+//import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+//import com.nokia.finance.tasks.config.JobConfig;
+//import com.nokia.finance.tasks.enums.DataStageEnum;
+//import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+//import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+//import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+//import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+//import com.nokia.finance.tasks.service.car.CarService;
+//import com.nokia.finance.tasks.service.common.AreaService;
+//import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+//import com.nokia.finance.tasks.service.common.OrganizationService;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.commons.csv.CSVFormat;
+//import org.apache.commons.csv.CSVPrinter;
+//import org.apache.poi.ss.usermodel.Cell;
+//import org.apache.poi.ss.usermodel.DateUtil;
+//import org.apache.poi.ss.usermodel.Row;
+//import org.apache.poi.ss.usermodel.Sheet;
+//import org.apache.poi.ss.usermodel.Workbook;
+//import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+//import org.springframework.scheduling.annotation.Scheduled;
+//import org.springframework.stereotype.Service;
+//import org.springframework.util.CollectionUtils;
+//import org.springframework.util.StringUtils;
+//
+//import java.io.IOException;
+//import java.io.InputStream;
+//import java.io.OutputStreamWriter;
+//import java.nio.charset.StandardCharsets;
+//import java.nio.file.Files;
+//import java.nio.file.Path;
+//import java.nio.file.Paths;
+//import java.nio.file.StandardCopyOption;
+//import java.time.LocalDate;
+//import java.time.format.DateTimeFormatter;
+//import java.util.ArrayList;
+//import java.util.LinkedHashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.concurrent.CompletableFuture;
+//import java.util.concurrent.ConcurrentHashMap;
+//import java.util.concurrent.TimeUnit;
+//import java.util.function.Function;
+//import java.util.function.Predicate;
+//import java.util.stream.Stream;
+//
+///**
+// * 睿行车辆报废月数据入库定时任务
+// */
+//@Slf4j
+//@Service
+//public class CarBaoFeiJob {
+//    private final JobConfig jobConfig;
+//    private final CarService carService;
+//    private final OrganizationService organizationService;
+//    private final AreaService areaService;
+//    private final DataLogServiceImpl dataLogService;
+//
+//    public CarBaoFeiJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+//                        AreaService areaService, DataLogServiceImpl dataLogService) {
+//        this.jobConfig = jobConfig;
+//        this.carService = carService;
+//        this.organizationService = organizationService;
+//        this.areaService = areaService;
+//        this.dataLogService = dataLogService;
+//    }
+//
+//    /**
+//     * 执行任务
+//     */
+//    @Scheduled(cron = "0 0 5 1 * ?")
+//    public void runJob() {
+//        List<DataLogPo> dataLogPoList = new ArrayList<>();
+//        // 数据目录
+//        Path dir = Paths.get(jobConfig.getCarBaoFeiSourcePath());
+//        try (Stream<Path> stream = Files.list(dir)) {
+//            // 获取数据目录下的文件列表
+//            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
+//            log.info("睿行车辆报废月数据文件列表: {}", pathList);
+//            if (CollectionUtils.isEmpty(pathList)) {
+//                throw new MyRuntimeException("睿行车辆报废月数据没有文件");
+//            }
+//            for (Path path : pathList) {
+//                CompletableFuture.runAsync(() -> {
+//                    try {
+//                        singleJob(path, dataLogPoList);
+//                    } catch (Exception e) {
+//                        throw new MyRuntimeException(e);
+//                    }
+//                }).get(1, TimeUnit.MINUTES);
+//            }
+//        } catch (InterruptedException e) {
+//            log.error("线程中断: {}", e, e);
+//            Thread.currentThread().interrupt();
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆报废月数据", DataStageEnum.CC, "入库");
+//        } catch (Exception e) {
+//            log.error(e.toString(), e);
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆报废月数据", DataStageEnum.CC, "入库");
+//        } finally {
+//            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+//                dataLogService.saveBatch(dataLogPoList);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * 处理单个文件
+//     *
+//     * @param path          文件路径
+//     * @param dataLogPoList 数据处理日志列表
+//     */
+//    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+//        DataLogPo dataLogPo = new DataLogPo();
+//        dataLogPo.setDataName("睿行车辆报废月数据");
+//        dataLogPo.setObject(path.getFileName().toString());
+//        dataLogPo.setStage(DataStageEnum.CC.value);
+//        dataLogPo.setOperationName("入库");
+//        long fileSize = Files.size(path);
+//        dataLogPo.setDataSize(fileSize);
+//        dataLogPoList.add(dataLogPo);
+//        if (fileSize == 0) {
+//            move(path);
+//            throw new MyRuntimeException(path.getFileName() + " 空文件");
+//        }
+//        List<Map<String, String>> list = readFile(path);
+//        List<Map<String, String>> distinctList = dataProcessing(path, list);
+//        dataLogPo.setDataCount(distinctList.size());
+//        Path csvPath = toCsv(path, distinctList);
+//        copyCsv(csvPath);
+//        move(path);
+//    }
+//
+//    /**
+//     * 读取文件
+//     *
+//     * @param path 文件路径
+//     */
+//    public List<Map<String, String>> readFile(Path path) throws IOException {
+//        log.info("读取: {}", path);
+//        List<String> rawHeaders = Stream.of("车牌号码", "车辆所属单位", "报废类型", "报废标准", "报废日期",
+//                "行驶公里数(Km)", "备注", "资产编号", "资产名称", "规格型号", "实际使用年限", "资产原值(万元)",
+//                "累计折旧值(万元)").toList();
+//        List<String> headers = Stream.of("che_pai_hao", "che_liang_suo_shu_dan_wei", "bai_fei_lei_xing",
+//                "bao_fei_biao_zhun", "bao_fei_ri_qi", "xing_shi_gong_li_shu", "bei_zhu", "zi_chan_bian_hao",
+//                "zi_chan_ming_cheng", "gui_ge_xing_hao", "shi_ji_shi_yong_nian_xian", "zi_chan_yuan_zhi_wan_yuan",
+//                "lei_ji_zhe_jiu_zhi_wan_yuan").toList();
+//        try (InputStream inputStream = Files.newInputStream(path);
+//             Workbook workbook = new XSSFWorkbook(inputStream)
+//        ) {
+//            List<Map<String, String>> resultList = new ArrayList<>();
+//            // 读取第一个工作表
+//            Sheet sheet = workbook.getSheetAt(0);
+//            // 表头行
+//            Row headerRow = sheet.getRow(0);
+//            // 列数
+//            int columnCount = headerRow.getPhysicalNumberOfCells();
+//            log.info("columnCount: {}", columnCount);
+//            // 检查表头
+//            if (headers.size() != columnCount) {
+//                throw new MyRuntimeException(path.getFileName() + "列数错误");
+//            }
+//            for (int i = 0; i < columnCount; i++) {
+//                Cell cell = headerRow.getCell(i);
+//                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
+//                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
+//                }
+//            }
+//            // 最后行数
+//            int lastRowNum = sheet.getLastRowNum();
+//            log.info("lastRowNum: {}", lastRowNum);
+//            if (lastRowNum == 0) {
+//                move(path);
+//                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+//            }
+//            // 遍历行
+//            for (int i = 1; i <= lastRowNum; i++) {
+//                log.debug("row: {}", i);
+//                Row row = sheet.getRow(i);
+//                if (row == null || row.getCell(0) == null) {
+//                    continue;
+//                }
+//                Map<String, String> rowMap = new LinkedHashMap<>();
+//                // 遍历列
+//                for (int j = 0; j < columnCount; j++) {
+//                    log.debug("column: {}", j);
+//                    String cellValue = "";
+//                    rowMap.put(headers.get(j), cellValue);
+//                    Cell cell = row.getCell(j);
+//                    if (cell == null) {
+//                        continue;
+//                    }
+//                    switch (cell.getCellType()) {
+//                        case STRING:
+//                            // 删除字符串空白字符
+//                            cellValue = StringUtils.trimAllWhitespace(cell.getStringCellValue());
+//                            break;
+//                        case NUMERIC:
+//                            if (DateUtil.isCellDateFormatted(cell)) {
+//                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
+//                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+//                                break;
+//                            }
+//                            cellValue = String.valueOf(cell.getNumericCellValue());
+//                            break;
+//                        case BOOLEAN:
+//                            cellValue = String.valueOf(cell.getBooleanCellValue());
+//                            break;
+//                        default:
+//                            break;
+//                    }
+//                    rowMap.put(headers.get(j), cellValue);
+//                }
+//                resultList.add(rowMap);
+//            }
+//            return resultList;
+//        }
+//    }
+//
+//    /**
+//     * 数据加工
+//     *
+//     * @param path 文件路径
+//     * @param list 数据
+//     */
+//    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+//        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+//        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+//        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+//        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+//                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+//        List<AreaPo> cities = areaService.getCities();
+//        List<AreaPo> districts = areaService.getDistricts();
+//        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+//        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+//        for (Map<String, String> map : list) {
+//            String baoFeiRiQi = map.get("bao_fei_ri_qi");
+//            LocalDate localDate = LocalDate.parse(baoFeiRiQi, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+//            String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+//            String year = String.valueOf(localDate.getYear());
+//            String month = String.valueOf(localDate.getMonthValue());
+//            map.put("year_month", yearMonth);
+//            map.put("year_no", year);
+//            map.put("month_no", month);
+//            String rawChePaiHao = map.get("che_pai_hao");
+//            map.put("raw_che_pai_hao", rawChePaiHao);
+//            String chePaiHao = carService.getChePai(rawChePaiHao);
+//            map.put("che_pai_hao", chePaiHao);
+//            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+//            map.put("che_pai_fail", chePaiFail);
+//            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+//            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+//            String firstUnit = carService.getFirstUnit(carUnitBo);
+//            if (!StringUtils.hasText(firstUnit)) {
+//                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+//            }
+//            map.put("first_unit", firstUnit);
+//            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+//            map.put("second_unit", secondUnit);
+//            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+//            map.put("third_unit", thirdUnit);
+//            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+//            map.put("area_no", areaNo);
+//            String areaName = carService.getOrgName(orgMap, areaNo);
+//            map.put("area_name", areaName);
+//            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+//            map.put("city_no", cityNo);
+//            String cityName = carService.getOrgName(orgMap, cityNo);
+//            map.put("city_name", cityName);
+//            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+//            map.put("area_no2", areaNo2);
+//            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+//            map.put("area_name2", areaName2);
+//            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+//            map.put("city_id", cityId);
+//            String city = carService.getAreaName(areaMap, cityId);
+//            map.put("city", city);
+//            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+//            map.put("district_id", districtId);
+//            String district = carService.getAreaName(areaMap, districtId);
+//            map.put("district", district);
+//            map.put("manual", "0");
+//            map.put("valid", "1");
+//            map.put("source", path.getFileName().toString());
+//        }
+//        // 去重
+//        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao") + map.get("bao_fei_ri_qi"))).toList();
+//    }
+//
+//    /**
+//     * 去重
+//     */
+//    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+//        Set<Object> set = ConcurrentHashMap.newKeySet();
+//        return t -> set.add(keyExtractor.apply(t));
+//    }
+//
+//    /**
+//     * 生成csv
+//     *
+//     * @param path 源文件路径
+//     * @param list 数据
+//     */
+//    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+//        log.info("去重后条数:{}", list.size());
+//        Files.createDirectories(Paths.get(jobConfig.getCarBaoFeiHistoryPath()));
+//        Path csvPath = Paths.get(jobConfig.getCarBaoFeiHistoryPath() + path.getFileName() + ".csv");
+//        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+//                StandardCharsets.UTF_8);
+//             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+//            // 添加bom头避免excel乱码
+//            osw.write('\ufeff');
+//            Map<String, String> header = list.get(0);
+//            // 表头
+//            printer.printRecord(header.keySet());
+//            for (Map<String, String> map : list) {
+//                printer.printRecord(map.values());
+//            }
+//        }
+//        return csvPath;
+//    }
+//
+//    /**
+//     * 导入数据库
+//     *
+//     * @param path 文件路径
+//     */
+//    public void copyCsv(Path path) {
+//        String dbTable = "car.car_bao_fei";
+//        String csv = path.toString();
+//        String columns = "(che_pai_hao,che_liang_suo_shu_dan_wei,bai_fei_lei_xing,bao_fei_biao_zhun,bao_fei_ri_qi,xing_shi_gong_li_shu,bei_zhu,zi_chan_bian_hao,zi_chan_ming_cheng,gui_ge_xing_hao,shi_ji_shi_yong_nian_xian,zi_chan_yuan_zhi_wan_yuan,lei_ji_zhe_jiu_zhi_wan_yuan,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,manual,valid,source)";
+//        Long timeout = 60000L;
+//        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+//                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+//                timeout, null);
+//    }
+//
+//    /**
+//     * 移动源文件到历史文件夹
+//     *
+//     * @param path 源文件路径
+//     */
+//    public void move(Path path) throws IOException {
+//        Path targetPath = Paths.get(jobConfig.getCarBaoFeiHistoryPath(), path.getFileName().toString());
+//        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
+//    }
+//}

+ 379 - 379
src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarBaseDataDayJob.java

@@ -1,379 +1,379 @@
-package com.nokia.finance.tasks.jobs.car.ruixing;
-
-import com.nokia.finance.tasks.common.exception.MyRuntimeException;
-import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
-import com.nokia.finance.tasks.config.JobConfig;
-import com.nokia.finance.tasks.enums.DataStageEnum;
-import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
-import com.nokia.finance.tasks.pojo.po.common.AreaPo;
-import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
-import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
-import com.nokia.finance.tasks.service.car.CarService;
-import com.nokia.finance.tasks.service.common.AreaService;
-import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
-import com.nokia.finance.tasks.service.common.OrganizationService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVPrinter;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Stream;
-
-/**
- * 睿行车辆基本信息日数据入库定时任务
- */
-@Slf4j
-@Service
-public class CarBaseDataDayJob {
-    private final JobConfig jobConfig;
-    private final CarService carService;
-    private final OrganizationService organizationService;
-    private final AreaService areaService;
-    private final DataLogServiceImpl dataLogService;
-
-    public CarBaseDataDayJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
-                             AreaService areaService, DataLogServiceImpl dataLogService) {
-        this.jobConfig = jobConfig;
-        this.carService = carService;
-        this.organizationService = organizationService;
-        this.areaService = areaService;
-        this.dataLogService = dataLogService;
-    }
-
-    /**
-     * 执行任务
-     */
-    @Scheduled(cron = "0 56 23 * * ?")
-    public void runJob() {
-        List<DataLogPo> dataLogPoList = new ArrayList<>();
-        // 数据目录
-        Path dir = Paths.get(jobConfig.getCarBaseDataDaySourcePath());
-        try (Stream<Path> stream = Files.list(dir)) {
-            // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
-            log.info("睿行车辆基本信息日数据文件列表: {}", pathList);
-            if (CollectionUtils.isEmpty(pathList)) {
-                throw new MyRuntimeException("睿行车辆基本信息日数据没有文件");
-            }
-            for (Path path : pathList) {
-                CompletableFuture.runAsync(() -> {
-                    try {
-                        singleJob(path, dataLogPoList);
-                    } catch (Exception e) {
-                        throw new MyRuntimeException(e);
-                    }
-                }).get(1, TimeUnit.MINUTES);
-            }
-        } catch (InterruptedException e) {
-            log.error("线程中断: {}", e, e);
-            Thread.currentThread().interrupt();
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆基本信息日数据", DataStageEnum.CC, "入库");
-        } catch (Exception e) {
-            log.error(e.toString(), e);
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆基本信息日数据", DataStageEnum.CC, "入库");
-        } finally {
-            if (!CollectionUtils.isEmpty(dataLogPoList)) {
-                dataLogService.saveBatch(dataLogPoList);
-            }
-        }
-    }
-
-    /**
-     * 处理单个文件
-     *
-     * @param path          文件路径
-     * @param dataLogPoList 数据处理日志列表
-     */
-    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
-        DataLogPo dataLogPo = new DataLogPo();
-        dataLogPo.setDataName("睿行车辆基本信息日数据");
-        dataLogPo.setObject(path.getFileName().toString());
-        dataLogPo.setStage(DataStageEnum.CC.value);
-        dataLogPo.setOperationName("入库");
-        long fileSize = Files.size(path);
-        dataLogPo.setDataSize(fileSize);
-        dataLogPoList.add(dataLogPo);
-        if (fileSize == 0) {
-            move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
-        }
-        List<Map<String, String>> list = readFile(path);
-        List<Map<String, String>> distinctList = dataProcessing(path, list);
-        dataLogPo.setDataCount(distinctList.size());
-        Path csvPath = toCsv(path, distinctList);
-        copyCsv(csvPath);
-        move(path);
-    }
-
-    /**
-     * 读取文件
-     *
-     * @param path 文件路径
-     */
-    public List<Map<String, String>> readFile(Path path) throws IOException {
-        log.info("读取: {}", path);
-        List<String> rawHeaders = Stream.of("车牌号", "车辆品牌", "排量", "排量类型", "燃油类型", "燃油标号",
-                "登记日期", "车辆来源", "车辆类型", "车辆使用性质", "环保等级", "用车模式", "发动机号", "车架号", "初始里程",
-                "车辆所属单位", "行驶证号", "备注", "审核状态", "车辆状态", "资产编号", "绑定驾驶员姓名", "购置价格(万元)",
-                "车龄(年)", "标准百公里油耗", "设备工作模式").toList();
-        List<String> headers = Stream.of("che_pai_hao", "che_liang_pin_pai", "pai_liang", "pai_liang_lei_xing",
-                "ran_you_lei_xing", "ran_you_biao_hao", "deng_ji_ri_qi", "che_liang_lai_yuan", "che_liang_lei_xing",
-                "che_liang_shi_yong_xing_zhi", "huan_bao_deng_ji", "yong_che_mo_shi", "fa_dong_ji_hao", "che_jia_hao",
-                "chu_shi_li_cheng", "che_liang_suo_shu_dan_wei", "xing_shi_zheng_hao", "bei_zhu", "shen_he_zhuang_tai",
-                "che_liang_zhuang_tai", "zi_chan_bian_hao", "bang_ding_jia_shi_yuan_xing_ming", "gou_zhi_jia_ge",
-                "che_ling_nian", "biao_zhun_bai_gong_li_you_hao", "she_bei_gong_zuo_mo_shi").toList();
-        try (InputStream inputStream = Files.newInputStream(path);
-             Workbook workbook = new XSSFWorkbook(inputStream)
-        ) {
-            List<Map<String, String>> resultList = new ArrayList<>();
-            // 读取第一个工作表
-            Sheet sheet = workbook.getSheetAt(0);
-            // 表头行
-            Row headerRow = sheet.getRow(0);
-            // 列数
-            int columnCount = headerRow.getPhysicalNumberOfCells();
-            log.info("columnCount: {}", columnCount);
-            // 检查表头
-            if (headers.size() != columnCount) {
-                throw new MyRuntimeException(path.getFileName() + "列数错误");
-            }
-            for (int i = 0; i < columnCount; i++) {
-                Cell cell = headerRow.getCell(i);
-                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
-                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
-                }
-            }
-            // 最后行数
-            int lastRowNum = sheet.getLastRowNum();
-            log.info("lastRowNum: {}", lastRowNum);
-            if (lastRowNum == 0) {
-                move(path);
-                throw new MyRuntimeException(path.getFileName() + " 数据0条");
-            }
-            // 遍历行
-            for (int i = 1; i <= lastRowNum; i++) {
-                log.debug("row: {}", i);
-                Row row = sheet.getRow(i);
-                if (row == null || row.getCell(0) == null) {
-                    continue;
-                }
-                Map<String, String> rowMap = new LinkedHashMap<>();
-                // 遍历列
-                for (int j = 0; j < columnCount; j++) {
-                    log.debug("column: {}", j);
-                    String cellValue = "";
-                    rowMap.put(headers.get(j), cellValue);
-                    Cell cell = row.getCell(j);
-                    if (cell == null) {
-                        continue;
-                    }
-                    switch (cell.getCellType()) {
-                        case STRING:
-                            // 删除字符串空白字符
-                            cellValue = StringUtils.trimAllWhitespace(cell.getStringCellValue());
-                            break;
-                        case NUMERIC:
-                            if (DateUtil.isCellDateFormatted(cell)) {
-                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
-                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                                break;
-                            }
-                            cellValue = String.valueOf(cell.getNumericCellValue());
-                            break;
-                        case BOOLEAN:
-                            cellValue = String.valueOf(cell.getBooleanCellValue());
-                            break;
-                        default:
-                            break;
-                    }
-                    rowMap.put(headers.get(j), cellValue);
-                }
-                resultList.add(rowMap);
-            }
-            return resultList;
-        }
-    }
-
-    /**
-     * 数据加工
-     *
-     * @param path 文件路径
-     * @param list 数据
-     */
-    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
-        // 从文件名提取日期
-        String regex = "\\d{8}";
-        Pattern pattern = Pattern.compile(regex);
-        Matcher matcher = pattern.matcher(path.getFileName().toString());
-        String dateString;
-        if (matcher.find()) {
-            dateString = matcher.group();
-        } else {
-            throw new MyRuntimeException(path.getFileName() + " 提取日期失败");
-        }
-        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
-        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
-        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
-        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
-                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
-        List<AreaPo> cities = areaService.getCities();
-        List<AreaPo> districts = areaService.getDistricts();
-        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
-        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
-        LocalDate localDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyyMMdd"));
-        LocalDate lastMonthDate = localDate.minusMonths(1);
-        String dataDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-        String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
-        String year = String.valueOf(localDate.getYear());
-        String month = String.valueOf(localDate.getMonthValue());
-        String lastMonth = lastMonthDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
-        for (Map<String, String> map : list) {
-            map.put("data_date", dataDate);
-            map.put("year_month", yearMonth);
-            map.put("year_no", year);
-            map.put("month_no", month);
-            map.put("last_month", lastMonth);
-            String rawChePaiHao = map.get("che_pai_hao");
-            map.put("raw_che_pai_hao", rawChePaiHao);
-            String chePaiHao = carService.getChePai(rawChePaiHao);
-            map.put("che_pai_hao", chePaiHao);
-            String chePaiFail = carService.chePaiFail(rawChePaiHao);
-            map.put("che_pai_fail", chePaiFail);
-            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
-            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
-            String firstUnit = carService.getFirstUnit(carUnitBo);
-            if (!StringUtils.hasText(firstUnit)) {
-                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
-            }
-            map.put("first_unit", firstUnit);
-            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
-            map.put("second_unit", secondUnit);
-            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
-            map.put("third_unit", thirdUnit);
-            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
-            map.put("area_no", areaNo);
-            String areaName = carService.getOrgName(orgMap, areaNo);
-            map.put("area_name", areaName);
-            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
-            map.put("city_no", cityNo);
-            String cityName = carService.getOrgName(orgMap, cityNo);
-            map.put("city_name", cityName);
-            String areaNo2 = carService.getAreaNo2(areaName, cityName);
-            map.put("area_no2", areaNo2);
-            String areaName2 = carService.getOrgName(orgMap, areaNo2);
-            map.put("area_name2", areaName2);
-            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
-            map.put("city_id", cityId);
-            String city = carService.getAreaName(areaMap, cityId);
-            map.put("city", city);
-            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
-            map.put("district_id", districtId);
-            String district = carService.getAreaName(areaMap, districtId);
-            map.put("district", district);
-            String cheLing = "0";
-            String dengJiRiQi = map.get("deng_ji_ri_qi");
-            if (StringUtils.hasText(dengJiRiQi)) {
-                LocalDate dengJiRiQiDate = LocalDate.parse(dengJiRiQi, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                long days = ChronoUnit.DAYS.between(dengJiRiQiDate, localDate);
-                if (days > 0) {
-                    BigDecimal n = BigDecimal.valueOf(days).divide(BigDecimal.valueOf(365), 1, RoundingMode.HALF_UP);
-                    cheLing = n.toString();
-                }
-            }
-            map.put("che_ling", cheLing);
-            map.put("source", path.getFileName().toString());
-        }
-        // 去重
-        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao"))).toList();
-    }
-
-    /**
-     * 去重
-     */
-    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
-        Set<Object> set = ConcurrentHashMap.newKeySet();
-        return t -> set.add(keyExtractor.apply(t));
-    }
-
-    /**
-     * 生成csv
-     *
-     * @param path 源文件路径
-     * @param list 数据
-     */
-    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
-        log.info("去重后条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarBaseDataDayHistoryPath()));
-        Path csvPath = Paths.get(jobConfig.getCarBaseDataDayHistoryPath() + path.getFileName() + ".csv");
-        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
-                StandardCharsets.UTF_8);
-             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
-            // 添加bom头避免excel乱码
-            osw.write('\ufeff');
-            Map<String, String> header = list.get(0);
-            // 表头
-            printer.printRecord(header.keySet());
-            for (Map<String, String> map : list) {
-                printer.printRecord(map.values());
-            }
-        }
-        return csvPath;
-    }
-
-    /**
-     * 导入数据库
-     * @param path 文件路径
-     */
-    public void copyCsv(Path path) {
-        String dbTable = "car.car_base_data_day";
-        String csv = path.toString();
-        String columns = "(che_pai_hao,che_liang_pin_pai,pai_liang,pai_liang_lei_xing,ran_you_lei_xing,ran_you_biao_hao,deng_ji_ri_qi,che_liang_lai_yuan,che_liang_lei_xing,che_liang_shi_yong_xing_zhi,huan_bao_deng_ji,yong_che_mo_shi,fa_dong_ji_hao,che_jia_hao,chu_shi_li_cheng,che_liang_suo_shu_dan_wei,xing_shi_zheng_hao,bei_zhu,shen_he_zhuang_tai,che_liang_zhuang_tai,zi_chan_bian_hao,bang_ding_jia_shi_yuan_xing_ming,gou_zhi_jia_ge,che_ling_nian,biao_zhun_bai_gong_li_you_hao,she_bei_gong_zuo_mo_shi,data_date,year_month,year_no,month_no,last_month,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,che_ling,source)";
-        Long timeout = 60000L;
-        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
-                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
-                timeout, null);
-    }
-
-    /**
-     * 移动源文件到历史文件夹
-     * @param path 源文件路径
-     */
-    public void move(Path path) throws IOException {
-        Path targetPath = Paths.get(jobConfig.getCarBaseDataDayHistoryPath(), path.getFileName().toString());
-        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
-    }
-}
+//package com.nokia.finance.tasks.jobs.car.ruixing;
+//
+//import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+//import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+//import com.nokia.finance.tasks.config.JobConfig;
+//import com.nokia.finance.tasks.enums.DataStageEnum;
+//import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+//import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+//import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+//import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+//import com.nokia.finance.tasks.service.car.CarService;
+//import com.nokia.finance.tasks.service.common.AreaService;
+//import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+//import com.nokia.finance.tasks.service.common.OrganizationService;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.commons.csv.CSVFormat;
+//import org.apache.commons.csv.CSVPrinter;
+//import org.apache.poi.ss.usermodel.Cell;
+//import org.apache.poi.ss.usermodel.DateUtil;
+//import org.apache.poi.ss.usermodel.Row;
+//import org.apache.poi.ss.usermodel.Sheet;
+//import org.apache.poi.ss.usermodel.Workbook;
+//import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+//import org.springframework.scheduling.annotation.Scheduled;
+//import org.springframework.stereotype.Service;
+//import org.springframework.util.CollectionUtils;
+//import org.springframework.util.StringUtils;
+//
+//import java.io.IOException;
+//import java.io.InputStream;
+//import java.io.OutputStreamWriter;
+//import java.math.BigDecimal;
+//import java.math.RoundingMode;
+//import java.nio.charset.StandardCharsets;
+//import java.nio.file.Files;
+//import java.nio.file.Path;
+//import java.nio.file.Paths;
+//import java.nio.file.StandardCopyOption;
+//import java.time.LocalDate;
+//import java.time.format.DateTimeFormatter;
+//import java.time.temporal.ChronoUnit;
+//import java.util.ArrayList;
+//import java.util.LinkedHashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.concurrent.CompletableFuture;
+//import java.util.concurrent.ConcurrentHashMap;
+//import java.util.concurrent.TimeUnit;
+//import java.util.function.Function;
+//import java.util.function.Predicate;
+//import java.util.regex.Matcher;
+//import java.util.regex.Pattern;
+//import java.util.stream.Stream;
+//
+///**
+// * 睿行车辆基本信息日数据入库定时任务
+// */
+//@Slf4j
+//@Service
+//public class CarBaseDataDayJob {
+//    private final JobConfig jobConfig;
+//    private final CarService carService;
+//    private final OrganizationService organizationService;
+//    private final AreaService areaService;
+//    private final DataLogServiceImpl dataLogService;
+//
+//    public CarBaseDataDayJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+//                             AreaService areaService, DataLogServiceImpl dataLogService) {
+//        this.jobConfig = jobConfig;
+//        this.carService = carService;
+//        this.organizationService = organizationService;
+//        this.areaService = areaService;
+//        this.dataLogService = dataLogService;
+//    }
+//
+//    /**
+//     * 执行任务
+//     */
+//    @Scheduled(cron = "0 56 23 * * ?")
+//    public void runJob() {
+//        List<DataLogPo> dataLogPoList = new ArrayList<>();
+//        // 数据目录
+//        Path dir = Paths.get(jobConfig.getCarBaseDataDaySourcePath());
+//        try (Stream<Path> stream = Files.list(dir)) {
+//            // 获取数据目录下的文件列表
+//            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
+//            log.info("睿行车辆基本信息日数据文件列表: {}", pathList);
+//            if (CollectionUtils.isEmpty(pathList)) {
+//                throw new MyRuntimeException("睿行车辆基本信息日数据没有文件");
+//            }
+//            for (Path path : pathList) {
+//                CompletableFuture.runAsync(() -> {
+//                    try {
+//                        singleJob(path, dataLogPoList);
+//                    } catch (Exception e) {
+//                        throw new MyRuntimeException(e);
+//                    }
+//                }).get(1, TimeUnit.MINUTES);
+//            }
+//        } catch (InterruptedException e) {
+//            log.error("线程中断: {}", e, e);
+//            Thread.currentThread().interrupt();
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆基本信息日数据", DataStageEnum.CC, "入库");
+//        } catch (Exception e) {
+//            log.error(e.toString(), e);
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆基本信息日数据", DataStageEnum.CC, "入库");
+//        } finally {
+//            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+//                dataLogService.saveBatch(dataLogPoList);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * 处理单个文件
+//     *
+//     * @param path          文件路径
+//     * @param dataLogPoList 数据处理日志列表
+//     */
+//    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+//        DataLogPo dataLogPo = new DataLogPo();
+//        dataLogPo.setDataName("睿行车辆基本信息日数据");
+//        dataLogPo.setObject(path.getFileName().toString());
+//        dataLogPo.setStage(DataStageEnum.CC.value);
+//        dataLogPo.setOperationName("入库");
+//        long fileSize = Files.size(path);
+//        dataLogPo.setDataSize(fileSize);
+//        dataLogPoList.add(dataLogPo);
+//        if (fileSize == 0) {
+//            move(path);
+//            throw new MyRuntimeException(path.getFileName() + " 空文件");
+//        }
+//        List<Map<String, String>> list = readFile(path);
+//        List<Map<String, String>> distinctList = dataProcessing(path, list);
+//        dataLogPo.setDataCount(distinctList.size());
+//        Path csvPath = toCsv(path, distinctList);
+//        copyCsv(csvPath);
+//        move(path);
+//    }
+//
+//    /**
+//     * 读取文件
+//     *
+//     * @param path 文件路径
+//     */
+//    public List<Map<String, String>> readFile(Path path) throws IOException {
+//        log.info("读取: {}", path);
+//        List<String> rawHeaders = Stream.of("车牌号", "车辆品牌", "排量", "排量类型", "燃油类型", "燃油标号",
+//                "登记日期", "车辆来源", "车辆类型", "车辆使用性质", "环保等级", "用车模式", "发动机号", "车架号", "初始里程",
+//                "车辆所属单位", "行驶证号", "备注", "审核状态", "车辆状态", "资产编号", "绑定驾驶员姓名", "购置价格(万元)",
+//                "车龄(年)", "标准百公里油耗", "设备工作模式").toList();
+//        List<String> headers = Stream.of("che_pai_hao", "che_liang_pin_pai", "pai_liang", "pai_liang_lei_xing",
+//                "ran_you_lei_xing", "ran_you_biao_hao", "deng_ji_ri_qi", "che_liang_lai_yuan", "che_liang_lei_xing",
+//                "che_liang_shi_yong_xing_zhi", "huan_bao_deng_ji", "yong_che_mo_shi", "fa_dong_ji_hao", "che_jia_hao",
+//                "chu_shi_li_cheng", "che_liang_suo_shu_dan_wei", "xing_shi_zheng_hao", "bei_zhu", "shen_he_zhuang_tai",
+//                "che_liang_zhuang_tai", "zi_chan_bian_hao", "bang_ding_jia_shi_yuan_xing_ming", "gou_zhi_jia_ge",
+//                "che_ling_nian", "biao_zhun_bai_gong_li_you_hao", "she_bei_gong_zuo_mo_shi").toList();
+//        try (InputStream inputStream = Files.newInputStream(path);
+//             Workbook workbook = new XSSFWorkbook(inputStream)
+//        ) {
+//            List<Map<String, String>> resultList = new ArrayList<>();
+//            // 读取第一个工作表
+//            Sheet sheet = workbook.getSheetAt(0);
+//            // 表头行
+//            Row headerRow = sheet.getRow(0);
+//            // 列数
+//            int columnCount = headerRow.getPhysicalNumberOfCells();
+//            log.info("columnCount: {}", columnCount);
+//            // 检查表头
+//            if (headers.size() != columnCount) {
+//                throw new MyRuntimeException(path.getFileName() + "列数错误");
+//            }
+//            for (int i = 0; i < columnCount; i++) {
+//                Cell cell = headerRow.getCell(i);
+//                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
+//                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
+//                }
+//            }
+//            // 最后行数
+//            int lastRowNum = sheet.getLastRowNum();
+//            log.info("lastRowNum: {}", lastRowNum);
+//            if (lastRowNum == 0) {
+//                move(path);
+//                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+//            }
+//            // 遍历行
+//            for (int i = 1; i <= lastRowNum; i++) {
+//                log.debug("row: {}", i);
+//                Row row = sheet.getRow(i);
+//                if (row == null || row.getCell(0) == null) {
+//                    continue;
+//                }
+//                Map<String, String> rowMap = new LinkedHashMap<>();
+//                // 遍历列
+//                for (int j = 0; j < columnCount; j++) {
+//                    log.debug("column: {}", j);
+//                    String cellValue = "";
+//                    rowMap.put(headers.get(j), cellValue);
+//                    Cell cell = row.getCell(j);
+//                    if (cell == null) {
+//                        continue;
+//                    }
+//                    switch (cell.getCellType()) {
+//                        case STRING:
+//                            // 删除字符串空白字符
+//                            cellValue = StringUtils.trimAllWhitespace(cell.getStringCellValue());
+//                            break;
+//                        case NUMERIC:
+//                            if (DateUtil.isCellDateFormatted(cell)) {
+//                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
+//                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+//                                break;
+//                            }
+//                            cellValue = String.valueOf(cell.getNumericCellValue());
+//                            break;
+//                        case BOOLEAN:
+//                            cellValue = String.valueOf(cell.getBooleanCellValue());
+//                            break;
+//                        default:
+//                            break;
+//                    }
+//                    rowMap.put(headers.get(j), cellValue);
+//                }
+//                resultList.add(rowMap);
+//            }
+//            return resultList;
+//        }
+//    }
+//
+//    /**
+//     * 数据加工
+//     *
+//     * @param path 文件路径
+//     * @param list 数据
+//     */
+//    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+//        // 从文件名提取日期
+//        String regex = "\\d{8}";
+//        Pattern pattern = Pattern.compile(regex);
+//        Matcher matcher = pattern.matcher(path.getFileName().toString());
+//        String dateString;
+//        if (matcher.find()) {
+//            dateString = matcher.group();
+//        } else {
+//            throw new MyRuntimeException(path.getFileName() + " 提取日期失败");
+//        }
+//        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+//        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+//        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+//        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+//                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+//        List<AreaPo> cities = areaService.getCities();
+//        List<AreaPo> districts = areaService.getDistricts();
+//        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+//        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+//        LocalDate localDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyyMMdd"));
+//        LocalDate lastMonthDate = localDate.minusMonths(1);
+//        String dataDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+//        String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+//        String year = String.valueOf(localDate.getYear());
+//        String month = String.valueOf(localDate.getMonthValue());
+//        String lastMonth = lastMonthDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+//        for (Map<String, String> map : list) {
+//            map.put("data_date", dataDate);
+//            map.put("year_month", yearMonth);
+//            map.put("year_no", year);
+//            map.put("month_no", month);
+//            map.put("last_month", lastMonth);
+//            String rawChePaiHao = map.get("che_pai_hao");
+//            map.put("raw_che_pai_hao", rawChePaiHao);
+//            String chePaiHao = carService.getChePai(rawChePaiHao);
+//            map.put("che_pai_hao", chePaiHao);
+//            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+//            map.put("che_pai_fail", chePaiFail);
+//            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+//            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+//            String firstUnit = carService.getFirstUnit(carUnitBo);
+//            if (!StringUtils.hasText(firstUnit)) {
+//                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+//            }
+//            map.put("first_unit", firstUnit);
+//            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+//            map.put("second_unit", secondUnit);
+//            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+//            map.put("third_unit", thirdUnit);
+//            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+//            map.put("area_no", areaNo);
+//            String areaName = carService.getOrgName(orgMap, areaNo);
+//            map.put("area_name", areaName);
+//            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+//            map.put("city_no", cityNo);
+//            String cityName = carService.getOrgName(orgMap, cityNo);
+//            map.put("city_name", cityName);
+//            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+//            map.put("area_no2", areaNo2);
+//            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+//            map.put("area_name2", areaName2);
+//            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+//            map.put("city_id", cityId);
+//            String city = carService.getAreaName(areaMap, cityId);
+//            map.put("city", city);
+//            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+//            map.put("district_id", districtId);
+//            String district = carService.getAreaName(areaMap, districtId);
+//            map.put("district", district);
+//            String cheLing = "0";
+//            String dengJiRiQi = map.get("deng_ji_ri_qi");
+//            if (StringUtils.hasText(dengJiRiQi)) {
+//                LocalDate dengJiRiQiDate = LocalDate.parse(dengJiRiQi, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+//                long days = ChronoUnit.DAYS.between(dengJiRiQiDate, localDate);
+//                if (days > 0) {
+//                    BigDecimal n = BigDecimal.valueOf(days).divide(BigDecimal.valueOf(365), 1, RoundingMode.HALF_UP);
+//                    cheLing = n.toString();
+//                }
+//            }
+//            map.put("che_ling", cheLing);
+//            map.put("source", path.getFileName().toString());
+//        }
+//        // 去重
+//        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao"))).toList();
+//    }
+//
+//    /**
+//     * 去重
+//     */
+//    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+//        Set<Object> set = ConcurrentHashMap.newKeySet();
+//        return t -> set.add(keyExtractor.apply(t));
+//    }
+//
+//    /**
+//     * 生成csv
+//     *
+//     * @param path 源文件路径
+//     * @param list 数据
+//     */
+//    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+//        log.info("去重后条数:{}", list.size());
+//        Files.createDirectories(Paths.get(jobConfig.getCarBaseDataDayHistoryPath()));
+//        Path csvPath = Paths.get(jobConfig.getCarBaseDataDayHistoryPath() + path.getFileName() + ".csv");
+//        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+//                StandardCharsets.UTF_8);
+//             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+//            // 添加bom头避免excel乱码
+//            osw.write('\ufeff');
+//            Map<String, String> header = list.get(0);
+//            // 表头
+//            printer.printRecord(header.keySet());
+//            for (Map<String, String> map : list) {
+//                printer.printRecord(map.values());
+//            }
+//        }
+//        return csvPath;
+//    }
+//
+//    /**
+//     * 导入数据库
+//     * @param path 文件路径
+//     */
+//    public void copyCsv(Path path) {
+//        String dbTable = "car.car_base_data_day";
+//        String csv = path.toString();
+//        String columns = "(che_pai_hao,che_liang_pin_pai,pai_liang,pai_liang_lei_xing,ran_you_lei_xing,ran_you_biao_hao,deng_ji_ri_qi,che_liang_lai_yuan,che_liang_lei_xing,che_liang_shi_yong_xing_zhi,huan_bao_deng_ji,yong_che_mo_shi,fa_dong_ji_hao,che_jia_hao,chu_shi_li_cheng,che_liang_suo_shu_dan_wei,xing_shi_zheng_hao,bei_zhu,shen_he_zhuang_tai,che_liang_zhuang_tai,zi_chan_bian_hao,bang_ding_jia_shi_yuan_xing_ming,gou_zhi_jia_ge,che_ling_nian,biao_zhun_bai_gong_li_you_hao,she_bei_gong_zuo_mo_shi,data_date,year_month,year_no,month_no,last_month,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,che_ling,source)";
+//        Long timeout = 60000L;
+//        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+//                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+//                timeout, null);
+//    }
+//
+//    /**
+//     * 移动源文件到历史文件夹
+//     * @param path 源文件路径
+//     */
+//    public void move(Path path) throws IOException {
+//        Path targetPath = Paths.get(jobConfig.getCarBaseDataDayHistoryPath(), path.getFileName().toString());
+//        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
+//    }
+//}

+ 365 - 365
src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarLiChengDayJob.java

@@ -1,365 +1,365 @@
-package com.nokia.finance.tasks.jobs.car.ruixing;
-
-import com.nokia.finance.tasks.common.exception.MyRuntimeException;
-import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
-import com.nokia.finance.tasks.config.JobConfig;
-import com.nokia.finance.tasks.enums.DataStageEnum;
-import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
-import com.nokia.finance.tasks.pojo.po.common.AreaPo;
-import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
-import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
-import com.nokia.finance.tasks.service.car.CarService;
-import com.nokia.finance.tasks.service.common.AreaService;
-import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
-import com.nokia.finance.tasks.service.common.OrganizationService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVPrinter;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Stream;
-
-/**
- * 睿行车辆行驶里程日数据入库定时任务
- */
-@Slf4j
-@Service
-public class CarLiChengDayJob {
-    private final JobConfig jobConfig;
-    private final CarService carService;
-    private final OrganizationService organizationService;
-    private final AreaService areaService;
-    private final DataLogServiceImpl dataLogService;
-
-    public CarLiChengDayJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
-                            AreaService areaService, DataLogServiceImpl dataLogService) {
-        this.jobConfig = jobConfig;
-        this.carService = carService;
-        this.organizationService = organizationService;
-        this.areaService = areaService;
-        this.dataLogService = dataLogService;
-    }
-
-    /**
-     * 执行任务
-     */
-    @Scheduled(cron = "0 48 5 * * ?")
-    public void runJob() {
-        List<DataLogPo> dataLogPoList = new ArrayList<>();
-        // 数据目录
-        Path dir = Paths.get(jobConfig.getCarLiChengDaySourcePath());
-        try (Stream<Path> stream = Files.list(dir)) {
-            // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
-            log.info("睿行车辆行驶里程日数据文件列表: {}", pathList);
-            if (CollectionUtils.isEmpty(pathList)) {
-                throw new MyRuntimeException("睿行车辆行驶里程日数据没有文件");
-            }
-            for (Path path : pathList) {
-                CompletableFuture.runAsync(() -> {
-                    try {
-                        singleJob(path, dataLogPoList);
-                    } catch (Exception e) {
-                        throw new MyRuntimeException(e);
-                    }
-                }).get(1, TimeUnit.MINUTES);
-            }
-        } catch (InterruptedException e) {
-            log.error("线程中断: {}", e, e);
-            Thread.currentThread().interrupt();
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程日数据", DataStageEnum.CC, "入库");
-        } catch (Exception e) {
-            log.error(e.toString(), e);
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程日数据", DataStageEnum.CC, "入库");
-        } finally {
-            if (!CollectionUtils.isEmpty(dataLogPoList)) {
-                dataLogService.saveBatch(dataLogPoList);
-            }
-        }
-    }
-
-    /**
-     * 处理单个文件
-     *
-     * @param path          文件路径
-     * @param dataLogPoList 数据处理日志列表
-     */
-    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
-        DataLogPo dataLogPo = new DataLogPo();
-        dataLogPo.setDataName("睿行车辆行驶里程日数据");
-        dataLogPo.setObject(path.getFileName().toString());
-        dataLogPo.setStage(DataStageEnum.CC.value);
-        dataLogPo.setOperationName("入库");
-        long fileSize = Files.size(path);
-        dataLogPo.setDataSize(fileSize);
-        dataLogPoList.add(dataLogPo);
-        if (fileSize == 0) {
-            move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
-        }
-        List<Map<String, String>> list = readFile(path);
-        List<Map<String, String>> distinctList = dataProcessing(path, list);
-        dataLogPo.setDataCount(distinctList.size());
-        Path csvPath = toCsv(path, distinctList);
-        copyCsv(csvPath);
-        move(path);
-    }
-
-    /**
-     * 读取文件
-     *
-     * @param path 文件路径
-     */
-    public List<Map<String, String>> readFile(Path path) throws IOException {
-        log.info("读取: {}", path);
-        List<String> rawHeaders = Stream.of("车辆所属单位", "车牌号码", "车辆类型", "车辆来源", "车辆使用性质",
-                "行驶时长(小时)", "行驶天数", "总里程(公里)", "OBD总油耗(升)", "百公里油耗(升)").toList();
-        List<String> headers = Stream.of("che_liang_suo_shu_dan_wei", "che_pai_hao", "che_liang_lei_xing",
-                "che_liang_lai_yuan", "che_liang_shi_yong_xing_zhi", "xing_shi_shi_chang", "xing_shi_tian_shu",
-                "zong_li_cheng", "obd_you_hao", "bai_gong_li_you_hao").toList();
-        try (InputStream inputStream = Files.newInputStream(path);
-             Workbook workbook = new XSSFWorkbook(inputStream)
-        ) {
-            List<Map<String, String>> resultList = new ArrayList<>();
-            // 读取第一个工作表
-            Sheet sheet = workbook.getSheetAt(0);
-            // 表头行
-            Row headerRow = sheet.getRow(0);
-            // 列数
-            int columnCount = headerRow.getPhysicalNumberOfCells();
-            log.info("columnCount: {}", columnCount);
-            int headersSize = headers.size();
-            // 检查表头
-            if (headersSize > columnCount) {
-                throw new MyRuntimeException(path.getFileName() + "列数错误");
-            }
-            for (int i = 0; i < headersSize; i++) {
-                Cell cell = headerRow.getCell(i);
-                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
-                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
-                }
-            }
-            // 最后行数
-            int lastRowNum = sheet.getLastRowNum();
-            log.info("lastRowNum: {}", lastRowNum);
-            if (lastRowNum == 0) {
-                move(path);
-                throw new MyRuntimeException(path.getFileName() + " 数据0条");
-            }
-            // 遍历行
-            for (int i = 1; i <= lastRowNum; i++) {
-                log.debug("row: {}", i);
-                Row row = sheet.getRow(i);
-                if (row == null || row.getCell(0) == null) {
-                    continue;
-                }
-                Map<String, String> rowMap = new LinkedHashMap<>();
-                // 遍历列
-                for (int j = 0; j < headersSize; j++) {
-                    log.debug("column: {}", j);
-                    String cellValue = "";
-                    rowMap.put(headers.get(j), cellValue);
-                    Cell cell = row.getCell(j);
-                    if (cell == null) {
-                        continue;
-                    }
-                    switch (cell.getCellType()) {
-                        case STRING:
-                            // 删除字符串空白字符
-                            cellValue = StringUtils.trimAllWhitespace(cell.getStringCellValue());
-                            break;
-                        case NUMERIC:
-                            if (DateUtil.isCellDateFormatted(cell)) {
-                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
-                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-                                break;
-                            }
-                            cellValue = String.valueOf(cell.getNumericCellValue());
-                            break;
-                        case BOOLEAN:
-                            cellValue = String.valueOf(cell.getBooleanCellValue());
-                            break;
-                        default:
-                            break;
-                    }
-                    rowMap.put(headers.get(j), cellValue);
-                }
-                resultList.add(rowMap);
-            }
-            return resultList;
-        }
-    }
-
-    /**
-     * 数据加工
-     *
-     * @param path 文件路径
-     * @param list 数据
-     */
-    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
-        // 从文件名提取日期
-        String regex = "\\d{8}";
-        Pattern pattern = Pattern.compile(regex);
-        Matcher matcher = pattern.matcher(path.getFileName().toString());
-        String dateString;
-        if (matcher.find()) {
-            dateString = matcher.group();
-        } else {
-            throw new MyRuntimeException(path.getFileName() + " 提取日期失败");
-        }
-        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
-        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
-        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
-        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
-                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
-        List<AreaPo> cities = areaService.getCities();
-        List<AreaPo> districts = areaService.getDistricts();
-        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
-        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
-        LocalDate localDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyyMMdd"));
-        String dataDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-        String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
-        String year = String.valueOf(localDate.getYear());
-        String month = String.valueOf(localDate.getMonthValue());
-        for (Map<String, String> map : list) {
-            map.put("data_date", dataDate);
-            map.put("year_month", yearMonth);
-            map.put("year_no", year);
-            map.put("month_no", month);
-            String rawChePaiHao = map.get("che_pai_hao");
-            map.put("raw_che_pai_hao", rawChePaiHao);
-            String chePaiHao = carService.getChePai(rawChePaiHao);
-            map.put("che_pai_hao", chePaiHao);
-            String chePaiFail = carService.chePaiFail(rawChePaiHao);
-            map.put("che_pai_fail", chePaiFail);
-            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
-            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
-            String firstUnit = carService.getFirstUnit(carUnitBo);
-            if (!StringUtils.hasText(firstUnit)) {
-                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
-            }
-            map.put("first_unit", firstUnit);
-            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
-            map.put("second_unit", secondUnit);
-            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
-            map.put("third_unit", thirdUnit);
-            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
-            map.put("area_no", areaNo);
-            String areaName = carService.getOrgName(orgMap, areaNo);
-            map.put("area_name", areaName);
-            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
-            map.put("city_no", cityNo);
-            String cityName = carService.getOrgName(orgMap, cityNo);
-            map.put("city_name", cityName);
-            String areaNo2 = carService.getAreaNo2(areaName, cityName);
-            map.put("area_no2", areaNo2);
-            String areaName2 = carService.getOrgName(orgMap, areaNo2);
-            map.put("area_name2", areaName2);
-            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
-            map.put("city_id", cityId);
-            String city = carService.getAreaName(areaMap, cityId);
-            map.put("city", city);
-            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
-            map.put("district_id", districtId);
-            String district = carService.getAreaName(areaMap, districtId);
-            map.put("district", district);
-            String baoFei = carService.baoFei(rawChePaiHao);
-            map.put("bao_fei", baoFei);
-            if ("1".equals(baoFei)) {
-                map.put("che_pai_hao", rawChePaiHao);
-            }
-            map.put("source", path.getFileName().toString());
-        }
-        // 去重
-        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao"))).toList();
-    }
-
-    /**
-     * 去重
-     */
-    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
-        Set<Object> set = ConcurrentHashMap.newKeySet();
-        return t -> set.add(keyExtractor.apply(t));
-    }
-
-    /**
-     * 生成csv
-     *
-     * @param path 源文件路径
-     * @param list 数据
-     */
-    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
-        log.info("去重后条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarLiChengDayHistoryPath()));
-        Path csvPath = Paths.get(jobConfig.getCarLiChengDayHistoryPath() + path.getFileName() + ".csv");
-        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
-                StandardCharsets.UTF_8);
-             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
-            // 添加bom头避免excel乱码
-            osw.write('\ufeff');
-            Map<String, String> header = list.get(0);
-            // 表头
-            printer.printRecord(header.keySet());
-            for (Map<String, String> map : list) {
-                printer.printRecord(map.values());
-            }
-        }
-        return csvPath;
-    }
-
-    /**
-     * 导入数据库
-     *
-     * @param path 文件路径
-     */
-    public void copyCsv(Path path) {
-        String dbTable = "car.car_li_cheng_day";
-        String csv = path.toString();
-        String columns = "(che_liang_suo_shu_dan_wei,che_pai_hao,che_liang_lei_xing,che_liang_lai_yuan,che_liang_shi_yong_xing_zhi,xing_shi_shi_chang,xing_shi_tian_shu,zong_li_cheng,obd_you_hao,bai_gong_li_you_hao,data_date,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
-        Long timeout = 60000L;
-        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
-                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
-                timeout, null);
-    }
-
-    /**
-     * 移动源文件到历史文件夹
-     *
-     * @param path 源文件路径
-     */
-    public void move(Path path) throws IOException {
-        Path targetPath = Paths.get(jobConfig.getCarLiChengDayHistoryPath(), path.getFileName().toString());
-        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
-    }
-}
+//package com.nokia.finance.tasks.jobs.car.ruixing;
+//
+//import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+//import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+//import com.nokia.finance.tasks.config.JobConfig;
+//import com.nokia.finance.tasks.enums.DataStageEnum;
+//import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+//import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+//import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+//import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+//import com.nokia.finance.tasks.service.car.CarService;
+//import com.nokia.finance.tasks.service.common.AreaService;
+//import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+//import com.nokia.finance.tasks.service.common.OrganizationService;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.commons.csv.CSVFormat;
+//import org.apache.commons.csv.CSVPrinter;
+//import org.apache.poi.ss.usermodel.Cell;
+//import org.apache.poi.ss.usermodel.DateUtil;
+//import org.apache.poi.ss.usermodel.Row;
+//import org.apache.poi.ss.usermodel.Sheet;
+//import org.apache.poi.ss.usermodel.Workbook;
+//import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+//import org.springframework.scheduling.annotation.Scheduled;
+//import org.springframework.stereotype.Service;
+//import org.springframework.util.CollectionUtils;
+//import org.springframework.util.StringUtils;
+//
+//import java.io.IOException;
+//import java.io.InputStream;
+//import java.io.OutputStreamWriter;
+//import java.nio.charset.StandardCharsets;
+//import java.nio.file.Files;
+//import java.nio.file.Path;
+//import java.nio.file.Paths;
+//import java.nio.file.StandardCopyOption;
+//import java.time.LocalDate;
+//import java.time.format.DateTimeFormatter;
+//import java.util.ArrayList;
+//import java.util.LinkedHashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.concurrent.CompletableFuture;
+//import java.util.concurrent.ConcurrentHashMap;
+//import java.util.concurrent.TimeUnit;
+//import java.util.function.Function;
+//import java.util.function.Predicate;
+//import java.util.regex.Matcher;
+//import java.util.regex.Pattern;
+//import java.util.stream.Stream;
+//
+///**
+// * 睿行车辆行驶里程日数据入库定时任务
+// */
+//@Slf4j
+//@Service
+//public class CarLiChengDayJob {
+//    private final JobConfig jobConfig;
+//    private final CarService carService;
+//    private final OrganizationService organizationService;
+//    private final AreaService areaService;
+//    private final DataLogServiceImpl dataLogService;
+//
+//    public CarLiChengDayJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+//                            AreaService areaService, DataLogServiceImpl dataLogService) {
+//        this.jobConfig = jobConfig;
+//        this.carService = carService;
+//        this.organizationService = organizationService;
+//        this.areaService = areaService;
+//        this.dataLogService = dataLogService;
+//    }
+//
+//    /**
+//     * 执行任务
+//     */
+//    @Scheduled(cron = "0 48 5 * * ?")
+//    public void runJob() {
+//        List<DataLogPo> dataLogPoList = new ArrayList<>();
+//        // 数据目录
+//        Path dir = Paths.get(jobConfig.getCarLiChengDaySourcePath());
+//        try (Stream<Path> stream = Files.list(dir)) {
+//            // 获取数据目录下的文件列表
+//            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
+//            log.info("睿行车辆行驶里程日数据文件列表: {}", pathList);
+//            if (CollectionUtils.isEmpty(pathList)) {
+//                throw new MyRuntimeException("睿行车辆行驶里程日数据没有文件");
+//            }
+//            for (Path path : pathList) {
+//                CompletableFuture.runAsync(() -> {
+//                    try {
+//                        singleJob(path, dataLogPoList);
+//                    } catch (Exception e) {
+//                        throw new MyRuntimeException(e);
+//                    }
+//                }).get(1, TimeUnit.MINUTES);
+//            }
+//        } catch (InterruptedException e) {
+//            log.error("线程中断: {}", e, e);
+//            Thread.currentThread().interrupt();
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程日数据", DataStageEnum.CC, "入库");
+//        } catch (Exception e) {
+//            log.error(e.toString(), e);
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程日数据", DataStageEnum.CC, "入库");
+//        } finally {
+//            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+//                dataLogService.saveBatch(dataLogPoList);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * 处理单个文件
+//     *
+//     * @param path          文件路径
+//     * @param dataLogPoList 数据处理日志列表
+//     */
+//    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+//        DataLogPo dataLogPo = new DataLogPo();
+//        dataLogPo.setDataName("睿行车辆行驶里程日数据");
+//        dataLogPo.setObject(path.getFileName().toString());
+//        dataLogPo.setStage(DataStageEnum.CC.value);
+//        dataLogPo.setOperationName("入库");
+//        long fileSize = Files.size(path);
+//        dataLogPo.setDataSize(fileSize);
+//        dataLogPoList.add(dataLogPo);
+//        if (fileSize == 0) {
+//            move(path);
+//            throw new MyRuntimeException(path.getFileName() + " 空文件");
+//        }
+//        List<Map<String, String>> list = readFile(path);
+//        List<Map<String, String>> distinctList = dataProcessing(path, list);
+//        dataLogPo.setDataCount(distinctList.size());
+//        Path csvPath = toCsv(path, distinctList);
+//        copyCsv(csvPath);
+//        move(path);
+//    }
+//
+//    /**
+//     * 读取文件
+//     *
+//     * @param path 文件路径
+//     */
+//    public List<Map<String, String>> readFile(Path path) throws IOException {
+//        log.info("读取: {}", path);
+//        List<String> rawHeaders = Stream.of("车辆所属单位", "车牌号码", "车辆类型", "车辆来源", "车辆使用性质",
+//                "行驶时长(小时)", "行驶天数", "总里程(公里)", "OBD总油耗(升)", "百公里油耗(升)").toList();
+//        List<String> headers = Stream.of("che_liang_suo_shu_dan_wei", "che_pai_hao", "che_liang_lei_xing",
+//                "che_liang_lai_yuan", "che_liang_shi_yong_xing_zhi", "xing_shi_shi_chang", "xing_shi_tian_shu",
+//                "zong_li_cheng", "obd_you_hao", "bai_gong_li_you_hao").toList();
+//        try (InputStream inputStream = Files.newInputStream(path);
+//             Workbook workbook = new XSSFWorkbook(inputStream)
+//        ) {
+//            List<Map<String, String>> resultList = new ArrayList<>();
+//            // 读取第一个工作表
+//            Sheet sheet = workbook.getSheetAt(0);
+//            // 表头行
+//            Row headerRow = sheet.getRow(0);
+//            // 列数
+//            int columnCount = headerRow.getPhysicalNumberOfCells();
+//            log.info("columnCount: {}", columnCount);
+//            int headersSize = headers.size();
+//            // 检查表头
+//            if (headersSize > columnCount) {
+//                throw new MyRuntimeException(path.getFileName() + "列数错误");
+//            }
+//            for (int i = 0; i < headersSize; i++) {
+//                Cell cell = headerRow.getCell(i);
+//                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
+//                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
+//                }
+//            }
+//            // 最后行数
+//            int lastRowNum = sheet.getLastRowNum();
+//            log.info("lastRowNum: {}", lastRowNum);
+//            if (lastRowNum == 0) {
+//                move(path);
+//                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+//            }
+//            // 遍历行
+//            for (int i = 1; i <= lastRowNum; i++) {
+//                log.debug("row: {}", i);
+//                Row row = sheet.getRow(i);
+//                if (row == null || row.getCell(0) == null) {
+//                    continue;
+//                }
+//                Map<String, String> rowMap = new LinkedHashMap<>();
+//                // 遍历列
+//                for (int j = 0; j < headersSize; j++) {
+//                    log.debug("column: {}", j);
+//                    String cellValue = "";
+//                    rowMap.put(headers.get(j), cellValue);
+//                    Cell cell = row.getCell(j);
+//                    if (cell == null) {
+//                        continue;
+//                    }
+//                    switch (cell.getCellType()) {
+//                        case STRING:
+//                            // 删除字符串空白字符
+//                            cellValue = StringUtils.trimAllWhitespace(cell.getStringCellValue());
+//                            break;
+//                        case NUMERIC:
+//                            if (DateUtil.isCellDateFormatted(cell)) {
+//                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
+//                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+//                                break;
+//                            }
+//                            cellValue = String.valueOf(cell.getNumericCellValue());
+//                            break;
+//                        case BOOLEAN:
+//                            cellValue = String.valueOf(cell.getBooleanCellValue());
+//                            break;
+//                        default:
+//                            break;
+//                    }
+//                    rowMap.put(headers.get(j), cellValue);
+//                }
+//                resultList.add(rowMap);
+//            }
+//            return resultList;
+//        }
+//    }
+//
+//    /**
+//     * 数据加工
+//     *
+//     * @param path 文件路径
+//     * @param list 数据
+//     */
+//    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+//        // 从文件名提取日期
+//        String regex = "\\d{8}";
+//        Pattern pattern = Pattern.compile(regex);
+//        Matcher matcher = pattern.matcher(path.getFileName().toString());
+//        String dateString;
+//        if (matcher.find()) {
+//            dateString = matcher.group();
+//        } else {
+//            throw new MyRuntimeException(path.getFileName() + " 提取日期失败");
+//        }
+//        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+//        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+//        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+//        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+//                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+//        List<AreaPo> cities = areaService.getCities();
+//        List<AreaPo> districts = areaService.getDistricts();
+//        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+//        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+//        LocalDate localDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyyMMdd"));
+//        String dataDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+//        String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+//        String year = String.valueOf(localDate.getYear());
+//        String month = String.valueOf(localDate.getMonthValue());
+//        for (Map<String, String> map : list) {
+//            map.put("data_date", dataDate);
+//            map.put("year_month", yearMonth);
+//            map.put("year_no", year);
+//            map.put("month_no", month);
+//            String rawChePaiHao = map.get("che_pai_hao");
+//            map.put("raw_che_pai_hao", rawChePaiHao);
+//            String chePaiHao = carService.getChePai(rawChePaiHao);
+//            map.put("che_pai_hao", chePaiHao);
+//            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+//            map.put("che_pai_fail", chePaiFail);
+//            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+//            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+//            String firstUnit = carService.getFirstUnit(carUnitBo);
+//            if (!StringUtils.hasText(firstUnit)) {
+//                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+//            }
+//            map.put("first_unit", firstUnit);
+//            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+//            map.put("second_unit", secondUnit);
+//            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+//            map.put("third_unit", thirdUnit);
+//            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+//            map.put("area_no", areaNo);
+//            String areaName = carService.getOrgName(orgMap, areaNo);
+//            map.put("area_name", areaName);
+//            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+//            map.put("city_no", cityNo);
+//            String cityName = carService.getOrgName(orgMap, cityNo);
+//            map.put("city_name", cityName);
+//            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+//            map.put("area_no2", areaNo2);
+//            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+//            map.put("area_name2", areaName2);
+//            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+//            map.put("city_id", cityId);
+//            String city = carService.getAreaName(areaMap, cityId);
+//            map.put("city", city);
+//            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+//            map.put("district_id", districtId);
+//            String district = carService.getAreaName(areaMap, districtId);
+//            map.put("district", district);
+//            String baoFei = carService.baoFei(rawChePaiHao);
+//            map.put("bao_fei", baoFei);
+//            if ("1".equals(baoFei)) {
+//                map.put("che_pai_hao", rawChePaiHao);
+//            }
+//            map.put("source", path.getFileName().toString());
+//        }
+//        // 去重
+//        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao"))).toList();
+//    }
+//
+//    /**
+//     * 去重
+//     */
+//    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+//        Set<Object> set = ConcurrentHashMap.newKeySet();
+//        return t -> set.add(keyExtractor.apply(t));
+//    }
+//
+//    /**
+//     * 生成csv
+//     *
+//     * @param path 源文件路径
+//     * @param list 数据
+//     */
+//    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+//        log.info("去重后条数:{}", list.size());
+//        Files.createDirectories(Paths.get(jobConfig.getCarLiChengDayHistoryPath()));
+//        Path csvPath = Paths.get(jobConfig.getCarLiChengDayHistoryPath() + path.getFileName() + ".csv");
+//        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+//                StandardCharsets.UTF_8);
+//             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+//            // 添加bom头避免excel乱码
+//            osw.write('\ufeff');
+//            Map<String, String> header = list.get(0);
+//            // 表头
+//            printer.printRecord(header.keySet());
+//            for (Map<String, String> map : list) {
+//                printer.printRecord(map.values());
+//            }
+//        }
+//        return csvPath;
+//    }
+//
+//    /**
+//     * 导入数据库
+//     *
+//     * @param path 文件路径
+//     */
+//    public void copyCsv(Path path) {
+//        String dbTable = "car.car_li_cheng_day";
+//        String csv = path.toString();
+//        String columns = "(che_liang_suo_shu_dan_wei,che_pai_hao,che_liang_lei_xing,che_liang_lai_yuan,che_liang_shi_yong_xing_zhi,xing_shi_shi_chang,xing_shi_tian_shu,zong_li_cheng,obd_you_hao,bai_gong_li_you_hao,data_date,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+//        Long timeout = 60000L;
+//        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+//                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+//                timeout, null);
+//    }
+//
+//    /**
+//     * 移动源文件到历史文件夹
+//     *
+//     * @param path 源文件路径
+//     */
+//    public void move(Path path) throws IOException {
+//        Path targetPath = Paths.get(jobConfig.getCarLiChengDayHistoryPath(), path.getFileName().toString());
+//        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
+//    }
+//}

+ 368 - 368
src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarLiChengMonthJob.java

@@ -1,368 +1,368 @@
-package com.nokia.finance.tasks.jobs.car.ruixing;
-
-import com.nokia.finance.tasks.common.exception.MyRuntimeException;
-import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
-import com.nokia.finance.tasks.config.JobConfig;
-import com.nokia.finance.tasks.enums.DataStageEnum;
-import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
-import com.nokia.finance.tasks.pojo.po.common.AreaPo;
-import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
-import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
-import com.nokia.finance.tasks.service.car.CarService;
-import com.nokia.finance.tasks.service.common.AreaService;
-import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
-import com.nokia.finance.tasks.service.common.OrganizationService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVPrinter;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Stream;
-
-/**
- * 睿行车辆行驶里程月数据入库定时任务
- */
-@Slf4j
-@Service
-public class CarLiChengMonthJob {
-    private final JobConfig jobConfig;
-    private final CarService carService;
-    private final OrganizationService organizationService;
-    private final AreaService areaService;
-    private final DataLogServiceImpl dataLogService;
-
-    public CarLiChengMonthJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
-                              AreaService areaService, DataLogServiceImpl dataLogService) {
-        this.jobConfig = jobConfig;
-        this.carService = carService;
-        this.organizationService = organizationService;
-        this.areaService = areaService;
-        this.dataLogService = dataLogService;
-    }
-
-    /**
-     * 执行任务
-     */
-    @Scheduled(cron = "0 54 5 1 * ?")
-    public void runJob() {
-        List<DataLogPo> dataLogPoList = new ArrayList<>();
-        // 数据目录
-        Path dir = Paths.get(jobConfig.getCarLiChengMonthSourcePath());
-        try (Stream<Path> stream = Files.list(dir)) {
-            // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
-            log.info("睿行车辆行驶里程月数据文件列表: {}", pathList);
-            if (CollectionUtils.isEmpty(pathList)) {
-                throw new MyRuntimeException("睿行车辆行驶里程月数据没有文件");
-            }
-            for (Path path : pathList) {
-                CompletableFuture.runAsync(() -> {
-                    try {
-                        singleJob(path, dataLogPoList);
-                    } catch (Exception e) {
-                        throw new MyRuntimeException(e);
-                    }
-                }).get(1, TimeUnit.MINUTES);
-            }
-        } catch (InterruptedException e) {
-            log.error("线程中断: {}", e, e);
-            Thread.currentThread().interrupt();
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程月数据", DataStageEnum.CC, "入库");
-        } catch (Exception e) {
-            log.error(e.toString(), e);
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程月数据", DataStageEnum.CC, "入库");
-        } finally {
-            if (!CollectionUtils.isEmpty(dataLogPoList)) {
-                dataLogService.saveBatch(dataLogPoList);
-            }
-        }
-    }
-
-    /**
-     * 处理单个文件
-     *
-     * @param path          文件路径
-     * @param dataLogPoList 数据处理日志列表
-     */
-    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
-        DataLogPo dataLogPo = new DataLogPo();
-        dataLogPo.setDataName("睿行车辆行驶里程日数据");
-        dataLogPo.setObject(path.getFileName().toString());
-        dataLogPo.setStage(DataStageEnum.CC.value);
-        dataLogPo.setOperationName("入库");
-        long fileSize = Files.size(path);
-        dataLogPo.setDataSize(fileSize);
-        dataLogPoList.add(dataLogPo);
-        if (fileSize == 0) {
-            move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
-        }
-        // 从文件名提取日期
-        String regex = "\\d{6}";
-        Pattern pattern = Pattern.compile(regex);
-        Matcher matcher = pattern.matcher(path.getFileName().toString());
-        String dateString;
-        if (matcher.find()) {
-            dateString = matcher.group() + "01";
-        } else {
-            throw new MyRuntimeException(path.getFileName() + " 提取日期失败");
-        }
-        List<Map<String, String>> list = readFile(path);
-        List<Map<String, String>> distinctList = dataProcessing(path, list, dateString);
-        dataLogPo.setDataCount(distinctList.size());
-        Path csvPath = toCsv(path, distinctList);
-        copyCsv(csvPath);
-        move(path);
-    }
-
-    /**
-     * 读取文件
-     *
-     * @param path 文件路径
-     */
-    public List<Map<String, String>> readFile(Path path) throws IOException {
-        log.info("读取: {}", path);
-        List<String> rawHeaders = Stream.of("车牌号码", "车辆所属单位", "车辆类型", "车辆来源", "车辆使用性质",
-                "行驶时长(小时)", "行驶天数", "总里程(公里)", "OBD总油耗(升)", "百公里油耗(升)").toList();
-        List<String> headers = Stream.of("che_pai_hao", "che_liang_suo_shu_dan_wei", "che_liang_lei_xing",
-                "che_liang_lai_yuan", "che_liang_shi_yong_xing_zhi", "xing_shi_shi_chang", "xing_shi_tian_shu",
-                "zong_li_cheng", "obd_you_hao", "bai_gong_li_you_hao").toList();
-        try (InputStream inputStream = Files.newInputStream(path);
-             Workbook workbook = new XSSFWorkbook(inputStream)
-        ) {
-            List<Map<String, String>> resultList = new ArrayList<>();
-            // 读取第一个工作表
-            Sheet sheet = workbook.getSheetAt(0);
-            // 表头行
-            Row headerRow = sheet.getRow(0);
-            // 列数
-            int columnCount = headerRow.getPhysicalNumberOfCells();
-            log.info("columnCount: {}", columnCount);
-            // 检查表头
-            if (headers.size() != columnCount) {
-                throw new MyRuntimeException(path.getFileName() + "列数错误");
-            }
-            for (int i = 0; i < columnCount; i++) {
-                Cell cell = headerRow.getCell(i);
-                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
-                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
-                }
-            }
-            // 最后行数
-            int lastRowNum = sheet.getLastRowNum();
-            log.info("lastRowNum: {}", lastRowNum);
-            if (lastRowNum == 0) {
-                move(path);
-                throw new MyRuntimeException(path.getFileName() + " 数据0条");
-            }
-            // 遍历行
-            for (int i = 1; i <= lastRowNum; i++) {
-                log.debug("row: {}", i);
-                Row row = sheet.getRow(i);
-                if (row == null || row.getCell(0) == null) {
-                    continue;
-                }
-                Map<String, String> rowMap = new LinkedHashMap<>();
-                // 遍历列
-                for (int j = 0; j < columnCount; j++) {
-                    log.debug("column: {}", j);
-                    String cellValue = "";
-                    rowMap.put(headers.get(j), cellValue);
-                    Cell cell = row.getCell(j);
-                    if (cell == null) {
-                        continue;
-                    }
-                    switch (cell.getCellType()) {
-                        case STRING:
-                            // 删除字符串空白字符
-                            cellValue = StringUtils.trimAllWhitespace(cell.getStringCellValue());
-                            break;
-                        case NUMERIC:
-                            if (DateUtil.isCellDateFormatted(cell)) {
-                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
-                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-                                break;
-                            }
-                            cellValue = String.valueOf(cell.getNumericCellValue());
-                            break;
-                        case BOOLEAN:
-                            cellValue = String.valueOf(cell.getBooleanCellValue());
-                            break;
-                        default:
-                            break;
-                    }
-                    rowMap.put(headers.get(j), cellValue);
-                }
-                resultList.add(rowMap);
-            }
-            return resultList;
-        }
-    }
-
-    /**
-     * 数据加工
-     *
-     * @param path       文件路径
-     * @param list       数据
-     * @param dateString 日期字符串
-     */
-    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list, String dateString) {
-        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
-        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
-        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
-        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
-                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
-        List<AreaPo> cities = areaService.getCities();
-        List<AreaPo> districts = areaService.getDistricts();
-        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
-        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
-        LocalDate localDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyyMMdd")).minusMonths(1);
-        LocalDate lastMonthDate = localDate.minusMonths(1);
-        String dataDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-        String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
-        String year = String.valueOf(localDate.getYear());
-        String month = String.valueOf(localDate.getMonthValue());
-        String lastMonth = lastMonthDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
-        for (Map<String, String> map : list) {
-            map.put("data_date", dataDate);
-            map.put("year_month", yearMonth);
-            map.put("year_no", year);
-            map.put("month_no", month);
-            map.put("last_month", lastMonth);
-            String rawChePaiHao = map.get("che_pai_hao");
-            map.put("raw_che_pai_hao", rawChePaiHao);
-            String chePaiHao = carService.getChePai(rawChePaiHao);
-            map.put("che_pai_hao", chePaiHao);
-            String chePaiFail = carService.chePaiFail(rawChePaiHao);
-            map.put("che_pai_fail", chePaiFail);
-            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
-            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
-            String firstUnit = carService.getFirstUnit(carUnitBo);
-            if (!StringUtils.hasText(firstUnit)) {
-                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
-            }
-            map.put("first_unit", firstUnit);
-            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
-            map.put("second_unit", secondUnit);
-            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
-            map.put("third_unit", thirdUnit);
-            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
-            map.put("area_no", areaNo);
-            String areaName = carService.getOrgName(orgMap, areaNo);
-            map.put("area_name", areaName);
-            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
-            map.put("city_no", cityNo);
-            String cityName = carService.getOrgName(orgMap, cityNo);
-            map.put("city_name", cityName);
-            String areaNo2 = carService.getAreaNo2(areaName, cityName);
-            map.put("area_no2", areaNo2);
-            String areaName2 = carService.getOrgName(orgMap, areaNo2);
-            map.put("area_name2", areaName2);
-            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
-            map.put("city_id", cityId);
-            String city = carService.getAreaName(areaMap, cityId);
-            map.put("city", city);
-            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
-            map.put("district_id", districtId);
-            String district = carService.getAreaName(areaMap, districtId);
-            map.put("district", district);
-            String baoFei = carService.baoFei(rawChePaiHao);
-            map.put("bao_fei", baoFei);
-            if ("1".equals(baoFei)) {
-                map.put("che_pai_hao", rawChePaiHao);
-            }
-            map.put("source", path.getFileName().toString());
-        }
-        // 去重
-        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao"))).toList();
-    }
-
-    /**
-     * 去重
-     */
-    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
-        Set<Object> set = ConcurrentHashMap.newKeySet();
-        return t -> set.add(keyExtractor.apply(t));
-    }
-
-    /**
-     * 生成csv
-     *
-     * @param path 源文件路径
-     * @param list 数据
-     */
-    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
-        log.info("去重后条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarLiChengMonthHistoryPath()));
-        Path csvPath = Paths.get(jobConfig.getCarLiChengMonthHistoryPath() + path.getFileName() + ".csv");
-        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
-                StandardCharsets.UTF_8);
-             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
-            // 添加bom头避免excel乱码
-            osw.write('\ufeff');
-            Map<String, String> header = list.get(0);
-            // 表头
-            printer.printRecord(header.keySet());
-            for (Map<String, String> map : list) {
-                printer.printRecord(map.values());
-            }
-        }
-        return csvPath;
-    }
-
-    /**
-     * 导入数据库
-     *
-     * @param path 文件路径
-     */
-    public void copyCsv(Path path) {
-        String dbTable = "car.car_li_cheng_month";
-        String csv = path.toString();
-        String columns = "(che_pai_hao,che_liang_suo_shu_dan_wei,che_liang_lei_xing,che_liang_lai_yuan,che_liang_shi_yong_xing_zhi,xing_shi_shi_chang,xing_shi_tian_shu,zong_li_cheng,obd_you_hao,bai_gong_li_you_hao,data_date,year_month,year_no,month_no,last_month,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
-        Long timeout = 60000L;
-        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
-                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
-                timeout, null);
-    }
-
-    /**
-     * 移动源文件到历史文件夹
-     *
-     * @param path 源文件路径
-     */
-    public void move(Path path) throws IOException {
-        Path targetPath = Paths.get(jobConfig.getCarLiChengMonthHistoryPath(), path.getFileName().toString());
-        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
-    }
-}
+//package com.nokia.finance.tasks.jobs.car.ruixing;
+//
+//import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+//import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+//import com.nokia.finance.tasks.config.JobConfig;
+//import com.nokia.finance.tasks.enums.DataStageEnum;
+//import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+//import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+//import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+//import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+//import com.nokia.finance.tasks.service.car.CarService;
+//import com.nokia.finance.tasks.service.common.AreaService;
+//import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+//import com.nokia.finance.tasks.service.common.OrganizationService;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.commons.csv.CSVFormat;
+//import org.apache.commons.csv.CSVPrinter;
+//import org.apache.poi.ss.usermodel.Cell;
+//import org.apache.poi.ss.usermodel.DateUtil;
+//import org.apache.poi.ss.usermodel.Row;
+//import org.apache.poi.ss.usermodel.Sheet;
+//import org.apache.poi.ss.usermodel.Workbook;
+//import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+//import org.springframework.scheduling.annotation.Scheduled;
+//import org.springframework.stereotype.Service;
+//import org.springframework.util.CollectionUtils;
+//import org.springframework.util.StringUtils;
+//
+//import java.io.IOException;
+//import java.io.InputStream;
+//import java.io.OutputStreamWriter;
+//import java.nio.charset.StandardCharsets;
+//import java.nio.file.Files;
+//import java.nio.file.Path;
+//import java.nio.file.Paths;
+//import java.nio.file.StandardCopyOption;
+//import java.time.LocalDate;
+//import java.time.format.DateTimeFormatter;
+//import java.util.ArrayList;
+//import java.util.LinkedHashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.concurrent.CompletableFuture;
+//import java.util.concurrent.ConcurrentHashMap;
+//import java.util.concurrent.TimeUnit;
+//import java.util.function.Function;
+//import java.util.function.Predicate;
+//import java.util.regex.Matcher;
+//import java.util.regex.Pattern;
+//import java.util.stream.Stream;
+//
+///**
+// * 睿行车辆行驶里程月数据入库定时任务
+// */
+//@Slf4j
+//@Service
+//public class CarLiChengMonthJob {
+//    private final JobConfig jobConfig;
+//    private final CarService carService;
+//    private final OrganizationService organizationService;
+//    private final AreaService areaService;
+//    private final DataLogServiceImpl dataLogService;
+//
+//    public CarLiChengMonthJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+//                              AreaService areaService, DataLogServiceImpl dataLogService) {
+//        this.jobConfig = jobConfig;
+//        this.carService = carService;
+//        this.organizationService = organizationService;
+//        this.areaService = areaService;
+//        this.dataLogService = dataLogService;
+//    }
+//
+//    /**
+//     * 执行任务
+//     */
+//    @Scheduled(cron = "0 54 5 1 * ?")
+//    public void runJob() {
+//        List<DataLogPo> dataLogPoList = new ArrayList<>();
+//        // 数据目录
+//        Path dir = Paths.get(jobConfig.getCarLiChengMonthSourcePath());
+//        try (Stream<Path> stream = Files.list(dir)) {
+//            // 获取数据目录下的文件列表
+//            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
+//            log.info("睿行车辆行驶里程月数据文件列表: {}", pathList);
+//            if (CollectionUtils.isEmpty(pathList)) {
+//                throw new MyRuntimeException("睿行车辆行驶里程月数据没有文件");
+//            }
+//            for (Path path : pathList) {
+//                CompletableFuture.runAsync(() -> {
+//                    try {
+//                        singleJob(path, dataLogPoList);
+//                    } catch (Exception e) {
+//                        throw new MyRuntimeException(e);
+//                    }
+//                }).get(1, TimeUnit.MINUTES);
+//            }
+//        } catch (InterruptedException e) {
+//            log.error("线程中断: {}", e, e);
+//            Thread.currentThread().interrupt();
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程月数据", DataStageEnum.CC, "入库");
+//        } catch (Exception e) {
+//            log.error(e.toString(), e);
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程月数据", DataStageEnum.CC, "入库");
+//        } finally {
+//            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+//                dataLogService.saveBatch(dataLogPoList);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * 处理单个文件
+//     *
+//     * @param path          文件路径
+//     * @param dataLogPoList 数据处理日志列表
+//     */
+//    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+//        DataLogPo dataLogPo = new DataLogPo();
+//        dataLogPo.setDataName("睿行车辆行驶里程日数据");
+//        dataLogPo.setObject(path.getFileName().toString());
+//        dataLogPo.setStage(DataStageEnum.CC.value);
+//        dataLogPo.setOperationName("入库");
+//        long fileSize = Files.size(path);
+//        dataLogPo.setDataSize(fileSize);
+//        dataLogPoList.add(dataLogPo);
+//        if (fileSize == 0) {
+//            move(path);
+//            throw new MyRuntimeException(path.getFileName() + " 空文件");
+//        }
+//        // 从文件名提取日期
+//        String regex = "\\d{6}";
+//        Pattern pattern = Pattern.compile(regex);
+//        Matcher matcher = pattern.matcher(path.getFileName().toString());
+//        String dateString;
+//        if (matcher.find()) {
+//            dateString = matcher.group() + "01";
+//        } else {
+//            throw new MyRuntimeException(path.getFileName() + " 提取日期失败");
+//        }
+//        List<Map<String, String>> list = readFile(path);
+//        List<Map<String, String>> distinctList = dataProcessing(path, list, dateString);
+//        dataLogPo.setDataCount(distinctList.size());
+//        Path csvPath = toCsv(path, distinctList);
+//        copyCsv(csvPath);
+//        move(path);
+//    }
+//
+//    /**
+//     * 读取文件
+//     *
+//     * @param path 文件路径
+//     */
+//    public List<Map<String, String>> readFile(Path path) throws IOException {
+//        log.info("读取: {}", path);
+//        List<String> rawHeaders = Stream.of("车牌号码", "车辆所属单位", "车辆类型", "车辆来源", "车辆使用性质",
+//                "行驶时长(小时)", "行驶天数", "总里程(公里)", "OBD总油耗(升)", "百公里油耗(升)").toList();
+//        List<String> headers = Stream.of("che_pai_hao", "che_liang_suo_shu_dan_wei", "che_liang_lei_xing",
+//                "che_liang_lai_yuan", "che_liang_shi_yong_xing_zhi", "xing_shi_shi_chang", "xing_shi_tian_shu",
+//                "zong_li_cheng", "obd_you_hao", "bai_gong_li_you_hao").toList();
+//        try (InputStream inputStream = Files.newInputStream(path);
+//             Workbook workbook = new XSSFWorkbook(inputStream)
+//        ) {
+//            List<Map<String, String>> resultList = new ArrayList<>();
+//            // 读取第一个工作表
+//            Sheet sheet = workbook.getSheetAt(0);
+//            // 表头行
+//            Row headerRow = sheet.getRow(0);
+//            // 列数
+//            int columnCount = headerRow.getPhysicalNumberOfCells();
+//            log.info("columnCount: {}", columnCount);
+//            // 检查表头
+//            if (headers.size() != columnCount) {
+//                throw new MyRuntimeException(path.getFileName() + "列数错误");
+//            }
+//            for (int i = 0; i < columnCount; i++) {
+//                Cell cell = headerRow.getCell(i);
+//                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
+//                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
+//                }
+//            }
+//            // 最后行数
+//            int lastRowNum = sheet.getLastRowNum();
+//            log.info("lastRowNum: {}", lastRowNum);
+//            if (lastRowNum == 0) {
+//                move(path);
+//                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+//            }
+//            // 遍历行
+//            for (int i = 1; i <= lastRowNum; i++) {
+//                log.debug("row: {}", i);
+//                Row row = sheet.getRow(i);
+//                if (row == null || row.getCell(0) == null) {
+//                    continue;
+//                }
+//                Map<String, String> rowMap = new LinkedHashMap<>();
+//                // 遍历列
+//                for (int j = 0; j < columnCount; j++) {
+//                    log.debug("column: {}", j);
+//                    String cellValue = "";
+//                    rowMap.put(headers.get(j), cellValue);
+//                    Cell cell = row.getCell(j);
+//                    if (cell == null) {
+//                        continue;
+//                    }
+//                    switch (cell.getCellType()) {
+//                        case STRING:
+//                            // 删除字符串空白字符
+//                            cellValue = StringUtils.trimAllWhitespace(cell.getStringCellValue());
+//                            break;
+//                        case NUMERIC:
+//                            if (DateUtil.isCellDateFormatted(cell)) {
+//                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
+//                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+//                                break;
+//                            }
+//                            cellValue = String.valueOf(cell.getNumericCellValue());
+//                            break;
+//                        case BOOLEAN:
+//                            cellValue = String.valueOf(cell.getBooleanCellValue());
+//                            break;
+//                        default:
+//                            break;
+//                    }
+//                    rowMap.put(headers.get(j), cellValue);
+//                }
+//                resultList.add(rowMap);
+//            }
+//            return resultList;
+//        }
+//    }
+//
+//    /**
+//     * 数据加工
+//     *
+//     * @param path       文件路径
+//     * @param list       数据
+//     * @param dateString 日期字符串
+//     */
+//    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list, String dateString) {
+//        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+//        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+//        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+//        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+//                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+//        List<AreaPo> cities = areaService.getCities();
+//        List<AreaPo> districts = areaService.getDistricts();
+//        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+//        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+//        LocalDate localDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyyMMdd")).minusMonths(1);
+//        LocalDate lastMonthDate = localDate.minusMonths(1);
+//        String dataDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+//        String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+//        String year = String.valueOf(localDate.getYear());
+//        String month = String.valueOf(localDate.getMonthValue());
+//        String lastMonth = lastMonthDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+//        for (Map<String, String> map : list) {
+//            map.put("data_date", dataDate);
+//            map.put("year_month", yearMonth);
+//            map.put("year_no", year);
+//            map.put("month_no", month);
+//            map.put("last_month", lastMonth);
+//            String rawChePaiHao = map.get("che_pai_hao");
+//            map.put("raw_che_pai_hao", rawChePaiHao);
+//            String chePaiHao = carService.getChePai(rawChePaiHao);
+//            map.put("che_pai_hao", chePaiHao);
+//            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+//            map.put("che_pai_fail", chePaiFail);
+//            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+//            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+//            String firstUnit = carService.getFirstUnit(carUnitBo);
+//            if (!StringUtils.hasText(firstUnit)) {
+//                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+//            }
+//            map.put("first_unit", firstUnit);
+//            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+//            map.put("second_unit", secondUnit);
+//            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+//            map.put("third_unit", thirdUnit);
+//            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+//            map.put("area_no", areaNo);
+//            String areaName = carService.getOrgName(orgMap, areaNo);
+//            map.put("area_name", areaName);
+//            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+//            map.put("city_no", cityNo);
+//            String cityName = carService.getOrgName(orgMap, cityNo);
+//            map.put("city_name", cityName);
+//            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+//            map.put("area_no2", areaNo2);
+//            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+//            map.put("area_name2", areaName2);
+//            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+//            map.put("city_id", cityId);
+//            String city = carService.getAreaName(areaMap, cityId);
+//            map.put("city", city);
+//            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+//            map.put("district_id", districtId);
+//            String district = carService.getAreaName(areaMap, districtId);
+//            map.put("district", district);
+//            String baoFei = carService.baoFei(rawChePaiHao);
+//            map.put("bao_fei", baoFei);
+//            if ("1".equals(baoFei)) {
+//                map.put("che_pai_hao", rawChePaiHao);
+//            }
+//            map.put("source", path.getFileName().toString());
+//        }
+//        // 去重
+//        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao"))).toList();
+//    }
+//
+//    /**
+//     * 去重
+//     */
+//    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+//        Set<Object> set = ConcurrentHashMap.newKeySet();
+//        return t -> set.add(keyExtractor.apply(t));
+//    }
+//
+//    /**
+//     * 生成csv
+//     *
+//     * @param path 源文件路径
+//     * @param list 数据
+//     */
+//    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+//        log.info("去重后条数:{}", list.size());
+//        Files.createDirectories(Paths.get(jobConfig.getCarLiChengMonthHistoryPath()));
+//        Path csvPath = Paths.get(jobConfig.getCarLiChengMonthHistoryPath() + path.getFileName() + ".csv");
+//        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+//                StandardCharsets.UTF_8);
+//             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+//            // 添加bom头避免excel乱码
+//            osw.write('\ufeff');
+//            Map<String, String> header = list.get(0);
+//            // 表头
+//            printer.printRecord(header.keySet());
+//            for (Map<String, String> map : list) {
+//                printer.printRecord(map.values());
+//            }
+//        }
+//        return csvPath;
+//    }
+//
+//    /**
+//     * 导入数据库
+//     *
+//     * @param path 文件路径
+//     */
+//    public void copyCsv(Path path) {
+//        String dbTable = "car.car_li_cheng_month";
+//        String csv = path.toString();
+//        String columns = "(che_pai_hao,che_liang_suo_shu_dan_wei,che_liang_lei_xing,che_liang_lai_yuan,che_liang_shi_yong_xing_zhi,xing_shi_shi_chang,xing_shi_tian_shu,zong_li_cheng,obd_you_hao,bai_gong_li_you_hao,data_date,year_month,year_no,month_no,last_month,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+//        Long timeout = 60000L;
+//        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+//                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+//                timeout, null);
+//    }
+//
+//    /**
+//     * 移动源文件到历史文件夹
+//     *
+//     * @param path 源文件路径
+//     */
+//    public void move(Path path) throws IOException {
+//        Path targetPath = Paths.get(jobConfig.getCarLiChengMonthHistoryPath(), path.getFileName().toString());
+//        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
+//    }
+//}

+ 354 - 354
src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarWuDanYongCheJob.java

@@ -1,354 +1,354 @@
-package com.nokia.finance.tasks.jobs.car.ruixing;
-
-import com.nokia.finance.tasks.common.exception.MyRuntimeException;
-import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
-import com.nokia.finance.tasks.config.JobConfig;
-import com.nokia.finance.tasks.enums.DataStageEnum;
-import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
-import com.nokia.finance.tasks.pojo.po.common.AreaPo;
-import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
-import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
-import com.nokia.finance.tasks.service.car.CarService;
-import com.nokia.finance.tasks.service.common.AreaService;
-import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
-import com.nokia.finance.tasks.service.common.OrganizationService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVPrinter;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-/**
- * 睿行车辆无单用车报警月统计数据入库定时任务
- */
-@Slf4j
-@Service
-public class CarWuDanYongCheJob {
-    private final JobConfig jobConfig;
-    private final CarService carService;
-    private final OrganizationService organizationService;
-    private final AreaService areaService;
-    private final DataLogServiceImpl dataLogService;
-
-    public CarWuDanYongCheJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
-                              AreaService areaService, DataLogServiceImpl dataLogService) {
-        this.jobConfig = jobConfig;
-        this.carService = carService;
-        this.organizationService = organizationService;
-        this.areaService = areaService;
-        this.dataLogService = dataLogService;
-    }
-
-    /**
-     * 执行任务
-     */
-    @Scheduled(cron = "0 56 5 1 * ?")
-    public void runJob() {
-        List<DataLogPo> dataLogPoList = new ArrayList<>();
-        // 数据目录
-        Path dir = Paths.get(jobConfig.getCarWuDanYongCheSourcePath());
-        try (Stream<Path> stream = Files.list(dir)) {
-            // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
-            log.info("睿行车辆无单用车报警月统计数据文件列表: {}", pathList);
-            if (CollectionUtils.isEmpty(pathList)) {
-                throw new MyRuntimeException("睿行车辆无单用车报警月统计数据没有文件");
-            }
-            for (Path path : pathList) {
-                CompletableFuture.runAsync(() -> {
-                    try {
-                        singleJob(path, dataLogPoList);
-                    } catch (Exception e) {
-                        throw new MyRuntimeException(e);
-                    }
-                }).get(1, TimeUnit.MINUTES);
-            }
-        } catch (InterruptedException e) {
-            log.error("线程中断: {}", e, e);
-            Thread.currentThread().interrupt();
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆无单用车报警月统计数据", DataStageEnum.CC, "入库");
-        } catch (Exception e) {
-            log.error(e.toString(), e);
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆无单用车报警月统计数据", DataStageEnum.CC, "入库");
-        } finally {
-            if (!CollectionUtils.isEmpty(dataLogPoList)) {
-                dataLogService.saveBatch(dataLogPoList);
-            }
-        }
-    }
-
-    /**
-     * 处理单个文件
-     *
-     * @param path          文件路径
-     * @param dataLogPoList 数据处理日志列表
-     */
-    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
-        DataLogPo dataLogPo = new DataLogPo();
-        dataLogPo.setDataName("睿行车辆无单用车报警月统计数据");
-        dataLogPo.setObject(path.getFileName().toString());
-        dataLogPo.setStage(DataStageEnum.CC.value);
-        dataLogPo.setOperationName("入库");
-        long fileSize = Files.size(path);
-        dataLogPo.setDataSize(fileSize);
-        dataLogPoList.add(dataLogPo);
-        if (fileSize == 0) {
-            move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
-        }
-        List<Map<String, String>> list = readFile(path);
-        List<Map<String, String>> distinctList = dataProcessing(path, list);
-        dataLogPo.setDataCount(distinctList.size());
-        Path csvPath = toCsv(path, distinctList);
-        copyCsv(csvPath);
-        move(path);
-    }
-
-    /**
-     * 读取文件
-     *
-     * @param path 文件路径
-     */
-    public List<Map<String, String>> readFile(Path path) throws IOException {
-        log.info("读取: {}", path);
-        List<String> rawHeaders = Stream.of("车辆所属单位", "车牌号码", "违规开始时间", "违规结束时间",
-                "违规持续时间(分)").toList();
-        List<String> headers = Stream.of("che_liang_suo_shu_dan_wei", "che_pai_hao", "wei_gui_kai_shi_shi_jian",
-                "wei_gui_jie_shu_shi_jian", "wei_gui_chi_xu_shi_jian").toList();
-        try (InputStream inputStream = Files.newInputStream(path);
-             Workbook workbook = new XSSFWorkbook(inputStream)
-        ) {
-            List<Map<String, String>> resultList = new ArrayList<>();
-            // 读取第一个工作表
-            Sheet sheet = workbook.getSheetAt(0);
-            // 表头行
-            Row headerRow = sheet.getRow(0);
-            // 列数
-            int columnCount = headerRow.getPhysicalNumberOfCells();
-            log.info("columnCount: {}", columnCount);
-            // 检查表头
-            if (headers.size() != columnCount) {
-                throw new MyRuntimeException(path.getFileName() + "列数错误");
-            }
-            for (int i = 0; i < columnCount; i++) {
-                Cell cell = headerRow.getCell(i);
-                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
-                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
-                }
-            }
-            // 最后行数
-            int lastRowNum = sheet.getLastRowNum();
-            log.info("lastRowNum: {}", lastRowNum);
-            if (lastRowNum == 0) {
-                move(path);
-                throw new MyRuntimeException(path.getFileName() + " 数据0条");
-            }
-            // 遍历行
-            for (int i = 1; i <= lastRowNum; i++) {
-                log.debug("row: {}", i);
-                Row row = sheet.getRow(i);
-                if (row == null || row.getCell(0) == null) {
-                    continue;
-                }
-                Map<String, String> rowMap = new LinkedHashMap<>();
-                // 遍历列
-                for (int j = 0; j < columnCount; j++) {
-                    log.debug("column: {}", j);
-                    String header = headers.get(j);
-                    String cellValue = "";
-                    rowMap.put(header, cellValue);
-                    Cell cell = row.getCell(j);
-                    if (cell == null) {
-                        continue;
-                    }
-                    switch (cell.getCellType()) {
-                        case STRING:
-                            boolean skipTrim = "wei_gui_kai_shi_shi_jian".equals(header)
-                                    || "wei_gui_jie_shu_shi_jian".equals(header);
-                            // 删除字符串空白字符
-                            cellValue = skipTrim ? cell.getStringCellValue()
-                                    : StringUtils.trimAllWhitespace(cell.getStringCellValue());
-                            break;
-                        case NUMERIC:
-                            if (DateUtil.isCellDateFormatted(cell)) {
-                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
-                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-                                break;
-                            }
-                            cellValue = String.valueOf(cell.getNumericCellValue());
-                            break;
-                        case BOOLEAN:
-                            cellValue = String.valueOf(cell.getBooleanCellValue());
-                            break;
-                        default:
-                            break;
-                    }
-                    rowMap.put(header, cellValue);
-                }
-                resultList.add(rowMap);
-            }
-            return resultList;
-        }
-    }
-
-    /**
-     * 数据加工
-     *
-     * @param path 文件路径
-     * @param list 数据
-     */
-    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
-        String lastMonth = LocalDateTime.now().minusMonths(1).format(DateTimeFormatter.ofPattern("yyyyMM"));
-        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
-        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
-        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
-        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
-                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
-        List<AreaPo> cities = areaService.getCities();
-        List<AreaPo> districts = areaService.getDistricts();
-        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
-        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
-        for (Map<String, String> map : list) {
-            String weiGuiKaiShiShiJian = map.get("wei_gui_kai_shi_shi_jian");
-            LocalDateTime localDateTime = LocalDateTime.parse(weiGuiKaiShiShiJian,
-                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-            String yearMonth = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
-            String year = String.valueOf(localDateTime.getYear());
-            String month = String.valueOf(localDateTime.getMonthValue());
-            map.put("year_month", yearMonth);
-            map.put("year_no", year);
-            map.put("month_no", month);
-            String rawChePaiHao = map.get("che_pai_hao");
-            map.put("raw_che_pai_hao", rawChePaiHao);
-            String chePaiHao = carService.getChePai(rawChePaiHao);
-            map.put("che_pai_hao", chePaiHao);
-            String chePaiFail = carService.chePaiFail(rawChePaiHao);
-            map.put("che_pai_fail", chePaiFail);
-            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
-            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
-            String firstUnit = carService.getFirstUnit(carUnitBo);
-            if (!StringUtils.hasText(firstUnit)) {
-                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
-            }
-            map.put("first_unit", firstUnit);
-            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
-            map.put("second_unit", secondUnit);
-            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
-            map.put("third_unit", thirdUnit);
-            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
-            map.put("area_no", areaNo);
-            String areaName = carService.getOrgName(orgMap, areaNo);
-            map.put("area_name", areaName);
-            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
-            map.put("city_no", cityNo);
-            String cityName = carService.getOrgName(orgMap, cityNo);
-            map.put("city_name", cityName);
-            String areaNo2 = carService.getAreaNo2(areaName, cityName);
-            map.put("area_no2", areaNo2);
-            String areaName2 = carService.getOrgName(orgMap, areaNo2);
-            map.put("area_name2", areaName2);
-            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
-            map.put("city_id", cityId);
-            String city = carService.getAreaName(areaMap, cityId);
-            map.put("city", city);
-            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
-            map.put("district_id", districtId);
-            String district = carService.getAreaName(areaMap, districtId);
-            map.put("district", district);
-            String baoFei = carService.baoFei(rawChePaiHao);
-            map.put("bao_fei", baoFei);
-            map.put("source", path.getFileName().toString());
-        }
-        // 去重
-        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao") + map.get("wei_gui_kai_shi_shi_jian")))
-                .filter(t -> lastMonth.equals(t.get("year_month"))).toList();
-    }
-
-    /**
-     * 去重
-     */
-    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
-        Set<Object> set = ConcurrentHashMap.newKeySet();
-        return t -> set.add(keyExtractor.apply(t));
-    }
-
-    /**
-     * 生成csv
-     *
-     * @param path 源文件路径
-     * @param list 数据
-     */
-    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
-        log.info("去重后条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarWuDanYongCheHistoryPath()));
-        Path csvPath = Paths.get(jobConfig.getCarWuDanYongCheHistoryPath() + path.getFileName() + ".csv");
-        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
-                StandardCharsets.UTF_8);
-             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
-            // 添加bom头避免excel乱码
-            osw.write('\ufeff');
-            Map<String, String> header = list.get(0);
-            // 表头
-            printer.printRecord(header.keySet());
-            for (Map<String, String> map : list) {
-                printer.printRecord(map.values());
-            }
-        }
-        return csvPath;
-    }
-
-    /**
-     * 导入数据库
-     *
-     * @param path 文件路径
-     */
-    public void copyCsv(Path path) {
-        String dbTable = "car.car_wu_dan_yong_che";
-        String csv = path.toString();
-        String columns = "(che_liang_suo_shu_dan_wei,che_pai_hao,wei_gui_kai_shi_shi_jian,wei_gui_jie_shu_shi_jian,wei_gui_chi_xu_shi_jian,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
-        Long timeout = 60000L;
-        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
-                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
-                timeout, null);
-    }
-
-    /**
-     * 移动源文件到历史文件夹
-     *
-     * @param path 源文件路径
-     */
-    public void move(Path path) throws IOException {
-        Path targetPath = Paths.get(jobConfig.getCarWuDanYongCheHistoryPath(), path.getFileName().toString());
-        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
-    }
-}
+//package com.nokia.finance.tasks.jobs.car.ruixing;
+//
+//import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+//import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+//import com.nokia.finance.tasks.config.JobConfig;
+//import com.nokia.finance.tasks.enums.DataStageEnum;
+//import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+//import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+//import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+//import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+//import com.nokia.finance.tasks.service.car.CarService;
+//import com.nokia.finance.tasks.service.common.AreaService;
+//import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+//import com.nokia.finance.tasks.service.common.OrganizationService;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.commons.csv.CSVFormat;
+//import org.apache.commons.csv.CSVPrinter;
+//import org.apache.poi.ss.usermodel.Cell;
+//import org.apache.poi.ss.usermodel.DateUtil;
+//import org.apache.poi.ss.usermodel.Row;
+//import org.apache.poi.ss.usermodel.Sheet;
+//import org.apache.poi.ss.usermodel.Workbook;
+//import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+//import org.springframework.scheduling.annotation.Scheduled;
+//import org.springframework.stereotype.Service;
+//import org.springframework.util.CollectionUtils;
+//import org.springframework.util.StringUtils;
+//
+//import java.io.IOException;
+//import java.io.InputStream;
+//import java.io.OutputStreamWriter;
+//import java.nio.charset.StandardCharsets;
+//import java.nio.file.Files;
+//import java.nio.file.Path;
+//import java.nio.file.Paths;
+//import java.nio.file.StandardCopyOption;
+//import java.time.LocalDateTime;
+//import java.time.format.DateTimeFormatter;
+//import java.util.ArrayList;
+//import java.util.LinkedHashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.concurrent.CompletableFuture;
+//import java.util.concurrent.ConcurrentHashMap;
+//import java.util.concurrent.TimeUnit;
+//import java.util.function.Function;
+//import java.util.function.Predicate;
+//import java.util.stream.Stream;
+//
+///**
+// * 睿行车辆无单用车报警月统计数据入库定时任务
+// */
+//@Slf4j
+//@Service
+//public class CarWuDanYongCheJob {
+//    private final JobConfig jobConfig;
+//    private final CarService carService;
+//    private final OrganizationService organizationService;
+//    private final AreaService areaService;
+//    private final DataLogServiceImpl dataLogService;
+//
+//    public CarWuDanYongCheJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+//                              AreaService areaService, DataLogServiceImpl dataLogService) {
+//        this.jobConfig = jobConfig;
+//        this.carService = carService;
+//        this.organizationService = organizationService;
+//        this.areaService = areaService;
+//        this.dataLogService = dataLogService;
+//    }
+//
+//    /**
+//     * 执行任务
+//     */
+//    @Scheduled(cron = "0 56 5 1 * ?")
+//    public void runJob() {
+//        List<DataLogPo> dataLogPoList = new ArrayList<>();
+//        // 数据目录
+//        Path dir = Paths.get(jobConfig.getCarWuDanYongCheSourcePath());
+//        try (Stream<Path> stream = Files.list(dir)) {
+//            // 获取数据目录下的文件列表
+//            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
+//            log.info("睿行车辆无单用车报警月统计数据文件列表: {}", pathList);
+//            if (CollectionUtils.isEmpty(pathList)) {
+//                throw new MyRuntimeException("睿行车辆无单用车报警月统计数据没有文件");
+//            }
+//            for (Path path : pathList) {
+//                CompletableFuture.runAsync(() -> {
+//                    try {
+//                        singleJob(path, dataLogPoList);
+//                    } catch (Exception e) {
+//                        throw new MyRuntimeException(e);
+//                    }
+//                }).get(1, TimeUnit.MINUTES);
+//            }
+//        } catch (InterruptedException e) {
+//            log.error("线程中断: {}", e, e);
+//            Thread.currentThread().interrupt();
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆无单用车报警月统计数据", DataStageEnum.CC, "入库");
+//        } catch (Exception e) {
+//            log.error(e.toString(), e);
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆无单用车报警月统计数据", DataStageEnum.CC, "入库");
+//        } finally {
+//            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+//                dataLogService.saveBatch(dataLogPoList);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * 处理单个文件
+//     *
+//     * @param path          文件路径
+//     * @param dataLogPoList 数据处理日志列表
+//     */
+//    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+//        DataLogPo dataLogPo = new DataLogPo();
+//        dataLogPo.setDataName("睿行车辆无单用车报警月统计数据");
+//        dataLogPo.setObject(path.getFileName().toString());
+//        dataLogPo.setStage(DataStageEnum.CC.value);
+//        dataLogPo.setOperationName("入库");
+//        long fileSize = Files.size(path);
+//        dataLogPo.setDataSize(fileSize);
+//        dataLogPoList.add(dataLogPo);
+//        if (fileSize == 0) {
+//            move(path);
+//            throw new MyRuntimeException(path.getFileName() + " 空文件");
+//        }
+//        List<Map<String, String>> list = readFile(path);
+//        List<Map<String, String>> distinctList = dataProcessing(path, list);
+//        dataLogPo.setDataCount(distinctList.size());
+//        Path csvPath = toCsv(path, distinctList);
+//        copyCsv(csvPath);
+//        move(path);
+//    }
+//
+//    /**
+//     * 读取文件
+//     *
+//     * @param path 文件路径
+//     */
+//    public List<Map<String, String>> readFile(Path path) throws IOException {
+//        log.info("读取: {}", path);
+//        List<String> rawHeaders = Stream.of("车辆所属单位", "车牌号码", "违规开始时间", "违规结束时间",
+//                "违规持续时间(分)").toList();
+//        List<String> headers = Stream.of("che_liang_suo_shu_dan_wei", "che_pai_hao", "wei_gui_kai_shi_shi_jian",
+//                "wei_gui_jie_shu_shi_jian", "wei_gui_chi_xu_shi_jian").toList();
+//        try (InputStream inputStream = Files.newInputStream(path);
+//             Workbook workbook = new XSSFWorkbook(inputStream)
+//        ) {
+//            List<Map<String, String>> resultList = new ArrayList<>();
+//            // 读取第一个工作表
+//            Sheet sheet = workbook.getSheetAt(0);
+//            // 表头行
+//            Row headerRow = sheet.getRow(0);
+//            // 列数
+//            int columnCount = headerRow.getPhysicalNumberOfCells();
+//            log.info("columnCount: {}", columnCount);
+//            // 检查表头
+//            if (headers.size() != columnCount) {
+//                throw new MyRuntimeException(path.getFileName() + "列数错误");
+//            }
+//            for (int i = 0; i < columnCount; i++) {
+//                Cell cell = headerRow.getCell(i);
+//                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
+//                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
+//                }
+//            }
+//            // 最后行数
+//            int lastRowNum = sheet.getLastRowNum();
+//            log.info("lastRowNum: {}", lastRowNum);
+//            if (lastRowNum == 0) {
+//                move(path);
+//                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+//            }
+//            // 遍历行
+//            for (int i = 1; i <= lastRowNum; i++) {
+//                log.debug("row: {}", i);
+//                Row row = sheet.getRow(i);
+//                if (row == null || row.getCell(0) == null) {
+//                    continue;
+//                }
+//                Map<String, String> rowMap = new LinkedHashMap<>();
+//                // 遍历列
+//                for (int j = 0; j < columnCount; j++) {
+//                    log.debug("column: {}", j);
+//                    String header = headers.get(j);
+//                    String cellValue = "";
+//                    rowMap.put(header, cellValue);
+//                    Cell cell = row.getCell(j);
+//                    if (cell == null) {
+//                        continue;
+//                    }
+//                    switch (cell.getCellType()) {
+//                        case STRING:
+//                            boolean skipTrim = "wei_gui_kai_shi_shi_jian".equals(header)
+//                                    || "wei_gui_jie_shu_shi_jian".equals(header);
+//                            // 删除字符串空白字符
+//                            cellValue = skipTrim ? cell.getStringCellValue()
+//                                    : StringUtils.trimAllWhitespace(cell.getStringCellValue());
+//                            break;
+//                        case NUMERIC:
+//                            if (DateUtil.isCellDateFormatted(cell)) {
+//                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
+//                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+//                                break;
+//                            }
+//                            cellValue = String.valueOf(cell.getNumericCellValue());
+//                            break;
+//                        case BOOLEAN:
+//                            cellValue = String.valueOf(cell.getBooleanCellValue());
+//                            break;
+//                        default:
+//                            break;
+//                    }
+//                    rowMap.put(header, cellValue);
+//                }
+//                resultList.add(rowMap);
+//            }
+//            return resultList;
+//        }
+//    }
+//
+//    /**
+//     * 数据加工
+//     *
+//     * @param path 文件路径
+//     * @param list 数据
+//     */
+//    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+//        String lastMonth = LocalDateTime.now().minusMonths(1).format(DateTimeFormatter.ofPattern("yyyyMM"));
+//        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+//        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+//        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+//        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+//                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+//        List<AreaPo> cities = areaService.getCities();
+//        List<AreaPo> districts = areaService.getDistricts();
+//        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+//        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+//        for (Map<String, String> map : list) {
+//            String weiGuiKaiShiShiJian = map.get("wei_gui_kai_shi_shi_jian");
+//            LocalDateTime localDateTime = LocalDateTime.parse(weiGuiKaiShiShiJian,
+//                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+//            String yearMonth = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
+//            String year = String.valueOf(localDateTime.getYear());
+//            String month = String.valueOf(localDateTime.getMonthValue());
+//            map.put("year_month", yearMonth);
+//            map.put("year_no", year);
+//            map.put("month_no", month);
+//            String rawChePaiHao = map.get("che_pai_hao");
+//            map.put("raw_che_pai_hao", rawChePaiHao);
+//            String chePaiHao = carService.getChePai(rawChePaiHao);
+//            map.put("che_pai_hao", chePaiHao);
+//            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+//            map.put("che_pai_fail", chePaiFail);
+//            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+//            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+//            String firstUnit = carService.getFirstUnit(carUnitBo);
+//            if (!StringUtils.hasText(firstUnit)) {
+//                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+//            }
+//            map.put("first_unit", firstUnit);
+//            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+//            map.put("second_unit", secondUnit);
+//            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+//            map.put("third_unit", thirdUnit);
+//            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+//            map.put("area_no", areaNo);
+//            String areaName = carService.getOrgName(orgMap, areaNo);
+//            map.put("area_name", areaName);
+//            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+//            map.put("city_no", cityNo);
+//            String cityName = carService.getOrgName(orgMap, cityNo);
+//            map.put("city_name", cityName);
+//            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+//            map.put("area_no2", areaNo2);
+//            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+//            map.put("area_name2", areaName2);
+//            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+//            map.put("city_id", cityId);
+//            String city = carService.getAreaName(areaMap, cityId);
+//            map.put("city", city);
+//            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+//            map.put("district_id", districtId);
+//            String district = carService.getAreaName(areaMap, districtId);
+//            map.put("district", district);
+//            String baoFei = carService.baoFei(rawChePaiHao);
+//            map.put("bao_fei", baoFei);
+//            map.put("source", path.getFileName().toString());
+//        }
+//        // 去重
+//        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao") + map.get("wei_gui_kai_shi_shi_jian")))
+//                .filter(t -> lastMonth.equals(t.get("year_month"))).toList();
+//    }
+//
+//    /**
+//     * 去重
+//     */
+//    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+//        Set<Object> set = ConcurrentHashMap.newKeySet();
+//        return t -> set.add(keyExtractor.apply(t));
+//    }
+//
+//    /**
+//     * 生成csv
+//     *
+//     * @param path 源文件路径
+//     * @param list 数据
+//     */
+//    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+//        log.info("去重后条数:{}", list.size());
+//        Files.createDirectories(Paths.get(jobConfig.getCarWuDanYongCheHistoryPath()));
+//        Path csvPath = Paths.get(jobConfig.getCarWuDanYongCheHistoryPath() + path.getFileName() + ".csv");
+//        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+//                StandardCharsets.UTF_8);
+//             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+//            // 添加bom头避免excel乱码
+//            osw.write('\ufeff');
+//            Map<String, String> header = list.get(0);
+//            // 表头
+//            printer.printRecord(header.keySet());
+//            for (Map<String, String> map : list) {
+//                printer.printRecord(map.values());
+//            }
+//        }
+//        return csvPath;
+//    }
+//
+//    /**
+//     * 导入数据库
+//     *
+//     * @param path 文件路径
+//     */
+//    public void copyCsv(Path path) {
+//        String dbTable = "car.car_wu_dan_yong_che";
+//        String csv = path.toString();
+//        String columns = "(che_liang_suo_shu_dan_wei,che_pai_hao,wei_gui_kai_shi_shi_jian,wei_gui_jie_shu_shi_jian,wei_gui_chi_xu_shi_jian,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+//        Long timeout = 60000L;
+//        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+//                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+//                timeout, null);
+//    }
+//
+//    /**
+//     * 移动源文件到历史文件夹
+//     *
+//     * @param path 源文件路径
+//     */
+//    public void move(Path path) throws IOException {
+//        Path targetPath = Paths.get(jobConfig.getCarWuDanYongCheHistoryPath(), path.getFileName().toString());
+//        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
+//    }
+//}

+ 382 - 382
src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarYongCheJob.java

@@ -1,383 +1,383 @@
-package com.nokia.finance.tasks.jobs.car.ruixing;
-
-import com.nokia.finance.tasks.common.exception.MyRuntimeException;
-import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
-import com.nokia.finance.tasks.config.JobConfig;
-import com.nokia.finance.tasks.enums.DataStageEnum;
-import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
-import com.nokia.finance.tasks.pojo.po.common.AreaPo;
-import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
-import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
-import com.nokia.finance.tasks.service.car.CarService;
-import com.nokia.finance.tasks.service.common.AreaService;
-import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
-import com.nokia.finance.tasks.service.common.OrganizationService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVPrinter;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Stream;
-
-/**
- * 睿行车辆用车月统计数据入库定时任务
- */
-@Slf4j
-@Service
-public class CarYongCheJob {
-    private final JobConfig jobConfig;
-    private final CarService carService;
-    private final OrganizationService organizationService;
-    private final AreaService areaService;
-    private final DataLogServiceImpl dataLogService;
-
-    public CarYongCheJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
-                         AreaService areaService, DataLogServiceImpl dataLogService) {
-        this.jobConfig = jobConfig;
-        this.carService = carService;
-        this.organizationService = organizationService;
-        this.areaService = areaService;
-        this.dataLogService = dataLogService;
-    }
-
-    /**
-     * 执行任务
-     */
-    @Scheduled(cron = "0 58 5 1 * ?")
-    public void runJob() {
-        List<DataLogPo> dataLogPoList = new ArrayList<>();
-        // 数据目录
-        Path dir = Paths.get(jobConfig.getCarYongCheSourcePath());
-        try (Stream<Path> stream = Files.list(dir)) {
-            // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
-            log.info("睿行车辆用车月统计数据文件列表: {}", pathList);
-            if (CollectionUtils.isEmpty(pathList)) {
-                throw new MyRuntimeException("睿行车辆用车月统计数据没有文件");
-            }
-            for (Path path : pathList) {
-                CompletableFuture.runAsync(() -> {
-                    try {
-                        singleJob(path, dataLogPoList);
-                    } catch (Exception e) {
-                        throw new MyRuntimeException(e);
-                    }
-                }).get(1, TimeUnit.MINUTES);
-            }
-        } catch (InterruptedException e) {
-            log.error("线程中断: {}", e, e);
-            Thread.currentThread().interrupt();
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆用车月统计数据", DataStageEnum.CC, "入库");
-        } catch (Exception e) {
-            log.error(e.toString(), e);
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆用车月统计数据", DataStageEnum.CC, "入库");
-        } finally {
-            if (!CollectionUtils.isEmpty(dataLogPoList)) {
-                dataLogService.saveBatch(dataLogPoList);
-            }
-        }
-    }
-
-    /**
-     * 处理单个文件
-     *
-     * @param path          文件路径
-     * @param dataLogPoList 数据处理日志列表
-     */
-    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
-        DataLogPo dataLogPo = new DataLogPo();
-        dataLogPo.setDataName("睿行车辆用车月统计数据");
-        dataLogPo.setObject(path.getFileName().toString());
-        dataLogPo.setStage(DataStageEnum.CC.value);
-        dataLogPo.setOperationName("入库");
-        long fileSize = Files.size(path);
-        dataLogPo.setDataSize(fileSize);
-        dataLogPoList.add(dataLogPo);
-        if (fileSize == 0) {
-            move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
-        }
-        // 从文件名提取日期
-        String regex = "\\d{6}";
-        Pattern pattern = Pattern.compile(regex);
-        Matcher matcher = pattern.matcher(path.getFileName().toString());
-        String dateString;
-        if (matcher.find()) {
-            dateString = matcher.group() + "01";
-        } else {
-            throw new MyRuntimeException(path.getFileName() + " 提取日期失败");
-        }
-        List<Map<String, String>> list = readFile(path);
-        List<Map<String, String>> distinctList = dataProcessing(path, list, dateString);
-        dataLogPo.setDataCount(distinctList.size());
-        Path csvPath = toCsv(path, distinctList);
-        copyCsv(csvPath);
-        move(path);
-    }
-
-    /**
-     * 读取文件
-     *
-     * @param path 文件路径
-     */
-    public List<Map<String, String>> readFile(Path path) throws IOException {
-        log.info("读取: {}", path);
-        List<String> rawHeaders = Stream.of("申请单号", "派遣单号", "申请类型", "车牌号", "车辆类型", "车辆级别",
-                "司机名称", "用车人", "用车部门", "用车事由", "出发地", "目的地", "出发时间", "归队时间", "行驶里程", "出车时长")
-                .toList();
-        List<String> headers = Stream.of("shen_qing_dan_hao", "pai_qian_dan_hao", "shen_qing_lei_xing",
-                "che_pai_hao", "che_liang_lei_xing", "che_liang_ji_bie", "si_ji_ming_cheng", "yong_che_ren",
-                "yong_che_bu_men", "yong_che_shi_you", "chu_fa_di", "mu_di_di", "chu_fa_shi_jian", "gui_dui_shi_jian",
-                "xing_shi_li_cheng", "chu_che_shi_chang").toList();
-        try (InputStream inputStream = Files.newInputStream(path);
-             Workbook workbook = new XSSFWorkbook(inputStream)
-        ) {
-            List<Map<String, String>> resultList = new ArrayList<>();
-            // 读取第一个工作表
-            Sheet sheet = workbook.getSheetAt(0);
-            // 表头行
-            Row headerRow = sheet.getRow(0);
-            // 列数
-            int columnCount = headerRow.getPhysicalNumberOfCells();
-            log.info("columnCount: {}", columnCount);
-            // 检查表头
-            if (headers.size() != columnCount) {
-                throw new MyRuntimeException(path.getFileName() + "列数错误");
-            }
-            for (int i = 0; i < columnCount; i++) {
-                Cell cell = headerRow.getCell(i);
-                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
-                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
-                }
-            }
-            // 最后行数
-            int lastRowNum = sheet.getLastRowNum();
-            log.info("lastRowNum: {}", lastRowNum);
-            if (lastRowNum == 0) {
-                move(path);
-                throw new MyRuntimeException(path.getFileName() + " 数据0条");
-            }
-            // 遍历行
-            for (int i = 1; i <= lastRowNum; i++) {
-                log.debug("row: {}", i);
-                Row row = sheet.getRow(i);
-                if (row == null || row.getCell(0) == null) {
-                    continue;
-                }
-                Map<String, String> rowMap = new LinkedHashMap<>();
-                // 遍历列
-                for (int j = 0; j < columnCount; j++) {
-                    log.debug("column: {}", j);
-                    String header = headers.get(j);
-                    String cellValue = "";
-                    rowMap.put(header, cellValue);
-                    Cell cell = row.getCell(j);
-                    if (cell == null) {
-                        continue;
-                    }
-                    switch (cell.getCellType()) {
-                        case STRING:
-                            boolean skipTrim = "chu_fa_shi_jian".equals(header)
-                                    || "gui_dui_shi_jian".equals(header);
-                            // 删除字符串空白字符
-                            cellValue = skipTrim ? cell.getStringCellValue()
-                                    : StringUtils.trimAllWhitespace(cell.getStringCellValue());
-                            if ("chu_fa_shi_jian".equals(header)
-                                    || "gui_dui_shi_jian".equals(header)) {
-                                if (StringUtils.hasText(cellValue)) {
-                                    try {
-                                        cellValue = LocalDateTime.parse(cellValue,
-                                                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
-                                                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-                                    } catch (Exception e1) {
-                                        try {
-                                            cellValue = LocalDate.parse(cellValue,
-                                                            DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay()
-                                                    .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-                                        } catch (Exception e2) {
-                                            log.error("{} 时间格式化失败", cellValue);
-                                        }
-                                    }
-                                }
-                            }
-                            break;
-                        case NUMERIC:
-                            if (DateUtil.isCellDateFormatted(cell)) {
-                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
-                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-                                break;
-                            }
-                            cellValue = String.valueOf(cell.getNumericCellValue());
-                            break;
-                        case BOOLEAN:
-                            cellValue = String.valueOf(cell.getBooleanCellValue());
-                            break;
-                        default:
-                            break;
-                    }
-                    rowMap.put(header, cellValue);
-                }
-                resultList.add(rowMap);
-            }
-            return resultList;
-        }
-    }
-
-    /**
-     * 数据加工
-     *
-     * @param path       文件路径
-     * @param list       数据
-     * @param dateString 日期字符串
-     */
-    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list, String dateString) {
-        LocalDate localDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyyMMdd"));
-        String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
-        String year = String.valueOf(localDate.getYear());
-        String month = String.valueOf(localDate.getMonthValue());
-        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
-        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
-        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
-        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
-                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
-        List<AreaPo> cities = areaService.getCities();
-        List<AreaPo> districts = areaService.getDistricts();
-        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
-        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
-        for (Map<String, String> map : list) {
-//            String yearMonth = "";
-//            String year = "";
-//            String month = "";
-//            String chuFaShiJian = map.get("chu_fa_shi_jian");
-//            if (StringUtils.hasText(chuFaShiJian)) {
-//                LocalDateTime localDateTime = LocalDateTime.parse(chuFaShiJian,
-//                        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-//                yearMonth = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
-//                year = String.valueOf(localDateTime.getYear());
-//                month = String.valueOf(localDateTime.getMonthValue());
+//package com.nokia.finance.tasks.jobs.car.ruixing;
+//
+//import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+//import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+//import com.nokia.finance.tasks.config.JobConfig;
+//import com.nokia.finance.tasks.enums.DataStageEnum;
+//import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+//import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+//import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+//import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+//import com.nokia.finance.tasks.service.car.CarService;
+//import com.nokia.finance.tasks.service.common.AreaService;
+//import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+//import com.nokia.finance.tasks.service.common.OrganizationService;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.commons.csv.CSVFormat;
+//import org.apache.commons.csv.CSVPrinter;
+//import org.apache.poi.ss.usermodel.Cell;
+//import org.apache.poi.ss.usermodel.DateUtil;
+//import org.apache.poi.ss.usermodel.Row;
+//import org.apache.poi.ss.usermodel.Sheet;
+//import org.apache.poi.ss.usermodel.Workbook;
+//import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+//import org.springframework.scheduling.annotation.Scheduled;
+//import org.springframework.stereotype.Service;
+//import org.springframework.util.CollectionUtils;
+//import org.springframework.util.StringUtils;
+//
+//import java.io.IOException;
+//import java.io.InputStream;
+//import java.io.OutputStreamWriter;
+//import java.nio.charset.StandardCharsets;
+//import java.nio.file.Files;
+//import java.nio.file.Path;
+//import java.nio.file.Paths;
+//import java.nio.file.StandardCopyOption;
+//import java.time.LocalDate;
+//import java.time.LocalDateTime;
+//import java.time.format.DateTimeFormatter;
+//import java.util.ArrayList;
+//import java.util.LinkedHashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.concurrent.CompletableFuture;
+//import java.util.concurrent.TimeUnit;
+//import java.util.regex.Matcher;
+//import java.util.regex.Pattern;
+//import java.util.stream.Stream;
+//
+///**
+// * 睿行车辆用车月统计数据入库定时任务
+// */
+//@Slf4j
+//@Service
+//public class CarYongCheJob {
+//    private final JobConfig jobConfig;
+//    private final CarService carService;
+//    private final OrganizationService organizationService;
+//    private final AreaService areaService;
+//    private final DataLogServiceImpl dataLogService;
+//
+//    public CarYongCheJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+//                         AreaService areaService, DataLogServiceImpl dataLogService) {
+//        this.jobConfig = jobConfig;
+//        this.carService = carService;
+//        this.organizationService = organizationService;
+//        this.areaService = areaService;
+//        this.dataLogService = dataLogService;
+//    }
+//
+//    /**
+//     * 执行任务
+//     */
+//    @Scheduled(cron = "0 58 5 1 * ?")
+//    public void runJob() {
+//        List<DataLogPo> dataLogPoList = new ArrayList<>();
+//        // 数据目录
+//        Path dir = Paths.get(jobConfig.getCarYongCheSourcePath());
+//        try (Stream<Path> stream = Files.list(dir)) {
+//            // 获取数据目录下的文件列表
+//            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
+//            log.info("睿行车辆用车月统计数据文件列表: {}", pathList);
+//            if (CollectionUtils.isEmpty(pathList)) {
+//                throw new MyRuntimeException("睿行车辆用车月统计数据没有文件");
 //            }
-            map.put("year_month", yearMonth);
-            map.put("year_no", year);
-            map.put("month_no", month);
-            String rawChePaiHao = map.get("che_pai_hao");
-            map.put("raw_che_pai_hao", rawChePaiHao);
-            String chePaiHao = carService.getChePai(rawChePaiHao);
-            map.put("che_pai_hao", chePaiHao);
-            String chePaiFail = carService.chePaiFail(rawChePaiHao);
-            map.put("che_pai_fail", chePaiFail);
-            String cheLiangSuoShuDanWei = map.get("yong_che_bu_men");
-            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
-            String firstUnit = carService.getFirstUnit(carUnitBo);
-            if (!StringUtils.hasText(firstUnit)) {
-                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
-            }
-            map.put("first_unit", firstUnit);
-            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
-            map.put("second_unit", secondUnit);
-            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
-            map.put("third_unit", thirdUnit);
-            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
-            map.put("area_no", areaNo);
-            String areaName = carService.getOrgName(orgMap, areaNo);
-            map.put("area_name", areaName);
-            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
-            map.put("city_no", cityNo);
-            String cityName = carService.getOrgName(orgMap, cityNo);
-            map.put("city_name", cityName);
-            String areaNo2 = carService.getAreaNo2(areaName, cityName);
-            map.put("area_no2", areaNo2);
-            String areaName2 = carService.getOrgName(orgMap, areaNo2);
-            map.put("area_name2", areaName2);
-            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
-            map.put("city_id", cityId);
-            String city = carService.getAreaName(areaMap, cityId);
-            map.put("city", city);
-            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
-            map.put("district_id", districtId);
-            String district = carService.getAreaName(areaMap, districtId);
-            map.put("district", district);
-            String baoFei = carService.baoFei(rawChePaiHao);
-            map.put("bao_fei", baoFei);
-            map.put("source", path.getFileName().toString());
-        }
-        return list;
-    }
-
-    /**
-     * 生成csv
-     *
-     * @param path 源文件路径
-     * @param list 数据
-     */
-    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
-        log.info("去重后条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarYongCheHistoryPath()));
-        Path csvPath = Paths.get(jobConfig.getCarYongCheHistoryPath() + path.getFileName() + ".csv");
-        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
-                StandardCharsets.UTF_8);
-             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
-            // 添加bom头避免excel乱码
-            osw.write('\ufeff');
-            Map<String, String> header = list.get(0);
-            // 表头
-            printer.printRecord(header.keySet());
-            for (Map<String, String> map : list) {
-                printer.printRecord(map.values());
-            }
-        }
-        return csvPath;
-    }
-
-    /**
-     * 导入数据库
-     *
-     * @param path 文件路径
-     */
-    public void copyCsv(Path path) {
-        String dbTable = "car.car_yong_che";
-        String csv = path.toString();
-        String columns = "(shen_qing_dan_hao,pai_qian_dan_hao,shen_qing_lei_xing,che_pai_hao,che_liang_lei_xing,che_liang_ji_bie,si_ji_ming_cheng,yong_che_ren,yong_che_bu_men,yong_che_shi_you,chu_fa_di,mu_di_di,chu_fa_shi_jian,gui_dui_shi_jian,xing_shi_li_cheng,chu_che_shi_chang,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
-        Long timeout = 60000L;
-        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
-                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
-                timeout, null);
-    }
-
-    /**
-     * 移动源文件到历史文件夹
-     *
-     * @param path 源文件路径
-     */
-    public void move(Path path) throws IOException {
-        Path targetPath = Paths.get(jobConfig.getCarYongCheHistoryPath(), path.getFileName().toString());
-        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
-    }
-}
+//            for (Path path : pathList) {
+//                CompletableFuture.runAsync(() -> {
+//                    try {
+//                        singleJob(path, dataLogPoList);
+//                    } catch (Exception e) {
+//                        throw new MyRuntimeException(e);
+//                    }
+//                }).get(1, TimeUnit.MINUTES);
+//            }
+//        } catch (InterruptedException e) {
+//            log.error("线程中断: {}", e, e);
+//            Thread.currentThread().interrupt();
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆用车月统计数据", DataStageEnum.CC, "入库");
+//        } catch (Exception e) {
+//            log.error(e.toString(), e);
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆用车月统计数据", DataStageEnum.CC, "入库");
+//        } finally {
+//            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+//                dataLogService.saveBatch(dataLogPoList);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * 处理单个文件
+//     *
+//     * @param path          文件路径
+//     * @param dataLogPoList 数据处理日志列表
+//     */
+//    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+//        DataLogPo dataLogPo = new DataLogPo();
+//        dataLogPo.setDataName("睿行车辆用车月统计数据");
+//        dataLogPo.setObject(path.getFileName().toString());
+//        dataLogPo.setStage(DataStageEnum.CC.value);
+//        dataLogPo.setOperationName("入库");
+//        long fileSize = Files.size(path);
+//        dataLogPo.setDataSize(fileSize);
+//        dataLogPoList.add(dataLogPo);
+//        if (fileSize == 0) {
+//            move(path);
+//            throw new MyRuntimeException(path.getFileName() + " 空文件");
+//        }
+//        // 从文件名提取日期
+//        String regex = "\\d{6}";
+//        Pattern pattern = Pattern.compile(regex);
+//        Matcher matcher = pattern.matcher(path.getFileName().toString());
+//        String dateString;
+//        if (matcher.find()) {
+//            dateString = matcher.group() + "01";
+//        } else {
+//            throw new MyRuntimeException(path.getFileName() + " 提取日期失败");
+//        }
+//        List<Map<String, String>> list = readFile(path);
+//        List<Map<String, String>> distinctList = dataProcessing(path, list, dateString);
+//        dataLogPo.setDataCount(distinctList.size());
+//        Path csvPath = toCsv(path, distinctList);
+//        copyCsv(csvPath);
+//        move(path);
+//    }
+//
+//    /**
+//     * 读取文件
+//     *
+//     * @param path 文件路径
+//     */
+//    public List<Map<String, String>> readFile(Path path) throws IOException {
+//        log.info("读取: {}", path);
+//        List<String> rawHeaders = Stream.of("申请单号", "派遣单号", "申请类型", "车牌号", "车辆类型", "车辆级别",
+//                "司机名称", "用车人", "用车部门", "用车事由", "出发地", "目的地", "出发时间", "归队时间", "行驶里程", "出车时长")
+//                .toList();
+//        List<String> headers = Stream.of("shen_qing_dan_hao", "pai_qian_dan_hao", "shen_qing_lei_xing",
+//                "che_pai_hao", "che_liang_lei_xing", "che_liang_ji_bie", "si_ji_ming_cheng", "yong_che_ren",
+//                "yong_che_bu_men", "yong_che_shi_you", "chu_fa_di", "mu_di_di", "chu_fa_shi_jian", "gui_dui_shi_jian",
+//                "xing_shi_li_cheng", "chu_che_shi_chang").toList();
+//        try (InputStream inputStream = Files.newInputStream(path);
+//             Workbook workbook = new XSSFWorkbook(inputStream)
+//        ) {
+//            List<Map<String, String>> resultList = new ArrayList<>();
+//            // 读取第一个工作表
+//            Sheet sheet = workbook.getSheetAt(0);
+//            // 表头行
+//            Row headerRow = sheet.getRow(0);
+//            // 列数
+//            int columnCount = headerRow.getPhysicalNumberOfCells();
+//            log.info("columnCount: {}", columnCount);
+//            // 检查表头
+//            if (headers.size() != columnCount) {
+//                throw new MyRuntimeException(path.getFileName() + "列数错误");
+//            }
+//            for (int i = 0; i < columnCount; i++) {
+//                Cell cell = headerRow.getCell(i);
+//                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
+//                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
+//                }
+//            }
+//            // 最后行数
+//            int lastRowNum = sheet.getLastRowNum();
+//            log.info("lastRowNum: {}", lastRowNum);
+//            if (lastRowNum == 0) {
+//                move(path);
+//                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+//            }
+//            // 遍历行
+//            for (int i = 1; i <= lastRowNum; i++) {
+//                log.debug("row: {}", i);
+//                Row row = sheet.getRow(i);
+//                if (row == null || row.getCell(0) == null) {
+//                    continue;
+//                }
+//                Map<String, String> rowMap = new LinkedHashMap<>();
+//                // 遍历列
+//                for (int j = 0; j < columnCount; j++) {
+//                    log.debug("column: {}", j);
+//                    String header = headers.get(j);
+//                    String cellValue = "";
+//                    rowMap.put(header, cellValue);
+//                    Cell cell = row.getCell(j);
+//                    if (cell == null) {
+//                        continue;
+//                    }
+//                    switch (cell.getCellType()) {
+//                        case STRING:
+//                            boolean skipTrim = "chu_fa_shi_jian".equals(header)
+//                                    || "gui_dui_shi_jian".equals(header);
+//                            // 删除字符串空白字符
+//                            cellValue = skipTrim ? cell.getStringCellValue()
+//                                    : StringUtils.trimAllWhitespace(cell.getStringCellValue());
+//                            if ("chu_fa_shi_jian".equals(header)
+//                                    || "gui_dui_shi_jian".equals(header)) {
+//                                if (StringUtils.hasText(cellValue)) {
+//                                    try {
+//                                        cellValue = LocalDateTime.parse(cellValue,
+//                                                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
+//                                                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+//                                    } catch (Exception e1) {
+//                                        try {
+//                                            cellValue = LocalDate.parse(cellValue,
+//                                                            DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay()
+//                                                    .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+//                                        } catch (Exception e2) {
+//                                            log.error("{} 时间格式化失败", cellValue);
+//                                        }
+//                                    }
+//                                }
+//                            }
+//                            break;
+//                        case NUMERIC:
+//                            if (DateUtil.isCellDateFormatted(cell)) {
+//                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
+//                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+//                                break;
+//                            }
+//                            cellValue = String.valueOf(cell.getNumericCellValue());
+//                            break;
+//                        case BOOLEAN:
+//                            cellValue = String.valueOf(cell.getBooleanCellValue());
+//                            break;
+//                        default:
+//                            break;
+//                    }
+//                    rowMap.put(header, cellValue);
+//                }
+//                resultList.add(rowMap);
+//            }
+//            return resultList;
+//        }
+//    }
+//
+//    /**
+//     * 数据加工
+//     *
+//     * @param path       文件路径
+//     * @param list       数据
+//     * @param dateString 日期字符串
+//     */
+//    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list, String dateString) {
+//        LocalDate localDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyyMMdd"));
+//        String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+//        String year = String.valueOf(localDate.getYear());
+//        String month = String.valueOf(localDate.getMonthValue());
+//        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+//        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+//        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+//        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+//                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+//        List<AreaPo> cities = areaService.getCities();
+//        List<AreaPo> districts = areaService.getDistricts();
+//        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+//        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+//        for (Map<String, String> map : list) {
+////            String yearMonth = "";
+////            String year = "";
+////            String month = "";
+////            String chuFaShiJian = map.get("chu_fa_shi_jian");
+////            if (StringUtils.hasText(chuFaShiJian)) {
+////                LocalDateTime localDateTime = LocalDateTime.parse(chuFaShiJian,
+////                        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+////                yearMonth = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
+////                year = String.valueOf(localDateTime.getYear());
+////                month = String.valueOf(localDateTime.getMonthValue());
+////            }
+//            map.put("year_month", yearMonth);
+//            map.put("year_no", year);
+//            map.put("month_no", month);
+//            String rawChePaiHao = map.get("che_pai_hao");
+//            map.put("raw_che_pai_hao", rawChePaiHao);
+//            String chePaiHao = carService.getChePai(rawChePaiHao);
+//            map.put("che_pai_hao", chePaiHao);
+//            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+//            map.put("che_pai_fail", chePaiFail);
+//            String cheLiangSuoShuDanWei = map.get("yong_che_bu_men");
+//            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+//            String firstUnit = carService.getFirstUnit(carUnitBo);
+//            if (!StringUtils.hasText(firstUnit)) {
+//                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+//            }
+//            map.put("first_unit", firstUnit);
+//            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+//            map.put("second_unit", secondUnit);
+//            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+//            map.put("third_unit", thirdUnit);
+//            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+//            map.put("area_no", areaNo);
+//            String areaName = carService.getOrgName(orgMap, areaNo);
+//            map.put("area_name", areaName);
+//            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+//            map.put("city_no", cityNo);
+//            String cityName = carService.getOrgName(orgMap, cityNo);
+//            map.put("city_name", cityName);
+//            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+//            map.put("area_no2", areaNo2);
+//            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+//            map.put("area_name2", areaName2);
+//            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+//            map.put("city_id", cityId);
+//            String city = carService.getAreaName(areaMap, cityId);
+//            map.put("city", city);
+//            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+//            map.put("district_id", districtId);
+//            String district = carService.getAreaName(areaMap, districtId);
+//            map.put("district", district);
+//            String baoFei = carService.baoFei(rawChePaiHao);
+//            map.put("bao_fei", baoFei);
+//            map.put("source", path.getFileName().toString());
+//        }
+//        return list;
+//    }
+//
+//    /**
+//     * 生成csv
+//     *
+//     * @param path 源文件路径
+//     * @param list 数据
+//     */
+//    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+//        log.info("去重后条数:{}", list.size());
+//        Files.createDirectories(Paths.get(jobConfig.getCarYongCheHistoryPath()));
+//        Path csvPath = Paths.get(jobConfig.getCarYongCheHistoryPath() + path.getFileName() + ".csv");
+//        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+//                StandardCharsets.UTF_8);
+//             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+//            // 添加bom头避免excel乱码
+//            osw.write('\ufeff');
+//            Map<String, String> header = list.get(0);
+//            // 表头
+//            printer.printRecord(header.keySet());
+//            for (Map<String, String> map : list) {
+//                printer.printRecord(map.values());
+//            }
+//        }
+//        return csvPath;
+//    }
+//
+//    /**
+//     * 导入数据库
+//     *
+//     * @param path 文件路径
+//     */
+//    public void copyCsv(Path path) {
+//        String dbTable = "car.car_yong_che";
+//        String csv = path.toString();
+//        String columns = "(shen_qing_dan_hao,pai_qian_dan_hao,shen_qing_lei_xing,che_pai_hao,che_liang_lei_xing,che_liang_ji_bie,si_ji_ming_cheng,yong_che_ren,yong_che_bu_men,yong_che_shi_you,chu_fa_di,mu_di_di,chu_fa_shi_jian,gui_dui_shi_jian,xing_shi_li_cheng,chu_che_shi_chang,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+//        Long timeout = 60000L;
+//        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+//                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+//                timeout, null);
+//    }
+//
+//    /**
+//     * 移动源文件到历史文件夹
+//     *
+//     * @param path 源文件路径
+//     */
+//    public void move(Path path) throws IOException {
+//        Path targetPath = Paths.get(jobConfig.getCarYongCheHistoryPath(), path.getFileName().toString());
+//        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
+//    }
+//}

+ 354 - 354
src/main/java/com/nokia/finance/tasks/jobs/car/ruixing/CarYueJieJob.java

@@ -1,354 +1,354 @@
-package com.nokia.finance.tasks.jobs.car.ruixing;
-
-import com.nokia.finance.tasks.common.exception.MyRuntimeException;
-import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
-import com.nokia.finance.tasks.config.JobConfig;
-import com.nokia.finance.tasks.enums.DataStageEnum;
-import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
-import com.nokia.finance.tasks.pojo.po.common.AreaPo;
-import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
-import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
-import com.nokia.finance.tasks.service.car.CarService;
-import com.nokia.finance.tasks.service.common.AreaService;
-import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
-import com.nokia.finance.tasks.service.common.OrganizationService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVPrinter;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-/**
- * 睿行车辆越界报警日数据入库定时任务
- */
-@Slf4j
-@Service
-public class CarYueJieJob {
-    private final JobConfig jobConfig;
-    private final CarService carService;
-    private final OrganizationService organizationService;
-    private final AreaService areaService;
-    private final DataLogServiceImpl dataLogService;
-
-    public CarYueJieJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
-                        AreaService areaService, DataLogServiceImpl dataLogService) {
-        this.jobConfig = jobConfig;
-        this.carService = carService;
-        this.organizationService = organizationService;
-        this.areaService = areaService;
-        this.dataLogService = dataLogService;
-    }
-
-    /**
-     * 执行任务
-     */
-    @Scheduled(cron = "0 58 23 * * ?")
-    public void runJob() {
-        List<DataLogPo> dataLogPoList = new ArrayList<>();
-        // 数据目录
-        Path dir = Paths.get(jobConfig.getCarYueJieSourcePath());
-        try (Stream<Path> stream = Files.list(dir)) {
-            // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
-            log.info("睿行车辆越界报警日数据文件列表: {}", pathList);
-            if (CollectionUtils.isEmpty(pathList)) {
-                throw new MyRuntimeException("睿行车辆越界报警日数据没有文件");
-            }
-            for (Path path : pathList) {
-                CompletableFuture.runAsync(() -> {
-                    try {
-                        singleJob(path, dataLogPoList);
-                    } catch (Exception e) {
-                        throw new MyRuntimeException(e);
-                    }
-                }).get(1, TimeUnit.MINUTES);
-            }
-        } catch (InterruptedException e) {
-            log.error("线程中断: {}", e, e);
-            Thread.currentThread().interrupt();
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆越界报警日数据", DataStageEnum.CC, "入库");
-        } catch (Exception e) {
-            log.error(e.toString(), e);
-            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆越界报警日数据", DataStageEnum.CC, "入库");
-        } finally {
-            if (!CollectionUtils.isEmpty(dataLogPoList)) {
-                dataLogService.saveBatch(dataLogPoList);
-            }
-        }
-    }
-
-    /**
-     * 处理单个文件
-     *
-     * @param path          文件路径
-     * @param dataLogPoList 数据处理日志列表
-     */
-    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
-        DataLogPo dataLogPo = new DataLogPo();
-        dataLogPo.setDataName("睿行车辆越界报警日数据");
-        dataLogPo.setObject(path.getFileName().toString());
-        dataLogPo.setStage(DataStageEnum.CC.value);
-        dataLogPo.setOperationName("入库");
-        long fileSize = Files.size(path);
-        dataLogPo.setDataSize(fileSize);
-        dataLogPoList.add(dataLogPo);
-        if (fileSize == 0) {
-            move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
-        }
-        List<Map<String, String>> list = readFile(path);
-        List<Map<String, String>> distinctList = dataProcessing(path, list);
-        dataLogPo.setDataCount(distinctList.size());
-        Path csvPath = toCsv(path, distinctList);
-        copyCsv(csvPath);
-        move(path);
-    }
-
-    /**
-     * 读取文件
-     *
-     * @param path 文件路径
-     */
-    public List<Map<String, String>> readFile(Path path) throws IOException {
-        log.info("读取: {}", path);
-        List<String> rawHeaders = Stream.of("车辆所属单位", "车牌号码", "车辆类型", "车辆使用性质", "报警区域描述",
-                "报警规则描述", "越界时间", "是否执行中越界", "详情").toList();
-        List<String> headers = Stream.of("che_liang_suo_shu_dan_wei", "che_pai_hao", "che_liang_lei_xing",
-                "che_liang_shi_yong_xing_zhi", "bao_jing_qu_yu_miao_shu", "bao_jing_gui_ze_miao_shu",
-                "yue_jie_shi_jian", "shi_fou_zhi_xing_zhong_yue_jie", "xiang_qing").toList();
-        try (InputStream inputStream = Files.newInputStream(path);
-             Workbook workbook = new XSSFWorkbook(inputStream)
-        ) {
-            List<Map<String, String>> resultList = new ArrayList<>();
-            // 读取第一个工作表
-            Sheet sheet = workbook.getSheetAt(0);
-            // 表头行
-            Row headerRow = sheet.getRow(0);
-            // 列数
-            int columnCount = headerRow.getPhysicalNumberOfCells();
-            log.info("columnCount: {}", columnCount);
-            // 检查表头
-            if (headers.size() != columnCount) {
-                throw new MyRuntimeException(path.getFileName() + "列数错误");
-            }
-            for (int i = 0; i < columnCount; i++) {
-                Cell cell = headerRow.getCell(i);
-                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
-                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
-                }
-            }
-            // 最后行数
-            int lastRowNum = sheet.getLastRowNum();
-            log.info("lastRowNum: {}", lastRowNum);
-            if (lastRowNum == 0) {
-                move(path);
-                throw new MyRuntimeException(path.getFileName() + " 数据0条");
-            }
-            // 遍历行
-            for (int i = 1; i <= lastRowNum; i++) {
-                log.debug("row: {}", i);
-                Row row = sheet.getRow(i);
-                if (row == null || row.getCell(0) == null) {
-                    continue;
-                }
-                Map<String, String> rowMap = new LinkedHashMap<>();
-                // 遍历列
-                for (int j = 0; j < columnCount; j++) {
-                    log.debug("column: {}", j);
-                    String header = headers.get(j);
-                    String cellValue = "";
-                    rowMap.put(header, cellValue);
-                    Cell cell = row.getCell(j);
-                    if (cell == null) {
-                        continue;
-                    }
-                    switch (cell.getCellType()) {
-                        case STRING:
-                            boolean skipTrim = "yue_jie_shi_jian".equals(header);
-                            // 删除字符串空白字符
-                            cellValue = skipTrim ? cell.getStringCellValue()
-                                    : StringUtils.trimAllWhitespace(cell.getStringCellValue());
-                            break;
-                        case NUMERIC:
-                            if (DateUtil.isCellDateFormatted(cell)) {
-                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
-                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-                                break;
-                            }
-                            cellValue = String.valueOf(cell.getNumericCellValue());
-                            break;
-                        case BOOLEAN:
-                            cellValue = String.valueOf(cell.getBooleanCellValue());
-                            break;
-                        default:
-                            break;
-                    }
-                    rowMap.put(headers.get(j), cellValue);
-                }
-                resultList.add(rowMap);
-            }
-            return resultList;
-        }
-    }
-
-    /**
-     * 数据加工
-     *
-     * @param path 文件路径
-     * @param list 数据
-     */
-    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
-        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
-        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
-        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
-        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
-                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
-        List<AreaPo> cities = areaService.getCities();
-        List<AreaPo> districts = areaService.getDistricts();
-        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
-        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
-        for (Map<String, String> map : list) {
-            String yueJieShiJian = map.get("yue_jie_shi_jian");
-            LocalDateTime localDateTime = LocalDateTime.parse(yueJieShiJian,
-                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
-            String dataDate = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-            String yearMonth = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
-            String year = String.valueOf(localDateTime.getYear());
-            String month = String.valueOf(localDateTime.getMonthValue());
-            map.put("data_date", dataDate);
-            map.put("year_month", yearMonth);
-            map.put("year_no", year);
-            map.put("month_no", month);
-            String rawChePaiHao = map.get("che_pai_hao");
-            map.put("raw_che_pai_hao", rawChePaiHao);
-            String chePaiHao = carService.getChePai(rawChePaiHao);
-            map.put("che_pai_hao", chePaiHao);
-            String chePaiFail = carService.chePaiFail(rawChePaiHao);
-            map.put("che_pai_fail", chePaiFail);
-            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
-            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
-            String firstUnit = carService.getFirstUnit(carUnitBo);
-            if (!StringUtils.hasText(firstUnit)) {
-                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
-            }
-            map.put("first_unit", firstUnit);
-            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
-            map.put("second_unit", secondUnit);
-            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
-            map.put("third_unit", thirdUnit);
-            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
-            map.put("area_no", areaNo);
-            String areaName = carService.getOrgName(orgMap, areaNo);
-            map.put("area_name", areaName);
-            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
-            map.put("city_no", cityNo);
-            String cityName = carService.getOrgName(orgMap, cityNo);
-            map.put("city_name", cityName);
-            String areaNo2 = carService.getAreaNo2(areaName, cityName);
-            map.put("area_no2", areaNo2);
-            String areaName2 = carService.getOrgName(orgMap, areaNo2);
-            map.put("area_name2", areaName2);
-            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
-            map.put("city_id", cityId);
-            String city = carService.getAreaName(areaMap, cityId);
-            map.put("city", city);
-            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
-            map.put("district_id", districtId);
-            String district = carService.getAreaName(areaMap, districtId);
-            map.put("district", district);
-            String baoFei = carService.baoFei(rawChePaiHao);
-            map.put("bao_fei", baoFei);
-            map.put("source", path.getFileName().toString());
-        }
-        // 去重
-        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao") + map.get("yue_jie_shi_jian"))).toList();
-    }
-
-    /**
-     * 去重
-     */
-    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
-        Set<Object> set = ConcurrentHashMap.newKeySet();
-        return t -> set.add(keyExtractor.apply(t));
-    }
-
-    /**
-     * 生成csv
-     *
-     * @param path 源文件路径
-     * @param list 数据
-     */
-    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
-        log.info("去重后条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarYueJieHistoryPath()));
-        Path csvPath = Paths.get(jobConfig.getCarYueJieHistoryPath() + path.getFileName() + ".csv");
-        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
-                StandardCharsets.UTF_8);
-             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
-            // 添加bom头避免excel乱码
-            osw.write('\ufeff');
-            Map<String, String> header = list.get(0);
-            // 表头
-            printer.printRecord(header.keySet());
-            for (Map<String, String> map : list) {
-                printer.printRecord(map.values());
-            }
-        }
-        return csvPath;
-    }
-
-    /**
-     * 导入数据库
-     *
-     * @param path 文件路径
-     */
-    public void copyCsv(Path path) {
-        String dbTable = "car.car_yue_jie";
-        String csv = path.toString();
-        String columns = "(che_liang_suo_shu_dan_wei,che_pai_hao,che_liang_lei_xing,che_liang_shi_yong_xing_zhi,bao_jing_qu_yu_miao_shu,bao_jing_gui_ze_miao_shu,yue_jie_shi_jian,shi_fou_zhi_xing_zhong_yue_jie,xiang_qing,data_date,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
-        Long timeout = 60000L;
-        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
-                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
-                timeout, null);
-    }
-
-    /**
-     * 移动源文件到历史文件夹
-     *
-     * @param path 源文件路径
-     */
-    public void move(Path path) throws IOException {
-        Path targetPath = Paths.get(jobConfig.getCarYueJieHistoryPath(), path.getFileName().toString());
-        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
-    }
-}
+//package com.nokia.finance.tasks.jobs.car.ruixing;
+//
+//import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+//import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+//import com.nokia.finance.tasks.config.JobConfig;
+//import com.nokia.finance.tasks.enums.DataStageEnum;
+//import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+//import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+//import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+//import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+//import com.nokia.finance.tasks.service.car.CarService;
+//import com.nokia.finance.tasks.service.common.AreaService;
+//import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+//import com.nokia.finance.tasks.service.common.OrganizationService;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.commons.csv.CSVFormat;
+//import org.apache.commons.csv.CSVPrinter;
+//import org.apache.poi.ss.usermodel.Cell;
+//import org.apache.poi.ss.usermodel.DateUtil;
+//import org.apache.poi.ss.usermodel.Row;
+//import org.apache.poi.ss.usermodel.Sheet;
+//import org.apache.poi.ss.usermodel.Workbook;
+//import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+//import org.springframework.scheduling.annotation.Scheduled;
+//import org.springframework.stereotype.Service;
+//import org.springframework.util.CollectionUtils;
+//import org.springframework.util.StringUtils;
+//
+//import java.io.IOException;
+//import java.io.InputStream;
+//import java.io.OutputStreamWriter;
+//import java.nio.charset.StandardCharsets;
+//import java.nio.file.Files;
+//import java.nio.file.Path;
+//import java.nio.file.Paths;
+//import java.nio.file.StandardCopyOption;
+//import java.time.LocalDateTime;
+//import java.time.format.DateTimeFormatter;
+//import java.util.ArrayList;
+//import java.util.LinkedHashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.Set;
+//import java.util.concurrent.CompletableFuture;
+//import java.util.concurrent.ConcurrentHashMap;
+//import java.util.concurrent.TimeUnit;
+//import java.util.function.Function;
+//import java.util.function.Predicate;
+//import java.util.stream.Stream;
+//
+///**
+// * 睿行车辆越界报警日数据入库定时任务
+// */
+//@Slf4j
+//@Service
+//public class CarYueJieJob {
+//    private final JobConfig jobConfig;
+//    private final CarService carService;
+//    private final OrganizationService organizationService;
+//    private final AreaService areaService;
+//    private final DataLogServiceImpl dataLogService;
+//
+//    public CarYueJieJob(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+//                        AreaService areaService, DataLogServiceImpl dataLogService) {
+//        this.jobConfig = jobConfig;
+//        this.carService = carService;
+//        this.organizationService = organizationService;
+//        this.areaService = areaService;
+//        this.dataLogService = dataLogService;
+//    }
+//
+//    /**
+//     * 执行任务
+//     */
+//    @Scheduled(cron = "0 58 23 * * ?")
+//    public void runJob() {
+//        List<DataLogPo> dataLogPoList = new ArrayList<>();
+//        // 数据目录
+//        Path dir = Paths.get(jobConfig.getCarYueJieSourcePath());
+//        try (Stream<Path> stream = Files.list(dir)) {
+//            // 获取数据目录下的文件列表
+//            List<Path> pathList = stream.filter(t -> t.toString().endsWith(".xlsx")).sorted().toList();
+//            log.info("睿行车辆越界报警日数据文件列表: {}", pathList);
+//            if (CollectionUtils.isEmpty(pathList)) {
+//                throw new MyRuntimeException("睿行车辆越界报警日数据没有文件");
+//            }
+//            for (Path path : pathList) {
+//                CompletableFuture.runAsync(() -> {
+//                    try {
+//                        singleJob(path, dataLogPoList);
+//                    } catch (Exception e) {
+//                        throw new MyRuntimeException(e);
+//                    }
+//                }).get(1, TimeUnit.MINUTES);
+//            }
+//        } catch (InterruptedException e) {
+//            log.error("线程中断: {}", e, e);
+//            Thread.currentThread().interrupt();
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆越界报警日数据", DataStageEnum.CC, "入库");
+//        } catch (Exception e) {
+//            log.error(e.toString(), e);
+//            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆越界报警日数据", DataStageEnum.CC, "入库");
+//        } finally {
+//            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+//                dataLogService.saveBatch(dataLogPoList);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * 处理单个文件
+//     *
+//     * @param path          文件路径
+//     * @param dataLogPoList 数据处理日志列表
+//     */
+//    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+//        DataLogPo dataLogPo = new DataLogPo();
+//        dataLogPo.setDataName("睿行车辆越界报警日数据");
+//        dataLogPo.setObject(path.getFileName().toString());
+//        dataLogPo.setStage(DataStageEnum.CC.value);
+//        dataLogPo.setOperationName("入库");
+//        long fileSize = Files.size(path);
+//        dataLogPo.setDataSize(fileSize);
+//        dataLogPoList.add(dataLogPo);
+//        if (fileSize == 0) {
+//            move(path);
+//            throw new MyRuntimeException(path.getFileName() + " 空文件");
+//        }
+//        List<Map<String, String>> list = readFile(path);
+//        List<Map<String, String>> distinctList = dataProcessing(path, list);
+//        dataLogPo.setDataCount(distinctList.size());
+//        Path csvPath = toCsv(path, distinctList);
+//        copyCsv(csvPath);
+//        move(path);
+//    }
+//
+//    /**
+//     * 读取文件
+//     *
+//     * @param path 文件路径
+//     */
+//    public List<Map<String, String>> readFile(Path path) throws IOException {
+//        log.info("读取: {}", path);
+//        List<String> rawHeaders = Stream.of("车辆所属单位", "车牌号码", "车辆类型", "车辆使用性质", "报警区域描述",
+//                "报警规则描述", "越界时间", "是否执行中越界", "详情").toList();
+//        List<String> headers = Stream.of("che_liang_suo_shu_dan_wei", "che_pai_hao", "che_liang_lei_xing",
+//                "che_liang_shi_yong_xing_zhi", "bao_jing_qu_yu_miao_shu", "bao_jing_gui_ze_miao_shu",
+//                "yue_jie_shi_jian", "shi_fou_zhi_xing_zhong_yue_jie", "xiang_qing").toList();
+//        try (InputStream inputStream = Files.newInputStream(path);
+//             Workbook workbook = new XSSFWorkbook(inputStream)
+//        ) {
+//            List<Map<String, String>> resultList = new ArrayList<>();
+//            // 读取第一个工作表
+//            Sheet sheet = workbook.getSheetAt(0);
+//            // 表头行
+//            Row headerRow = sheet.getRow(0);
+//            // 列数
+//            int columnCount = headerRow.getPhysicalNumberOfCells();
+//            log.info("columnCount: {}", columnCount);
+//            // 检查表头
+//            if (headers.size() != columnCount) {
+//                throw new MyRuntimeException(path.getFileName() + "列数错误");
+//            }
+//            for (int i = 0; i < columnCount; i++) {
+//                Cell cell = headerRow.getCell(i);
+//                if (cell == null || !rawHeaders.get(i).equals(cell.getStringCellValue())) {
+//                    throw new MyRuntimeException(path.getFileName() + " 表头错误");
+//                }
+//            }
+//            // 最后行数
+//            int lastRowNum = sheet.getLastRowNum();
+//            log.info("lastRowNum: {}", lastRowNum);
+//            if (lastRowNum == 0) {
+//                move(path);
+//                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+//            }
+//            // 遍历行
+//            for (int i = 1; i <= lastRowNum; i++) {
+//                log.debug("row: {}", i);
+//                Row row = sheet.getRow(i);
+//                if (row == null || row.getCell(0) == null) {
+//                    continue;
+//                }
+//                Map<String, String> rowMap = new LinkedHashMap<>();
+//                // 遍历列
+//                for (int j = 0; j < columnCount; j++) {
+//                    log.debug("column: {}", j);
+//                    String header = headers.get(j);
+//                    String cellValue = "";
+//                    rowMap.put(header, cellValue);
+//                    Cell cell = row.getCell(j);
+//                    if (cell == null) {
+//                        continue;
+//                    }
+//                    switch (cell.getCellType()) {
+//                        case STRING:
+//                            boolean skipTrim = "yue_jie_shi_jian".equals(header);
+//                            // 删除字符串空白字符
+//                            cellValue = skipTrim ? cell.getStringCellValue()
+//                                    : StringUtils.trimAllWhitespace(cell.getStringCellValue());
+//                            break;
+//                        case NUMERIC:
+//                            if (DateUtil.isCellDateFormatted(cell)) {
+//                                cellValue = DateUtil.getLocalDateTime(cell.getNumericCellValue())
+//                                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+//                                break;
+//                            }
+//                            cellValue = String.valueOf(cell.getNumericCellValue());
+//                            break;
+//                        case BOOLEAN:
+//                            cellValue = String.valueOf(cell.getBooleanCellValue());
+//                            break;
+//                        default:
+//                            break;
+//                    }
+//                    rowMap.put(headers.get(j), cellValue);
+//                }
+//                resultList.add(rowMap);
+//            }
+//            return resultList;
+//        }
+//    }
+//
+//    /**
+//     * 数据加工
+//     *
+//     * @param path 文件路径
+//     * @param list 数据
+//     */
+//    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+//        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+//        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+//        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+//        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+//                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+//        List<AreaPo> cities = areaService.getCities();
+//        List<AreaPo> districts = areaService.getDistricts();
+//        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+//        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+//        for (Map<String, String> map : list) {
+//            String yueJieShiJian = map.get("yue_jie_shi_jian");
+//            LocalDateTime localDateTime = LocalDateTime.parse(yueJieShiJian,
+//                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+//            String dataDate = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+//            String yearMonth = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
+//            String year = String.valueOf(localDateTime.getYear());
+//            String month = String.valueOf(localDateTime.getMonthValue());
+//            map.put("data_date", dataDate);
+//            map.put("year_month", yearMonth);
+//            map.put("year_no", year);
+//            map.put("month_no", month);
+//            String rawChePaiHao = map.get("che_pai_hao");
+//            map.put("raw_che_pai_hao", rawChePaiHao);
+//            String chePaiHao = carService.getChePai(rawChePaiHao);
+//            map.put("che_pai_hao", chePaiHao);
+//            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+//            map.put("che_pai_fail", chePaiFail);
+//            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+//            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+//            String firstUnit = carService.getFirstUnit(carUnitBo);
+//            if (!StringUtils.hasText(firstUnit)) {
+//                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+//            }
+//            map.put("first_unit", firstUnit);
+//            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+//            map.put("second_unit", secondUnit);
+//            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+//            map.put("third_unit", thirdUnit);
+//            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+//            map.put("area_no", areaNo);
+//            String areaName = carService.getOrgName(orgMap, areaNo);
+//            map.put("area_name", areaName);
+//            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+//            map.put("city_no", cityNo);
+//            String cityName = carService.getOrgName(orgMap, cityNo);
+//            map.put("city_name", cityName);
+//            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+//            map.put("area_no2", areaNo2);
+//            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+//            map.put("area_name2", areaName2);
+//            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+//            map.put("city_id", cityId);
+//            String city = carService.getAreaName(areaMap, cityId);
+//            map.put("city", city);
+//            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+//            map.put("district_id", districtId);
+//            String district = carService.getAreaName(areaMap, districtId);
+//            map.put("district", district);
+//            String baoFei = carService.baoFei(rawChePaiHao);
+//            map.put("bao_fei", baoFei);
+//            map.put("source", path.getFileName().toString());
+//        }
+//        // 去重
+//        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao") + map.get("yue_jie_shi_jian"))).toList();
+//    }
+//
+//    /**
+//     * 去重
+//     */
+//    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+//        Set<Object> set = ConcurrentHashMap.newKeySet();
+//        return t -> set.add(keyExtractor.apply(t));
+//    }
+//
+//    /**
+//     * 生成csv
+//     *
+//     * @param path 源文件路径
+//     * @param list 数据
+//     */
+//    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+//        log.info("去重后条数:{}", list.size());
+//        Files.createDirectories(Paths.get(jobConfig.getCarYueJieHistoryPath()));
+//        Path csvPath = Paths.get(jobConfig.getCarYueJieHistoryPath() + path.getFileName() + ".csv");
+//        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+//                StandardCharsets.UTF_8);
+//             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+//            // 添加bom头避免excel乱码
+//            osw.write('\ufeff');
+//            Map<String, String> header = list.get(0);
+//            // 表头
+//            printer.printRecord(header.keySet());
+//            for (Map<String, String> map : list) {
+//                printer.printRecord(map.values());
+//            }
+//        }
+//        return csvPath;
+//    }
+//
+//    /**
+//     * 导入数据库
+//     *
+//     * @param path 文件路径
+//     */
+//    public void copyCsv(Path path) {
+//        String dbTable = "car.car_yue_jie";
+//        String csv = path.toString();
+//        String columns = "(che_liang_suo_shu_dan_wei,che_pai_hao,che_liang_lei_xing,che_liang_shi_yong_xing_zhi,bao_jing_qu_yu_miao_shu,bao_jing_gui_ze_miao_shu,yue_jie_shi_jian,shi_fou_zhi_xing_zhong_yue_jie,xiang_qing,data_date,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+//        Long timeout = 60000L;
+//        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+//                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+//                timeout, null);
+//    }
+//
+//    /**
+//     * 移动源文件到历史文件夹
+//     *
+//     * @param path 源文件路径
+//     */
+//    public void move(Path path) throws IOException {
+//        Path targetPath = Paths.get(jobConfig.getCarYueJieHistoryPath(), path.getFileName().toString());
+//        Files.move(path, targetPath, StandardCopyOption.REPLACE_EXISTING);
+//    }
+//}

+ 305 - 0
src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarBaoFeiMonthTask.java

@@ -0,0 +1,305 @@
+package com.nokia.finance.tasks.jobs.car.rx;
+
+import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+import com.nokia.finance.tasks.config.JobConfig;
+import com.nokia.finance.tasks.enums.DataStageEnum;
+import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+import com.nokia.finance.tasks.service.car.CarService;
+import com.nokia.finance.tasks.service.common.AreaService;
+import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+import com.nokia.finance.tasks.service.common.OrganizationService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * 睿行车辆报废月数据入库定时任务
+ */
+@Slf4j
+@Service
+public class CarBaoFeiMonthTask {
+    private final JobConfig jobConfig;
+    private final CarService carService;
+    private final OrganizationService organizationService;
+    private final AreaService areaService;
+    private final DataLogServiceImpl dataLogService;
+
+    public CarBaoFeiMonthTask(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+                              AreaService areaService, DataLogServiceImpl dataLogService) {
+        this.jobConfig = jobConfig;
+        this.carService = carService;
+        this.organizationService = organizationService;
+        this.areaService = areaService;
+        this.dataLogService = dataLogService;
+    }
+
+    /**
+     * 执行任务
+     */
+    @Scheduled(cron = "0 30 22 1 * ?")
+    public void runJob() {
+        List<DataLogPo> dataLogPoList = new ArrayList<>();
+        // 数据目录
+        Path dir = Paths.get(jobConfig.getCarBaoFeiSourcePath());
+        try (Stream<Path> stream = Files.list(dir)) {
+            // 获取数据目录下的文件列表
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
+            log.info("睿行车辆报废月数据文件列表: {}", pathList);
+            if (CollectionUtils.isEmpty(pathList)) {
+                throw new MyRuntimeException("睿行车辆报废月数据没有文件");
+            }
+            Files.createDirectories(Paths.get(jobConfig.getCarBaoFeiHistoryPath()));
+            for (Path path : pathList) {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        singleJob(path, dataLogPoList);
+                    } catch (Exception e) {
+                        throw new MyRuntimeException(e);
+                    }
+                }).get(1, TimeUnit.MINUTES);
+            }
+        } catch (InterruptedException e) {
+            log.error("线程中断: {}", e, e);
+            Thread.currentThread().interrupt();
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆报废月数据", DataStageEnum.CC, "入库");
+        } catch (Exception e) {
+            log.error(e.toString(), e);
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆报废月数据", DataStageEnum.CC, "入库");
+        } finally {
+            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+                dataLogService.saveBatch(dataLogPoList);
+            }
+        }
+    }
+
+    /**
+     * 处理单个文件
+     *
+     * @param path          文件路径
+     * @param dataLogPoList 数据处理日志列表
+     */
+    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+        DataLogPo dataLogPo = new DataLogPo();
+        dataLogPo.setDataName("睿行车辆报废月数据");
+        dataLogPo.setObject(path.getFileName().toString());
+        dataLogPo.setStage(DataStageEnum.CC.value);
+        dataLogPo.setOperationName("入库");
+        long fileSize = Files.size(path);
+        dataLogPo.setDataSize(fileSize);
+        dataLogPoList.add(dataLogPo);
+        if (fileSize == 0) {
+            move(path);
+            log.error("{} 空文件", path.getFileName());
+            return;
+        }
+        List<Map<String, String>> list = readFile(path);
+        List<Map<String, String>> distinctList = dataProcessing(path, list);
+        dataLogPo.setDataCount(distinctList.size());
+        Path csvPath = toCsv(path, distinctList);
+        copyCsv(csvPath);
+        move(path);
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param path 文件路径
+     */
+    public List<Map<String, String>> readFile(Path path) throws IOException {
+        log.info("读取: {}", path);
+        List<String> headers = Stream.of(
+                "month_id", "che_pai_hao", "che_liang_suo_shu_dan_wei", "bai_fei_lei_xing",
+                "bao_fei_biao_zhun", "bao_fei_ri_qi", "xing_shi_gong_li_shu", "bei_zhu", "zi_chan_bian_hao",
+                "zi_chan_ming_cheng", "gui_ge_xing_hao", "shi_ji_shi_yong_nian_xian", "zi_chan_yuan_zhi_wan_yuan",
+                "lei_ji_zhe_jiu_zhi_wan_yuan").toList();
+        int headerSize = headers.size();
+        char delimiter = 1;
+        try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+        ) {
+            List<Map<String, String>> resultList = new ArrayList<>();
+            for (CSVRecord csvRecord : parser) {
+                Map<String, String> rowMap = new LinkedHashMap<>();
+                for (int i = 0; i < headerSize; i++) {
+                    String header = headers.get(i);
+                    String value = csvRecord.get(i);
+                    // 删除空白字符
+                    value = StringUtils.trimAllWhitespace(value);
+                    rowMap.put(header, value);
+                }
+                resultList.add(rowMap);
+            }
+            if (CollectionUtils.isEmpty(resultList)) {
+                move(path);
+                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+            }
+            return resultList;
+        }
+    }
+
+    /**
+     * 数据加工
+     *
+     * @param path 文件路径
+     * @param list 数据
+     */
+    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+        List<AreaPo> cities = areaService.getCities();
+        List<AreaPo> districts = areaService.getDistricts();
+        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+        for (Map<String, String> map : list) {
+            String baoFeiRiQi = map.get("bao_fei_ri_qi");
+            LocalDate localDate = LocalDate.parse(baoFeiRiQi, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+            String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            String year = String.valueOf(localDate.getYear());
+            String month = String.valueOf(localDate.getMonthValue());
+            map.put("year_month", yearMonth);
+            map.put("year_no", year);
+            map.put("month_no", month);
+            String rawChePaiHao = map.get("che_pai_hao");
+            map.put("raw_che_pai_hao", rawChePaiHao);
+            String chePaiHao = carService.getChePai(rawChePaiHao);
+            map.put("che_pai_hao", chePaiHao);
+            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+            map.put("che_pai_fail", chePaiFail);
+            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+            String firstUnit = carService.getFirstUnit(carUnitBo);
+            if (!StringUtils.hasText(firstUnit)) {
+                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+            }
+            map.put("first_unit", firstUnit);
+            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+            map.put("second_unit", secondUnit);
+            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+            map.put("third_unit", thirdUnit);
+            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+            map.put("area_no", areaNo);
+            String areaName = carService.getOrgName(orgMap, areaNo);
+            map.put("area_name", areaName);
+            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+            map.put("city_no", cityNo);
+            String cityName = carService.getOrgName(orgMap, cityNo);
+            map.put("city_name", cityName);
+            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+            map.put("area_no2", areaNo2);
+            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+            map.put("area_name2", areaName2);
+            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+            map.put("city_id", cityId);
+            String city = carService.getAreaName(areaMap, cityId);
+            map.put("city", city);
+            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+            map.put("district_id", districtId);
+            String district = carService.getAreaName(areaMap, districtId);
+            map.put("district", district);
+            map.put("manual", "0");
+            map.put("valid", "1");
+            map.put("source", path.getFileName().toString());
+        }
+        // 去重
+        return list.stream().filter(t -> t.get("month_id").equals(t.get("year_month")))
+                .filter(distinctByKey(map -> map.get("che_pai_hao") + map.get("bao_fei_ri_qi")))
+                .toList();
+    }
+
+    /**
+     * 去重
+     */
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Set<Object> set = ConcurrentHashMap.newKeySet();
+        return t -> set.add(keyExtractor.apply(t));
+    }
+
+    /**
+     * 生成csv
+     *
+     * @param path 源文件路径
+     * @param list 数据
+     */
+    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+        log.info("去重后条数条数:{}", list.size());
+        Path csvPath = Paths.get(jobConfig.getCarBaoFeiHistoryPath() + path.getFileName() + ".csv");
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+                StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            Map<String, String> header = list.get(0);
+            // 表头
+            printer.printRecord(header.keySet());
+            for (Map<String, String> map : list) {
+                printer.printRecord(map.values());
+            }
+        }
+        return csvPath;
+    }
+
+    /**
+     * 导入数据库
+     *
+     * @param path 文件路径
+     */
+    public void copyCsv(Path path) {
+        String dbTable = "car.car_bao_fei";
+        String csv = path.toString();
+        String columns = "(month_id,che_pai_hao,che_liang_suo_shu_dan_wei,bai_fei_lei_xing,bao_fei_biao_zhun,bao_fei_ri_qi,xing_shi_gong_li_shu,bei_zhu,zi_chan_bian_hao,zi_chan_ming_cheng,gui_ge_xing_hao,shi_ji_shi_yong_nian_xian,zi_chan_yuan_zhi_wan_yuan,lei_ji_zhe_jiu_zhi_wan_yuan,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,manual,valid,source)";
+        Long timeout = 60000L;
+        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+                timeout, null);
+    }
+
+    /**
+     * 移动源文件到历史文件夹
+     *
+     * @param path 源文件路径
+     */
+    public void move(Path path) throws IOException {
+        if (Files.exists(Paths.get(path + ".MD5"))) {
+            Files.move(Paths.get(path + ".MD5"),
+                    Paths.get(jobConfig.getCarBaoFeiHistoryPath(), path.getFileName().toString() + ".MD5"),
+                    StandardCopyOption.REPLACE_EXISTING);
+        }
+        Files.move(path, Paths.get(jobConfig.getCarBaoFeiHistoryPath(), path.getFileName().toString()),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}

+ 323 - 0
src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarBaseDataDayTask.java

@@ -0,0 +1,323 @@
+package com.nokia.finance.tasks.jobs.car.rx;
+
+import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+import com.nokia.finance.tasks.config.JobConfig;
+import com.nokia.finance.tasks.enums.DataStageEnum;
+import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+import com.nokia.finance.tasks.service.car.CarService;
+import com.nokia.finance.tasks.service.common.AreaService;
+import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+import com.nokia.finance.tasks.service.common.OrganizationService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * 睿行车辆基本信息日数据入库定时任务
+ */
+@Slf4j
+@Service
+public class CarBaseDataDayTask {
+    private final JobConfig jobConfig;
+    private final CarService carService;
+    private final OrganizationService organizationService;
+    private final AreaService areaService;
+    private final DataLogServiceImpl dataLogService;
+
+    public CarBaseDataDayTask(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+                              AreaService areaService, DataLogServiceImpl dataLogService) {
+        this.jobConfig = jobConfig;
+        this.carService = carService;
+        this.organizationService = organizationService;
+        this.areaService = areaService;
+        this.dataLogService = dataLogService;
+    }
+
+    /**
+     * 执行任务
+     */
+    @Scheduled(cron = "0 40 22 * * ?")
+    public void runJob() {
+        List<DataLogPo> dataLogPoList = new ArrayList<>();
+        // 数据目录
+        Path dir = Paths.get(jobConfig.getCarBaseDataDaySourcePath());
+        try (Stream<Path> stream = Files.list(dir)) {
+            // 获取数据目录下的文件列表
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
+            log.info("睿行车辆基本信息日数据文件列表: {}", pathList);
+            if (CollectionUtils.isEmpty(pathList)) {
+                throw new MyRuntimeException("睿行车辆基本信息日数据没有文件");
+            }
+            Files.createDirectories(Paths.get(jobConfig.getCarBaseDataDayHistoryPath()));
+            for (Path path : pathList) {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        singleJob(path, dataLogPoList);
+                    } catch (Exception e) {
+                        throw new MyRuntimeException(e);
+                    }
+                }).get(1, TimeUnit.MINUTES);
+            }
+        } catch (InterruptedException e) {
+            log.error("线程中断: {}", e, e);
+            Thread.currentThread().interrupt();
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆基本信息日数据", DataStageEnum.CC, "入库");
+        } catch (Exception e) {
+            log.error(e.toString(), e);
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆基本信息日数据", DataStageEnum.CC, "入库");
+        } finally {
+            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+                dataLogService.saveBatch(dataLogPoList);
+            }
+        }
+    }
+
+    /**
+     * 处理单个文件
+     *
+     * @param path          文件路径
+     * @param dataLogPoList 数据处理日志列表
+     */
+    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+        DataLogPo dataLogPo = new DataLogPo();
+        dataLogPo.setDataName("睿行车辆基本信息日数据");
+        dataLogPo.setObject(path.getFileName().toString());
+        dataLogPo.setStage(DataStageEnum.CC.value);
+        dataLogPo.setOperationName("入库");
+        long fileSize = Files.size(path);
+        dataLogPo.setDataSize(fileSize);
+        dataLogPoList.add(dataLogPo);
+        if (fileSize == 0) {
+            move(path);
+            log.error("{} 空文件", path.getFileName());
+            return;
+        }
+        List<Map<String, String>> list = readFile(path);
+        List<Map<String, String>> distinctList = dataProcessing(path, list);
+        dataLogPo.setDataCount(distinctList.size());
+        Path csvPath = toCsv(path, distinctList);
+        copyCsv(csvPath);
+        move(path);
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param path 文件路径
+     */
+    public List<Map<String, String>> readFile(Path path) throws IOException {
+        log.info("读取: {}", path);
+        List<String> headers = Stream.of(
+                "month_id", "day_id", "che_pai_hao", "che_liang_pin_pai", "pai_liang", "pai_liang_lei_xing",
+                "ran_you_lei_xing", "ran_you_biao_hao", "deng_ji_ri_qi", "che_liang_lai_yuan", "che_liang_lei_xing",
+                "che_liang_shi_yong_xing_zhi", "huan_bao_deng_ji", "yong_che_mo_shi", "fa_dong_ji_hao", "che_jia_hao",
+                "chu_shi_li_cheng", "che_liang_suo_shu_dan_wei", "xing_shi_zheng_hao", "bei_zhu", "shen_he_zhuang_tai",
+                "che_liang_zhuang_tai", "zi_chan_bian_hao", "bang_ding_jia_shi_yuan_xing_ming", "gou_zhi_jia_ge",
+                "che_ling_nian", "biao_zhun_bai_gong_li_you_hao", "she_bei_gong_zuo_mo_shi").toList();
+        int headerSize = headers.size();
+        char delimiter = 1;
+        try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+        ) {
+            List<Map<String, String>> resultList = new ArrayList<>();
+            for (CSVRecord csvRecord : parser) {
+                Map<String, String> rowMap = new LinkedHashMap<>();
+                for (int i = 0; i < headerSize; i++) {
+                    String header = headers.get(i);
+                    String value = csvRecord.get(i);
+                    // 删除空白字符
+                    value = StringUtils.trimAllWhitespace(value);
+                    rowMap.put(header, value);
+                }
+                resultList.add(rowMap);
+            }
+            if (CollectionUtils.isEmpty(resultList)) {
+                move(path);
+                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+            }
+            return resultList;
+        }
+    }
+
+    /**
+     * 数据加工
+     *
+     * @param path 文件路径
+     * @param list 数据
+     */
+    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+        List<AreaPo> cities = areaService.getCities();
+        List<AreaPo> districts = areaService.getDistricts();
+        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+        for (Map<String, String> map : list) {
+            String monthId = map.get("month_id");
+            String dayId = map.get("day_id");
+            LocalDate localDate = LocalDate.parse(monthId + dayId, DateTimeFormatter.ofPattern("yyyyMMdd"));
+            LocalDate lastMonthDate = localDate.minusMonths(1);
+            String dataDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+            String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            String year = String.valueOf(localDate.getYear());
+            String month = String.valueOf(localDate.getMonthValue());
+            String lastMonth = lastMonthDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            map.put("data_date", dataDate);
+            map.put("year_month", yearMonth);
+            map.put("year_no", year);
+            map.put("month_no", month);
+            map.put("last_month", lastMonth);
+            String rawChePaiHao = map.get("che_pai_hao");
+            map.put("raw_che_pai_hao", rawChePaiHao);
+            String chePaiHao = carService.getChePai(rawChePaiHao);
+            map.put("che_pai_hao", chePaiHao);
+            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+            map.put("che_pai_fail", chePaiFail);
+            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+            String firstUnit = carService.getFirstUnit(carUnitBo);
+            if (!StringUtils.hasText(firstUnit)) {
+                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+            }
+            map.put("first_unit", firstUnit);
+            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+            map.put("second_unit", secondUnit);
+            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+            map.put("third_unit", thirdUnit);
+            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+            map.put("area_no", areaNo);
+            String areaName = carService.getOrgName(orgMap, areaNo);
+            map.put("area_name", areaName);
+            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+            map.put("city_no", cityNo);
+            String cityName = carService.getOrgName(orgMap, cityNo);
+            map.put("city_name", cityName);
+            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+            map.put("area_no2", areaNo2);
+            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+            map.put("area_name2", areaName2);
+            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+            map.put("city_id", cityId);
+            String city = carService.getAreaName(areaMap, cityId);
+            map.put("city", city);
+            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+            map.put("district_id", districtId);
+            String district = carService.getAreaName(areaMap, districtId);
+            map.put("district", district);
+            String cheLing = "0";
+            String dengJiRiQi = map.get("deng_ji_ri_qi");
+            if (StringUtils.hasText(dengJiRiQi)) {
+                LocalDate dengJiRiQiDate = LocalDate.parse(dengJiRiQi, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+                long days = ChronoUnit.DAYS.between(dengJiRiQiDate, localDate);
+                if (days > 0) {
+                    BigDecimal n = BigDecimal.valueOf(days).divide(BigDecimal.valueOf(365), 1, RoundingMode.HALF_UP);
+                    cheLing = n.toString();
+                }
+            }
+            map.put("che_ling", cheLing);
+            map.put("source", path.getFileName().toString());
+        }
+        // 去重
+        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao"))).toList();
+    }
+
+    /**
+     * 去重
+     */
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Set<Object> set = ConcurrentHashMap.newKeySet();
+        return t -> set.add(keyExtractor.apply(t));
+    }
+
+    /**
+     * 生成csv
+     *
+     * @param path 源文件路径
+     * @param list 数据
+     */
+    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+        log.info("去重后条数条数:{}", list.size());
+        Path csvPath = Paths.get(jobConfig.getCarBaseDataDayHistoryPath() + path.getFileName() + ".csv");
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+                StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            Map<String, String> header = list.get(0);
+            // 表头
+            printer.printRecord(header.keySet());
+            for (Map<String, String> map : list) {
+                printer.printRecord(map.values());
+            }
+        }
+        return csvPath;
+    }
+
+    /**
+     * 导入数据库
+     *
+     * @param path 文件路径
+     */
+    public void copyCsv(Path path) {
+        String dbTable = "car.car_base_data_day";
+        String csv = path.toString();
+        String columns = "(month_id,day_id,che_pai_hao,che_liang_pin_pai,pai_liang,pai_liang_lei_xing,ran_you_lei_xing,ran_you_biao_hao,deng_ji_ri_qi,che_liang_lai_yuan,che_liang_lei_xing,che_liang_shi_yong_xing_zhi,huan_bao_deng_ji,yong_che_mo_shi,fa_dong_ji_hao,che_jia_hao,chu_shi_li_cheng,che_liang_suo_shu_dan_wei,xing_shi_zheng_hao,bei_zhu,shen_he_zhuang_tai,che_liang_zhuang_tai,zi_chan_bian_hao,bang_ding_jia_shi_yuan_xing_ming,gou_zhi_jia_ge,che_ling_nian,biao_zhun_bai_gong_li_you_hao,she_bei_gong_zuo_mo_shi,data_date,year_month,year_no,month_no,last_month,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,che_ling,source)";
+        Long timeout = 60000L;
+        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+                timeout, null);
+    }
+
+    /**
+     * 移动源文件到历史文件夹
+     *
+     * @param path 源文件路径
+     */
+    public void move(Path path) throws IOException {
+        if (Files.exists(Paths.get(path + ".MD5"))) {
+            Files.move(Paths.get(path + ".MD5"),
+                    Paths.get(jobConfig.getCarBaseDataDayHistoryPath(), path.getFileName().toString() + ".MD5"),
+                    StandardCopyOption.REPLACE_EXISTING);
+        }
+        Files.move(path, Paths.get(jobConfig.getCarBaseDataDayHistoryPath(), path.getFileName().toString()),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}

+ 308 - 0
src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarLiChengDayTask.java

@@ -0,0 +1,308 @@
+package com.nokia.finance.tasks.jobs.car.rx;
+
+import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+import com.nokia.finance.tasks.config.JobConfig;
+import com.nokia.finance.tasks.enums.DataStageEnum;
+import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+import com.nokia.finance.tasks.service.car.CarService;
+import com.nokia.finance.tasks.service.common.AreaService;
+import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+import com.nokia.finance.tasks.service.common.OrganizationService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * 睿行车辆行驶里程日数据入库定时任务
+ */
+@Slf4j
+@Service
+public class CarLiChengDayTask {
+    private final JobConfig jobConfig;
+    private final CarService carService;
+    private final OrganizationService organizationService;
+    private final AreaService areaService;
+    private final DataLogServiceImpl dataLogService;
+
+    public CarLiChengDayTask(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+                             AreaService areaService, DataLogServiceImpl dataLogService) {
+        this.jobConfig = jobConfig;
+        this.carService = carService;
+        this.organizationService = organizationService;
+        this.areaService = areaService;
+        this.dataLogService = dataLogService;
+    }
+
+    /**
+     * 执行任务
+     */
+    @Scheduled(cron = "0 44 22 * * ?")
+    public void runJob() {
+        List<DataLogPo> dataLogPoList = new ArrayList<>();
+        // 数据目录
+        Path dir = Paths.get(jobConfig.getCarLiChengDaySourcePath());
+        try (Stream<Path> stream = Files.list(dir)) {
+            // 获取数据目录下的文件列表
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
+            log.info("睿行车辆行驶里程日数据文件列表: {}", pathList);
+            if (CollectionUtils.isEmpty(pathList)) {
+                throw new MyRuntimeException("睿行车辆行驶里程日数据没有文件");
+            }
+            Files.createDirectories(Paths.get(jobConfig.getCarLiChengDayHistoryPath()));
+            for (Path path : pathList) {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        singleJob(path, dataLogPoList);
+                    } catch (Exception e) {
+                        throw new MyRuntimeException(e);
+                    }
+                }).get(1, TimeUnit.MINUTES);
+            }
+        } catch (InterruptedException e) {
+            log.error("线程中断: {}", e, e);
+            Thread.currentThread().interrupt();
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程日数据", DataStageEnum.CC, "入库");
+        } catch (Exception e) {
+            log.error(e.toString(), e);
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程日数据", DataStageEnum.CC, "入库");
+        } finally {
+            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+                dataLogService.saveBatch(dataLogPoList);
+            }
+        }
+    }
+
+    /**
+     * 处理单个文件
+     *
+     * @param path          文件路径
+     * @param dataLogPoList 数据处理日志列表
+     */
+    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+        DataLogPo dataLogPo = new DataLogPo();
+        dataLogPo.setDataName("睿行车辆行驶里程日数据");
+        dataLogPo.setObject(path.getFileName().toString());
+        dataLogPo.setStage(DataStageEnum.CC.value);
+        dataLogPo.setOperationName("入库");
+        long fileSize = Files.size(path);
+        dataLogPo.setDataSize(fileSize);
+        dataLogPoList.add(dataLogPo);
+        if (fileSize == 0) {
+            move(path);
+            log.error("{} 空文件", path.getFileName());
+            return;
+        }
+        List<Map<String, String>> list = readFile(path);
+        List<Map<String, String>> distinctList = dataProcessing(path, list);
+        dataLogPo.setDataCount(distinctList.size());
+        Path csvPath = toCsv(path, distinctList);
+        copyCsv(csvPath);
+        move(path);
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param path 文件路径
+     */
+    public List<Map<String, String>> readFile(Path path) throws IOException {
+        log.info("读取: {}", path);
+        List<String> headers = Stream.of(
+                "month_id", "day_id", "che_liang_suo_shu_dan_wei", "che_pai_hao", "che_liang_lei_xing",
+                "che_liang_lai_yuan", "che_liang_shi_yong_xing_zhi", "xing_shi_shi_chang", "xing_shi_tian_shu",
+                "zong_li_cheng", "obd_you_hao", "bai_gong_li_you_hao").toList();
+        int headerSize = headers.size();
+        char delimiter = 1;
+        try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+        ) {
+            List<Map<String, String>> resultList = new ArrayList<>();
+            for (CSVRecord csvRecord : parser) {
+                Map<String, String> rowMap = new LinkedHashMap<>();
+                for (int i = 0; i < headerSize; i++) {
+                    String header = headers.get(i);
+                    String value = csvRecord.get(i);
+                    // 删除空白字符
+                    value = StringUtils.trimAllWhitespace(value);
+                    rowMap.put(header, value);
+                }
+                resultList.add(rowMap);
+            }
+            if (CollectionUtils.isEmpty(resultList)) {
+                move(path);
+                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+            }
+            return resultList;
+        }
+    }
+
+    /**
+     * 数据加工
+     *
+     * @param path 文件路径
+     * @param list 数据
+     */
+    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+        List<AreaPo> cities = areaService.getCities();
+        List<AreaPo> districts = areaService.getDistricts();
+        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+        for (Map<String, String> map : list) {
+            String monthId = map.get("month_id");
+            String dayId = map.get("day_id");
+            LocalDate localDate = LocalDate.parse(monthId + dayId, DateTimeFormatter.ofPattern("yyyyMMdd"));
+            String dataDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+            String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            String year = String.valueOf(localDate.getYear());
+            String month = String.valueOf(localDate.getMonthValue());
+            map.put("data_date", dataDate);
+            map.put("year_month", yearMonth);
+            map.put("year_no", year);
+            map.put("month_no", month);
+            String rawChePaiHao = map.get("che_pai_hao");
+            map.put("raw_che_pai_hao", rawChePaiHao);
+            String chePaiHao = carService.getChePai(rawChePaiHao);
+            map.put("che_pai_hao", chePaiHao);
+            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+            map.put("che_pai_fail", chePaiFail);
+            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+            String firstUnit = carService.getFirstUnit(carUnitBo);
+            if (!StringUtils.hasText(firstUnit)) {
+                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+            }
+            map.put("first_unit", firstUnit);
+            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+            map.put("second_unit", secondUnit);
+            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+            map.put("third_unit", thirdUnit);
+            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+            map.put("area_no", areaNo);
+            String areaName = carService.getOrgName(orgMap, areaNo);
+            map.put("area_name", areaName);
+            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+            map.put("city_no", cityNo);
+            String cityName = carService.getOrgName(orgMap, cityNo);
+            map.put("city_name", cityName);
+            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+            map.put("area_no2", areaNo2);
+            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+            map.put("area_name2", areaName2);
+            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+            map.put("city_id", cityId);
+            String city = carService.getAreaName(areaMap, cityId);
+            map.put("city", city);
+            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+            map.put("district_id", districtId);
+            String district = carService.getAreaName(areaMap, districtId);
+            map.put("district", district);
+            String baoFei = carService.baoFei(rawChePaiHao);
+            map.put("bao_fei", baoFei);
+            if ("1".equals(baoFei)) {
+                map.put("che_pai_hao", rawChePaiHao);
+            }
+            map.put("source", path.getFileName().toString());
+        }
+        // 去重
+        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao"))).toList();
+    }
+
+    /**
+     * 去重
+     */
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Set<Object> set = ConcurrentHashMap.newKeySet();
+        return t -> set.add(keyExtractor.apply(t));
+    }
+
+    /**
+     * 生成csv
+     *
+     * @param path 源文件路径
+     * @param list 数据
+     */
+    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+        log.info("去重后条数条数:{}", list.size());
+        Path csvPath = Paths.get(jobConfig.getCarLiChengDayHistoryPath() + path.getFileName() + ".csv");
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+                StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            Map<String, String> header = list.get(0);
+            // 表头
+            printer.printRecord(header.keySet());
+            for (Map<String, String> map : list) {
+                printer.printRecord(map.values());
+            }
+        }
+        return csvPath;
+    }
+
+    /**
+     * 导入数据库
+     *
+     * @param path 文件路径
+     */
+    public void copyCsv(Path path) {
+        String dbTable = "car.car_li_cheng_day";
+        String csv = path.toString();
+        String columns = "(month_id,day_id,che_liang_suo_shu_dan_wei,che_pai_hao,che_liang_lei_xing,che_liang_lai_yuan,che_liang_shi_yong_xing_zhi,xing_shi_shi_chang,xing_shi_tian_shu,zong_li_cheng,obd_you_hao,bai_gong_li_you_hao,data_date,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+        Long timeout = 60000L;
+        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+                timeout, null);
+    }
+
+    /**
+     * 移动源文件到历史文件夹
+     *
+     * @param path 源文件路径
+     */
+    public void move(Path path) throws IOException {
+        if (Files.exists(Paths.get(path + ".MD5"))) {
+            Files.move(Paths.get(path + ".MD5"),
+                    Paths.get(jobConfig.getCarLiChengDayHistoryPath(), path.getFileName().toString() + ".MD5"),
+                    StandardCopyOption.REPLACE_EXISTING);
+        }
+        Files.move(path, Paths.get(jobConfig.getCarLiChengDayHistoryPath(), path.getFileName().toString()),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}

+ 310 - 0
src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarLiChengMonthTask.java

@@ -0,0 +1,310 @@
+package com.nokia.finance.tasks.jobs.car.rx;
+
+import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+import com.nokia.finance.tasks.config.JobConfig;
+import com.nokia.finance.tasks.enums.DataStageEnum;
+import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+import com.nokia.finance.tasks.service.car.CarService;
+import com.nokia.finance.tasks.service.common.AreaService;
+import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+import com.nokia.finance.tasks.service.common.OrganizationService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * 睿行车辆行驶里程月数据入库定时任务
+ */
+@Slf4j
+@Service
+public class CarLiChengMonthTask {
+    private final JobConfig jobConfig;
+    private final CarService carService;
+    private final OrganizationService organizationService;
+    private final AreaService areaService;
+    private final DataLogServiceImpl dataLogService;
+
+    public CarLiChengMonthTask(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+                               AreaService areaService, DataLogServiceImpl dataLogService) {
+        this.jobConfig = jobConfig;
+        this.carService = carService;
+        this.organizationService = organizationService;
+        this.areaService = areaService;
+        this.dataLogService = dataLogService;
+    }
+
+    /**
+     * 执行任务
+     */
+    @Scheduled(cron = "0 32 22 1 * ?")
+    public void runJob() {
+        List<DataLogPo> dataLogPoList = new ArrayList<>();
+        // 数据目录
+        Path dir = Paths.get(jobConfig.getCarLiChengMonthSourcePath());
+        try (Stream<Path> stream = Files.list(dir)) {
+            // 获取数据目录下的文件列表
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
+            log.info("睿行车辆行驶里程月数据文件列表: {}", pathList);
+            if (CollectionUtils.isEmpty(pathList)) {
+                throw new MyRuntimeException("睿行车辆行驶里程月数据没有文件");
+            }
+            Files.createDirectories(Paths.get(jobConfig.getCarLiChengMonthHistoryPath()));
+            for (Path path : pathList) {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        singleJob(path, dataLogPoList);
+                    } catch (Exception e) {
+                        throw new MyRuntimeException(e);
+                    }
+                }).get(1, TimeUnit.MINUTES);
+            }
+        } catch (InterruptedException e) {
+            log.error("线程中断: {}", e, e);
+            Thread.currentThread().interrupt();
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程月数据", DataStageEnum.CC, "入库");
+        } catch (Exception e) {
+            log.error(e.toString(), e);
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆行驶里程月数据", DataStageEnum.CC, "入库");
+        } finally {
+            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+                dataLogService.saveBatch(dataLogPoList);
+            }
+        }
+    }
+
+    /**
+     * 处理单个文件
+     *
+     * @param path          文件路径
+     * @param dataLogPoList 数据处理日志列表
+     */
+    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+        DataLogPo dataLogPo = new DataLogPo();
+        dataLogPo.setDataName("睿行车辆行驶里程月数据");
+        dataLogPo.setObject(path.getFileName().toString());
+        dataLogPo.setStage(DataStageEnum.CC.value);
+        dataLogPo.setOperationName("入库");
+        long fileSize = Files.size(path);
+        dataLogPo.setDataSize(fileSize);
+        dataLogPoList.add(dataLogPo);
+        if (fileSize == 0) {
+            move(path);
+            log.error("{} 空文件", path.getFileName());
+            return;
+        }
+        List<Map<String, String>> list = readFile(path);
+        List<Map<String, String>> distinctList = dataProcessing(path, list);
+        dataLogPo.setDataCount(distinctList.size());
+        Path csvPath = toCsv(path, distinctList);
+        copyCsv(csvPath);
+        move(path);
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param path 文件路径
+     */
+    public List<Map<String, String>> readFile(Path path) throws IOException {
+        log.info("读取: {}", path);
+        List<String> headers = Stream.of(
+                "month_id", "che_pai_hao", "che_liang_suo_shu_dan_wei", "che_liang_lei_xing",
+                "che_liang_lai_yuan", "che_liang_shi_yong_xing_zhi", "xing_shi_shi_chang", "xing_shi_tian_shu",
+                "zong_li_cheng", "obd_you_hao", "bai_gong_li_you_hao").toList();
+        int headerSize = headers.size();
+        char delimiter = 1;
+        try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+        ) {
+            List<Map<String, String>> resultList = new ArrayList<>();
+            for (CSVRecord csvRecord : parser) {
+                Map<String, String> rowMap = new LinkedHashMap<>();
+                for (int i = 0; i < headerSize; i++) {
+                    String header = headers.get(i);
+                    String value = csvRecord.get(i);
+                    // 删除空白字符
+                    value = StringUtils.trimAllWhitespace(value);
+                    rowMap.put(header, value);
+                }
+                resultList.add(rowMap);
+            }
+            if (CollectionUtils.isEmpty(resultList)) {
+                move(path);
+                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+            }
+            return resultList;
+        }
+    }
+
+    /**
+     * 数据加工
+     *
+     * @param path 文件路径
+     * @param list 数据
+     */
+    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+        List<AreaPo> cities = areaService.getCities();
+        List<AreaPo> districts = areaService.getDistricts();
+        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+        for (Map<String, String> map : list) {
+            String monthId = map.get("month_id");
+            LocalDate localDate = LocalDate.parse(monthId + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
+            LocalDate lastMonthDate = localDate.minusMonths(1);
+            String dataDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+            String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            String year = String.valueOf(localDate.getYear());
+            String month = String.valueOf(localDate.getMonthValue());
+            String lastMonth = lastMonthDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            map.put("data_date", dataDate);
+            map.put("year_month", yearMonth);
+            map.put("year_no", year);
+            map.put("month_no", month);
+            map.put("last_month", lastMonth);
+            String rawChePaiHao = map.get("che_pai_hao");
+            map.put("raw_che_pai_hao", rawChePaiHao);
+            String chePaiHao = carService.getChePai(rawChePaiHao);
+            map.put("che_pai_hao", chePaiHao);
+            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+            map.put("che_pai_fail", chePaiFail);
+            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+            String firstUnit = carService.getFirstUnit(carUnitBo);
+            if (!StringUtils.hasText(firstUnit)) {
+                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+            }
+            map.put("first_unit", firstUnit);
+            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+            map.put("second_unit", secondUnit);
+            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+            map.put("third_unit", thirdUnit);
+            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+            map.put("area_no", areaNo);
+            String areaName = carService.getOrgName(orgMap, areaNo);
+            map.put("area_name", areaName);
+            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+            map.put("city_no", cityNo);
+            String cityName = carService.getOrgName(orgMap, cityNo);
+            map.put("city_name", cityName);
+            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+            map.put("area_no2", areaNo2);
+            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+            map.put("area_name2", areaName2);
+            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+            map.put("city_id", cityId);
+            String city = carService.getAreaName(areaMap, cityId);
+            map.put("city", city);
+            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+            map.put("district_id", districtId);
+            String district = carService.getAreaName(areaMap, districtId);
+            map.put("district", district);
+            String baoFei = carService.baoFei(rawChePaiHao);
+            map.put("bao_fei", baoFei);
+            if ("1".equals(baoFei)) {
+                map.put("che_pai_hao", rawChePaiHao);
+            }
+            map.put("source", path.getFileName().toString());
+        }
+        // 去重
+        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao"))).toList();
+    }
+
+    /**
+     * 去重
+     */
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Set<Object> set = ConcurrentHashMap.newKeySet();
+        return t -> set.add(keyExtractor.apply(t));
+    }
+
+    /**
+     * 生成csv
+     *
+     * @param path 源文件路径
+     * @param list 数据
+     */
+    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+        log.info("去重后条数条数:{}", list.size());
+        Path csvPath = Paths.get(jobConfig.getCarLiChengMonthHistoryPath() + path.getFileName() + ".csv");
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+                StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            Map<String, String> header = list.get(0);
+            // 表头
+            printer.printRecord(header.keySet());
+            for (Map<String, String> map : list) {
+                printer.printRecord(map.values());
+            }
+        }
+        return csvPath;
+    }
+
+    /**
+     * 导入数据库
+     *
+     * @param path 文件路径
+     */
+    public void copyCsv(Path path) {
+        String dbTable = "car.car_li_cheng_month";
+        String csv = path.toString();
+        String columns = "(month_id,che_pai_hao,che_liang_suo_shu_dan_wei,che_liang_lei_xing,che_liang_lai_yuan,che_liang_shi_yong_xing_zhi,xing_shi_shi_chang,xing_shi_tian_shu,zong_li_cheng,obd_you_hao,bai_gong_li_you_hao,data_date,year_month,year_no,month_no,last_month,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+        Long timeout = 60000L;
+        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+                timeout, null);
+    }
+
+    /**
+     * 移动源文件到历史文件夹
+     *
+     * @param path 源文件路径
+     */
+    public void move(Path path) throws IOException {
+        if (Files.exists(Paths.get(path + ".MD5"))) {
+            Files.move(Paths.get(path + ".MD5"),
+                    Paths.get(jobConfig.getCarLiChengMonthHistoryPath(), path.getFileName().toString() + ".MD5"),
+                    StandardCopyOption.REPLACE_EXISTING);
+        }
+        Files.move(path, Paths.get(jobConfig.getCarLiChengMonthHistoryPath(), path.getFileName().toString()),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}

+ 305 - 0
src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarWuDanYongCheDayTask.java

@@ -0,0 +1,305 @@
+package com.nokia.finance.tasks.jobs.car.rx;
+
+import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+import com.nokia.finance.tasks.config.JobConfig;
+import com.nokia.finance.tasks.enums.DataStageEnum;
+import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+import com.nokia.finance.tasks.service.car.CarService;
+import com.nokia.finance.tasks.service.common.AreaService;
+import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+import com.nokia.finance.tasks.service.common.OrganizationService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * 睿行车辆无单用车报警日统计数据入库定时任务
+ */
+@Slf4j
+@Service
+public class CarWuDanYongCheDayTask {
+    private final JobConfig jobConfig;
+    private final CarService carService;
+    private final OrganizationService organizationService;
+    private final AreaService areaService;
+    private final DataLogServiceImpl dataLogService;
+
+    public CarWuDanYongCheDayTask(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+                                  AreaService areaService, DataLogServiceImpl dataLogService) {
+        this.jobConfig = jobConfig;
+        this.carService = carService;
+        this.organizationService = organizationService;
+        this.areaService = areaService;
+        this.dataLogService = dataLogService;
+    }
+
+    /**
+     * 执行任务
+     */
+    @Scheduled(cron = "0 46 22 * * ?")
+    public void runJob() {
+        List<DataLogPo> dataLogPoList = new ArrayList<>();
+        // 数据目录
+        Path dir = Paths.get(jobConfig.getCarWuDanYongCheDaySourcePath());
+        try (Stream<Path> stream = Files.list(dir)) {
+            // 获取数据目录下的文件列表
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
+            log.info("睿行车辆无单用车报警日统计数据文件列表: {}", pathList);
+            if (CollectionUtils.isEmpty(pathList)) {
+                throw new MyRuntimeException("睿行车辆无单用车报警日统计数据没有文件");
+            }
+            Files.createDirectories(Paths.get(jobConfig.getCarWuDanYongCheDayHistoryPath()));
+            for (Path path : pathList) {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        singleJob(path, dataLogPoList);
+                    } catch (Exception e) {
+                        throw new MyRuntimeException(e);
+                    }
+                }).get(1, TimeUnit.MINUTES);
+            }
+        } catch (InterruptedException e) {
+            log.error("线程中断: {}", e, e);
+            Thread.currentThread().interrupt();
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆无单用车报警日统计数据", DataStageEnum.CC, "入库");
+        } catch (Exception e) {
+            log.error(e.toString(), e);
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆无单用车报警日统计数据", DataStageEnum.CC, "入库");
+        } finally {
+            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+                dataLogService.saveBatch(dataLogPoList);
+            }
+        }
+    }
+
+    /**
+     * 处理单个文件
+     *
+     * @param path          文件路径
+     * @param dataLogPoList 数据处理日志列表
+     */
+    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+        DataLogPo dataLogPo = new DataLogPo();
+        dataLogPo.setDataName("睿行车辆无单用车报警日统计数据");
+        dataLogPo.setObject(path.getFileName().toString());
+        dataLogPo.setStage(DataStageEnum.CC.value);
+        dataLogPo.setOperationName("入库");
+        long fileSize = Files.size(path);
+        dataLogPo.setDataSize(fileSize);
+        dataLogPoList.add(dataLogPo);
+        if (fileSize == 0) {
+            move(path);
+            log.error("{} 空文件", path.getFileName());
+            return;
+        }
+        List<Map<String, String>> list = readFile(path);
+        List<Map<String, String>> distinctList = dataProcessing(path, list);
+        dataLogPo.setDataCount(distinctList.size());
+        Path csvPath = toCsv(path, distinctList);
+        copyCsv(csvPath);
+        move(path);
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param path 文件路径
+     */
+    public List<Map<String, String>> readFile(Path path) throws IOException {
+        log.info("读取: {}", path);
+        List<String> headers = Stream.of(
+                "month_id", "day_id", "che_liang_suo_shu_dan_wei", "che_pai_hao", "wei_gui_kai_shi_shi_jian",
+                "wei_gui_jie_shu_shi_jian", "wei_gui_chi_xu_shi_jian").toList();
+        int headerSize = headers.size();
+        char delimiter = 1;
+        try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+        ) {
+            List<Map<String, String>> resultList = new ArrayList<>();
+            for (CSVRecord csvRecord : parser) {
+                Map<String, String> rowMap = new LinkedHashMap<>();
+                for (int i = 0; i < headerSize; i++) {
+                    String header = headers.get(i);
+                    String value = csvRecord.get(i);
+                    boolean skipTrim = "wei_gui_kai_shi_shi_jian".equals(header)
+                            || "wei_gui_jie_shu_shi_jian".equals(header);
+                    // 删除字符串空白字符
+                    value = skipTrim ? value : StringUtils.trimAllWhitespace(value);
+                    rowMap.put(header, value);
+                }
+                resultList.add(rowMap);
+            }
+            if (CollectionUtils.isEmpty(resultList)) {
+                move(path);
+                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+            }
+            return resultList;
+        }
+    }
+
+    /**
+     * 数据加工
+     *
+     * @param path 文件路径
+     * @param list 数据
+     */
+    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+        List<AreaPo> cities = areaService.getCities();
+        List<AreaPo> districts = areaService.getDistricts();
+        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+        for (Map<String, String> map : list) {
+            String weiGuiKaiShiShiJian = map.get("wei_gui_kai_shi_shi_jian");
+            LocalDateTime localDateTime = LocalDateTime.parse(weiGuiKaiShiShiJian,
+                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+            String yearMonth = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            String year = String.valueOf(localDateTime.getYear());
+            String month = String.valueOf(localDateTime.getMonthValue());
+            map.put("year_month", yearMonth);
+            map.put("year_no", year);
+            map.put("month_no", month);
+            String rawChePaiHao = map.get("che_pai_hao");
+            map.put("raw_che_pai_hao", rawChePaiHao);
+            String chePaiHao = carService.getChePai(rawChePaiHao);
+            map.put("che_pai_hao", chePaiHao);
+            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+            map.put("che_pai_fail", chePaiFail);
+            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+            String firstUnit = carService.getFirstUnit(carUnitBo);
+            if (!StringUtils.hasText(firstUnit)) {
+                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+            }
+            map.put("first_unit", firstUnit);
+            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+            map.put("second_unit", secondUnit);
+            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+            map.put("third_unit", thirdUnit);
+            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+            map.put("area_no", areaNo);
+            String areaName = carService.getOrgName(orgMap, areaNo);
+            map.put("area_name", areaName);
+            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+            map.put("city_no", cityNo);
+            String cityName = carService.getOrgName(orgMap, cityNo);
+            map.put("city_name", cityName);
+            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+            map.put("area_no2", areaNo2);
+            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+            map.put("area_name2", areaName2);
+            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+            map.put("city_id", cityId);
+            String city = carService.getAreaName(areaMap, cityId);
+            map.put("city", city);
+            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+            map.put("district_id", districtId);
+            String district = carService.getAreaName(areaMap, districtId);
+            map.put("district", district);
+            String baoFei = carService.baoFei(rawChePaiHao);
+            map.put("bao_fei", baoFei);
+            map.put("source", path.getFileName().toString());
+        }
+        // 去重
+        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao") 
+                        + map.get("wei_gui_kai_shi_shi_jian"))).toList();
+    }
+
+    /**
+     * 去重
+     */
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Set<Object> set = ConcurrentHashMap.newKeySet();
+        return t -> set.add(keyExtractor.apply(t));
+    }
+
+    /**
+     * 生成csv
+     *
+     * @param path 源文件路径
+     * @param list 数据
+     */
+    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+        log.info("去重后条数条数:{}", list.size());
+        Path csvPath = Paths.get(jobConfig.getCarWuDanYongCheDayHistoryPath() + path.getFileName() + ".csv");
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+                StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            Map<String, String> header = list.get(0);
+            // 表头
+            printer.printRecord(header.keySet());
+            for (Map<String, String> map : list) {
+                printer.printRecord(map.values());
+            }
+        }
+        return csvPath;
+    }
+
+    /**
+     * 导入数据库
+     *
+     * @param path 文件路径
+     */
+    public void copyCsv(Path path) {
+        String dbTable = "car.car_wu_dan_yong_che_day";
+        String csv = path.toString();
+        String columns = "(month_id,day_id,che_liang_suo_shu_dan_wei,che_pai_hao,wei_gui_kai_shi_shi_jian,wei_gui_jie_shu_shi_jian,wei_gui_chi_xu_shi_jian,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+        Long timeout = 60000L;
+        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+                timeout, null);
+    }
+
+    /**
+     * 移动源文件到历史文件夹
+     *
+     * @param path 源文件路径
+     */
+    public void move(Path path) throws IOException {
+        if (Files.exists(Paths.get(path + ".MD5"))) {
+            Files.move(Paths.get(path + ".MD5"),
+                    Paths.get(jobConfig.getCarWuDanYongCheDayHistoryPath(), path.getFileName().toString() + ".MD5"),
+                    StandardCopyOption.REPLACE_EXISTING);
+        }
+        Files.move(path, Paths.get(jobConfig.getCarWuDanYongCheDayHistoryPath(), path.getFileName().toString()),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}

+ 307 - 0
src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarWuDanYongCheMonthTask.java

@@ -0,0 +1,307 @@
+package com.nokia.finance.tasks.jobs.car.rx;
+
+import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+import com.nokia.finance.tasks.config.JobConfig;
+import com.nokia.finance.tasks.enums.DataStageEnum;
+import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+import com.nokia.finance.tasks.service.car.CarService;
+import com.nokia.finance.tasks.service.common.AreaService;
+import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+import com.nokia.finance.tasks.service.common.OrganizationService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * 睿行车辆无单用车报警月统计数据入库定时任务
+ */
+@Slf4j
+@Service
+public class CarWuDanYongCheMonthTask {
+    private final JobConfig jobConfig;
+    private final CarService carService;
+    private final OrganizationService organizationService;
+    private final AreaService areaService;
+    private final DataLogServiceImpl dataLogService;
+
+    public CarWuDanYongCheMonthTask(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+                                    AreaService areaService, DataLogServiceImpl dataLogService) {
+        this.jobConfig = jobConfig;
+        this.carService = carService;
+        this.organizationService = organizationService;
+        this.areaService = areaService;
+        this.dataLogService = dataLogService;
+    }
+
+    /**
+     * 执行任务
+     */
+    @Scheduled(cron = "0 34 22 1 * ?")
+    public void runJob() {
+        List<DataLogPo> dataLogPoList = new ArrayList<>();
+        // 数据目录
+        Path dir = Paths.get(jobConfig.getCarWuDanYongCheSourcePath());
+        try (Stream<Path> stream = Files.list(dir)) {
+            // 获取数据目录下的文件列表
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
+            log.info("睿行车辆无单用车报警月统计数据文件列表: {}", pathList);
+            if (CollectionUtils.isEmpty(pathList)) {
+                throw new MyRuntimeException("睿行车辆无单用车报警月统计数据没有文件");
+            }
+            Files.createDirectories(Paths.get(jobConfig.getCarWuDanYongCheHistoryPath()));
+            for (Path path : pathList) {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        singleJob(path, dataLogPoList);
+                    } catch (Exception e) {
+                        throw new MyRuntimeException(e);
+                    }
+                }).get(1, TimeUnit.MINUTES);
+            }
+        } catch (InterruptedException e) {
+            log.error("线程中断: {}", e, e);
+            Thread.currentThread().interrupt();
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆无单用车报警月统计数据", DataStageEnum.CC, "入库");
+        } catch (Exception e) {
+            log.error(e.toString(), e);
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆无单用车报警月统计数据", DataStageEnum.CC, "入库");
+        } finally {
+            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+                dataLogService.saveBatch(dataLogPoList);
+            }
+        }
+    }
+
+    /**
+     * 处理单个文件
+     *
+     * @param path          文件路径
+     * @param dataLogPoList 数据处理日志列表
+     */
+    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+        DataLogPo dataLogPo = new DataLogPo();
+        dataLogPo.setDataName("睿行车辆无单用车报警月统计数据");
+        dataLogPo.setObject(path.getFileName().toString());
+        dataLogPo.setStage(DataStageEnum.CC.value);
+        dataLogPo.setOperationName("入库");
+        long fileSize = Files.size(path);
+        dataLogPo.setDataSize(fileSize);
+        dataLogPoList.add(dataLogPo);
+        if (fileSize == 0) {
+            move(path);
+            log.error("{} 空文件", path.getFileName());
+            return;
+        }
+        List<Map<String, String>> list = readFile(path);
+        List<Map<String, String>> distinctList = dataProcessing(path, list);
+        dataLogPo.setDataCount(distinctList.size());
+        Path csvPath = toCsv(path, distinctList);
+        copyCsv(csvPath);
+        move(path);
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param path 文件路径
+     */
+    public List<Map<String, String>> readFile(Path path) throws IOException {
+        log.info("读取: {}", path);
+        List<String> headers = Stream.of(
+                "month_id", "che_liang_suo_shu_dan_wei", "che_pai_hao", "wei_gui_kai_shi_shi_jian",
+                "wei_gui_jie_shu_shi_jian", "wei_gui_chi_xu_shi_jian").toList();
+        int headerSize = headers.size();
+        char delimiter = 1;
+        try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+        ) {
+            List<Map<String, String>> resultList = new ArrayList<>();
+            for (CSVRecord csvRecord : parser) {
+                Map<String, String> rowMap = new LinkedHashMap<>();
+                for (int i = 0; i < headerSize; i++) {
+                    String header = headers.get(i);
+                    String value = csvRecord.get(i);
+                    boolean skipTrim = "wei_gui_kai_shi_shi_jian".equals(header)
+                            || "wei_gui_jie_shu_shi_jian".equals(header);
+                    // 删除字符串空白字符
+                    value = skipTrim ? value : StringUtils.trimAllWhitespace(value);
+                    rowMap.put(header, value);
+                }
+                resultList.add(rowMap);
+            }
+            if (CollectionUtils.isEmpty(resultList)) {
+                move(path);
+                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+            }
+            return resultList;
+        }
+    }
+
+    /**
+     * 数据加工
+     *
+     * @param path 文件路径
+     * @param list 数据
+     */
+    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+        List<AreaPo> cities = areaService.getCities();
+        List<AreaPo> districts = areaService.getDistricts();
+        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+        for (Map<String, String> map : list) {
+            String weiGuiKaiShiShiJian = map.get("wei_gui_kai_shi_shi_jian");
+            LocalDateTime localDateTime = LocalDateTime.parse(weiGuiKaiShiShiJian,
+                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+            String yearMonth = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            String year = String.valueOf(localDateTime.getYear());
+            String month = String.valueOf(localDateTime.getMonthValue());
+            map.put("year_month", yearMonth);
+            map.put("year_no", year);
+            map.put("month_no", month);
+            String rawChePaiHao = map.get("che_pai_hao");
+            map.put("raw_che_pai_hao", rawChePaiHao);
+            String chePaiHao = carService.getChePai(rawChePaiHao);
+            map.put("che_pai_hao", chePaiHao);
+            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+            map.put("che_pai_fail", chePaiFail);
+            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+            String firstUnit = carService.getFirstUnit(carUnitBo);
+            if (!StringUtils.hasText(firstUnit)) {
+                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+            }
+            map.put("first_unit", firstUnit);
+            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+            map.put("second_unit", secondUnit);
+            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+            map.put("third_unit", thirdUnit);
+            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+            map.put("area_no", areaNo);
+            String areaName = carService.getOrgName(orgMap, areaNo);
+            map.put("area_name", areaName);
+            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+            map.put("city_no", cityNo);
+            String cityName = carService.getOrgName(orgMap, cityNo);
+            map.put("city_name", cityName);
+            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+            map.put("area_no2", areaNo2);
+            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+            map.put("area_name2", areaName2);
+            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+            map.put("city_id", cityId);
+            String city = carService.getAreaName(areaMap, cityId);
+            map.put("city", city);
+            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+            map.put("district_id", districtId);
+            String district = carService.getAreaName(areaMap, districtId);
+            map.put("district", district);
+            String baoFei = carService.baoFei(rawChePaiHao);
+            map.put("bao_fei", baoFei);
+            map.put("source", path.getFileName().toString());
+        }
+        // 去重
+        return list.stream()
+                .filter(t -> t.get("month_id").equals(t.get("year_month")))
+                .filter(distinctByKey(map -> map.get("che_pai_hao")
+                        + map.get("wei_gui_kai_shi_shi_jian"))).toList();
+    }
+
+    /**
+     * 去重
+     */
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Set<Object> set = ConcurrentHashMap.newKeySet();
+        return t -> set.add(keyExtractor.apply(t));
+    }
+
+    /**
+     * 生成csv
+     *
+     * @param path 源文件路径
+     * @param list 数据
+     */
+    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+        log.info("去重后条数条数:{}", list.size());
+        Path csvPath = Paths.get(jobConfig.getCarWuDanYongCheHistoryPath() + path.getFileName() + ".csv");
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+                StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            Map<String, String> header = list.get(0);
+            // 表头
+            printer.printRecord(header.keySet());
+            for (Map<String, String> map : list) {
+                printer.printRecord(map.values());
+            }
+        }
+        return csvPath;
+    }
+
+    /**
+     * 导入数据库
+     *
+     * @param path 文件路径
+     */
+    public void copyCsv(Path path) {
+        String dbTable = "car.car_wu_dan_yong_che";
+        String csv = path.toString();
+        String columns = "(month_id,che_liang_suo_shu_dan_wei,che_pai_hao,wei_gui_kai_shi_shi_jian,wei_gui_jie_shu_shi_jian,wei_gui_chi_xu_shi_jian,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+        Long timeout = 60000L;
+        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+                timeout, null);
+    }
+
+    /**
+     * 移动源文件到历史文件夹
+     *
+     * @param path 源文件路径
+     */
+    public void move(Path path) throws IOException {
+        if (Files.exists(Paths.get(path + ".MD5"))) {
+            Files.move(Paths.get(path + ".MD5"),
+                    Paths.get(jobConfig.getCarWuDanYongCheHistoryPath(), path.getFileName().toString() + ".MD5"),
+                    StandardCopyOption.REPLACE_EXISTING);
+        }
+        Files.move(path, Paths.get(jobConfig.getCarWuDanYongCheHistoryPath(), path.getFileName().toString()),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}

+ 293 - 0
src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarYongCheDayTask.java

@@ -0,0 +1,293 @@
+package com.nokia.finance.tasks.jobs.car.rx;
+
+import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+import com.nokia.finance.tasks.config.JobConfig;
+import com.nokia.finance.tasks.enums.DataStageEnum;
+import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+import com.nokia.finance.tasks.service.car.CarService;
+import com.nokia.finance.tasks.service.common.AreaService;
+import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+import com.nokia.finance.tasks.service.common.OrganizationService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+/**
+ * 睿行车辆用车日统计数据入库定时任务
+ */
+@Slf4j
+@Service
+public class CarYongCheDayTask {
+    private final JobConfig jobConfig;
+    private final CarService carService;
+    private final OrganizationService organizationService;
+    private final AreaService areaService;
+    private final DataLogServiceImpl dataLogService;
+
+    public CarYongCheDayTask(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+                             AreaService areaService, DataLogServiceImpl dataLogService) {
+        this.jobConfig = jobConfig;
+        this.carService = carService;
+        this.organizationService = organizationService;
+        this.areaService = areaService;
+        this.dataLogService = dataLogService;
+    }
+
+    /**
+     * 执行任务
+     */
+    @Scheduled(cron = "0 48 22 * * ?")
+    public void runJob() {
+        List<DataLogPo> dataLogPoList = new ArrayList<>();
+        // 数据目录
+        Path dir = Paths.get(jobConfig.getCarYongCheDaySourcePath());
+        try (Stream<Path> stream = Files.list(dir)) {
+            // 获取数据目录下的文件列表
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
+            log.info("睿行车辆用车日统计数据文件列表: {}", pathList);
+            if (CollectionUtils.isEmpty(pathList)) {
+                throw new MyRuntimeException("睿行车辆用车日统计数据没有文件");
+            }
+            Files.createDirectories(Paths.get(jobConfig.getCarYongCheDayHistoryPath()));
+            for (Path path : pathList) {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        singleJob(path, dataLogPoList);
+                    } catch (Exception e) {
+                        throw new MyRuntimeException(e);
+                    }
+                }).get(1, TimeUnit.MINUTES);
+            }
+        } catch (InterruptedException e) {
+            log.error("线程中断: {}", e, e);
+            Thread.currentThread().interrupt();
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆用车日统计数据", DataStageEnum.CC, "入库");
+        } catch (Exception e) {
+            log.error(e.toString(), e);
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆用车日统计数据", DataStageEnum.CC, "入库");
+        } finally {
+            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+                dataLogService.saveBatch(dataLogPoList);
+            }
+        }
+    }
+
+    /**
+     * 处理单个文件
+     *
+     * @param path          文件路径
+     * @param dataLogPoList 数据处理日志列表
+     */
+    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+        DataLogPo dataLogPo = new DataLogPo();
+        dataLogPo.setDataName("睿行车辆用车日统计数据");
+        dataLogPo.setObject(path.getFileName().toString());
+        dataLogPo.setStage(DataStageEnum.CC.value);
+        dataLogPo.setOperationName("入库");
+        long fileSize = Files.size(path);
+        dataLogPo.setDataSize(fileSize);
+        dataLogPoList.add(dataLogPo);
+        if (fileSize == 0) {
+            move(path);
+            log.error("{} 空文件", path.getFileName());
+            return;
+        }
+        List<Map<String, String>> list = readFile(path);
+        List<Map<String, String>> distinctList = dataProcessing(path, list);
+        dataLogPo.setDataCount(distinctList.size());
+        Path csvPath = toCsv(path, distinctList);
+        copyCsv(csvPath);
+        move(path);
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param path 文件路径
+     */
+    public List<Map<String, String>> readFile(Path path) throws IOException {
+        log.info("读取: {}", path);
+        List<String> headers = Stream.of(
+                "month_id", "day_id", "shen_qing_dan_hao", "pai_qian_dan_hao", "shen_qing_lei_xing",
+                "che_pai_hao", "che_liang_lei_xing", "che_liang_ji_bie", "si_ji_ming_cheng", "yong_che_ren",
+                "yong_che_bu_men", "yong_che_shi_you", "chu_fa_di", "mu_di_di", "chu_fa_shi_jian", "gui_dui_shi_jian",
+                "xing_shi_li_cheng", "chu_che_shi_chang").toList();
+        int headerSize = headers.size();
+        char delimiter = 1;
+        try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+        ) {
+            List<Map<String, String>> resultList = new ArrayList<>();
+            for (CSVRecord csvRecord : parser) {
+                Map<String, String> rowMap = new LinkedHashMap<>();
+                for (int i = 0; i < headerSize; i++) {
+                    String header = headers.get(i);
+                    String value = csvRecord.get(i);
+                    boolean skipTrim = "chu_fa_shi_jian".equals(header)
+                            || "gui_dui_shi_jian".equals(header);
+                    // 删除字符串空白字符
+                    value = skipTrim ? value
+                            : StringUtils.trimAllWhitespace(value);
+                    rowMap.put(header, value);
+                }
+                resultList.add(rowMap);
+            }
+            if (CollectionUtils.isEmpty(resultList)) {
+                move(path);
+                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+            }
+            return resultList;
+        }
+    }
+
+    /**
+     * 数据加工
+     *
+     * @param path 文件路径
+     * @param list 数据
+     */
+    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+        List<AreaPo> cities = areaService.getCities();
+        List<AreaPo> districts = areaService.getDistricts();
+        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+        for (Map<String, String> map : list) {
+            String monthId = map.get("month_id");
+            LocalDate localDate = LocalDate.parse(monthId + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
+            String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            String year = String.valueOf(localDate.getYear());
+            String month = String.valueOf(localDate.getMonthValue());
+            map.put("year_month", yearMonth);
+            map.put("year_no", year);
+            map.put("month_no", month);
+            String rawChePaiHao = map.get("che_pai_hao");
+            map.put("raw_che_pai_hao", rawChePaiHao);
+            String chePaiHao = carService.getChePai(rawChePaiHao);
+            map.put("che_pai_hao", chePaiHao);
+            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+            map.put("che_pai_fail", chePaiFail);
+            String cheLiangSuoShuDanWei = map.get("yong_che_bu_men");
+            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+            String firstUnit = carService.getFirstUnit(carUnitBo);
+            if (!StringUtils.hasText(firstUnit)) {
+                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+            }
+            map.put("first_unit", firstUnit);
+            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+            map.put("second_unit", secondUnit);
+            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+            map.put("third_unit", thirdUnit);
+            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+            map.put("area_no", areaNo);
+            String areaName = carService.getOrgName(orgMap, areaNo);
+            map.put("area_name", areaName);
+            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+            map.put("city_no", cityNo);
+            String cityName = carService.getOrgName(orgMap, cityNo);
+            map.put("city_name", cityName);
+            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+            map.put("area_no2", areaNo2);
+            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+            map.put("area_name2", areaName2);
+            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+            map.put("city_id", cityId);
+            String city = carService.getAreaName(areaMap, cityId);
+            map.put("city", city);
+            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+            map.put("district_id", districtId);
+            String district = carService.getAreaName(areaMap, districtId);
+            map.put("district", district);
+            String baoFei = carService.baoFei(rawChePaiHao);
+            map.put("bao_fei", baoFei);
+            map.put("source", path.getFileName().toString());
+        }
+        return list;
+    }
+
+    /**
+     * 生成csv
+     *
+     * @param path 源文件路径
+     * @param list 数据
+     */
+    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+        log.info("去重后条数条数:{}", list.size());
+        Path csvPath = Paths.get(jobConfig.getCarYongCheDayHistoryPath() + path.getFileName() + ".csv");
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+                StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            Map<String, String> header = list.get(0);
+            // 表头
+            printer.printRecord(header.keySet());
+            for (Map<String, String> map : list) {
+                printer.printRecord(map.values());
+            }
+        }
+        return csvPath;
+    }
+
+    /**
+     * 导入数据库
+     *
+     * @param path 文件路径
+     */
+    public void copyCsv(Path path) {
+        String dbTable = "car.car_yong_che_day";
+        String csv = path.toString();
+        String columns = "(month_id,day_id,shen_qing_dan_hao,pai_qian_dan_hao,shen_qing_lei_xing,che_pai_hao,che_liang_lei_xing,che_liang_ji_bie,si_ji_ming_cheng,yong_che_ren,yong_che_bu_men,yong_che_shi_you,chu_fa_di,mu_di_di,chu_fa_shi_jian,gui_dui_shi_jian,xing_shi_li_cheng,chu_che_shi_chang,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+        Long timeout = 60000L;
+        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+                timeout, null);
+    }
+
+    /**
+     * 移动源文件到历史文件夹
+     *
+     * @param path 源文件路径
+     */
+    public void move(Path path) throws IOException {
+        if (Files.exists(Paths.get(path + ".MD5"))) {
+            Files.move(Paths.get(path + ".MD5"),
+                    Paths.get(jobConfig.getCarYongCheDayHistoryPath(), path.getFileName().toString() + ".MD5"),
+                    StandardCopyOption.REPLACE_EXISTING);
+        }
+        Files.move(path, Paths.get(jobConfig.getCarYongCheDayHistoryPath(), path.getFileName().toString()),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}

+ 293 - 0
src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarYongCheMonthTask.java

@@ -0,0 +1,293 @@
+package com.nokia.finance.tasks.jobs.car.rx;
+
+import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+import com.nokia.finance.tasks.config.JobConfig;
+import com.nokia.finance.tasks.enums.DataStageEnum;
+import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+import com.nokia.finance.tasks.service.car.CarService;
+import com.nokia.finance.tasks.service.common.AreaService;
+import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+import com.nokia.finance.tasks.service.common.OrganizationService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+/**
+ * 睿行车辆用车月统计数据入库定时任务
+ */
+@Slf4j
+@Service
+public class CarYongCheMonthTask {
+    private final JobConfig jobConfig;
+    private final CarService carService;
+    private final OrganizationService organizationService;
+    private final AreaService areaService;
+    private final DataLogServiceImpl dataLogService;
+
+    public CarYongCheMonthTask(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+                               AreaService areaService, DataLogServiceImpl dataLogService) {
+        this.jobConfig = jobConfig;
+        this.carService = carService;
+        this.organizationService = organizationService;
+        this.areaService = areaService;
+        this.dataLogService = dataLogService;
+    }
+
+    /**
+     * 执行任务
+     */
+    @Scheduled(cron = "0 36 22 1 * ?")
+    public void runJob() {
+        List<DataLogPo> dataLogPoList = new ArrayList<>();
+        // 数据目录
+        Path dir = Paths.get(jobConfig.getCarYongCheSourcePath());
+        try (Stream<Path> stream = Files.list(dir)) {
+            // 获取数据目录下的文件列表
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
+            log.info("睿行车辆用车月统计数据文件列表: {}", pathList);
+            if (CollectionUtils.isEmpty(pathList)) {
+                throw new MyRuntimeException("睿行车辆用车月统计数据没有文件");
+            }
+            Files.createDirectories(Paths.get(jobConfig.getCarYongCheHistoryPath()));
+            for (Path path : pathList) {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        singleJob(path, dataLogPoList);
+                    } catch (Exception e) {
+                        throw new MyRuntimeException(e);
+                    }
+                }).get(1, TimeUnit.MINUTES);
+            }
+        } catch (InterruptedException e) {
+            log.error("线程中断: {}", e, e);
+            Thread.currentThread().interrupt();
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆用车月统计数据", DataStageEnum.CC, "入库");
+        } catch (Exception e) {
+            log.error(e.toString(), e);
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆用车月统计数据", DataStageEnum.CC, "入库");
+        } finally {
+            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+                dataLogService.saveBatch(dataLogPoList);
+            }
+        }
+    }
+
+    /**
+     * 处理单个文件
+     *
+     * @param path          文件路径
+     * @param dataLogPoList 数据处理日志列表
+     */
+    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+        DataLogPo dataLogPo = new DataLogPo();
+        dataLogPo.setDataName("睿行车辆用车月统计数据");
+        dataLogPo.setObject(path.getFileName().toString());
+        dataLogPo.setStage(DataStageEnum.CC.value);
+        dataLogPo.setOperationName("入库");
+        long fileSize = Files.size(path);
+        dataLogPo.setDataSize(fileSize);
+        dataLogPoList.add(dataLogPo);
+        if (fileSize == 0) {
+            move(path);
+            log.error("{} 空文件", path.getFileName());
+            return;
+        }
+        List<Map<String, String>> list = readFile(path);
+        List<Map<String, String>> distinctList = dataProcessing(path, list);
+        dataLogPo.setDataCount(distinctList.size());
+        Path csvPath = toCsv(path, distinctList);
+        copyCsv(csvPath);
+        move(path);
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param path 文件路径
+     */
+    public List<Map<String, String>> readFile(Path path) throws IOException {
+        log.info("读取: {}", path);
+        List<String> headers = Stream.of(
+                "month_id", "shen_qing_dan_hao", "pai_qian_dan_hao", "shen_qing_lei_xing",
+                "che_pai_hao", "che_liang_lei_xing", "che_liang_ji_bie", "si_ji_ming_cheng", "yong_che_ren",
+                "yong_che_bu_men", "yong_che_shi_you", "chu_fa_di", "mu_di_di", "chu_fa_shi_jian", "gui_dui_shi_jian",
+                "xing_shi_li_cheng", "chu_che_shi_chang").toList();
+        int headerSize = headers.size();
+        char delimiter = 1;
+        try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+        ) {
+            List<Map<String, String>> resultList = new ArrayList<>();
+            for (CSVRecord csvRecord : parser) {
+                Map<String, String> rowMap = new LinkedHashMap<>();
+                for (int i = 0; i < headerSize; i++) {
+                    String header = headers.get(i);
+                    String value = csvRecord.get(i);
+                    boolean skipTrim = "chu_fa_shi_jian".equals(header)
+                            || "gui_dui_shi_jian".equals(header);
+                    // 删除字符串空白字符
+                    value = skipTrim ? value
+                            : StringUtils.trimAllWhitespace(value);
+                    rowMap.put(header, value);
+                }
+                resultList.add(rowMap);
+            }
+            if (CollectionUtils.isEmpty(resultList)) {
+                move(path);
+                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+            }
+            return resultList;
+        }
+    }
+
+    /**
+     * 数据加工
+     *
+     * @param path 文件路径
+     * @param list 数据
+     */
+    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+        List<AreaPo> cities = areaService.getCities();
+        List<AreaPo> districts = areaService.getDistricts();
+        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+        for (Map<String, String> map : list) {
+            String monthId = map.get("month_id");
+            LocalDate localDate = LocalDate.parse(monthId + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
+            String yearMonth = localDate.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            String year = String.valueOf(localDate.getYear());
+            String month = String.valueOf(localDate.getMonthValue());
+            map.put("year_month", yearMonth);
+            map.put("year_no", year);
+            map.put("month_no", month);
+            String rawChePaiHao = map.get("che_pai_hao");
+            map.put("raw_che_pai_hao", rawChePaiHao);
+            String chePaiHao = carService.getChePai(rawChePaiHao);
+            map.put("che_pai_hao", chePaiHao);
+            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+            map.put("che_pai_fail", chePaiFail);
+            String cheLiangSuoShuDanWei = map.get("yong_che_bu_men");
+            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+            String firstUnit = carService.getFirstUnit(carUnitBo);
+            if (!StringUtils.hasText(firstUnit)) {
+                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+            }
+            map.put("first_unit", firstUnit);
+            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+            map.put("second_unit", secondUnit);
+            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+            map.put("third_unit", thirdUnit);
+            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+            map.put("area_no", areaNo);
+            String areaName = carService.getOrgName(orgMap, areaNo);
+            map.put("area_name", areaName);
+            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+            map.put("city_no", cityNo);
+            String cityName = carService.getOrgName(orgMap, cityNo);
+            map.put("city_name", cityName);
+            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+            map.put("area_no2", areaNo2);
+            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+            map.put("area_name2", areaName2);
+            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+            map.put("city_id", cityId);
+            String city = carService.getAreaName(areaMap, cityId);
+            map.put("city", city);
+            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+            map.put("district_id", districtId);
+            String district = carService.getAreaName(areaMap, districtId);
+            map.put("district", district);
+            String baoFei = carService.baoFei(rawChePaiHao);
+            map.put("bao_fei", baoFei);
+            map.put("source", path.getFileName().toString());
+        }
+        return list;
+    }
+
+    /**
+     * 生成csv
+     *
+     * @param path 源文件路径
+     * @param list 数据
+     */
+    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+        log.info("去重后条数条数:{}", list.size());
+        Path csvPath = Paths.get(jobConfig.getCarYongCheHistoryPath() + path.getFileName() + ".csv");
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+                StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            Map<String, String> header = list.get(0);
+            // 表头
+            printer.printRecord(header.keySet());
+            for (Map<String, String> map : list) {
+                printer.printRecord(map.values());
+            }
+        }
+        return csvPath;
+    }
+
+    /**
+     * 导入数据库
+     *
+     * @param path 文件路径
+     */
+    public void copyCsv(Path path) {
+        String dbTable = "car.car_yong_che";
+        String csv = path.toString();
+        String columns = "(month_id,shen_qing_dan_hao,pai_qian_dan_hao,shen_qing_lei_xing,che_pai_hao,che_liang_lei_xing,che_liang_ji_bie,si_ji_ming_cheng,yong_che_ren,yong_che_bu_men,yong_che_shi_you,chu_fa_di,mu_di_di,chu_fa_shi_jian,gui_dui_shi_jian,xing_shi_li_cheng,chu_che_shi_chang,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+        Long timeout = 60000L;
+        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+                timeout, null);
+    }
+
+    /**
+     * 移动源文件到历史文件夹
+     *
+     * @param path 源文件路径
+     */
+    public void move(Path path) throws IOException {
+        if (Files.exists(Paths.get(path + ".MD5"))) {
+            Files.move(Paths.get(path + ".MD5"),
+                    Paths.get(jobConfig.getCarYongCheHistoryPath(), path.getFileName().toString() + ".MD5"),
+                    StandardCopyOption.REPLACE_EXISTING);
+        }
+        Files.move(path, Paths.get(jobConfig.getCarYongCheHistoryPath(), path.getFileName().toString()),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}

+ 307 - 0
src/main/java/com/nokia/finance/tasks/jobs/car/rx/CarYueJieDayTask.java

@@ -0,0 +1,307 @@
+package com.nokia.finance.tasks.jobs.car.rx;
+
+import com.nokia.finance.tasks.common.exception.MyRuntimeException;
+import com.nokia.finance.tasks.common.utils.psql.PsqlUtil;
+import com.nokia.finance.tasks.config.JobConfig;
+import com.nokia.finance.tasks.enums.DataStageEnum;
+import com.nokia.finance.tasks.pojo.bo.car.CarUnitBo;
+import com.nokia.finance.tasks.pojo.po.common.AreaPo;
+import com.nokia.finance.tasks.pojo.po.common.DataLogPo;
+import com.nokia.finance.tasks.pojo.po.common.OrganizationPo;
+import com.nokia.finance.tasks.service.car.CarService;
+import com.nokia.finance.tasks.service.common.AreaService;
+import com.nokia.finance.tasks.service.common.DataLogServiceImpl;
+import com.nokia.finance.tasks.service.common.OrganizationService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.commons.csv.CSVRecord;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+/**
+ * 睿行车辆越界报警日数据入库定时任务
+ */
+@Slf4j
+@Service
+public class CarYueJieDayTask {
+    private final JobConfig jobConfig;
+    private final CarService carService;
+    private final OrganizationService organizationService;
+    private final AreaService areaService;
+    private final DataLogServiceImpl dataLogService;
+
+    public CarYueJieDayTask(JobConfig jobConfig, CarService carService, OrganizationService organizationService,
+                            AreaService areaService, DataLogServiceImpl dataLogService) {
+        this.jobConfig = jobConfig;
+        this.carService = carService;
+        this.organizationService = organizationService;
+        this.areaService = areaService;
+        this.dataLogService = dataLogService;
+    }
+
+    /**
+     * 执行任务
+     */
+    @Scheduled(cron = "0 42 22 * * ?")
+    public void runJob() {
+        List<DataLogPo> dataLogPoList = new ArrayList<>();
+        // 数据目录
+        Path dir = Paths.get(jobConfig.getCarYueJieSourcePath());
+        try (Stream<Path> stream = Files.list(dir)) {
+            // 获取数据目录下的文件列表
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
+            log.info("睿行车辆越界报警日数据文件列表: {}", pathList);
+            if (CollectionUtils.isEmpty(pathList)) {
+                throw new MyRuntimeException("睿行车辆越界报警日数据没有文件");
+            }
+            Files.createDirectories(Paths.get(jobConfig.getCarYueJieHistoryPath()));
+            for (Path path : pathList) {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        singleJob(path, dataLogPoList);
+                    } catch (Exception e) {
+                        throw new MyRuntimeException(e);
+                    }
+                }).get(1, TimeUnit.MINUTES);
+            }
+        } catch (InterruptedException e) {
+            log.error("线程中断: {}", e, e);
+            Thread.currentThread().interrupt();
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆越界报警日数据", DataStageEnum.CC, "入库");
+        } catch (Exception e) {
+            log.error(e.toString(), e);
+            DataLogPo.addExceptionInfo(dataLogPoList, e, "睿行车辆越界报警日数据", DataStageEnum.CC, "入库");
+        } finally {
+            if (!CollectionUtils.isEmpty(dataLogPoList)) {
+                dataLogService.saveBatch(dataLogPoList);
+            }
+        }
+    }
+
+    /**
+     * 处理单个文件
+     *
+     * @param path          文件路径
+     * @param dataLogPoList 数据处理日志列表
+     */
+    public void singleJob(Path path, List<DataLogPo> dataLogPoList) throws IOException {
+        DataLogPo dataLogPo = new DataLogPo();
+        dataLogPo.setDataName("睿行车辆越界报警日数据");
+        dataLogPo.setObject(path.getFileName().toString());
+        dataLogPo.setStage(DataStageEnum.CC.value);
+        dataLogPo.setOperationName("入库");
+        long fileSize = Files.size(path);
+        dataLogPo.setDataSize(fileSize);
+        dataLogPoList.add(dataLogPo);
+        if (fileSize == 0) {
+            move(path);
+            log.error("{} 空文件", path.getFileName());
+            return;
+        }
+        List<Map<String, String>> list = readFile(path);
+        List<Map<String, String>> distinctList = dataProcessing(path, list);
+        dataLogPo.setDataCount(distinctList.size());
+        Path csvPath = toCsv(path, distinctList);
+        copyCsv(csvPath);
+        move(path);
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param path 文件路径
+     */
+    public List<Map<String, String>> readFile(Path path) throws IOException {
+        log.info("读取: {}", path);
+        List<String> headers = Stream.of(
+                "month_id", "day_id", "che_liang_suo_shu_dan_wei", "che_pai_hao", "che_liang_lei_xing",
+                "che_liang_shi_yong_xing_zhi", "bao_jing_qu_yu_miao_shu", "bao_jing_gui_ze_miao_shu",
+                "yue_jie_shi_jian", "shi_fou_zhi_xing_zhong_yue_jie", "xiang_qing").toList();
+        int headerSize = headers.size();
+        char delimiter = 1;
+        try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+        ) {
+            List<Map<String, String>> resultList = new ArrayList<>();
+            for (CSVRecord csvRecord : parser) {
+                Map<String, String> rowMap = new LinkedHashMap<>();
+                for (int i = 0; i < headerSize; i++) {
+                    String header = headers.get(i);
+                    String value = csvRecord.get(i);
+                    boolean skipTrim = "yue_jie_shi_jian".equals(header);
+                    // 删除空白字符
+                    value = skipTrim ? value
+                            : StringUtils.trimAllWhitespace(value);
+                    rowMap.put(header, value);
+                }
+                resultList.add(rowMap);
+            }
+            if (CollectionUtils.isEmpty(resultList)) {
+                move(path);
+                throw new MyRuntimeException(path.getFileName() + " 数据0条");
+            }
+            return resultList;
+        }
+    }
+
+    /**
+     * 数据加工
+     *
+     * @param path 文件路径
+     * @param list 数据
+     */
+    public List<Map<String, String>> dataProcessing(Path path, List<Map<String, String>> list) {
+        List<OrganizationPo> secondOrgs = organizationService.getSecondOrgs();
+        List<OrganizationPo> thirdOrgs = organizationService.getThirdOrgs();
+        Map<String, OrganizationPo> orgMap = organizationService.getOrgMap(secondOrgs, thirdOrgs);
+        Map<String, List<OrganizationPo>> thirdOrganizationListMap =
+                organizationService.getThirdOrganizationListMap(secondOrgs, thirdOrgs);
+        List<AreaPo> cities = areaService.getCities();
+        List<AreaPo> districts = areaService.getDistricts();
+        Map<String, AreaPo> areaMap = areaService.getAreaMap(cities, districts);
+        Map<String, List<AreaPo>> districtListMap = areaService.getDistrictListMap(cities, districts);
+        for (Map<String, String> map : list) {
+            String yueJieShiJian = map.get("yue_jie_shi_jian");
+            LocalDateTime localDateTime = LocalDateTime.parse(yueJieShiJian,
+                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+            String dataDate = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+            String yearMonth = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMM"));
+            String year = String.valueOf(localDateTime.getYear());
+            String month = String.valueOf(localDateTime.getMonthValue());
+            map.put("data_date", dataDate);
+            map.put("year_month", yearMonth);
+            map.put("year_no", year);
+            map.put("month_no", month);
+            String rawChePaiHao = map.get("che_pai_hao");
+            map.put("raw_che_pai_hao", rawChePaiHao);
+            String chePaiHao = carService.getChePai(rawChePaiHao);
+            map.put("che_pai_hao", chePaiHao);
+            String chePaiFail = carService.chePaiFail(rawChePaiHao);
+            map.put("che_pai_fail", chePaiFail);
+            String cheLiangSuoShuDanWei = map.get("che_liang_suo_shu_dan_wei");
+            CarUnitBo carUnitBo = carService.getCarUnitBo(cheLiangSuoShuDanWei);
+            String firstUnit = carService.getFirstUnit(carUnitBo);
+            if (!StringUtils.hasText(firstUnit)) {
+                throw new MyRuntimeException("车辆单位错误:" + rawChePaiHao + " " + cheLiangSuoShuDanWei);
+            }
+            map.put("first_unit", firstUnit);
+            String secondUnit = carService.getSecondUnit(carUnitBo, firstUnit);
+            map.put("second_unit", secondUnit);
+            String thirdUnit = carService.getThirdUnit(carUnitBo, secondUnit);
+            map.put("third_unit", thirdUnit);
+            String areaNo = carService.getAreaNo(secondOrgs, firstUnit);
+            map.put("area_no", areaNo);
+            String areaName = carService.getOrgName(orgMap, areaNo);
+            map.put("area_name", areaName);
+            String cityNo = carService.getCityNo(thirdOrganizationListMap, areaNo, areaName, carUnitBo);
+            map.put("city_no", cityNo);
+            String cityName = carService.getOrgName(orgMap, cityNo);
+            map.put("city_name", cityName);
+            String areaNo2 = carService.getAreaNo2(areaName, cityName);
+            map.put("area_no2", areaNo2);
+            String areaName2 = carService.getOrgName(orgMap, areaNo2);
+            map.put("area_name2", areaName2);
+            String cityId = carService.getCityId(cities, cheLiangSuoShuDanWei);
+            map.put("city_id", cityId);
+            String city = carService.getAreaName(areaMap, cityId);
+            map.put("city", city);
+            String districtId = carService.getDistrictId(districtListMap, cityId, cityName, cheLiangSuoShuDanWei);
+            map.put("district_id", districtId);
+            String district = carService.getAreaName(areaMap, districtId);
+            map.put("district", district);
+            String baoFei = carService.baoFei(rawChePaiHao);
+            map.put("bao_fei", baoFei);
+            map.put("source", path.getFileName().toString());
+        }
+        // 去重
+        return list.stream().filter(distinctByKey(map -> map.get("che_pai_hao") + map.get("yue_jie_shi_jian"))).toList();
+    }
+
+    /**
+     * 去重
+     */
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Set<Object> set = ConcurrentHashMap.newKeySet();
+        return t -> set.add(keyExtractor.apply(t));
+    }
+
+    /**
+     * 生成csv
+     *
+     * @param path 源文件路径
+     * @param list 数据
+     */
+    public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
+        log.info("去重后条数条数:{}", list.size());
+        Path csvPath = Paths.get(jobConfig.getCarYueJieHistoryPath() + path.getFileName() + ".csv");
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
+                StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)) {
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            Map<String, String> header = list.get(0);
+            // 表头
+            printer.printRecord(header.keySet());
+            for (Map<String, String> map : list) {
+                printer.printRecord(map.values());
+            }
+        }
+        return csvPath;
+    }
+
+    /**
+     * 导入数据库
+     *
+     * @param path 文件路径
+     */
+    public void copyCsv(Path path) {
+        String dbTable = "car.car_yue_jie";
+        String csv = path.toString();
+        String columns = "(month_id,day_id,che_liang_suo_shu_dan_wei,che_pai_hao,che_liang_lei_xing,che_liang_shi_yong_xing_zhi,bao_jing_qu_yu_miao_shu,bao_jing_gui_ze_miao_shu,yue_jie_shi_jian,shi_fou_zhi_xing_zhong_yue_jie,xiang_qing,data_date,year_month,year_no,month_no,raw_che_pai_hao,che_pai_fail,first_unit,second_unit,third_unit,area_no,area_name,city_no,city_name,area_no2,area_name2,city_id,city,district_id,district,bao_fei,source)";
+        Long timeout = 60000L;
+        PsqlUtil.copyCsv(jobConfig.getCopyScriptPath(), jobConfig.getDbHost(), jobConfig.getDbPort(),
+                jobConfig.getDbUsername(), jobConfig.getDbPassword(), jobConfig.getDbName(), dbTable, csv, columns,
+                timeout, null);
+    }
+
+    /**
+     * 移动源文件到历史文件夹
+     *
+     * @param path 源文件路径
+     */
+    public void move(Path path) throws IOException {
+        if (Files.exists(Paths.get(path + ".MD5"))) {
+            Files.move(Paths.get(path + ".MD5"),
+                    Paths.get(jobConfig.getCarYueJieHistoryPath(), path.getFileName().toString() + ".MD5"),
+                    StandardCopyOption.REPLACE_EXISTING);
+        }
+        Files.move(path, Paths.get(jobConfig.getCarYueJieHistoryPath(), path.getFileName().toString()),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}

+ 16 - 4
src/main/java/com/nokia/finance/tasks/jobs/car/shujucangku/CarFeeBsJob.java

@@ -60,11 +60,12 @@ public class CarFeeBsJob {
         Path dir = Paths.get(jobConfig.getCarFeeBsSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北价值管理平台北十车辆费用月数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北价值管理平台北十车辆费用月数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarFeeBsHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -105,7 +106,8 @@ public class CarFeeBsJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -127,7 +129,11 @@ public class CarFeeBsJob {
         int headerSize = headers.size();
         char delimiter = 1;
         try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
-                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8));
+             OutputStreamWriter osw = new OutputStreamWriter(
+                     Files.newOutputStream(Paths.get(jobConfig.getTempOutputDir() + path.getFileName() + ".csv")),
+                     StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)
         ) {
             List<Map<String, String>> resultList = new ArrayList<>();
             for (CSVRecord csvRecord : parser) {
@@ -145,6 +151,13 @@ public class CarFeeBsJob {
                 move(path);
                 throw new MyRuntimeException(path.getFileName() + " 数据0条");
             }
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            // 表头
+            printer.printRecord(headers);
+            for (Map<String, String> map : resultList) {
+                printer.printRecord(map.values());
+            }
             return resultList;
         }
     }
@@ -180,7 +193,6 @@ public class CarFeeBsJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarFeeBsHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getCarFeeBsHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 16 - 4
src/main/java/com/nokia/finance/tasks/jobs/car/shujucangku/CarFeeHbJob.java

@@ -68,11 +68,12 @@ public class CarFeeHbJob {
         Path dir = Paths.get(jobConfig.getCarFeeHbSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北价值管理平台省内车辆费用月数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北价值管理平台省内车辆费用月数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getCarFeeHbHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -113,7 +114,8 @@ public class CarFeeHbJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -135,7 +137,11 @@ public class CarFeeHbJob {
         int headerSize = headers.size();
         char delimiter = 1;
         try (CSVParser parser = CSVFormat.DEFAULT.builder().setDelimiter(delimiter).build()
-                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
+                .parse(new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8));
+             OutputStreamWriter osw = new OutputStreamWriter(
+                     Files.newOutputStream(Paths.get(jobConfig.getTempOutputDir() + path.getFileName() + ".csv")),
+                     StandardCharsets.UTF_8);
+             CSVPrinter printer = new CSVPrinter(osw, CSVFormat.DEFAULT)
         ) {
             List<Map<String, String>> resultList = new ArrayList<>();
             for (CSVRecord csvRecord : parser) {
@@ -153,6 +159,13 @@ public class CarFeeHbJob {
                 move(path);
                 throw new MyRuntimeException(path.getFileName() + " 数据0条");
             }
+            // 添加bom头避免excel乱码
+            osw.write('\ufeff');
+            // 表头
+            printer.printRecord(headers);
+            for (Map<String, String> map : resultList) {
+                printer.printRecord(map.values());
+            }
             return resultList;
         }
     }
@@ -213,7 +226,6 @@ public class CarFeeHbJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getCarFeeHbHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getCarFeeHbHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 4 - 3
src/main/java/com/nokia/finance/tasks/jobs/house/chengben/HouseBuildingRepairMonthJob.java

@@ -60,11 +60,12 @@ public class HouseBuildingRepairMonthJob {
         Path dir = Paths.get(jobConfig.getHouseBuildingRepairMonthSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统自有类房产维修数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统自有类房产维修数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getHouseBuildingRepairMonthHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -105,7 +106,8 @@ public class HouseBuildingRepairMonthJob {
         dataLogPoList.add(dataLogPo);
         if (fileSize == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         List<Map<String, String>> list = readFile(path);
         List<Map<String, String>> distinctList = dataProcessing(path, list);
@@ -204,7 +206,6 @@ public class HouseBuildingRepairMonthJob {
      */
     public Path toCsv(Path path, List<Map<String, String>> list) throws IOException {
         log.info("条数:{}", list.size());
-        Files.createDirectories(Paths.get(jobConfig.getHouseBuildingRepairMonthHistoryPath()));
         Path csvPath = Paths.get(jobConfig.getHouseBuildingRepairMonthHistoryPath() + path.getFileName() + ".csv");
         try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(csvPath),
                 StandardCharsets.UTF_8);

+ 4 - 2
src/main/java/com/nokia/finance/tasks/jobs/house/chengben/HouseRentInRepairMonthJob.java

@@ -38,11 +38,12 @@ public class HouseRentInRepairMonthJob {
         Path dir = Paths.get(jobConfig.getHouseRentInRepairMonthSourcePath());
         try (Stream<Path> stream = Files.list(dir)) {
             // 获取数据目录下的文件列表
-            List<Path> pathList = stream.filter(t -> !t.toString().endsWith(".MD5")).sorted().toList();
+            List<Path> pathList = stream.filter(t -> !t.toString().toLowerCase().endsWith(".md5") && !t.toString().toLowerCase().endsWith(".dat")).sorted().toList();
             log.info("河北成本管理系统不动产租赁房产维修数据文件列表: {}", pathList);
             if (CollectionUtils.isEmpty(pathList)) {
                 throw new MyRuntimeException("河北成本管理系统不动产租赁房产维修数据没有文件");
             }
+            Files.createDirectories(Paths.get(jobConfig.getHouseRentInRepairMonthHistoryPath()));
             for (Path path : pathList) {
                 CompletableFuture.runAsync(() -> {
                     try {
@@ -68,7 +69,8 @@ public class HouseRentInRepairMonthJob {
     public void singleJob(Path path) throws IOException {
         if (Files.size(path) == 0) {
             move(path);
-            throw new MyRuntimeException(path.getFileName() + " 空文件");
+            log.error("{} 空文件", path.getFileName());
+            return;
         }
         move(path);
     }

+ 27 - 21
src/main/java/com/nokia/finance/tasks/service/JobService.java

@@ -13,13 +13,15 @@ import com.nokia.finance.tasks.jobs.car.chengben.CarSiCheGongYongJob;
 import com.nokia.finance.tasks.jobs.car.chengben.CarWeiXiuJob;
 import com.nokia.finance.tasks.jobs.car.chengben.CarZuLinJob;
 import com.nokia.finance.tasks.jobs.car.cxdp.CarCxdpJob;
-import com.nokia.finance.tasks.jobs.car.ruixing.CarBaoFeiJob;
-import com.nokia.finance.tasks.jobs.car.ruixing.CarBaseDataDayJob;
-import com.nokia.finance.tasks.jobs.car.ruixing.CarLiChengDayJob;
-import com.nokia.finance.tasks.jobs.car.ruixing.CarLiChengMonthJob;
-import com.nokia.finance.tasks.jobs.car.ruixing.CarWuDanYongCheJob;
-import com.nokia.finance.tasks.jobs.car.ruixing.CarYongCheJob;
-import com.nokia.finance.tasks.jobs.car.ruixing.CarYueJieJob;
+import com.nokia.finance.tasks.jobs.car.rx.CarBaoFeiMonthTask;
+import com.nokia.finance.tasks.jobs.car.rx.CarBaseDataDayTask;
+import com.nokia.finance.tasks.jobs.car.rx.CarLiChengDayTask;
+import com.nokia.finance.tasks.jobs.car.rx.CarLiChengMonthTask;
+import com.nokia.finance.tasks.jobs.car.rx.CarWuDanYongCheDayTask;
+import com.nokia.finance.tasks.jobs.car.rx.CarWuDanYongCheMonthTask;
+import com.nokia.finance.tasks.jobs.car.rx.CarYongCheDayTask;
+import com.nokia.finance.tasks.jobs.car.rx.CarYongCheMonthTask;
+import com.nokia.finance.tasks.jobs.car.rx.CarYueJieDayTask;
 import com.nokia.finance.tasks.jobs.car.shujucangku.CarFeeBsJob;
 import com.nokia.finance.tasks.jobs.car.shujucangku.CarFeeHbJob;
 import com.nokia.finance.tasks.jobs.car.strategy.CarHighFuelConsumptionJob;
@@ -49,12 +51,6 @@ import java.time.format.DateTimeFormatter;
 @RequiredArgsConstructor
 @Service
 public class JobService {
-    private final CarBaseDataDayJob carBaseDataDayJob;
-    private final CarYueJieJob carYueJieJob;
-    private final CarBaoFeiJob carBaoFeiJob;
-    private final CarLiChengMonthJob carLiChengMonthJob;
-    private final CarWuDanYongCheJob carWuDanYongCheJob;
-    private final CarYongCheJob carYongCheJob;
     private final CarRanYouJob carRanYouJob;
     private final CarDaWeiXiuJob carDaWeiXiuJob;
     private final CarWeiXiuJob carWeiXiuJob;
@@ -65,7 +61,6 @@ public class JobService {
     private final CarFeeHbJob carFeeHbJob;
     private final CarFeeBsJob carFeeBsJob;
     private final HouseBuildingRepairMonthJob houseBuildingRepairMonthJob;
-    private final CarLiChengDayJob carLiChengDayJob;
     private final CarSiCheGongYongJob carSiCheGongYongJob;
     private final CarFuWuFeiJob carFuWuFeiJob;
     private final HouseRentInRepairMonthJob houseRentInRepairMonthJob;
@@ -84,6 +79,15 @@ public class JobService {
     private final HouseBuildingLandCountJob houseBuildingLandCountJob;
     private final HouseRentalIncomeJob houseRentalIncomeJob;
     private final CarZuLinJob carZuLinJob;
+    private final CarBaoFeiMonthTask carBaoFeiMonthTask;
+    private final CarBaseDataDayTask carBaseDataDayTask;
+    private final CarLiChengDayTask carLiChengDayTask;
+    private final CarLiChengMonthTask carLiChengMonthTask;
+    private final CarWuDanYongCheMonthTask carWuDanYongCheMonthTask;
+    private final CarYongCheMonthTask carYongCheMonthTask;
+    private final CarYueJieDayTask carYueJieDayTask;
+    private final CarWuDanYongCheDayTask carWuDanYongCheDayTask;
+    private final CarYongCheDayTask carYongCheDayTask;
 
     @Transactional(timeout = 300, rollbackFor = Exception.class)
     public R<Object> runJob(RunJobDto dto) {
@@ -91,12 +95,12 @@ public class JobService {
         LocalDate ld = yearMonth == null ? LocalDate.now()
                 : LocalDate.parse(yearMonth + "01", DateTimeFormatter.ofPattern("yyyyMMdd")).plusMonths(1);
         switch (dto.getJobName()) {
-            case CAR_BASE_DATA_DAY_JOB -> carBaseDataDayJob.runJob();
-            case CAR_YUE_JIE_JOB -> carYueJieJob.runJob();
-            case CAR_BAO_FEI_JOB -> carBaoFeiJob.runJob();
-            case CAR_LI_CHENG_MONTH_JOB -> carLiChengMonthJob.runJob();
-            case CAR_WU_DAN_YONG_CHE_JOB -> carWuDanYongCheJob.runJob();
-            case CAR_YONG_CHE_JOB -> carYongCheJob.runJob();
+            case CAR_BASE_DATA_DAY_JOB -> carBaseDataDayTask.runJob();
+            case CAR_YUE_JIE_JOB -> carYueJieDayTask.runJob();
+            case CAR_BAO_FEI_JOB -> carBaoFeiMonthTask.runJob();
+            case CAR_LI_CHENG_MONTH_JOB -> carLiChengMonthTask.runJob();
+            case CAR_WU_DAN_YONG_CHE_JOB -> carWuDanYongCheMonthTask.runJob();
+            case CAR_YONG_CHE_JOB -> carYongCheMonthTask.runJob();
             case CAR_RAN_YOU_JOB -> carRanYouJob.runJob();
             case CAR_DA_WEI_XIU_JOB -> carDaWeiXiuJob.runJob();
             case CAR_WEI_XIU_JOB -> carWeiXiuJob.runJob();
@@ -107,7 +111,7 @@ public class JobService {
             case CAR_FEE_HB_JOB -> carFeeHbJob.runJob();
             case CAR_FEE_BS_JOB -> carFeeBsJob.runJob();
             case HOUSE_BUILDING_REPAIR_MONTH_JOB -> houseBuildingRepairMonthJob.runJob();
-            case CAR_LI_CHENG_DAY_JOB -> carLiChengDayJob.runJob();
+            case CAR_LI_CHENG_DAY_JOB -> carLiChengDayTask.runJob();
             case CAR_SI_CHE_GONG_YONG_JOB -> carSiCheGongYongJob.runJob();
             case CAR_FU_WU_FEI_JOB -> carFuWuFeiJob.runJob();
             case HOUSE_RENT_IN_REPAIR_MONTH_JOB -> houseRentInRepairMonthJob.runJob();
@@ -126,6 +130,8 @@ public class JobService {
             case HOUSE_BUILDING_LAND_COUNT_JOB -> houseBuildingLandCountJob.runJob();
             case HOUSE_RENTAL_INCOME_JOB -> houseRentalIncomeJob.runJob();
             case CAR_ZU_LIN_JOB -> carZuLinJob.runJob();
+            case CAR_WU_DAN_YONG_CHE_DAY_JOB -> carWuDanYongCheDayTask.runJob();
+            case CAR_YONG_CHE_DAY_JOB -> carYongCheDayTask.runJob();
         }
         return R.ok();
     }

+ 19 - 11
src/main/resources/application-dev.yml

@@ -9,8 +9,8 @@ spring:
     driver-class-name: org.postgresql.Driver
     username: postgres
     password: Test!234
-#    url: jdbc:postgresql://127.0.0.1:5432/financialdb
-    url: jdbc:postgresql://192.168.211.128:5432/financialdb
+    url: jdbc:postgresql://127.0.0.1:5432/financialdb
+#    url: jdbc:postgresql://192.168.65.128:5432/financialdb
 #    url: jdbc:postgresql://172.16.107.5:5432/financialdb
 #    username: finance
 #    password: Finance@unicom23
@@ -21,8 +21,8 @@ minio:
   accessKey: house-car
   bucket: house-car
 #  endpoint: http://192.168.10.7:19000/
-#  endpoint: http://127.0.0.1:19000/
-  endpoint: http://192.168.65.128:19000/
+  endpoint: http://127.0.0.1:19000/
+#  endpoint: http://192.168.65.128:19000/
   expiry: 15
   secretKey: EGqIq7zKZwfasMQ5eLIoLId631vmLaal
 job:
@@ -35,29 +35,37 @@ job:
     db-password: Test!234
     db-name: financialdb
     # 睿行车辆基本信息日数据路径
-    car-base-data-day-source-path: data/rxftp/cljbxx/
+    car-base-data-day-source-path: data/jzftp/rx/HE_D_DEMP_CLJBXX
     # 睿行车辆基本信息日数据归档路径
     car-base-data-day-history-path: data/history/rxftp/cljbxx/
     # 睿行车辆越界报警日数据路径
-    car-yue-jie-source-path: data/rxftp/yjbjrtj/
+    car-yue-jie-source-path: data/jzftp/rx/HE_D_DEMP_YJBJRTJ
     # 睿行车辆越界报警日数据归档路径
     car-yue-jie-history-path: data/history/rxftp/yjbjrtj/
     # 睿行车辆报废月数据路径
-    car-bao-fei-source-path: data/rxftp/clbf/
+    car-bao-fei-source-path: data/jzftp/rx/HE_M_DEMP_CLBF
     # 睿行车辆报废月数据归档路径
     car-bao-fei-history-path: data/history/rxftp/clbf/
     # 睿行车辆行驶里程月数据路径
-    car-li-cheng-month-source-path: data/rxftp/xslcytj/
+    car-li-cheng-month-source-path: data/jzftp/rx/HE_M_DEMP_XSLCYTJ
     # 睿行车辆行驶里程月数据归档路径
     car-li-cheng-month-history-path: data/history/rxftp/xslcytj/
     # 睿行车辆无单用车报警月统计数据路径
-    car-wu-dan-yong-che-source-path: data/rxftp/wdycbjytjbjcs/
+    car-wu-dan-yong-che-source-path: data/jzftp/rx/HE_M_DEMP_WDYCBJYTJBJCS
     # 睿行车辆无单用车报警月统计数据归档路径
     car-wu-dan-yong-che-history-path: data/history/rxftp/wdycbjytjbjcs/
     # 睿行车辆用车月统计数据路径
-    car-yong-che-source-path: data/rxftp/wdycbjytjcccs/
+    car-yong-che-source-path: data/jzftp/rx/HE_M_DEMP_WDYCBJYTJCCCS
     # 睿行车辆用车月统计数据归档路径
     car-yong-che-history-path: data/history/rxftp/wdycbjytjcccs/
+    # 睿行车辆无单用车报警日统计数据路径
+    car-wu-dan-yong-che-day-source-path: data/jzftp/rx/HE_D_DEMP_WDYCBJRTJBJCS
+    # 睿行车辆无单用车报警日统计数据归档路径
+    car-wu-dan-yong-che-day-history-path: data/history/rxftp/HE_D_DEMP_WDYCBJRTJBJCS/
+    # 睿行车辆用车日统计数据路径
+    car-yong-che-day-source-path: data/jzftp/rx/HE_D_DEMP_WDYCBJRTJCCCS
+    # 睿行车辆用车月统计数据归档路径
+    car-yong-che-day-history-path: data/history/rxftp/HE_D_DEMP_WDYCBJRTJCCCS/
     # 河北成本管理系统车辆燃油数据路径
     car-ran-you-source-path: data/jzftp/HE_M_MTC_VEHICLE_OIL/
     # 河北成本管理系统车辆燃油数据归档路径
@@ -99,7 +107,7 @@ job:
     # 河北成本管理系统自有类房产维修数据归档路径
     house-building-repair-month-history-path: data/history/jzftp/HE_M_MTC_HOUSE/
     # 睿行车辆行驶里程日数据路径
-    car-li-cheng-day-source-path: data/rxftp/xslcrtj/
+    car-li-cheng-day-source-path: data/jzftp/rx/HE_D_DEMP_XSLCRTJ
     # 睿行车辆行驶里程日数据归档路径
     car-li-cheng-day-history-path: data/history/rxftp/xslcrtj/
     # 违规车辆策略输出路径

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

@@ -27,29 +27,37 @@ job:
     db-password: Finance@unicom23
     db-name: financialdb
     # 睿行车辆基本信息日数据路径
-    car-base-data-day-source-path: /data/rxftp/cljbxx/
+    car-base-data-day-source-path: /data/jzftp/rx/HE_D_DEMP_CLJBXX
     # 睿行车辆基本信息日数据归档路径
     car-base-data-day-history-path: /data/history/rxftp/cljbxx/
     # 睿行车辆越界报警日数据路径
-    car-yue-jie-source-path: /data/rxftp/yjbjrtj/
+    car-yue-jie-source-path: /data/jzftp/rx/HE_D_DEMP_YJBJRTJ
     # 睿行车辆越界报警日数据归档路径
     car-yue-jie-history-path: /data/history/rxftp/yjbjrtj/
     # 睿行车辆报废月数据路径
-    car-bao-fei-source-path: /data/rxftp/clbf/
+    car-bao-fei-source-path: /data/jzftp/rx/HE_M_DEMP_CLBF
     # 睿行车辆报废月数据归档路径
     car-bao-fei-history-path: /data/history/rxftp/clbf/
     # 睿行车辆行驶里程月数据路径
-    car-li-cheng-month-source-path: /data/rxftp/xslcytj/
+    car-li-cheng-month-source-path: /data/jzftp/rx/HE_M_DEMP_XSLCYTJ
     # 睿行车辆行驶里程月数据归档路径
     car-li-cheng-month-history-path: /data/history/rxftp/xslcytj/
     # 睿行车辆无单用车报警月统计数据路径
-    car-wu-dan-yong-che-source-path: /data/rxftp/wdycbjytjbjcs/
+    car-wu-dan-yong-che-source-path: /data/jzftp/rx/HE_M_DEMP_WDYCBJYTJBJCS
     # 睿行车辆无单用车报警月统计数据归档路径
     car-wu-dan-yong-che-history-path: /data/history/rxftp/wdycbjytjbjcs/
     # 睿行车辆用车月统计数据路径
-    car-yong-che-source-path: /data/rxftp/wdycbjytjcccs/
-    # 睿行车辆用车统计数据归档路径
+    car-yong-che-source-path: /data/jzftp/rx/HE_M_DEMP_WDYCBJYTJCCCS
+    # 睿行车辆用车统计数据归档路径
     car-yong-che-history-path: /data/history/rxftp/wdycbjytjcccs/
+    # 睿行车辆无单用车报警日统计数据路径
+    car-wu-dan-yong-che-day-source-path: /data/jzftp/rx/HE_D_DEMP_WDYCBJRTJBJCS
+    # 睿行车辆无单用车报警日统计数据归档路径
+    car-wu-dan-yong-che-day-history-path: /data/history/rxftp/HE_D_DEMP_WDYCBJRTJBJCS/
+    # 睿行车辆用车日统计数据路径
+    car-yong-che-day-source-path: /data/jzftp/rx/HE_D_DEMP_WDYCBJRTJCCCS
+    # 睿行车辆用车月统计数据归档路径
+    car-yong-che-day-history-path: /data/history/rxftp/HE_D_DEMP_WDYCBJRTJCCCS/
     # 河北成本管理系统车辆燃油数据路径
     car-ran-you-source-path: /data/jzftp/HE_M_MTC_VEHICLE_OIL/
     # 河北成本管理系统车辆燃油数据归档路径
@@ -91,7 +99,7 @@ job:
     # 河北成本管理系统自有类房产维修数据归档路径
     house-building-repair-month-history-path: /data/history/jzftp/HE_M_MTC_HOUSE/
     # 睿行车辆行驶里程日数据路径
-    car-li-cheng-day-source-path: /data/rxftp/xslcrtj/
+    car-li-cheng-day-source-path: /data/jzftp/rx/HE_D_DEMP_XSLCRTJ
     # 睿行车辆行驶里程日数据归档路径
     car-li-cheng-day-history-path: /data/history/rxftp/xslcrtj/
     # 违规车辆策略输出路径

+ 3 - 3
src/test/java/com/nokia/finance/tasks/car/ruixing/CarBaoFeiJobTests.java

@@ -1,6 +1,6 @@
 package com.nokia.finance.tasks.car.ruixing;
 
-import com.nokia.finance.tasks.jobs.car.ruixing.CarBaoFeiJob;
+import com.nokia.finance.tasks.jobs.car.rx.CarBaoFeiMonthTask;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -12,11 +12,11 @@ import org.springframework.test.context.ActiveProfiles;
 @ActiveProfiles("dev")
 class CarBaoFeiJobTests {
     @Autowired
-    CarBaoFeiJob carBaoFeiJob;
+    CarBaoFeiMonthTask carBaoFeiMonthTask;
 
     @Test
     void runJobTest() {
-        carBaoFeiJob.runJob();
+        carBaoFeiMonthTask.runJob();
     }
 
 }

+ 3 - 3
src/test/java/com/nokia/finance/tasks/car/ruixing/CarBaseDataDayJobTests.java

@@ -1,6 +1,6 @@
 package com.nokia.finance.tasks.car.ruixing;
 
-import com.nokia.finance.tasks.jobs.car.ruixing.CarBaseDataDayJob;
+import com.nokia.finance.tasks.jobs.car.rx.CarBaseDataDayTask;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -12,11 +12,11 @@ import org.springframework.test.context.ActiveProfiles;
 @ActiveProfiles("dev")
 class CarBaseDataDayJobTests {
     @Autowired
-    CarBaseDataDayJob carBaseDataDayJob;
+    CarBaseDataDayTask carBaseDataDayTask;
 
     @Test
     void runJobTest() {
-        carBaseDataDayJob.runJob();
+        carBaseDataDayTask.runJob();
     }
 
 }

+ 3 - 3
src/test/java/com/nokia/finance/tasks/car/ruixing/CarLiChengDayJobTests.java

@@ -1,6 +1,6 @@
 package com.nokia.finance.tasks.car.ruixing;
 
-import com.nokia.finance.tasks.jobs.car.ruixing.CarLiChengDayJob;
+import com.nokia.finance.tasks.jobs.car.rx.CarLiChengDayTask;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -12,11 +12,11 @@ import org.springframework.test.context.ActiveProfiles;
 @ActiveProfiles("dev")
 class CarLiChengDayJobTests {
     @Autowired
-    CarLiChengDayJob carLiChengDayJob;
+    CarLiChengDayTask carLiChengDayTask;
 
     @Test
     void runJobTest() {
-        carLiChengDayJob.runJob();
+        carLiChengDayTask.runJob();
     }
 
 }

+ 3 - 3
src/test/java/com/nokia/finance/tasks/car/ruixing/CarLiChengMonthJobTests.java

@@ -1,6 +1,6 @@
 package com.nokia.finance.tasks.car.ruixing;
 
-import com.nokia.finance.tasks.jobs.car.ruixing.CarLiChengMonthJob;
+import com.nokia.finance.tasks.jobs.car.rx.CarLiChengMonthTask;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -12,11 +12,11 @@ import org.springframework.test.context.ActiveProfiles;
 @ActiveProfiles("dev")
 class CarLiChengMonthJobTests {
     @Autowired
-    CarLiChengMonthJob carLiChengMonthJob;
+    CarLiChengMonthTask carLiChengMonthTask;
 
     @Test
     void runJobTest() {
-        carLiChengMonthJob.runJob();
+        carLiChengMonthTask.runJob();
     }
 
 }

+ 22 - 0
src/test/java/com/nokia/finance/tasks/car/ruixing/CarWuDanYongCheDayJobTests.java

@@ -0,0 +1,22 @@
+package com.nokia.finance.tasks.car.ruixing;
+
+import com.nokia.finance.tasks.jobs.car.rx.CarWuDanYongCheDayTask;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+
+@Slf4j
+@SpringBootTest
+@ActiveProfiles("dev")
+class CarWuDanYongCheDayJobTests {
+    @Autowired
+    CarWuDanYongCheDayTask carWuDanYongCheDayTask;
+
+    @Test
+    void runJobTest() {
+        carWuDanYongCheDayTask.runJob();
+    }
+
+}

+ 3 - 3
src/test/java/com/nokia/finance/tasks/car/ruixing/CarWuDanYongCheJobTests.java

@@ -1,6 +1,6 @@
 package com.nokia.finance.tasks.car.ruixing;
 
-import com.nokia.finance.tasks.jobs.car.ruixing.CarWuDanYongCheJob;
+import com.nokia.finance.tasks.jobs.car.rx.CarWuDanYongCheMonthTask;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -12,11 +12,11 @@ import org.springframework.test.context.ActiveProfiles;
 @ActiveProfiles("dev")
 class CarWuDanYongCheJobTests {
     @Autowired
-    CarWuDanYongCheJob carWuDanYongCheJob;
+    CarWuDanYongCheMonthTask carWuDanYongCheMonthTask;
 
     @Test
     void runJobTest() {
-        carWuDanYongCheJob.runJob();
+        carWuDanYongCheMonthTask.runJob();
     }
 
 }

+ 22 - 0
src/test/java/com/nokia/finance/tasks/car/ruixing/CarYongCheDayJobTests.java

@@ -0,0 +1,22 @@
+package com.nokia.finance.tasks.car.ruixing;
+
+import com.nokia.finance.tasks.jobs.car.rx.CarYongCheDayTask;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+
+@Slf4j
+@SpringBootTest
+@ActiveProfiles("dev")
+class CarYongCheDayJobTests {
+    @Autowired
+    CarYongCheDayTask carYongCheDayTask;
+
+    @Test
+    void runJobTest() {
+        carYongCheDayTask.runJob();
+    }
+
+}

+ 3 - 3
src/test/java/com/nokia/finance/tasks/car/ruixing/CarYongCheJobTests.java

@@ -1,6 +1,6 @@
 package com.nokia.finance.tasks.car.ruixing;
 
-import com.nokia.finance.tasks.jobs.car.ruixing.CarYongCheJob;
+import com.nokia.finance.tasks.jobs.car.rx.CarYongCheMonthTask;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -12,11 +12,11 @@ import org.springframework.test.context.ActiveProfiles;
 @ActiveProfiles("dev")
 class CarYongCheJobTests {
     @Autowired
-    CarYongCheJob carYongCheJob;
+    CarYongCheMonthTask carYongCheMonthTask;
 
     @Test
     void runJobTest() {
-        carYongCheJob.runJob();
+        carYongCheMonthTask.runJob();
     }
 
 }

+ 3 - 3
src/test/java/com/nokia/finance/tasks/car/ruixing/CarYueJieJobTests.java

@@ -1,6 +1,6 @@
 package com.nokia.finance.tasks.car.ruixing;
 
-import com.nokia.finance.tasks.jobs.car.ruixing.CarYueJieJob;
+import com.nokia.finance.tasks.jobs.car.rx.CarYueJieDayTask;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -12,11 +12,11 @@ import org.springframework.test.context.ActiveProfiles;
 @ActiveProfiles("dev")
 class CarYueJieJobTests {
     @Autowired
-    CarYueJieJob carYueJieJob;
+    CarYueJieDayTask carYueJieDayTask;
 
     @Test
     void runJobTest() {
-        carYueJieJob.runJob();
+        carYueJieDayTask.runJob();
     }
 
 }

+ 22 - 22
src/test/java/com/nokia/finance/tasks/gdc/car/CarPhpRequestLogJobTests.java

@@ -1,22 +1,22 @@
-package com.nokia.finance.tasks.gdc.car;
-
-import com.nokia.finance.tasks.jobs.gdc.car.CarPhpRequestLogJob;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.ActiveProfiles;
-
-@Slf4j
-@SpringBootTest
-@ActiveProfiles("prod")
-class CarPhpRequestLogJobTests {
-    @Autowired
-    CarPhpRequestLogJob carPhpRequestLogJob;
-
-    @Test
-    void runJobTest() {
-        carPhpRequestLogJob.runJob();
-    }
-
-}
+//package com.nokia.finance.tasks.gdc.car;
+//
+//import com.nokia.finance.tasks.jobs.gdc.car.CarPhpRequestLogJob;
+//import lombok.extern.slf4j.Slf4j;
+//import org.junit.jupiter.api.Test;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.boot.test.context.SpringBootTest;
+//import org.springframework.test.context.ActiveProfiles;
+//
+//@Slf4j
+//@SpringBootTest
+//@ActiveProfiles("prod")
+//class CarPhpRequestLogJobTests {
+//    @Autowired
+//    CarPhpRequestLogJob carPhpRequestLogJob;
+//
+//    @Test
+//    void runJobTest() {
+//        carPhpRequestLogJob.runJob();
+//    }
+//
+//}