|
@@ -12,10 +12,13 @@ import com.jeeplus.common.utils.excel.ExportKnowledgeBaseExcel;
|
|
|
import com.jeeplus.common.web.BaseController;
|
|
import com.jeeplus.common.web.BaseController;
|
|
|
import com.jeeplus.modules.WorkKnowledgeBase.entity.UserPointDetail;
|
|
import com.jeeplus.modules.WorkKnowledgeBase.entity.UserPointDetail;
|
|
|
import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePoint;
|
|
import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePoint;
|
|
|
|
|
+import com.jeeplus.modules.WorkKnowledgeBase.entity.WorkKnowledgeBasePointRule;
|
|
|
|
|
+import com.jeeplus.modules.WorkKnowledgeBase.dao.WorkKnowledgeBasePointRuleDao;
|
|
|
import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBasePointDetailService;
|
|
import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBasePointDetailService;
|
|
|
import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBasePointExchangeService;
|
|
import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBasePointExchangeService;
|
|
|
import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBasePointService;
|
|
import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBasePointService;
|
|
|
import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBaseTreeService;
|
|
import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgeBaseTreeService;
|
|
|
|
|
+import com.jeeplus.modules.WorkKnowledgeBase.service.WorkKnowledgePointCategoryService;
|
|
|
import com.jeeplus.modules.sys.entity.User;
|
|
import com.jeeplus.modules.sys.entity.User;
|
|
|
import com.jeeplus.modules.sys.service.OfficeService;
|
|
import com.jeeplus.modules.sys.service.OfficeService;
|
|
|
import com.jeeplus.modules.sys.utils.UserUtils;
|
|
import com.jeeplus.modules.sys.utils.UserUtils;
|
|
@@ -61,6 +64,12 @@ public class WorkKnowledgeBasePointController extends BaseController {
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private WorkKnowledgeBaseTreeService treeService;
|
|
private WorkKnowledgeBaseTreeService treeService;
|
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private WorkKnowledgePointCategoryService workKnowledgePointCategoryService;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private WorkKnowledgeBasePointRuleDao pointRuleDao;
|
|
|
|
|
+
|
|
|
@ModelAttribute
|
|
@ModelAttribute
|
|
|
public WorkKnowledgeBasePoint get(@RequestParam(required=false) String id) {
|
|
public WorkKnowledgeBasePoint get(@RequestParam(required=false) String id) {
|
|
|
WorkKnowledgeBasePoint entity = null;
|
|
WorkKnowledgeBasePoint entity = null;
|
|
@@ -302,17 +311,17 @@ public class WorkKnowledgeBasePointController extends BaseController {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 积分统计三级导出:公司级、部门级、员工级
|
|
|
|
|
- * 列:上传文档数量、贡献积分额度、审核文档数量、审核积分额度、阅读积分额度、点赞积分额度、兑换积分额度
|
|
|
|
|
|
|
+ * 积分统计三层表头导出:公司级、部门级、员工级
|
|
|
|
|
+ * L1: parent_id=0的分类 → L2: 子分类 → L3: 规则point_name
|
|
|
|
|
+ * 每个L1组包含: L2子分类(L3规则列) + 兑现列 + 小计列
|
|
|
*/
|
|
*/
|
|
|
@RequiresPermissions("workKnowledgeBase:point:listAll")
|
|
@RequiresPermissions("workKnowledgeBase:point:listAll")
|
|
|
@RequestMapping(value = "exportPointStats")
|
|
@RequestMapping(value = "exportPointStats")
|
|
|
public void exportPointStats(WorkKnowledgeBasePoint queryParam, HttpServletResponse response) {
|
|
public void exportPointStats(WorkKnowledgeBasePoint queryParam, HttpServletResponse response) {
|
|
|
try {
|
|
try {
|
|
|
- // 查询所有员工积分统计(支持日期筛选,已按部门、姓名排序)
|
|
|
|
|
|
|
+ // 1. 查询所有员工积分统计
|
|
|
List<WorkKnowledgeBasePoint> employeeList = workKnowledgeBasePointDetailService.findAllEmployeePointStats(queryParam);
|
|
List<WorkKnowledgeBasePoint> employeeList = workKnowledgeBasePointDetailService.findAllEmployeePointStats(queryParam);
|
|
|
|
|
|
|
|
- // 构建时间范围标识(如传入了日期筛选)
|
|
|
|
|
String dateRangeSuffix = "";
|
|
String dateRangeSuffix = "";
|
|
|
if (StringUtils.isNotBlank(queryParam.getBeginDate()) || StringUtils.isNotBlank(queryParam.getEndDate())) {
|
|
if (StringUtils.isNotBlank(queryParam.getBeginDate()) || StringUtils.isNotBlank(queryParam.getEndDate())) {
|
|
|
String startDate = StringUtils.isNotBlank(queryParam.getBeginDate()) ? queryParam.getBeginDate() : "不限";
|
|
String startDate = StringUtils.isNotBlank(queryParam.getBeginDate()) ? queryParam.getBeginDate() : "不限";
|
|
@@ -320,308 +329,288 @@ public class WorkKnowledgeBasePointController extends BaseController {
|
|
|
dateRangeSuffix = "(" + startDate + " 至 " + endDate + ")";
|
|
dateRangeSuffix = "(" + startDate + " 至 " + endDate + ")";
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 定义固定的7个业务指标列(第一行表头)
|
|
|
|
|
- List<String> firstRowHeaders = Arrays.asList(
|
|
|
|
|
- "上传文档数量",
|
|
|
|
|
- "贡献积分额度",
|
|
|
|
|
- "审核文档数量",
|
|
|
|
|
- "审核积分额度",
|
|
|
|
|
- "阅读积分额度",
|
|
|
|
|
- "点赞积分额度",
|
|
|
|
|
- "已兑换积分额度"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 获取知识库分类树结构(一级分类列表,用于第二行表头细分)
|
|
|
|
|
- java.util.Map<String, List<String>> categoryTreeMap = treeService.getCategoryTreeForExport();
|
|
|
|
|
- List<String> categoryNames = new ArrayList<>(categoryTreeMap.keySet());
|
|
|
|
|
-
|
|
|
|
|
- // 7个业务指标对应的数据字段key(与entity中的getter对应)
|
|
|
|
|
- List<String> columnKeys = Arrays.asList(
|
|
|
|
|
- "uploadCount", "createPoint", "auditCount", "auditPoint",
|
|
|
|
|
- "readPoint", "likePoint", "exchangePoint"
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 构建第二行表头:每个固定列下包含"总量"+各一级分类
|
|
|
|
|
- List<List<String>> secondRowHeaders = new ArrayList<>();
|
|
|
|
|
- for (String columnHeader : firstRowHeaders) {
|
|
|
|
|
- List<String> subHeaders = new ArrayList<>();
|
|
|
|
|
- subHeaders.add("总量");
|
|
|
|
|
- for (String categoryName : categoryNames) {
|
|
|
|
|
- subHeaders.add(categoryName);
|
|
|
|
|
|
|
+ // 2. 构建三层表头结构(使用CategoryService已有的方法)
|
|
|
|
|
+ Map<String, Object> headerStructure = workKnowledgePointCategoryService.getThreeLevelHeaderStructure();
|
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
|
+ List<String> firstLevelHeaders = (List<String>) headerStructure.get("firstLevelHeaders");
|
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
|
+ List<List<String>> secondLevelHeaders = (List<List<String>>) headerStructure.get("secondLevelHeaders");
|
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
|
+ List<List<List<String>>> thirdLevelHeaders = (List<List<List<String>>>) headerStructure.get("thirdLevelHeaders");
|
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
|
+ List<Map<String, String>> flatColumnKeys = (List<Map<String, String>>) headerStructure.get("columnKeys");
|
|
|
|
|
+
|
|
|
|
|
+ // 从flatColumnKeys重建dataKeys结构 + 识别L2叶子列
|
|
|
|
|
+ List<List<List<String>>> dataKeysL3 = new ArrayList<>();
|
|
|
|
|
+ Set<Integer> l2LeafIndices = new HashSet<>(); // 编码为 i*1000+j
|
|
|
|
|
+ Set<Integer> directRuleIndices = new HashSet<>(); // 直接规则L2(无子分类的L1下的规则)
|
|
|
|
|
+ Set<Integer> subtotalIndices = new HashSet<>(); // 汇总列索引
|
|
|
|
|
+ Set<Integer> remainingIndices = new HashSet<>(); // 未兑换积分列索引
|
|
|
|
|
+ Map<Integer, Integer> exchangeColumnIndexMap = new HashMap<>(); // L1索引 -> 已兑换积分列的j索引
|
|
|
|
|
+ List<List<String>> secondLevelCategoryIds = new ArrayList<>(); // 每个L1对应的L2 categoryId列表
|
|
|
|
|
+ List<List<String>> directRuleIds = new ArrayList<>(); // 每个L1对应的直接规则ruleId列表
|
|
|
|
|
+ int keyIdx = 0;
|
|
|
|
|
+ for (int i = 0; i < firstLevelHeaders.size(); i++) {
|
|
|
|
|
+ List<String> l2ForL1 = secondLevelHeaders.get(i);
|
|
|
|
|
+ List<List<String>> l3ForL1 = thirdLevelHeaders.get(i);
|
|
|
|
|
+ List<List<String>> l3KeysForL1 = new ArrayList<>();
|
|
|
|
|
+ List<String> catIdsForL1 = new ArrayList<>();
|
|
|
|
|
+ List<String> drIdsForL1 = new ArrayList<>();
|
|
|
|
|
+ for (int j = 0; j < l2ForL1.size(); j++) {
|
|
|
|
|
+ List<String> l3ForL2 = l3ForL1.get(j);
|
|
|
|
|
+ List<String> l3Keys = new ArrayList<>();
|
|
|
|
|
+ if (!l3ForL2.isEmpty()) {
|
|
|
|
|
+ for (int k = 0; k < l3ForL2.size(); k++) {
|
|
|
|
|
+ if (keyIdx < flatColumnKeys.size()) {
|
|
|
|
|
+ l3Keys.add(flatColumnKeys.get(keyIdx).get("key")); // "rule_xxx"
|
|
|
|
|
+ keyIdx++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ catIdsForL1.add(""); // 有L3的L2,不需要categoryId
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 检查是"汇总"、"兑换"、"L2叶子"还是"直接规则"
|
|
|
|
|
+ if (keyIdx < flatColumnKeys.size()) {
|
|
|
|
|
+ Map<String, String> km = flatColumnKeys.get(keyIdx);
|
|
|
|
|
+ if ("l2leaf".equals(km.get("type"))) {
|
|
|
|
|
+ l2LeafIndices.add(i * 1000 + j);
|
|
|
|
|
+ catIdsForL1.add(km.get("categoryId"));
|
|
|
|
|
+ drIdsForL1.add("");
|
|
|
|
|
+ } else if ("directRule".equals(km.get("type"))) {
|
|
|
|
|
+ directRuleIndices.add(i * 1000 + j);
|
|
|
|
|
+ drIdsForL1.add(km.get("ruleId"));
|
|
|
|
|
+ catIdsForL1.add("");
|
|
|
|
|
+ } else if ("subtotal".equals(km.get("type"))) {
|
|
|
|
|
+ subtotalIndices.add(i * 1000 + j);
|
|
|
|
|
+ catIdsForL1.add("");
|
|
|
|
|
+ drIdsForL1.add("");
|
|
|
|
|
+ } else if ("remaining".equals(km.get("type"))) {
|
|
|
|
|
+ remainingIndices.add(i * 1000 + j);
|
|
|
|
|
+ catIdsForL1.add("");
|
|
|
|
|
+ drIdsForL1.add("");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // exchange类型,记录该L1组的exchange列索引
|
|
|
|
|
+ exchangeColumnIndexMap.put(i, j);
|
|
|
|
|
+ catIdsForL1.add("");
|
|
|
|
|
+ drIdsForL1.add("");
|
|
|
|
|
+ }
|
|
|
|
|
+ keyIdx++;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ catIdsForL1.add("");
|
|
|
|
|
+ drIdsForL1.add("");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ l3KeysForL1.add(l3Keys);
|
|
|
}
|
|
}
|
|
|
- secondRowHeaders.add(subHeaders);
|
|
|
|
|
|
|
+ dataKeysL3.add(l3KeysForL1);
|
|
|
|
|
+ secondLevelCategoryIds.add(catIdsForL1);
|
|
|
|
|
+ directRuleIds.add(drIdsForL1);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 收集所有用户ID
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 提取L1分类ID列表(从headerStructure中的columnKeys提取exchange对应的firstLevelId)
|
|
|
|
|
+ List<String> l1Ids = new ArrayList<>();
|
|
|
|
|
+ for (Map<String, String> km : flatColumnKeys) {
|
|
|
|
|
+ if ("exchange".equals(km.get("type"))) {
|
|
|
|
|
+ String exKey = km.get("key"); // "exchange_xxx"
|
|
|
|
|
+ l1Ids.add(exKey.substring(exKey.indexOf("_") + 1));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 收集用户ID
|
|
|
List<String> userIds = employeeList.stream()
|
|
List<String> userIds = employeeList.stream()
|
|
|
- .map(emp -> emp.getUserId())
|
|
|
|
|
|
|
+ .map(WorkKnowledgeBasePoint::getUserId)
|
|
|
.filter(StringUtils::isNotBlank)
|
|
.filter(StringUtils::isNotBlank)
|
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
|
-
|
|
|
|
|
- // ========== 分别查询7个业务指标的分类数据 ==========
|
|
|
|
|
-
|
|
|
|
|
- // 1. 上传文档数量(按一级分类统计用户上传的文档数)
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> uploadCountByCategory = new java.util.HashMap<>();
|
|
|
|
|
- if (!userIds.isEmpty() && !categoryNames.isEmpty()) {
|
|
|
|
|
- List<java.util.Map<String, Object>> results =
|
|
|
|
|
- workKnowledgeBasePointDetailService.countUploadDocsByTreeNodeIds(categoryNames, userIds, queryParam.getBeginDate(), queryParam.getEndDate());
|
|
|
|
|
- for (java.util.Map<String, Object> result : results) {
|
|
|
|
|
- String userId = (String) result.get("userId");
|
|
|
|
|
- String treeName = (String) result.get("treeName");
|
|
|
|
|
- Integer count = ((Number) result.get("docCount")).intValue();
|
|
|
|
|
- uploadCountByCategory.computeIfAbsent(userId, k -> new java.util.HashMap<>())
|
|
|
|
|
- .put(treeName, count);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 2. 贡献积分额度(change_type=1,创建积分)
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> createPointByCategory = new java.util.HashMap<>();
|
|
|
|
|
- if (!userIds.isEmpty() && !categoryNames.isEmpty()) {
|
|
|
|
|
- List<java.util.Map<String, Object>> results =
|
|
|
|
|
- workKnowledgeBasePointDetailService.sumPointsByTreeNodeIdsAndChangeType(categoryNames, userIds, 1, queryParam.getBeginDate(), queryParam.getEndDate());
|
|
|
|
|
- for (java.util.Map<String, Object> result : results) {
|
|
|
|
|
- String userId = (String) result.get("userId");
|
|
|
|
|
- String treeName = (String) result.get("treeName");
|
|
|
|
|
- Integer point = ((Number) result.get("totalPoint")).intValue();
|
|
|
|
|
- createPointByCategory.computeIfAbsent(userId, k -> new java.util.HashMap<>())
|
|
|
|
|
- .put(treeName, point);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 3. 审核文档数量(按一级分类统计用户审核的文档数)
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> auditCountByCategory = new java.util.HashMap<>();
|
|
|
|
|
- if (!userIds.isEmpty() && !categoryNames.isEmpty()) {
|
|
|
|
|
- List<java.util.Map<String, Object>> results =
|
|
|
|
|
- workKnowledgeBasePointDetailService.countAuditDocsByTreeNodeIds(categoryNames, userIds, queryParam.getBeginDate(), queryParam.getEndDate());
|
|
|
|
|
- for (java.util.Map<String, Object> result : results) {
|
|
|
|
|
- String userId = (String) result.get("userId");
|
|
|
|
|
- String treeName = (String) result.get("treeName");
|
|
|
|
|
- Integer count = ((Number) result.get("docCount")).intValue();
|
|
|
|
|
- auditCountByCategory.computeIfAbsent(userId, k -> new java.util.HashMap<>())
|
|
|
|
|
- .put(treeName, count);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 4. 审核积分额度(change_type=2,审核积分)
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> auditPointByCategory = new java.util.HashMap<>();
|
|
|
|
|
- if (!userIds.isEmpty() && !categoryNames.isEmpty()) {
|
|
|
|
|
- List<java.util.Map<String, Object>> results =
|
|
|
|
|
- workKnowledgeBasePointDetailService.sumPointsByTreeNodeIdsAndChangeType(categoryNames, userIds, 2, queryParam.getBeginDate(), queryParam.getEndDate());
|
|
|
|
|
- for (java.util.Map<String, Object> result : results) {
|
|
|
|
|
- String userId = (String) result.get("userId");
|
|
|
|
|
- String treeName = (String) result.get("treeName");
|
|
|
|
|
- Integer point = ((Number) result.get("totalPoint")).intValue();
|
|
|
|
|
- auditPointByCategory.computeIfAbsent(userId, k -> new java.util.HashMap<>())
|
|
|
|
|
- .put(treeName, point);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 4a. 按rule分组积分(point>0)
|
|
|
|
|
+ java.util.Map<String, java.util.Map<String, Integer>> pointsByRule = new java.util.HashMap<>();
|
|
|
|
|
+ if (!userIds.isEmpty()) {
|
|
|
|
|
+ List<java.util.Map<String, Object>> ruleResults =
|
|
|
|
|
+ workKnowledgeBasePointDetailService.sumPointsByRuleGrouped(userIds, queryParam.getBeginDate(), queryParam.getEndDate());
|
|
|
|
|
+ for (java.util.Map<String, Object> r : ruleResults) {
|
|
|
|
|
+ String uid = (String) r.get("userId");
|
|
|
|
|
+ String rid = String.valueOf(r.get("ruleId"));
|
|
|
|
|
+ int pts = ((Number) r.get("totalPoint")).intValue();
|
|
|
|
|
+ pointsByRule.computeIfAbsent(uid, k -> new java.util.HashMap<>()).put(rid, pts);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 5. 阅读积分额度(change_type=3,阅读积分)
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> readPointByCategory = new java.util.HashMap<>();
|
|
|
|
|
- if (!userIds.isEmpty() && !categoryNames.isEmpty()) {
|
|
|
|
|
- List<java.util.Map<String, Object>> results =
|
|
|
|
|
- workKnowledgeBasePointDetailService.sumPointsByTreeNodeIdsAndChangeType(categoryNames, userIds, 3, queryParam.getBeginDate(), queryParam.getEndDate());
|
|
|
|
|
- for (java.util.Map<String, Object> result : results) {
|
|
|
|
|
- String userId = (String) result.get("userId");
|
|
|
|
|
- String treeName = (String) result.get("treeName");
|
|
|
|
|
- Integer point = ((Number) result.get("totalPoint")).intValue();
|
|
|
|
|
- readPointByCategory.computeIfAbsent(userId, k -> new java.util.HashMap<>())
|
|
|
|
|
- .put(treeName, point);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 4a-extra. 汇总L2叶子分类的积分(用于无L3子列的L2叶子,如"阅读"、"点赞")
|
|
|
|
|
+ java.util.Map<String, java.util.Map<String, Integer>> l2PointsByCategory = new java.util.HashMap<>();
|
|
|
|
|
+ for (java.util.Map.Entry<String, java.util.Map<String, Integer>> entry : pointsByRule.entrySet()) {
|
|
|
|
|
+ String uid = entry.getKey();
|
|
|
|
|
+ java.util.Map<String, Integer> userRulePoints = entry.getValue();
|
|
|
|
|
+ for (int i = 0; i < secondLevelCategoryIds.size(); i++) {
|
|
|
|
|
+ List<String> catIds = secondLevelCategoryIds.get(i);
|
|
|
|
|
+ for (int j = 0; j < catIds.size(); j++) {
|
|
|
|
|
+ String catId = catIds.get(j);
|
|
|
|
|
+ if (catId.isEmpty()) continue;
|
|
|
|
|
+ // 查询该L2分类下的所有规则ID
|
|
|
|
|
+ List<WorkKnowledgeBasePointRule> catRules = pointRuleDao.findEnabledByCategoryId(catId);
|
|
|
|
|
+ int total = 0;
|
|
|
|
|
+ for (WorkKnowledgeBasePointRule r : catRules) {
|
|
|
|
|
+ total += userRulePoints.getOrDefault(r.getId(), 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ l2PointsByCategory.computeIfAbsent(uid, k -> new java.util.HashMap<>()).put(catId, total);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 6. 点赞积分额度(change_type=4,点赞积分)
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> likePointByCategory = new java.util.HashMap<>();
|
|
|
|
|
- if (!userIds.isEmpty() && !categoryNames.isEmpty()) {
|
|
|
|
|
- List<java.util.Map<String, Object>> results =
|
|
|
|
|
- workKnowledgeBasePointDetailService.sumPointsByTreeNodeIdsAndChangeType(categoryNames, userIds, 4, queryParam.getBeginDate(), queryParam.getEndDate());
|
|
|
|
|
- for (java.util.Map<String, Object> result : results) {
|
|
|
|
|
- String userId = (String) result.get("userId");
|
|
|
|
|
- String treeName = (String) result.get("treeName");
|
|
|
|
|
- Integer point = ((Number) result.get("totalPoint")).intValue();
|
|
|
|
|
- likePointByCategory.computeIfAbsent(userId, k -> new java.util.HashMap<>())
|
|
|
|
|
- .put(treeName, point);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 4b. 兑现积分(按L1分类,point<0取绝对值)
|
|
|
|
|
+ java.util.Map<String, java.util.Map<String, Integer>> exchangeByL1 = new java.util.HashMap<>();
|
|
|
|
|
+ if (!userIds.isEmpty()) {
|
|
|
|
|
+ List<java.util.Map<String, Object>> exResults =
|
|
|
|
|
+ workKnowledgeBasePointDetailService.sumExchangeByFirstLevelCategory(userIds, queryParam.getBeginDate(), queryParam.getEndDate());
|
|
|
|
|
+ for (java.util.Map<String, Object> r : exResults) {
|
|
|
|
|
+ String uid = (String) r.get("userId");
|
|
|
|
|
+ String lid = String.valueOf(r.get("firstLevelId"));
|
|
|
|
|
+ int pts = ((Number) r.get("totalPoint")).intValue();
|
|
|
|
|
+ exchangeByL1.computeIfAbsent(uid, k -> new java.util.HashMap<>()).put(lid, pts);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 7. 已兑换积分额度(point<0,兑换积分)
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> exchangePointByCategory = new java.util.HashMap<>();
|
|
|
|
|
- if (!userIds.isEmpty() && !categoryNames.isEmpty()) {
|
|
|
|
|
- List<java.util.Map<String, Object>> results =
|
|
|
|
|
- workKnowledgeBasePointDetailService.sumExchangePointsByTreeNodeIds(categoryNames, userIds, queryParam.getBeginDate(), queryParam.getEndDate());
|
|
|
|
|
- for (java.util.Map<String, Object> result : results) {
|
|
|
|
|
- String userId = (String) result.get("userId");
|
|
|
|
|
- String treeName = (String) result.get("treeName");
|
|
|
|
|
- Integer point = ((Number) result.get("totalPoint")).intValue();
|
|
|
|
|
- exchangePointByCategory.computeIfAbsent(userId, k -> new java.util.HashMap<>())
|
|
|
|
|
- .put(treeName, point);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 4c. 上传文档数量(从employeeList获取)
|
|
|
|
|
+ java.util.Map<String, Integer> uploadCountMap = new java.util.HashMap<>();
|
|
|
|
|
+ for (WorkKnowledgeBasePoint emp : employeeList) {
|
|
|
|
|
+ uploadCountMap.put(emp.getUserId(), emp.getUploadCount() != null ? emp.getUploadCount() : 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 业务指标字段与entity getter的映射
|
|
|
|
|
- java.util.Map<String, String> columnGetterMap = new java.util.LinkedHashMap<>();
|
|
|
|
|
- columnGetterMap.put("uploadCount", "getUploadCount");
|
|
|
|
|
- columnGetterMap.put("createPoint", "getCreatePoint");
|
|
|
|
|
- columnGetterMap.put("auditCount", "getAuditCount");
|
|
|
|
|
- columnGetterMap.put("auditPoint", "getAuditPoint");
|
|
|
|
|
- columnGetterMap.put("readPoint", "getReadPoint");
|
|
|
|
|
- columnGetterMap.put("likePoint", "getLikePoint");
|
|
|
|
|
- columnGetterMap.put("exchangePoint", "getExchangePoint");
|
|
|
|
|
|
|
+ // 5. 构建前缀列
|
|
|
|
|
+ List<String> prefixHeadersAll = Arrays.asList("部门名称|officeName", "用户姓名|userName");
|
|
|
|
|
+ List<String> prefixHeadersCompany = Arrays.asList("名称|label");
|
|
|
|
|
+ List<String> prefixHeadersDept = Arrays.asList("部门名称|officeName");
|
|
|
|
|
+
|
|
|
|
|
+ // === 辅助函数:构建数据行 ===
|
|
|
|
|
+ java.util.function.Function<List<WorkKnowledgeBasePoint>, Map<String, Object>> rowBuilder = (emps) -> {
|
|
|
|
|
+ Map<String, Object> row = new LinkedHashMap<>();
|
|
|
|
|
+ // 上传文档数量
|
|
|
|
|
+ int totalUpload = emps.stream().mapToInt(e -> e.getUploadCount() != null ? e.getUploadCount() : 0).sum();
|
|
|
|
|
+ row.put("uploadCount", totalUpload);
|
|
|
|
|
+
|
|
|
|
|
+ // 遍历每个L1组
|
|
|
|
|
+ for (int i = 0; i < firstLevelHeaders.size(); i++) {
|
|
|
|
|
+ List<String> l2ForL1 = secondLevelHeaders.get(i);
|
|
|
|
|
+ List<List<String>> l3ForL1 = thirdLevelHeaders.get(i);
|
|
|
|
|
+ String l1Id = (i < l1Ids.size()) ? l1Ids.get(i) : "";
|
|
|
|
|
+
|
|
|
|
|
+ for (int j = 0; j < l2ForL1.size(); j++) {
|
|
|
|
|
+ List<String> l3ForL2 = l3ForL1.get(j);
|
|
|
|
|
+ if (l3ForL2.isEmpty()) {
|
|
|
|
|
+ if (directRuleIndices.contains(i * 1000 + j)) {
|
|
|
|
|
+ // 直接规则L2(如"基础积分"下的规则),直接从pointsByRule取数据
|
|
|
|
|
+ String ruleId = (i < directRuleIds.size() && j < directRuleIds.get(i).size())
|
|
|
|
|
+ ? directRuleIds.get(i).get(j) : "";
|
|
|
|
|
+ int drVal = emps.stream().mapToInt(e -> {
|
|
|
|
|
+ java.util.Map<String, Integer> m = pointsByRule.get(e.getUserId());
|
|
|
|
|
+ return m != null && m.containsKey(ruleId) ? m.get(ruleId) : 0;
|
|
|
|
|
+ }).sum();
|
|
|
|
|
+ row.put("exchange_" + i + "_" + j, drVal);
|
|
|
|
|
+ } else if (l2LeafIndices.contains(i * 1000 + j)) {
|
|
|
|
|
+ // L2叶子列(如"阅读"、"点赞"),使用L2级汇总数据
|
|
|
|
|
+ String catId = (i < secondLevelCategoryIds.size() && j < secondLevelCategoryIds.get(i).size())
|
|
|
|
|
+ ? secondLevelCategoryIds.get(i).get(j) : "";
|
|
|
|
|
+ int leafVal = emps.stream().mapToInt(e -> {
|
|
|
|
|
+ java.util.Map<String, Integer> m = l2PointsByCategory.get(e.getUserId());
|
|
|
|
|
+ return m != null && m.containsKey(catId) ? m.get(catId) : 0;
|
|
|
|
|
+ }).sum();
|
|
|
|
|
+ row.put("exchange_" + i + "_" + j, leafVal);
|
|
|
|
|
+ } else if (subtotalIndices.contains(i * 1000 + j)) {
|
|
|
|
|
+ // 汇总列(占位符,后面会覆盖)
|
|
|
|
|
+ row.put("subtotal_" + i, 0);
|
|
|
|
|
+ } else if (remainingIndices.contains(i * 1000 + j)) {
|
|
|
|
|
+ // 未兑换积分列(占位符,后面计算 subtotal - exchange)
|
|
|
|
|
+ row.put("remaining_" + i, 0);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 已兑换积分列
|
|
|
|
|
+ int exVal = emps.stream().mapToInt(e -> {
|
|
|
|
|
+ java.util.Map<String, Integer> m = exchangeByL1.get(e.getUserId());
|
|
|
|
|
+ return m != null && m.containsKey(l1Id) ? m.get(l1Id) : 0;
|
|
|
|
|
+ }).sum();
|
|
|
|
|
+ row.put("exchange_" + i + "_" + j, exVal);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ for (int k = 0; k < l3ForL2.size(); k++) {
|
|
|
|
|
+ String ruleKey = (i < dataKeysL3.size() && j < dataKeysL3.get(i).size()
|
|
|
|
|
+ && k < dataKeysL3.get(i).get(j).size())
|
|
|
|
|
+ ? dataKeysL3.get(i).get(j).get(k) : "";
|
|
|
|
|
+ String ruleId = ruleKey.startsWith("rule_") ? ruleKey.substring(5) : "";
|
|
|
|
|
+ int ruleVal = emps.stream().mapToInt(e -> {
|
|
|
|
|
+ java.util.Map<String, Integer> m = pointsByRule.get(e.getUserId());
|
|
|
|
|
+ return m != null && m.containsKey(ruleId) ? m.get(ruleId) : 0;
|
|
|
|
|
+ }).sum();
|
|
|
|
|
+ row.put("rule_" + i + "_" + j + "_" + k, ruleVal);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 小计 = 所有规则列之和 + L2叶子列之和 + 直接规则列之和(不含汇总、已兑换、未兑换)
|
|
|
|
|
+ int subtotal = 0;
|
|
|
|
|
+ for (int j = 0; j < l2ForL1.size(); j++) {
|
|
|
|
|
+ List<String> l3ForL2 = l3ForL1.get(j);
|
|
|
|
|
+ if (subtotalIndices.contains(i * 1000 + j) || remainingIndices.contains(i * 1000 + j)) {
|
|
|
|
|
+ // 跳过汇总列和未兑换积分列本身
|
|
|
|
|
+ continue;
|
|
|
|
|
+ } else if (directRuleIndices.contains(i * 1000 + j) || l2LeafIndices.contains(i * 1000 + j)) {
|
|
|
|
|
+ // 直接规则L2或L2叶子列,直接取值
|
|
|
|
|
+ Object v = row.get("exchange_" + i + "_" + j);
|
|
|
|
|
+ if (v instanceof Number) subtotal += ((Number) v).intValue();
|
|
|
|
|
+ } else if (!l3ForL2.isEmpty()) {
|
|
|
|
|
+ // 有L3的规则列
|
|
|
|
|
+ for (int k = 0; k < l3ForL2.size(); k++) {
|
|
|
|
|
+ Object v = row.get("rule_" + i + "_" + j + "_" + k);
|
|
|
|
|
+ if (v instanceof Number) subtotal += ((Number) v).intValue();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 注意:已兑换积分列不计入小计
|
|
|
|
|
+ }
|
|
|
|
|
+ row.put("subtotal_" + i, subtotal);
|
|
|
|
|
+ // 剩余积分 = 积分汇总 - 已兑换积分
|
|
|
|
|
+ Integer exColIdx = exchangeColumnIndexMap.get(i);
|
|
|
|
|
+ int exVal = 0;
|
|
|
|
|
+ if (exColIdx != null) {
|
|
|
|
|
+ Object v = row.get("exchange_" + i + "_" + exColIdx);
|
|
|
|
|
+ if (v instanceof Number) {
|
|
|
|
|
+ exVal = ((Number) v).intValue();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ row.put("remaining_" + i, subtotal - exVal);
|
|
|
|
|
+ }
|
|
|
|
|
+ return row;
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
ExportKnowledgeBaseExcel excel = new ExportKnowledgeBaseExcel();
|
|
ExportKnowledgeBaseExcel excel = new ExportKnowledgeBaseExcel();
|
|
|
|
|
|
|
|
- // ========== 1. 公司级汇总(双表头)==========
|
|
|
|
|
|
|
+ // ========== 1. 公司级汇总 ==========
|
|
|
List<Map<String, Object>> companyData = new ArrayList<>();
|
|
List<Map<String, Object>> companyData = new ArrayList<>();
|
|
|
- Map<String, Object> companyRow = new LinkedHashMap<>();
|
|
|
|
|
|
|
+ Map<String, Object> companyRow = rowBuilder.apply(employeeList);
|
|
|
companyRow.put("label", "公司汇总");
|
|
companyRow.put("label", "公司汇总");
|
|
|
-
|
|
|
|
|
- for (int i = 0; i < firstRowHeaders.size(); i++) {
|
|
|
|
|
- String columnKey = columnKeys.get(i);
|
|
|
|
|
- List<String> subHeaders = secondRowHeaders.get(i);
|
|
|
|
|
-
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> dataSource;
|
|
|
|
|
- switch (i) {
|
|
|
|
|
- case 0: dataSource = uploadCountByCategory; break;
|
|
|
|
|
- case 1: dataSource = createPointByCategory; break;
|
|
|
|
|
- case 2: dataSource = auditCountByCategory; break;
|
|
|
|
|
- case 3: dataSource = auditPointByCategory; break;
|
|
|
|
|
- case 4: dataSource = readPointByCategory; break;
|
|
|
|
|
- case 5: dataSource = likePointByCategory; break;
|
|
|
|
|
- case 6: dataSource = exchangePointByCategory; break;
|
|
|
|
|
- default: dataSource = new java.util.HashMap<>();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- for (String subHeader : subHeaders) {
|
|
|
|
|
- String dataKey = columnKey + "_" + subHeader;
|
|
|
|
|
- if ("总量".equals(subHeader)) {
|
|
|
|
|
- // 总量从 employeeList 累加
|
|
|
|
|
- int total = employeeList.stream().mapToInt(emp -> {
|
|
|
|
|
- try {
|
|
|
|
|
- java.lang.reflect.Method m = emp.getClass().getMethod(columnGetterMap.get(columnKey));
|
|
|
|
|
- Number val = (Number) m.invoke(emp);
|
|
|
|
|
- return val != null ? val.intValue() : 0;
|
|
|
|
|
- } catch (Exception e) { return 0; }
|
|
|
|
|
- }).sum();
|
|
|
|
|
- companyRow.put(dataKey, total);
|
|
|
|
|
- } else {
|
|
|
|
|
- // 分类数据从分类查询结果获取
|
|
|
|
|
- int categorySum = employeeList.stream()
|
|
|
|
|
- .mapToInt(emp -> {
|
|
|
|
|
- java.util.Map<String, Integer> points = dataSource.get(emp.getUserId());
|
|
|
|
|
- return points != null && points.containsKey(subHeader) ? points.get(subHeader) : 0;
|
|
|
|
|
- }).sum();
|
|
|
|
|
- companyRow.put(dataKey, categorySum);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
companyData.add(companyRow);
|
|
companyData.add(companyRow);
|
|
|
-
|
|
|
|
|
- excel.addDoubleHeaderSheet("公司级", "公司级积分统计汇总" + dateRangeSuffix,
|
|
|
|
|
- Arrays.asList("名称|label"), firstRowHeaders, secondRowHeaders, columnKeys, companyData);
|
|
|
|
|
|
|
+ excel.addTripleHeaderSheet("公司级", "公司级积分统计汇总" + dateRangeSuffix,
|
|
|
|
|
+ prefixHeadersCompany, firstLevelHeaders, secondLevelHeaders, thirdLevelHeaders, companyData);
|
|
|
|
|
|
|
|
- // ========== 2. 部门级汇总(双表头)==========
|
|
|
|
|
- // 按部门分组
|
|
|
|
|
- java.util.Map<String, List<WorkKnowledgeBasePoint>> deptMap = new LinkedHashMap<>();
|
|
|
|
|
|
|
+ // ========== 2. 部门级汇总 ==========
|
|
|
|
|
+ Map<String, List<WorkKnowledgeBasePoint>> deptMap = new LinkedHashMap<>();
|
|
|
for (WorkKnowledgeBasePoint emp : employeeList) {
|
|
for (WorkKnowledgeBasePoint emp : employeeList) {
|
|
|
String dept = emp.getOfficeName() != null ? emp.getOfficeName() : "未分配部门";
|
|
String dept = emp.getOfficeName() != null ? emp.getOfficeName() : "未分配部门";
|
|
|
deptMap.computeIfAbsent(dept, k -> new ArrayList<>()).add(emp);
|
|
deptMap.computeIfAbsent(dept, k -> new ArrayList<>()).add(emp);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
List<Map<String, Object>> deptData = new ArrayList<>();
|
|
List<Map<String, Object>> deptData = new ArrayList<>();
|
|
|
- for (java.util.Map.Entry<String, List<WorkKnowledgeBasePoint>> entry : deptMap.entrySet()) {
|
|
|
|
|
- String deptName = entry.getKey();
|
|
|
|
|
- List<WorkKnowledgeBasePoint> deptEmps = entry.getValue();
|
|
|
|
|
-
|
|
|
|
|
- Map<String, Object> row = new LinkedHashMap<>();
|
|
|
|
|
- row.put("officeName", deptName);
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 0; i < firstRowHeaders.size(); i++) {
|
|
|
|
|
- String columnKey = columnKeys.get(i);
|
|
|
|
|
- List<String> subHeaders = secondRowHeaders.get(i);
|
|
|
|
|
-
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> dataSource;
|
|
|
|
|
- switch (i) {
|
|
|
|
|
- case 0: dataSource = uploadCountByCategory; break;
|
|
|
|
|
- case 1: dataSource = createPointByCategory; break;
|
|
|
|
|
- case 2: dataSource = auditCountByCategory; break;
|
|
|
|
|
- case 3: dataSource = auditPointByCategory; break;
|
|
|
|
|
- case 4: dataSource = readPointByCategory; break;
|
|
|
|
|
- case 5: dataSource = likePointByCategory; break;
|
|
|
|
|
- case 6: dataSource = exchangePointByCategory; break;
|
|
|
|
|
- default: dataSource = new java.util.HashMap<>();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- for (String subHeader : subHeaders) {
|
|
|
|
|
- String dataKey = columnKey + "_" + subHeader;
|
|
|
|
|
- if ("总量".equals(subHeader)) {
|
|
|
|
|
- int total = deptEmps.stream().mapToInt(emp -> {
|
|
|
|
|
- try {
|
|
|
|
|
- java.lang.reflect.Method m = emp.getClass().getMethod(columnGetterMap.get(columnKey));
|
|
|
|
|
- Number val = (Number) m.invoke(emp);
|
|
|
|
|
- return val != null ? val.intValue() : 0;
|
|
|
|
|
- } catch (Exception e) { return 0; }
|
|
|
|
|
- }).sum();
|
|
|
|
|
- row.put(dataKey, total);
|
|
|
|
|
- } else {
|
|
|
|
|
- int categorySum = deptEmps.stream()
|
|
|
|
|
- .mapToInt(emp -> {
|
|
|
|
|
- java.util.Map<String, Integer> points = dataSource.get(emp.getUserId());
|
|
|
|
|
- return points != null && points.containsKey(subHeader) ? points.get(subHeader) : 0;
|
|
|
|
|
- }).sum();
|
|
|
|
|
- row.put(dataKey, categorySum);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ for (Map.Entry<String, List<WorkKnowledgeBasePoint>> entry : deptMap.entrySet()) {
|
|
|
|
|
+ Map<String, Object> row = rowBuilder.apply(entry.getValue());
|
|
|
|
|
+ row.put("officeName", entry.getKey());
|
|
|
deptData.add(row);
|
|
deptData.add(row);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- excel.addDoubleHeaderSheet("部门级", "部门级积分统计汇总" + dateRangeSuffix,
|
|
|
|
|
- Arrays.asList("部门名称|officeName"), firstRowHeaders, secondRowHeaders, columnKeys, deptData);
|
|
|
|
|
|
|
+ excel.addTripleHeaderSheet("部门级", "部门级积分统计汇总" + dateRangeSuffix,
|
|
|
|
|
+ prefixHeadersDept, firstLevelHeaders, secondLevelHeaders, thirdLevelHeaders, deptData);
|
|
|
|
|
|
|
|
- // ========== 3. 员工级明细(双表头)==========
|
|
|
|
|
|
|
+ // ========== 3. 员工级明细 ==========
|
|
|
List<Map<String, Object>> empData = new ArrayList<>();
|
|
List<Map<String, Object>> empData = new ArrayList<>();
|
|
|
for (WorkKnowledgeBasePoint emp : employeeList) {
|
|
for (WorkKnowledgeBasePoint emp : employeeList) {
|
|
|
- Map<String, Object> row = new LinkedHashMap<>();
|
|
|
|
|
|
|
+ Map<String, Object> row = rowBuilder.apply(Arrays.asList(emp));
|
|
|
row.put("officeName", emp.getOfficeName() != null ? emp.getOfficeName() : "未分配部门");
|
|
row.put("officeName", emp.getOfficeName() != null ? emp.getOfficeName() : "未分配部门");
|
|
|
row.put("userName", emp.getUserName() != null ? emp.getUserName() : "");
|
|
row.put("userName", emp.getUserName() != null ? emp.getUserName() : "");
|
|
|
-
|
|
|
|
|
- for (int i = 0; i < firstRowHeaders.size(); i++) {
|
|
|
|
|
- String columnKey = columnKeys.get(i);
|
|
|
|
|
- List<String> subHeaders = secondRowHeaders.get(i);
|
|
|
|
|
-
|
|
|
|
|
- java.util.Map<String, java.util.Map<String, Integer>> dataSource;
|
|
|
|
|
- switch (i) {
|
|
|
|
|
- case 0: dataSource = uploadCountByCategory; break;
|
|
|
|
|
- case 1: dataSource = createPointByCategory; break;
|
|
|
|
|
- case 2: dataSource = auditCountByCategory; break;
|
|
|
|
|
- case 3: dataSource = auditPointByCategory; break;
|
|
|
|
|
- case 4: dataSource = readPointByCategory; break;
|
|
|
|
|
- case 5: dataSource = likePointByCategory; break;
|
|
|
|
|
- case 6: dataSource = exchangePointByCategory; break;
|
|
|
|
|
- default: dataSource = new java.util.HashMap<>();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- for (String subHeader : subHeaders) {
|
|
|
|
|
- String dataKey = columnKey + "_" + subHeader;
|
|
|
|
|
- if ("总量".equals(subHeader)) {
|
|
|
|
|
- try {
|
|
|
|
|
- java.lang.reflect.Method m = emp.getClass().getMethod(columnGetterMap.get(columnKey));
|
|
|
|
|
- Number val = (Number) m.invoke(emp);
|
|
|
|
|
- row.put(dataKey, val != null ? val.intValue() : 0);
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- row.put(dataKey, 0);
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- java.util.Map<String, Integer> points = dataSource.get(emp.getUserId());
|
|
|
|
|
- row.put(dataKey, points != null && points.containsKey(subHeader) ? points.get(subHeader) : 0);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
empData.add(row);
|
|
empData.add(row);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- excel.addDoubleHeaderSheet("员工级", "员工级积分统计明细" + dateRangeSuffix,
|
|
|
|
|
- Arrays.asList("部门名称|officeName", "用户姓名|userName"), firstRowHeaders, secondRowHeaders, columnKeys, empData);
|
|
|
|
|
|
|
+ excel.addTripleHeaderSheet("员工级", "员工级积分统计明细" + dateRangeSuffix,
|
|
|
|
|
+ prefixHeadersAll, firstLevelHeaders, secondLevelHeaders, thirdLevelHeaders, empData);
|
|
|
|
|
|
|
|
String fileName = "知识库统计表_" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
|
|
String fileName = "知识库统计表_" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
|
|
|
excel.write(response, fileName);
|
|
excel.write(response, fileName);
|