Browse Source

v1.6 新增客户端-战略考核数据表

lifuquan 1 year ago
parent
commit
6a0266b574
24 changed files with 694 additions and 110 deletions
  1. 4 0
      README.md
  2. BIN
      tsl_data/doc/目标输出/投诉清单各地市投诉率20230624-客户端-战略考核.xlsx
  3. BIN
      tsl_data/doc/输入数据/河北_CEM高品质2日统计/河北_CEM高品质2日统计_HE_D_HIGH_QUALITY.xlsx
  4. 1 1
      tsl_data/pom.xml
  5. 1 1
      tsl_data/src/main/java/com/nokia/common/excel/entity/CellInfo.java
  6. 2 1
      tsl_data/src/main/java/com/nokia/common/excel/entity/CellRect.java
  7. 1 0
      tsl_data/src/main/java/com/nokia/common/excel/poi/PoiUtil.java
  8. 15 0
      tsl_data/src/main/java/com/nokia/tsl_data/dao/AreaInfoDao.java
  9. 33 0
      tsl_data/src/main/java/com/nokia/tsl_data/dao/HighQualityCountDao.java
  10. 29 0
      tsl_data/src/main/java/com/nokia/tsl_data/dao/TargetTsRatioDao.java
  11. 2 0
      tsl_data/src/main/java/com/nokia/tsl_data/dao/TslDao.java
  12. 29 0
      tsl_data/src/main/java/com/nokia/tsl_data/dao/UserCountDao.java
  13. 18 0
      tsl_data/src/main/java/com/nokia/tsl_data/pojo/AreaInfo.java
  14. 17 0
      tsl_data/src/main/java/com/nokia/tsl_data/pojo/TargetTsRatio.java
  15. 11 1
      tsl_data/src/main/java/com/nokia/tsl_data/pojo/UserCount.java
  16. 77 0
      tsl_data/src/main/java/com/nokia/tsl_data/service/HighQualityCountService.java
  17. 101 63
      tsl_data/src/main/java/com/nokia/tsl_data/service/TslDataService.java
  18. 209 30
      tsl_data/src/main/java/com/nokia/tsl_data/service/TslReportService.java
  19. 11 6
      tsl_data/src/main/java/com/nokia/tsl_data/service/TslTaskService.java
  20. 97 0
      tsl_data/src/main/java/com/nokia/tsl_data/service/UserCountService.java
  21. 1 1
      tsl_data/src/main/resources/application.properties
  22. 12 0
      tsl_data/src/main/resources/mapper/AreaInfoDao.xml
  23. 18 0
      tsl_data/src/main/resources/mapper/HighQualityCountDao.xml
  24. 5 6
      tsl_data/src/test/java/com/nokia/tsl_data/TslDataApplicationTest.java

+ 4 - 0
README.md

@@ -12,6 +12,10 @@ nohup java -jar dingtalk_auto-1.2-exec.jar >output.log 2>&1 &
 
 ## tsl_data版本说明
 
+### v1.6
+
+1. 新增一个数据表--客户端-战略考核并且需要排在第二个sheet
+
 ### v1.5
 
 1. MOBILE_COMPLAINT_DETAILS数据从每日推送一天数据更新为每日推送从当月1日累计数据

BIN
tsl_data/doc/目标输出/投诉清单各地市投诉率20230624-客户端-战略考核.xlsx


BIN
tsl_data/doc/输入数据/河北_CEM高品质2日统计/河北_CEM高品质2日统计_HE_D_HIGH_QUALITY.xlsx


+ 1 - 1
tsl_data/pom.xml

@@ -13,7 +13,7 @@
 
     <groupId>com.nokia</groupId>
     <artifactId>tsl_data</artifactId>
-    <version>1.5</version>
+    <version>1.6</version>
 
     <packaging>jar</packaging>
 

+ 1 - 1
tsl_data/src/main/java/com/nokia/common/excel/entity/CellInfo.java

