EntPromotionSummaryRender.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. package com.yaoyicloud.render.cso;
  2. import java.io.IOException;
  3. import java.util.ArrayList;
  4. import java.util.HashMap;
  5. import java.util.HashSet;
  6. import java.util.List;
  7. import java.util.Map;
  8. import java.util.Set;
  9. import java.util.stream.Collectors;
  10. import com.yaoyicloud.easier.common.file.core.FileProperties;
  11. import com.yaoyicloud.easier.common.file.core.FileTemplate;
  12. import com.yaoyicloud.factory.CSOAbstractRender;
  13. import org.apache.commons.collections4.MapUtils;
  14. import com.deepoove.poi.config.Configure;
  15. import com.deepoove.poi.config.ConfigureBuilder;
  16. import com.deepoove.poi.policy.DynamicTableRenderPolicy;
  17. import com.fasterxml.jackson.core.type.TypeReference;
  18. import com.fasterxml.jackson.databind.ObjectMapper;
  19. import com.google.common.primitives.Longs;
  20. import com.google.protobuf.ByteString;
  21. import com.google.protobuf.ListValue;
  22. import com.google.protobuf.util.JsonFormat;
  23. import com.yaoyicloud.config.CommonDataCache;
  24. import com.yaoyicloud.config.FilerepoProperties;
  25. import com.yaoyicloud.message.CSOProtos;
  26. import lombok.extern.slf4j.Slf4j;
  27. @Slf4j
  28. public final class EntPromotionSummaryRender extends CSOAbstractRender {
  29. private final FilerepoProperties filerepoProperties;
  30. private final CommonDataCache commonDataCache;
  31. public EntPromotionSummaryRender(String cwd, FileTemplate ossTemplate, FileProperties properties,
  32. FilerepoProperties filerepoProperties,
  33. CommonDataCache commonDataCache) {
  34. super(cwd, ossTemplate, properties);
  35. this.filerepoProperties = filerepoProperties;
  36. this.commonDataCache = commonDataCache;
  37. }
  38. @Override
  39. protected Map<String, Object> renderDocx(String info, String relationId, Integer counter) throws IOException {
  40. log.info("开始渲染CSO企业报告推广总结模块,relationId: {}", relationId);
  41. CSOProtos.PromotionSummary.Builder promotionSummary = CSOProtos.PromotionSummary.newBuilder();
  42. JsonFormat.parser().merge(info, promotionSummary);
  43. // 获取用户提交的积分数据
  44. Map<String, ByteString> userSubmittedScoreMapMap = promotionSummary.getUserSubmittedScoreMapMap();
  45. // 关键步骤:将Protobuf的bytes数据转换为Map<String, List<Integer>>
  46. Map<String, List<Integer>> userScoreMap = new HashMap<>();
  47. for (Map.Entry<String, ByteString> entry : userSubmittedScoreMapMap.entrySet()) {
  48. String userId = entry.getKey();
  49. ByteString byteString = entry.getValue();
  50. // 解析bytes为ListValue
  51. ListValue listValue = ListValue.parseFrom(byteString);
  52. // 转换为List<Integer>
  53. List<Integer> scoreList = listValue.getValuesList().stream()
  54. .map(value -> (int) value.getNumberValue())
  55. .collect(Collectors.toList());
  56. userScoreMap.put(userId, scoreList);
  57. }
  58. CSOProtos.PromotionSummary defaultInstance = CSOProtos.PromotionSummary.getDefaultInstance();
  59. CSOProtos.PromotionSummary mergedProto = defaultInstance.toBuilder()
  60. .mergeFrom(promotionSummary.build())
  61. .build();
  62. String completeJson = JsonFormat.printer()
  63. .includingDefaultValueFields()
  64. .print(mergedProto);
  65. ObjectMapper objectMapper = new ObjectMapper();
  66. Map<String, Object> data = objectMapper.readValue(completeJson, new TypeReference<Map<String, Object>>() {});
  67. // 将用户积分数据添加到渲染数据中
  68. data.put("userScoreMap", userScoreMap); // 这将使数据在模板中可用
  69. Map<String, Object> commonDataCacheData = commonDataCache.getData(relationId);
  70. if (MapUtils.isNotEmpty(commonDataCacheData)) {
  71. data.putAll(commonDataCacheData);
  72. }
  73. commonDataCacheData.put("sensitiveFlag", data.get("sensitiveFlag"));
  74. data.put("levelInteger", counter);
  75. fillDefaultValues(data);
  76. return data;
  77. }
  78. @Override
  79. protected ConfigureBuilder builder(String relationId) {
  80. ConfigureBuilder builder = Configure.builder();
  81. DynamicTableRenderPolicy twoLevelTableDynamicPolicy = getTwoLevelTableDynamicPolicy();
  82. DynamicTableRenderPolicy lastRowDaynamicPolicy = getTableLastRowDynamicPolicy();
  83. Map<String, Object> commonDataCacheData = commonDataCache.getData(relationId);
  84. DynamicTableRenderPolicy tableDynamicPolicy = super.getDynamicTableRenderPolicy(commonDataCacheData);
  85. builder.bind("task_analysis_5_1", twoLevelTableDynamicPolicy);
  86. builder.bind("task_promotion_count_5_1_1", twoLevelTableDynamicPolicy);
  87. builder.bind("task_promotion_count_5_1_1_last", lastRowDaynamicPolicy);
  88. builder.bind("task_promotioner_5_4", tableDynamicPolicy);
  89. builder.bind("task_promotioner_quality_5_4_1", this.indicatorsRenderPolicyToProtobuf());
  90. builder.bind("task_promotioner_quality_5_4_1_last", lastRowDaynamicPolicy);
  91. return builder;
  92. }
  93. @Override
  94. protected String getBasicPath() throws IOException {
  95. return filerepoProperties.getBasePath();
  96. }
  97. @Override
  98. protected String getReportImagePath() {
  99. return filerepoProperties.getReportImagePath();
  100. }
  101. /**
  102. * 填充默认值,确保所有必要字段都存在
  103. */
  104. @SuppressWarnings("checkstyle:MethodLength")
  105. private void fillDefaultValues(Map<String, Object> data) {
  106. Integer submitedTaskScore = (Integer) data.get("submitedTaskScore");
  107. Integer totalApprovedScore = (Integer) data.get("totalApprovedScore");
  108. data.put("rejectedTaskScore", submitedTaskScore - totalApprovedScore);
  109. // 提取任务类型元数据(taskTypeMetas)
  110. List<Map<String, Object>> taskTypeMetas = (List<Map<String, Object>>) data.get("taskTypeMetas");
  111. // 提取按类型统计的任务数据(taskStatsByType)
  112. List<Map<String, Object>> taskStatsByTypeList = (List<Map<String, Object>>) data.get("taskStatsByType");
  113. // 提取按用户统计的任务数据(taskStatsByPerson)
  114. List<Map<String, Object>> taskStatsByPersonList = (List<Map<String, Object>>) data.get("taskStatsByPerson");
  115. // 提取全局统计字段
  116. int approvedCnt = (Integer) data.getOrDefault("taskPromotionerQuality541ApprovedCnt", 0);
  117. int submittedCnt = (Integer) data.getOrDefault("taskPromotionerQuality541SubmittedCnt", 0);
  118. int rejectedCnt = (Integer) data.getOrDefault("taskPromotionerQuality541RejectedCnt", 0);
  119. Map<String, List<Integer>> userScoreMap = (Map<String, List<Integer>>) data.get("userScoreMap");
  120. Long scoreSum = 0L;
  121. for (Map.Entry<String, List<Integer>> stringListEntry : userScoreMap.entrySet()) {
  122. scoreSum += stringListEntry.getValue().stream().mapToLong(Long::valueOf).sum();
  123. }
  124. Map<String, String> userNameMap = taskTypeMetas.stream()
  125. .collect(Collectors.toMap(
  126. m -> m.get("userId").toString(),
  127. m -> m.get("userName").toString(),
  128. (oldValue, newValue) -> oldValue));
  129. data.put("userNameMap", userNameMap);
  130. // 2. 复现 task_analysis_5_1(按任务类型的统计分析)
  131. Map<String, List<List<Object>>> taskAnalysis51 = new HashMap<>();
  132. Map<String, Integer> mpParentTypeCount = new HashMap<>();
  133. Map<String, Long> mpParentTypeScore = new HashMap<>();
  134. // 解析taskStatsByType(protobuf中是列表,实际应为单个对象,取第一个)
  135. if (!taskStatsByTypeList.isEmpty()) {
  136. Map<String, Object> taskStatsByType = taskStatsByTypeList.get(0);
  137. Map<String, Map<String, Object>> taskStatsMap =
  138. (Map<String, Map<String, Object>>) taskStatsByType.get("taskStats");
  139. for (Map.Entry<String, Map<String, Object>> entry : taskStatsMap.entrySet()) {
  140. String taskTypeId = entry.getKey();
  141. Map<String, Object> taskStat = entry.getValue();
  142. int count = (Integer) taskStat.get("count");
  143. Object o = taskStat.get("score");
  144. Long score = Longs.tryParse(o.toString());
  145. // 从taskTypeMetas中获取父/子分类名称(根据taskTypeId匹配)
  146. String parentName = "";
  147. String childName = "";
  148. for (Map<String, Object> meta : taskTypeMetas) {
  149. if (meta.get("taskTypeId").equals(taskTypeId)) {
  150. parentName = (String) meta.get("parentName");
  151. childName = (String) meta.get("childName");
  152. break;
  153. }
  154. }
  155. // 构建行数据
  156. List<Object> row = new ArrayList<>();
  157. row.add(childName);
  158. row.add(count);
  159. row.add(count * 1.0 / approvedCnt); // 占比=当前类型数量/总通过数量
  160. row.add(score);
  161. row.add(score * 1d / scoreSum); // 积分占比
  162. // 按父分类分组
  163. List<List<Object>> rowList = taskAnalysis51.getOrDefault(parentName, new ArrayList<>());
  164. rowList.add(row);
  165. taskAnalysis51.put(parentName, rowList);
  166. // 更新父分类的总数量和积分
  167. mpParentTypeCount.put(parentName, mpParentTypeCount.getOrDefault(parentName, 0) + count);
  168. mpParentTypeScore.put(parentName, mpParentTypeScore.getOrDefault(parentName, 0L) + score);
  169. }
  170. }
  171. data.put("task_analysis_5_1", taskAnalysis51);
  172. // 复现 task_analysis_5_1 的最大值(最多任务的父分类)
  173. if (!mpParentTypeCount.isEmpty()) {
  174. Map<String, Integer> starTaskMap = (Map<String, Integer>) data.get("starTaskMap");
  175. Map.Entry<String, Integer> maxEntry = starTaskMap.entrySet().iterator().next();
  176. data.put("task_analysis_5_1_maxName", maxEntry.getKey());
  177. data.put("task_analysis_5_1_maxCount", maxEntry.getValue().toString());
  178. // 计算最大父分类的积分占比
  179. long maxParentScore = mpParentTypeScore.getOrDefault(maxEntry.getKey(), 0L);
  180. data.put("task_analysis_5_1_maxPercent", String.format("%.2f", maxParentScore * 1.0 / scoreSum * 100));
  181. }
  182. // 3. 复现 task_promotion_count_5_1_1(按任务类型的推广人统计)
  183. Map<String, List<List<Object>>> taskPromotionCount511 = new HashMap<>();
  184. Set<String> allPromotioners = new HashSet<>(); // 所有推广人ID
  185. if (!taskStatsByTypeList.isEmpty()) {
  186. Map<String, Object> taskStatsByType = taskStatsByTypeList.get(0);
  187. Map<String, Map<String, Object>> taskStatsMap =
  188. (Map<String, Map<String, Object>>) taskStatsByType.get("taskStats");
  189. for (Map.Entry<String, Map<String, Object>> entry : taskStatsMap.entrySet()) {
  190. String taskTypeId = entry.getKey();
  191. Map<String, Object> taskStat = entry.getValue();
  192. int count = (Integer) taskStat.get("count");
  193. List<String> promotioners = (List<String>) taskStat.get("promotioners"); // 该任务类型的推广人列表
  194. if (promotioners != null) {
  195. allPromotioners.addAll(promotioners);
  196. }
  197. // 从taskTypeMetas中获取父/子分类名称
  198. String parentName = "";
  199. String childName = "";
  200. for (Map<String, Object> meta : taskTypeMetas) {
  201. if (meta.get("taskTypeId").equals(taskTypeId)) {
  202. parentName = (String) meta.get("parentName");
  203. childName = (String) meta.get("childName");
  204. break;
  205. }
  206. }
  207. // 构建行数据
  208. List<Object> row = new ArrayList<>();
  209. row.add(childName);
  210. row.add(promotioners != null ? promotioners.size() : 0); // 推广人数
  211. row.add(count); // 任务数量
  212. row.add(promotioners != null && !promotioners.isEmpty() ? count * 1.0 / promotioners.size() : 0); // 人均任务数
  213. // 按父分类分组
  214. List<List<Object>> rowList = taskPromotionCount511.getOrDefault(parentName, new ArrayList<>());
  215. rowList.add(row);
  216. taskPromotionCount511.put(parentName, rowList);
  217. }
  218. }
  219. data.put("task_promotion_count_5_1_1", taskPromotionCount511);
  220. // 复现推广人平均任务数
  221. int promotionerCount = allPromotioners.size();
  222. String avgByPerson =
  223. promotionerCount > 0 ? String.format("%.2f", approvedCnt * 1.0 / promotionerCount) : "0.00";
  224. data.put("task_promotion_count_5_1_1_avg", avgByPerson);
  225. // 复现task_promotion_count_5_1_1_last(合计行)
  226. List<Object> lastRow511 = new ArrayList<>();
  227. lastRow511.add(null); // label
  228. lastRow511.add(promotionerCount); // 总推广人数
  229. lastRow511.add(approvedCnt); // 总任务数
  230. lastRow511.add(avgByPerson); // 平均任务数
  231. data.put("task_promotion_count_5_1_1_last", lastRow511);
  232. // 4. 复现 task_promotioner_5_4(按推广人的任务类型统计)
  233. Map<String, List<List<Object>>> taskPromotioner54 = new HashMap<>();
  234. if (!taskStatsByPersonList.isEmpty()) {
  235. Map<String, Object> taskStatsByPerson = taskStatsByPersonList.get(0);
  236. Map<String, Map<String, Object>> userStatsMap =
  237. (Map<String, Map<String, Object>>) taskStatsByPerson.get("userStats");
  238. for (Map.Entry<String, Map<String, Object>> userEntry : userStatsMap.entrySet()) {
  239. String userId = userEntry.getKey();
  240. Map<String, Object> userTaskStats = userEntry.getValue();
  241. Map<String, Map<String, Object>> taskStatsByUser =
  242. (Map<String, Map<String, Object>>) userTaskStats.get("taskStats");
  243. // 获取用户名(从taskTypeMetas中匹配)
  244. // String userName = "无姓名";
  245. // for (Map<String, Object> meta : taskTypeMetas) {
  246. // if (meta.get("userId").equals(userId)) {
  247. // userName = (String) meta.get("userName");
  248. // break;
  249. // }
  250. // }
  251. // 构建该用户的任务统计行
  252. List<List<Object>> rowList = new ArrayList<>();
  253. for (Map.Entry<String, Map<String, Object>> taskEntry : taskStatsByUser.entrySet()) {
  254. String taskTypeId = taskEntry.getKey();
  255. Map<String, Object> taskStat = taskEntry.getValue();
  256. int count = (Integer) taskStat.get("count");
  257. Object o = taskStat.get("score");
  258. Long score = Longs.tryParse(o.toString());
  259. // 获取任务类型名称
  260. String taskTypeName = "";
  261. for (Map<String, Object> meta : taskTypeMetas) {
  262. if (meta.get("taskTypeId").equals(taskTypeId)) {
  263. taskTypeName = (String) meta.get("childName");
  264. break;
  265. }
  266. }
  267. List<Object> row = new ArrayList<>();
  268. row.add(taskTypeName);
  269. row.add(count);
  270. row.add(count * 1.0 / approvedCnt); // 任务占比
  271. row.add(score);
  272. row.add(score * 1d / scoreSum);
  273. rowList.add(row);
  274. }
  275. taskPromotioner54.put(userId, rowList);
  276. }
  277. }
  278. data.put("task_promotioner_5_4", taskPromotioner54);
  279. // 5. 复现 task_promotioner_quality_5_4_1(推广人质量统计)
  280. List<Map<String, Object>> taskPromotionerQuality541 = new ArrayList<>();
  281. int idx = 1;
  282. if (!taskStatsByPersonList.isEmpty()) {
  283. Map<String, Object> taskStatsByPerson = taskStatsByPersonList.get(0);
  284. Map<String, Map<String, Object>> userStatsMap =
  285. (Map<String, Map<String, Object>>) taskStatsByPerson.get("userStats");
  286. for (Map.Entry<String, Map<String, Object>> userEntry : userStatsMap.entrySet()) {
  287. String userId = userEntry.getKey();
  288. Map<String, Object> userTaskStats = userEntry.getValue();
  289. Map<String, Map<String, Object>> taskStatsByUser =
  290. (Map<String, Map<String, Object>>) userTaskStats.get("taskStats");
  291. // 计算该用户的总通过任务数和积分
  292. int userApprovedCnt = 0;
  293. long userApprovedScore = 0L;
  294. for (Map<String, Object> taskStat : taskStatsByUser.values()) {
  295. userApprovedCnt += (Integer) taskStat.get("count");
  296. userApprovedScore += Longs.tryParse(taskStat.get("score").toString());
  297. }
  298. int userSubmittedCnt = 0;
  299. int userSubmittedScore = 0;
  300. // 获取用户名
  301. String userName = "无姓名";
  302. for (Map<String, Object> meta : taskTypeMetas) {
  303. if (meta.get("userId").equals(userId)) {
  304. userSubmittedCnt = userScoreMap.get(meta.get("userId").toString()).size();
  305. userSubmittedScore =
  306. userScoreMap.get(meta.get("userId")).stream().mapToInt(Integer::intValue).sum();
  307. userName = (String) meta.get("userName");
  308. break;
  309. }
  310. }
  311. // 构建行数据
  312. Map<String, Object> row = new HashMap<>();
  313. row.put("seq", idx++);
  314. row.put("promotioner", userName);
  315. row.put("submittedCnt", userSubmittedCnt);
  316. row.put("approvedCnt", userApprovedCnt);
  317. row.put("taskRate", userSubmittedCnt > 0
  318. ? String.format("%.2f%%", userApprovedCnt * 1.0 / userSubmittedCnt * 100) : "0.00%");
  319. row.put("submittedScore", userSubmittedScore);
  320. row.put("approvedScore", userApprovedScore);
  321. row.put("scoreRate", userSubmittedScore > 0
  322. ? String.format("%.2f%%", userApprovedScore * 1.0 / userSubmittedScore * 100) : "0.00%");
  323. taskPromotionerQuality541.add(row);
  324. }
  325. }
  326. data.put("task_promotioner_quality_5_4_1", taskPromotionerQuality541);
  327. // 6. 复现 task_promotioner_quality_5_4_1_last(合计行)
  328. List<Object> lastRow541 = new ArrayList<>();
  329. lastRow541.add(null); // label
  330. lastRow541.add(submittedCnt); // 总提交数
  331. lastRow541.add(approvedCnt); // 总通过数
  332. String taskRate = submittedCnt > 0 ? String.format("%.2f%%", approvedCnt * 1.0 / submittedCnt * 100) : "0.00%";
  333. lastRow541.add(taskRate);
  334. Long totalSubmittedScore = Longs.tryParse(scoreSum.toString());
  335. lastRow541.add(totalSubmittedScore);
  336. lastRow541.add(scoreSum); // 总通过积分
  337. String scoreRate =
  338. totalSubmittedScore > 0 ? String.format("%.2f%%", scoreSum * 1.0 / totalSubmittedScore * 100) : "0.00%";
  339. lastRow541.add(scoreRate);
  340. data.put("task_promotioner_quality_5_4_1_last", lastRow541);
  341. // 7. 填充其他字段
  342. data.put("task_promotioner_quality_5_4_1_taskRate", taskRate.replace("%", ""));
  343. data.put("task_promotioner_quality_5_4_1_scoreRate", scoreRate.replace("%", ""));
  344. data.put("task_promotioner_quality_5_4_1_approvedCnt", approvedCnt);
  345. data.put("task_promotioner_quality_5_4_1_submittedCnt", submittedCnt);
  346. data.put("task_promotioner_quality_5_4_1_rejectedCnt", rejectedCnt);
  347. }
  348. }