@@ -30,7 +30,7 @@ public class CellInfo {
     // 单元格值的字符串表示--时间按统一格式,其他数字按照excel格式
     private String text;
     // 字体 默认字体 微软雅黑 普通 11号字
-    private Font font = Font.decode("微软雅黑-PLAIN-11");
+    private Font font = Font.decode("微软雅黑-PLAIN-12");
     // 是否加粗
     private boolean isBold = false;
     // 文字颜色

+ 2 - 1
tsl_data/src/main/java/com/nokia/common/excel/entity/CellRect.java

@@ -29,7 +29,8 @@ public class CellRect {
     private Color backgroundColor = Color.WHITE;
     // 统一字体
     private String fontFamily = null;
-    private int fontSizeMin = 11;
+    // 最小字体12号字,保证截图的清晰度
+    private int fontSizeMin = 12;
 
     // 范围内的全部单元格信息CellInfo
     private List<CellInfo> cellInfos;

+ 1 - 0
tsl_data/src/main/java/com/nokia/common/excel/poi/PoiUtil.java

@@ -129,6 +129,7 @@ public class PoiUtil {
             }
             // 写入值
             g2d.setColor(cellInfo.getTextColor());
+            // 获取cellInfo的字体
             java.awt.Font font = cellInfo.getFont();
             String text = cellInfo.getText();
             int stringWidth = g2d.getFontMetrics(font).stringWidth(text);

+ 15 - 0
tsl_data/src/main/java/com/nokia/tsl_data/dao/AreaInfoDao.java

@@ -0,0 +1,15 @@
+package com.nokia.tsl_data.dao;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import com.nokia.tsl_data.pojo.AreaInfo;
+
+@Mapper
+public interface AreaInfoDao {
+
+    List<String> getAllCityName();
+
+    void insertOne(AreaInfo area);
+}

+ 33 - 0
tsl_data/src/main/java/com/nokia/tsl_data/dao/HighQualityCountDao.java

@@ -0,0 +1,33 @@
+package com.nokia.tsl_data.dao;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 客户端数据表 高质量统计表
+ * 对应主表 report_auto.he_d_high_quality
+ */
+@Mapper
+public interface HighQualityCountDao {
+
+    /**
+     * 查询某个日期各个地市的客户端总数(总投诉量(办结量))(所得结果是当月0日到当天的一个累加量)
+     * 
+     * @param day
+     * @return
+     */
+    List<Map<String, Object>> selectTotalComplaintsForDay(String day);
+
+    /**
+     * 查询某个日期各个地市的客户端总数(总投诉量(办结量))(所得结果是当月0日到当天的一个累加量)
+     * 
+     * @param monthId
+     * @param DayId
+     * @return
+     */
+    List<Map<String, Object>> selectTotalComplaintsForMonthIdAndDay(@Param("monthId") String monthId,
+            @Param("day") String day);
+}

+ 29 - 0
tsl_data/src/main/java/com/nokia/tsl_data/dao/TargetTsRatioDao.java

@@ -0,0 +1,29 @@
+package com.nokia.tsl_data.dao;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+@Mapper
+public interface TargetTsRatioDao {
+
+    /**
+     * 按月查询管理端目标万投率
+     * 
+     * @param monthId
+     * @return
+     */
+    @Select("select city_name, management_target_ts_ratio from report_auto.target_ts_ratio where month_id = #{monthId}")
+    List<Map<String, Object>> selectMangementTargetTsRatioForMonth(String monthId);
+
+    /**
+     * 按月查询客户端目标万投率
+     * 
+     * @param monthId
+     * @return
+     */
+    @Select("select city_name, customer_target_ts_ratio from report_auto.target_ts_ratio where month_id = #{monthId}")
+    List<Map<String, Object>> selectCustomerTargetTsRatioForMonth(String monthId);
+}

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

@@ -138,6 +138,7 @@ public interface TslDao {
      * @param monthId
      * @return
      */
+    @Deprecated
     List<Map<String, Object>> selectUserCountForMonth(String monthId);
 
     /**
@@ -146,6 +147,7 @@ public interface TslDao {
      * @param monthId
      * @return
      */
+    @Deprecated
     List<Map<String, Object>> selectTargetTsRatioForMonth(String monthId);
 
     /**

+ 29 - 0
tsl_data/src/main/java/com/nokia/tsl_data/dao/UserCountDao.java

@@ -0,0 +1,29 @@
+package com.nokia.tsl_data.dao;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+@Mapper
+public interface UserCountDao {
+
+    /**
+     * 按月查询管理端用户数
+     * 
+     * @param monthId
+     * @return
+     */
+    @Select("select city_name, management_user_count from report_auto.user_count where month_id = #{monthId}")
+    List<Map<String, Object>> selectMangementUserCountForMonth(String monthId);
+
+    /**
+     * 按月查询客户端用户数
+     * 
+     * @param monthId
+     * @return
+     */
+    @Select("select city_name, customer_user_count from report_auto.user_count where month_id = #{monthId}")
+    List<Map<String, Object>> selectCustomerUserCountForMonth(String monthId);
+}

+ 18 - 0
tsl_data/src/main/java/com/nokia/tsl_data/pojo/AreaInfo.java

@@ -0,0 +1,18 @@
+package com.nokia.tsl_data.pojo;
+
+import lombok.Data;
+
+/**
+ * 区域信息
+ */
+@Data
+public class AreaInfo {
+
+    private Integer id;
+    private String areaName;
+    // 客户端表名称 雄安新区 对应areaName 雄安
+    // 这里暂时没有搞对应关系,是通过在service层特殊处理规避的
+    // private String highQualityName;
+    private String areaType;
+    private Integer ord;
+}

+ 17 - 0
tsl_data/src/main/java/com/nokia/tsl_data/pojo/TargetTsRatio.java

@@ -0,0 +1,17 @@
+package com.nokia.tsl_data.pojo;
+
+import lombok.Data;
+
+/**
+ * 目标万投率--与数据库表report_auto.target_ts_ratio对应
+ */
+@Data
+public class TargetTsRatio {
+    private Long id;
+    private String monthId;
+    private String cityName;
+    // 管理端用户数统计
+    private Double managementTargetTsRatio;
+    // 客户端用户数统计
+    private Double customerTargetTsRatio;
+}

+ 11 - 1
tsl_data/src/main/java/com/nokia/tsl_data/pojo/UserCount.java

@@ -2,10 +2,20 @@ package com.nokia.tsl_data.pojo;
 
 import lombok.Data;
 
+/**
+ * 对应表report_auto.user_count
+ * 
+ * 这里的实体类实际上尚未在代码中应用
+ */
+
 @Data
 public class UserCount {
 
     private Long id;
+    private String monthId;
     private String cityName;
-    private String userCount;
+    // 管理端用户数统计
+    private Double managementUserCount;
+    // 客户端用户数统计
+    private Double customerUserCount;
 }

+ 77 - 0
tsl_data/src/main/java/com/nokia/tsl_data/service/HighQualityCountService.java

@@ -0,0 +1,77 @@
+package com.nokia.tsl_data.service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.nokia.tsl_data.dao.AreaInfoDao;
+import com.nokia.tsl_data.dao.HighQualityCountDao;
+
+/**
+ * 处理客户端统计数据
+ */
+@Service
+public class HighQualityCountService {
+
+    @Autowired
+    private HighQualityCountDao highQualityCountDao;
+
+    @Autowired
+    private AreaInfoDao areaInfoDao;
+
+    /**
+     * 根据日期查询当月从1日起每天每个地市的客户端统计数据
+     * 
+     * @param day
+     * @return
+     */
+    public Map<String, int[]> getComplaintsForDay(String day) {
+        // 预处理时间
+        String monthId = day.substring(0, 6);
+        int dayIndex = Integer.parseInt(day.substring(6));
+
+        List<String> allCityName = areaInfoDao.getAllCityName();
+        Map<String, int[]> result = new HashMap<>();
+        // 每个地市一个数组,数组保存dayIndex天数据
+        for (String areaName : allCityName) {
+            result.put(areaName, new int[dayIndex + 1]);
+        }
+        // 全省
+        result.put("全省", new int[dayIndex + 1]);
+
+        for (int i = 1; i <= dayIndex; i++) {
+            // 拼接一个表示天的字符串,天如果小于10要补0
+            String newDay = i >= 10 ? monthId + i : monthId + "0" + i;
+            // 这里有一个查询操作
+            List<Map<String, Object>> totalComplaintsForDay = highQualityCountDao
+                    .selectTotalComplaintsForDay(newDay);
+            int provinceAll = 0;
+            for (Map<String, Object> map : totalComplaintsForDay) {
+                String city = map.get("businoareaname").toString();
+                // 这里雄安新区需要特殊处理一下
+                city = city.equals("雄安新区") ? "雄安" : city;
+                int[] arr = result.get(city);
+                arr[i - 1] = Integer.parseInt(map.get("total_complaints").toString());
+                provinceAll += arr[i - 1];
+                if (i == dayIndex) {
+                    arr[dayIndex] = arr[dayIndex - 1];
+                }
+            }
+            result.get("全省")[i - 1] = provinceAll;
+            if (i == dayIndex) {
+                result.get("全省")[dayIndex] = provinceAll;
+            }
+        }
+
+        // 以上得到的result是每天累加,需要计算一下每天的增量
+        for (int[] arr : result.values()) {
+            for (int i = dayIndex - 1; i >= 1; i--) {
+                arr[i] = arr[i] - arr[i - 1];
+            }
+        }
+        return result;
+    }
+}

+ 101 - 63
tsl_data/src/main/java/com/nokia/tsl_data/service/TslDataService.java

@@ -2,8 +2,6 @@ package com.nokia.tsl_data.service;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
@@ -16,11 +14,11 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
+import com.nokia.tsl_data.dao.AreaInfoDao;
 import com.nokia.tsl_data.dao.MobileCompDao;
+import com.nokia.tsl_data.dao.TargetTsRatioDao;
 import com.nokia.tsl_data.dao.TslDao;
 
-import lombok.Getter;
-
 /**
  * 计算输出到文件的数据
  */
@@ -33,6 +31,18 @@ public class TslDataService {
     @Autowired
     private MobileCompDao mobileCompDao;
 
+    @Autowired
+    private AreaInfoDao areaInfoDao;
+
+    @Autowired
+    private TargetTsRatioDao targetTsRatioDao;
+
+    @Autowired
+    private HighQualityCountService highQualityCountService;
+
+    @Autowired
+    private UserCountService userCountService;
+
     @Value("${tslTask.compliance.satisfied}")
     private double satisfiedCompliance;
     @Value("${tslTask.compliance.resolution}")
@@ -40,24 +50,6 @@ public class TslDataService {
     @Value("${tslTask.compliance.response}")
     private double responseCompliance;
 
-    @Getter
-    private final List<String> areas = new ArrayList<String>() {
-        {
-            add("保定");
-            add("沧州");
-            add("承德");
-            add("邯郸");
-            add("衡水");
-            add("廊坊");
-            add("秦皇岛");
-            add("石家庄");
-            add("唐山");
-            add("邢台");
-            add("雄安");
-            add("张家口");
-        }
-    };
-
     /**
      * 客户端-投诉问题解决满意度
      * 客户端-投诉问题解决率
@@ -85,7 +77,7 @@ public class TslDataService {
         list0 = new ArrayList<>();
         result.add(list0);
         // 地市满意度
-        for (String area : areas) {
+        for (String area : areaInfoDao.getAllCityName()) {
             list1 = new ArrayList<>(4);
             list0.add(list1);
             // 地市
@@ -115,7 +107,7 @@ public class TslDataService {
         list0 = new ArrayList<>();
         result.add(list0);
         // 地市解决率
-        for (String area : areas) {
+        for (String area : areaInfoDao.getAllCityName()) {
             list1 = new ArrayList<>(4);
             list0.add(list1);
             // 地市
@@ -144,7 +136,7 @@ public class TslDataService {
         // 响应率
         list0 = new ArrayList<>();
         result.add(list0);
-        for (String area : areas) {
+        for (String area : areaInfoDao.getAllCityName()) {
             list1 = new ArrayList<>(4);
             list0.add(list1);
             // 地市
@@ -185,7 +177,7 @@ public class TslDataService {
         }
         List<List<Object>> result = new ArrayList<>();
         // 各地市数据
-        for (String area : areas) {
+        for (String area : areaInfoDao.getAllCityName()) {
             // 地市 工单数 超时工单数 超时工单占比
             List<Object> list = new ArrayList<>(4);
             result.add(list);
@@ -255,7 +247,7 @@ public class TslDataService {
         }
         List<List<Object>> result = new ArrayList<>();
         // 各地市数据
-        for (String area : areas) {
+        for (String area : areaInfoDao.getAllCityName()) {
             // 地市 上月平均处理时长 当月平均处理时长 涨幅
             List<Object> list = new ArrayList<>(4);
             result.add(list);
@@ -300,7 +292,7 @@ public class TslDataService {
         }
         List<List<Object>> result = new ArrayList<>();
         // 各地市数据
-        for (String area : areas) {
+        for (String area : areaInfoDao.getAllCityName()) {
             List<Object> list = new ArrayList<>(7);
             result.add(list);
             list.add(0, area);
@@ -334,6 +326,79 @@ public class TslDataService {
         return result;
     }
 
+    /**
+     * 客户端-战略考核
+     * 
+     * @param day
+     * @return
+     */
+    public Map<String, List<Object>> getSheet1_1Data(String day) {
+        // 各地市和全省数据
+        Map<String, int[]> complaintsForDay = highQualityCountService.getComplaintsForDay(day);
+        Map<String, List<Object>> result = new HashMap<>();
+        // int dayIndex = Integer.parseInt(day.substring(6, 8));
+        // 写入各地市数据
+        for (String area : areaInfoDao.getAllCityName()) {
+            List<Object> list = new ArrayList<>();
+            int[] js = complaintsForDay.get(area);
+            for (int i = 0; i < js.length; i++) {
+                list.add(js[i]);
+            }
+            result.put(area, list);
+        }
+        // 写入全省数据
+        result.put("全省", new ArrayList<>());
+        int[] js = complaintsForDay.get("全省");
+        for (int i = 0; i < js.length; i++) {
+            result.get("全省").add(js[i]);
+        }
+        // 客户端用户数
+        Map<String, Double> customerUserCount = userCountService.getCustomerUserCountForMonth(day.substring(0, 6));
+        for (Entry<String, List<Object>> entry : result.entrySet()) {
+            entry.getValue().add(customerUserCount.get(entry.getKey()));
+        }
+
+        // 获取当前月
+        Calendar calendar = Calendar.getInstance(Locale.CHINA);
+        try {
+            calendar.setTime(new SimpleDateFormat("yyyyMMdd").parse(day));
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        int actualMaximumDayOfMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+        int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+        // 万投率和本月预测
+        for (Entry<String, List<Object>> entry : result.entrySet()) {
+            List<Object> list = entry.getValue();
+            int size = list.size();
+            // 计算万投率
+            double wtl = Double.parseDouble(list.get(size - 2).toString())
+                    / Double.parseDouble(list.get(size - 1).toString());
+            list.add(wtl);
+            // 计算预测万投率
+            double ycwtl = wtl * actualMaximumDayOfMonth / dayOfMonth;
+            list.add(ycwtl);
+        }
+
+        // 期望万投率--从数据库取出来是一个字符串
+        // 客户端目标投诉率
+        List<Map<String, Object>> targetTsRatio = targetTsRatioDao
+                .selectCustomerTargetTsRatioForMonth(day.substring(0, 6));
+        for (Map<String, Object> map : targetTsRatio) {
+            result.get(map.get("city_name")).add(Double.parseDouble(map.get("customer_target_ts_ratio").toString()));
+        }
+
+        // 与目标差距
+        for (Entry<String, List<Object>> entry : result.entrySet()) {
+            List<Object> list = entry.getValue();
+            int size = list.size();
+            double cj = ((double) list.get(size - 2)) - ((double) list.get(size - 1));
+            list.add(cj);
+        }
+
+        return result;
+    }
+
     /**
      * 管理端-移网质量类
      * 
@@ -357,14 +422,10 @@ public class TslDataService {
         List<Map<String, Object>> allTslforMonth = mobileCompDao.selectAllTslForMonth(day);
         List<Map<String, Object>> cityAllforMonth = mobileCompDao.selectCityAllForMonth(day);
         int total = mobileCompDao.selectAllForMonth(day);
-        // 当月用户数
-        List<Map<String, Object>> userCount = getUserCount(monthId);
-        // 目标投诉率
-        List<Map<String, Object>> targetTsRatio = tslDao.selectTargetTsRatioForMonth(monthId);
 
         int dayIndex = Integer.parseInt(day.substring(6, 8));
         Map<String, List<Object>> result = new HashMap<>();
-        for (String area : areas) {
+        for (String area : areaInfoDao.getAllCityName()) {
             List<Object> list = new ArrayList<>();
             // 需要初始化一下
             for (int i = 0; i < dayIndex; i++) {
@@ -389,9 +450,10 @@ public class TslDataService {
         }
         // 全省总量
         result.get("全省").add(total);
-        // 用户数
-        for (Map<String, Object> map : userCount) {
-            result.get(map.get("city_name")).add(map.get("user_count"));
+        // 当月管理端用户数
+        Map<String, Double> userCount = userCountService.getMangementUserCountForMonth(monthId);
+        for (Entry<String, List<Object>> entry : result.entrySet()) {
+            entry.getValue().add(userCount.get(entry.getKey()));
         }
 
         // 万投率和本月预测
@@ -408,8 +470,10 @@ public class TslDataService {
         }
 
         // 期望万投率--从数据库取出来是一个字符串
+        // 服务端目标投诉率
+        List<Map<String, Object>> targetTsRatio = targetTsRatioDao.selectMangementTargetTsRatioForMonth(monthId);
         for (Map<String, Object> map : targetTsRatio) {
-            result.get(map.get("city_name")).add(Double.parseDouble(map.get("target_ts_ratio").toString()));
+            result.get(map.get("city_name")).add(Double.parseDouble(map.get("management_target_ts_ratio").toString()));
         }
 
         // 与目标差距
@@ -422,30 +486,4 @@ public class TslDataService {
 
         return result;
     }
-
-    /**
-     * 读取用户数如果当前月份没有数据就读上一个月
-     * 
-     * 递归方式,最多递归2层
-     * 
-     * @param monthId
-     * @return
-     */
-    public List<Map<String, Object>> getUserCount(String monthId) {
-        return getUserCount(monthId, 2);
-    }
-
-    private List<Map<String, Object>> getUserCount(String monthId, int stackLayerCount) {
-        List<Map<String, Object>> result = tslDao.selectUserCountForMonth(monthId);
-        if (stackLayerCount != 0) {
-            stackLayerCount -= 1;
-            if (result == null || result.size() == 0) {
-                LocalDate localDate = LocalDate.parse(monthId + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
-                localDate = localDate.plusMonths(-1L);
-                String newMonthId = DateTimeFormatter.ofPattern("yyyyMM").format(localDate);
-                return getUserCount(newMonthId, stackLayerCount);
-            }
-        }
-        return result;
-    }
 }

+ 209 - 30
tsl_data/src/main/java/com/nokia/tsl_data/service/TslReportService.java

@@ -28,8 +28,11 @@ import org.apache.poi.xssf.usermodel.XSSFColor;
 import org.apache.poi.xssf.usermodel.XSSFDataFormat;
 import org.apache.poi.xssf.usermodel.XSSFFont;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import com.nokia.tsl_data.dao.AreaInfoDao;
+
 import lombok.extern.slf4j.Slf4j;
 
 /**
@@ -39,27 +42,42 @@ import lombok.extern.slf4j.Slf4j;
 @Service
 public class TslReportService {
 
-    private final TslDataService tslDataService;
+    @Autowired
+    private TslDataService tslDataService;
+
+    @Autowired
+    private AreaInfoDao areaInfoDao;
 
     private XSSFWorkbook workbook = null;
 
     private static final DateFormat DAY_FORMAT = new SimpleDateFormat("yyyyMMdd");
 
-    public TslReportService(TslDataService tslDataService) {
-        this.tslDataService = tslDataService;
-    }
-
+    /**
+     * 写入workbook
+     * 
+     * @param day
+     * @param path 应为带文件名的完整路径
+     */
     public void workbookToFile(String day, String path) {
+        // 每次需要重置workbook
+        workbook = new XSSFWorkbook();
+        // 按照顺序写入各个sheet
+        // 管理端-移网质量类
         getSheet1(day);
+        // 客户端-战略考核
+        getSheet1_1(day);
+        // 管理端-重复投诉率
         getSheet2(day);
+        // 投诉处理时长、超时工单概况
         getSheet3(day);
+        // 客户端-投诉问题解决满意度 客户端-投诉问题解决率 客户端-投诉问题响应率
         getSheet4_6(day);
         try (OutputStream outputStream = new FileOutputStream(path)) {
             workbook.write(outputStream);
             workbook.close();
             workbook = null;
         } catch (Exception e) {
-            log.error("写入失败。。。");
+            log.error("写入失败。。。" + e.getMessage());
         }
     }
 
@@ -163,10 +181,6 @@ public class TslReportService {
         for (int i = 0; i < 4; i++) {
             sheet4.setColumnWidth(i, 2848);
         }
-        // sheet4.setColumnWidth(0, 2048);
-        // sheet4.setColumnWidth(1, 2304);
-        // sheet4.setColumnWidth(2, 2048);
-        // sheet4.setColumnWidth(3, 2804);
 
         // 设置行高 15.0 15.0...
         for (int i = 0; i < 15; i++) {
@@ -223,10 +237,6 @@ public class TslReportService {
         for (int i = 0; i < 4; i++) {
             sheet5.setColumnWidth(i, 2848);
         }
-        // sheet5.setColumnWidth(0, 2048);
-        // sheet5.setColumnWidth(1, 2304);
-        // sheet5.setColumnWidth(2, 2048);
-        // sheet5.setColumnWidth(3, 2804);
 
         // 设置行高 15.0 15.0...
         for (int i = 0; i < 15; i++) {
@@ -619,6 +629,175 @@ public class TslReportService {
         }
     }
 
+    /**
+     * 20230627新增 客户端-战略考核
+     * 
+     * @param day
+     */
+    private void getSheet1_1(String day) {
+        Sheet sheet = getWorkbook().createSheet("客户端-战略考核");
+
+        // 计算天数
+        LocalDate date = LocalDate.parse(day, DateTimeFormatter.ofPattern("yyyyMMdd"));
+        int dayOfMonth = date.getDayOfMonth();
+
+        Row row;
+        Cell cell;
+        CellRangeAddress rangeAddress;
+        XSSFFont font;
+        XSSFDataFormat dataFormat = getWorkbook().createDataFormat();
+
+        // 基本模式 微软雅黑 10号字 带全边框 水平居中
+        XSSFCellStyle baseStyle = getWorkbook().createCellStyle();
+        font = getWorkbook().createFont();
+        font.setFontName("微软雅黑");
+        font.setFontHeightInPoints((short) 10);
+        baseStyle.setFont(font);
+        baseStyle.setAlignment(HorizontalAlignment.CENTER);
+        baseStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+        baseStyle.setBorderBottom(BorderStyle.THIN);
+        baseStyle.setBorderTop(BorderStyle.THIN);
+        baseStyle.setBorderLeft(BorderStyle.THIN);
+        baseStyle.setBorderRight(BorderStyle.THIN);
+        // 基础模式
+        XSSFCellStyle cellStyle1 = baseStyle.copy();
+        // 2位小数
+        XSSFCellStyle cellStyle2 = baseStyle.copy();
+        cellStyle2.setDataFormat(dataFormat.getFormat("0.00"));
+        // 微软雅黑 10号 加粗
+        XSSFCellStyle cellStyle3 = baseStyle.copy();
+        font = getWorkbook().createFont();
+        font.setFontName("微软雅黑");
+        font.setBold(true);
+        font.setFontHeightInPoints((short) 10);
+        cellStyle3.setFont(font);
+
+        // 第一行 标题栏
+        cell = sheet.createRow(0).createCell(0);
+        cell.setCellValue(day.substring(0, 4) + "年客服投诉清单各地市投诉率情况(管理端-移网质量类)");
+        cell.setCellStyle(cellStyle3);
+        // 合并单元格
+        rangeAddress = new CellRangeAddress(0, 0, 0, dayOfMonth + 7);
+        sheet.addMergedRegion(rangeAddress);
+        // 设置合并单元格的边框
+        RegionUtil.setBorderBottom(BorderStyle.THIN, rangeAddress, sheet);
+        RegionUtil.setBorderTop(BorderStyle.THIN, rangeAddress, sheet);
+        RegionUtil.setBorderLeft(BorderStyle.THIN, rangeAddress, sheet);
+        RegionUtil.setBorderRight(BorderStyle.THIN, rangeAddress, sheet);
+
+        // 第二行 列名
+        row = sheet.createRow(1);
+        cell = row.createCell(0);
+        cell.setCellValue("地市");
+        cell.setCellStyle(cellStyle1);
+        for (int i = 1; i <= dayOfMonth; i++) {
+            cell = row.createCell(i);
+            cell.setCellValue(i + "日");
+            cell.setCellStyle(cellStyle1);
+        }
+        cell = row.createCell(dayOfMonth + 1);
+        cell.setCellValue("投诉总量");
+        cell.setCellStyle(cellStyle1);
+        cell = row.createCell(dayOfMonth + 2);
+        cell.setCellValue("用户数");
+        cell.setCellStyle(cellStyle1);
+        cell = row.createCell(dayOfMonth + 3);
+        cell.setCellValue("目前万投率");
+        cell.setCellStyle(cellStyle1);
+        cell = row.createCell(dayOfMonth + 4);
+        cell.setCellValue("本月预测");
+        cell.setCellStyle(cellStyle1);
+        cell = row.createCell(dayOfMonth + 5);
+        cell.setCellValue("目标值");
+        cell.setCellStyle(cellStyle1);
+        cell = row.createCell(dayOfMonth + 6);
+        cell.setCellValue("与目标差距");
+        cell.setCellStyle(cellStyle1);
+        cell = row.createCell(dayOfMonth + 7);
+        cell.setCellValue("地市");
+        cell.setCellStyle(cellStyle1);
+
+        // 获取数据
+        Map<String, List<Object>> seet1_1Data = tslDataService.getSheet1_1Data(day);
+
+        int rowNum = 2;
+        int cellNum = 0;
+        // 写入各地市数据
+        for (String area : areaInfoDao.getAllCityName()) {
+            row = sheet.createRow(rowNum++);
+            // 写入A列的地市
+            cell = row.createCell(cellNum++);
+            cell.setCellValue(area);
+            cell.setCellStyle(cellStyle1);
+            for (Object obj : seet1_1Data.get(area)) {
+                cell = row.createCell(cellNum++);
+                cell.setCellValue(Double.parseDouble(obj.toString()));
+                cell.setCellStyle(cellStyle1);
+            }
+            // 写入最后一列的地市
+            cell = row.createCell(cellNum++);
+            cell.setCellValue(area);
+            cell.setCellStyle(cellStyle1);
+            // cellNum复位
+            cellNum = 0;
+        }
+        // 写入全省数据
+        row = sheet.createRow(rowNum);
+        // 写入A列的地市
+        cell = row.createCell(cellNum++);
+        cell.setCellValue("全省");
+        cell.setCellStyle(cellStyle1);
+        for (Object obj : seet1_1Data.get("全省")) {
+            cell = row.createCell(cellNum++);
+            cell.setCellValue(Double.parseDouble(obj.toString()));
+            cell.setCellStyle(cellStyle1);
+        }
+        // 写入最后一列的地市
+        cell = row.createCell(cellNum++);
+        cell.setCellValue("全省");
+        cell.setCellStyle(cellStyle1);
+
+        // 3-15行(2-14)dayOfMonth+2 - dayofMonth+6是浮点数,设置为显示小数点后2位
+        for (int i = 2; i <= 14; i++) {
+            row = sheet.getRow(i);
+            for (int j = dayOfMonth + 2; j <= dayOfMonth + 6; j++) {
+                cell = row.getCell(j);
+                cell.setCellStyle(cellStyle2);
+            }
+        }
+
+        // 添加条件格式B15-V15
+        rangeAddress = new CellRangeAddress(rowNum, rowNum, 1, dayOfMonth);
+        setConditionalFormatting(sheet, rangeAddress);
+        // 添加条件格式(dayOfMonth+3)(3-14)
+        rangeAddress = new CellRangeAddress(2, 13, dayOfMonth + 3, dayOfMonth + 3);
+        setConditionalFormatting(sheet, rangeAddress);
+        // 添加条件格式Z3-Z14
+        rangeAddress = new CellRangeAddress(2, 13, dayOfMonth + 4, dayOfMonth + 4);
+        setConditionalFormatting(sheet, rangeAddress);
+        // 添加条件格式AB3-AB14
+        rangeAddress = new CellRangeAddress(2, 13, dayOfMonth + 6, dayOfMonth + 6);
+        setConditionalFormatting(sheet, rangeAddress);
+
+        // 设置sheet的列宽
+        sheet.setColumnWidth(0, 1500);
+        for (int i = 1; i <= dayOfMonth; i++) {
+            sheet.setColumnWidth(i, 1100);
+        }
+        sheet.setColumnWidth(dayOfMonth + 1, 1700);
+        sheet.setColumnWidth(dayOfMonth + 2, 2100);
+        sheet.setColumnWidth(dayOfMonth + 3, 2100);
+        sheet.setColumnWidth(dayOfMonth + 4, 2100);
+        sheet.setColumnWidth(dayOfMonth + 5, 1700);
+        sheet.setColumnWidth(dayOfMonth + 6, 2100);
+        sheet.setColumnWidth(dayOfMonth + 7, 1500);
+
+        // 设置行高 15
+        for (int i = 0; i < rowNum; i++) {
+            sheet.getRow(i).setHeightInPoints(15F);
+        }
+    }
+
     /**
      * 管理端-移网质量类
      * 
@@ -640,7 +819,7 @@ public class TslReportService {
         XSSFFont font = getWorkbook().createFont();
         font.setFontName("微软雅黑");
         font.setBold(false);
-        font.setFontHeightInPoints((short) 9);
+        font.setFontHeightInPoints((short) 10);
         cellStyle1.setFont(font);
         cellStyle1.setBorderBottom(BorderStyle.THIN);
         cellStyle1.setBorderTop(BorderStyle.THIN);
@@ -662,7 +841,7 @@ public class TslReportService {
         font = getWorkbook().createFont();
         font.setFontName("微软雅黑");
         font.setBold(true);
-        font.setFontHeightInPoints((short) 9);
+        font.setFontHeightInPoints((short) 10);
         cellStyle2.setFont(font);
         cellStyle2.setBorderBottom(BorderStyle.THIN);
         cellStyle2.setBorderTop(BorderStyle.THIN);
@@ -671,7 +850,7 @@ public class TslReportService {
 
         // 第一行 标题栏
         cell = sheet.createRow(0).createCell(0);
-        cell.setCellValue("2023年客服投诉清单各地市投诉率情况(管理端-移网质量类)");
+        cell.setCellValue(day.substring(0, 4) + "年客服投诉清单各地市投诉率情况(管理端-移网质量类)");
         cell.setCellStyle(cellStyle2);
         // 合并单元格
         CellRangeAddress range = new CellRangeAddress(0, 0, 0, dayOfMonth + 7);
@@ -720,7 +899,7 @@ public class TslReportService {
         int rowNum = 2;
         int cellNum = 0;
         // 写入各地市数据
-        for (String area : tslDataService.getAreas()) {
+        for (String area : areaInfoDao.getAllCityName()) {
             row = sheet.createRow(rowNum++);
             // 写入A列的地市
             cell = row.createCell(cellNum++);
@@ -776,22 +955,22 @@ public class TslReportService {
         rangeAddress = new CellRangeAddress(2, 13, dayOfMonth + 6, dayOfMonth + 6);
         setConditionalFormatting(sheet, rangeAddress);
 
-        // 设置sheet的列宽 1409, 876, 876, ..., 876, 1792, 1665, 2177, 2844, 1409, 2177, 1409
-        sheet.setColumnWidth(0, 1409);
+        // 设置sheet的列宽
+        sheet.setColumnWidth(0, 1500);
         for (int i = 1; i <= dayOfMonth; i++) {
-            sheet.setColumnWidth(i, 876);
+            sheet.setColumnWidth(i, 1100);
         }
-        sheet.setColumnWidth(dayOfMonth + 1, 1792);
-        sheet.setColumnWidth(dayOfMonth + 2, 1665);
-        sheet.setColumnWidth(dayOfMonth + 3, 2177);
-        sheet.setColumnWidth(dayOfMonth + 4, 2844);
-        sheet.setColumnWidth(dayOfMonth + 5, 1409);
-        sheet.setColumnWidth(dayOfMonth + 6, 2177);
-        sheet.setColumnWidth(dayOfMonth + 7, 1409);
+        sheet.setColumnWidth(dayOfMonth + 1, 1700);
+        sheet.setColumnWidth(dayOfMonth + 2, 2100);
+        sheet.setColumnWidth(dayOfMonth + 3, 2100);
+        sheet.setColumnWidth(dayOfMonth + 4, 2100);
+        sheet.setColumnWidth(dayOfMonth + 5, 1700);
+        sheet.setColumnWidth(dayOfMonth + 6, 2100);
+        sheet.setColumnWidth(dayOfMonth + 7, 1500);
 
-        // 设置行高 12
+        // 设置行高 15
         for (int i = 0; i < rowNum; i++) {
-            sheet.getRow(i).setHeightInPoints(12F);
+            sheet.getRow(i).setHeightInPoints(15F);
         }
     }
 

+ 11 - 6
tsl_data/src/main/java/com/nokia/tsl_data/service/TslTaskService.java

@@ -143,30 +143,35 @@ public class TslTaskService {
             screenShot = PoiUtil.screenShot(workbook.getSheet("管理端-移网质量类"), area, "微软雅黑");
             ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-1-投诉率.png"));
 
+            // 新截图
+            String area2 = "A1:" + CellRect.getColumnName(dayOfMonth + 7) + "15";
+            screenShot = PoiUtil.screenShot(workbook.getSheet("客户端-战略考核"), area2, "微软雅黑");
+            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-2-客户端-战略考核.png"));
+
             // 截图2
             if (!day.endsWith("01")) {
                 screenShot = PoiUtil.screenShot(workbook.getSheet("管理端-重复投诉率"), "A1:G16", "微软雅黑");
-                ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-2-重复投诉率.png"));
+                ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-3-重复投诉率.png"));
             }
 
             // 截图3 4
             Sheet sheet = workbook.getSheet("投诉处理时长、超时工单概况");
             screenShot = PoiUtil.screenShot(sheet, "A1:D15", "微软雅黑");
-            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-3-超时工单.png"));
+            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-4-超时工单.png"));
             screenShot = PoiUtil.screenShot(sheet, "G1:J14", "微软雅黑");
-            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-4-处理时长.png"));
+            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-5-处理时长.png"));
 
             // 截图5
             screenShot = PoiUtil.screenShot(workbook.getSheet("客户端-投诉问题解决满意度"), "A1:D15", "微软雅黑");
-            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-5-满意率.png"));
+            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-6-满意率.png"));
 
             // 截图6
             screenShot = PoiUtil.screenShot(workbook.getSheet("客户端-投诉问题解决率"), "A1:D15", "微软雅黑");
-            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-6-解决率.png"));
+            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-7-解决率.png"));
 
             // 截图7
             screenShot = PoiUtil.screenShot(workbook.getSheet("客户端-投诉问题响应率"), "A1:D15", "微软雅黑");
-            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-7-响应率.png"));
+            ImageIO.write(screenShot, "png", new File(screenShotPath + day + "-8-响应率.png"));
         } catch (EncryptedDocumentException | IOException | ParseException e) {
             throw new RuntimeException(e.getMessage());
         }

+ 97 - 0
tsl_data/src/main/java/com/nokia/tsl_data/service/UserCountService.java

@@ -0,0 +1,97 @@
+package com.nokia.tsl_data.service;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.nokia.tsl_data.dao.UserCountDao;
+
+@Service
+public class UserCountService {
+
+    @Autowired
+    private UserCountDao userCountDao;
+
+    /**
+     * 读取管理端用户数如果当前月份没有数据就读上一个月
+     * 
+     * 递归方式,最多递归2层
+     * 
+     * @param monthId
+     * @return
+     */
+    public Map<String, Double> getMangementUserCountForMonth(String monthId) {
+        List<Map<String, Object>> mangementUserCountForMonth = getMangementUserCountForMonth(monthId, 2);
+        Map<String, Double> result = new HashMap<>();
+        for (Map<String, Object> map : mangementUserCountForMonth) {
+            result.put(map.get("city_name").toString(),
+                    Double.parseDouble(map.get("management_user_count").toString()));
+        }
+        return result;
+    }
+
+    /**
+     * 递归实现getangementUserCountForMonth
+     * 
+     * @param monthId
+     * @param stackLayerCount
+     * @return
+     */
+    private List<Map<String, Object>> getMangementUserCountForMonth(String monthId, int stackLayerCount) {
+        List<Map<String, Object>> result = userCountDao.selectMangementUserCountForMonth(monthId);
+        if (stackLayerCount != 0) {
+            stackLayerCount -= 1;
+            if (result == null || result.size() == 0) {
+                LocalDate localDate = LocalDate.parse(monthId + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
+                localDate = localDate.plusMonths(-1L);
+                String newMonthId = DateTimeFormatter.ofPattern("yyyyMM").format(localDate);
+                return getMangementUserCountForMonth(newMonthId, stackLayerCount);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 读取客户端用户数如果当前月份没有数据就读上一个月
+     * 
+     * 递归方式,最多递归2层
+     * 
+     * @param monthId
+     * @return
+     */
+    public Map<String, Double> getCustomerUserCountForMonth(String monthId) {
+        List<Map<String, Object>> mangementUserCountForMonth = getCustomerUserCountForMonth(monthId, 2);
+        Map<String, Double> result = new HashMap<>();
+        for (Map<String, Object> map : mangementUserCountForMonth) {
+            result.put(map.get("city_name").toString(),
+                    Double.parseDouble(map.get("customer_user_count").toString()));
+        }
+        return result;
+    }
+
+    /**
+     * 递归实现getangementUserCountForMonth
+     * 
+     * @param monthId
+     * @param stackLayerCount
+     * @return
+     */
+    private List<Map<String, Object>> getCustomerUserCountForMonth(String monthId, int stackLayerCount) {
+        List<Map<String, Object>> result = userCountDao.selectCustomerUserCountForMonth(monthId);
+        if (stackLayerCount != 0) {
+            stackLayerCount -= 1;
+            if (result == null || result.size() == 0) {
+                LocalDate localDate = LocalDate.parse(monthId + "01", DateTimeFormatter.ofPattern("yyyyMMdd"));
+                localDate = localDate.plusMonths(-1L);
+                String newMonthId = DateTimeFormatter.ofPattern("yyyyMM").format(localDate);
+                return getCustomerUserCountForMonth(newMonthId, stackLayerCount);
+            }
+        }
+        return result;
+    }
+}

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

@@ -1,4 +1,4 @@
-spring.profiles.active=pro
+spring.profiles.active=dev
 
 server.port=29100
 mybatis.mapper-locations=classpath:mapper/*.xml

+ 12 - 0
tsl_data/src/main/resources/mapper/AreaInfoDao.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.nokia.tsl_data.dao.AreaInfoDao">
+
+    <select id="getAllCityName" resultType="string"> select area_name from report_auto.area_info
+        where area_type = 'city' and ord is not null order by ord </select>
+
+    <insert id="insertOne"> INSERT INTO report_auto.area_info (area_name, area_type)
+        VALUES(#{areaName}, #{areaType}); </insert>
+
+</mapper>

+ 18 - 0
tsl_data/src/main/resources/mapper/HighQualityCountDao.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.nokia.tsl_data.dao.HighQualityCountDao">
+
+    <!-- 从客户端统计表获取某日的总投诉量(办结量) -->
+    <select id="selectTotalComplaintsForDay" resultType="map">select businoareaname,
+        total_complaints from report_auto.he_d_high_quality hdhq where month_id = substring(#{day}
+        from 1 for 6) and day_id = substring(#{day} from 7 for 2) and profes_dep = '网络质量' and
+        big_type_name = '移网网络体验' and small_type_name = '--'</select>
+
+    <!-- 从客户端统计表获取某日的总投诉量(办结量) 入参 monthId dayId -->
+    <select id="selectTotalComplaintsForMonthIdAndDay" resultType="map">select businoareaname,
+        total_complaints from report_auto.he_d_high_quality hdhq where month_id = #{monthId} and
+        day_id = #{day} and profes_dep = '网络质量' and big_type_name = '移网网络体验' and small_type_name =
+        '--'</select>
+
+</mapper>

+ 5 - 6
tsl_data/src/test/java/com/nokia/tsl_data/TslDataApplicationTest.java

@@ -4,19 +4,18 @@ import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
-import com.nokia.tsl_data.dao.TslDao;
+import com.nokia.tsl_data.service.TslTaskService;
 
 @SpringBootTest
 public class TslDataApplicationTest {
 
     @Autowired
-    private TslDao tslDao;
+    private TslTaskService service;
 
     @Test
     void test() {
-        String day = "20230601";
-        String dayId = day.substring(0, 4) + "-" + day.substring(4, 6) + "-" + day.substring(6);
-        int selectQualityCountForDay = tslDao.selectQualityCountForDay(dayId);
-        System.out.println(selectQualityCountForDay);
+        service.reportGenerateTask("20230621");
+        service.screenShotTask("20230621");
     }
+
 }