任务大厅导出:每个任务类型单独一列,方便数据分析
- 动态生成任务类型列:每种任务类型自动生成两列(数量和积分) - 表头格式:xxx(数量)、xxx(积分) - 同一任务的多个子任务组数据会汇总到一起 - 支持任意数量的任务类型,自动扩展列
This commit is contained in:
parent
27ed077290
commit
785248c5d7
@ -104,109 +104,144 @@ public class ExportService {
|
||||
}
|
||||
}
|
||||
|
||||
// 转换为导出数据
|
||||
List<TaskHallExportVO> exportList = new ArrayList<>();
|
||||
// 🔥 第一遍遍历:收集所有出现的任务类型名称(用于动态列)
|
||||
java.util.LinkedHashSet<String> allTypeNames = new java.util.LinkedHashSet<>();
|
||||
for (Task task : tasks) {
|
||||
TaskHallExportVO vo = new TaskHallExportVO();
|
||||
vo.setTaskNo(task.getTaskNo());
|
||||
vo.setTitle(task.getTitle());
|
||||
vo.setTaskType(taskTypeMap.getOrDefault(task.getTaskTypeId(), ""));
|
||||
// 需求类型使用 taskSubType 字段(新品/优化/实拍等)
|
||||
vo.setDemandType(task.getTaskSubType() != null ? task.getTaskSubType() : "");
|
||||
vo.setBrand(brandMap.getOrDefault(task.getBrandId(), ""));
|
||||
vo.setCategory(categoryMap.getOrDefault(task.getCategoryId(), ""));
|
||||
vo.setPlatform(platformMap.getOrDefault(task.getPlatformId(), ""));
|
||||
vo.setSpuInfo(task.getSpuInfo());
|
||||
vo.setScore(task.getScore() != null ? task.getScore().toString() : "0");
|
||||
vo.setEstimatedHours(task.getEstimatedHours() != null ? task.getEstimatedHours().toString() : "0");
|
||||
vo.setQuantity(task.getQuantity() != null ? task.getQuantity() : 1);
|
||||
vo.setPublisher(userMap.getOrDefault(task.getPublisherId(), ""));
|
||||
vo.setPublisherDept(deptMap.getOrDefault(task.getPublisherDeptId(), ""));
|
||||
vo.setReceiver(userMap.getOrDefault(task.getReceiverId(), ""));
|
||||
vo.setReceiverDept(deptMap.getOrDefault(task.getReceiverDeptId(), ""));
|
||||
vo.setStatus(getStatusText(task.getStatus()));
|
||||
vo.setReleaseType(getReleaseTypeText(task.getReleaseType()));
|
||||
vo.setIsUrgent(task.getIsUrgent() != null && task.getIsUrgent() == 1 ? "是" : "否");
|
||||
vo.setIsPipeline(task.getIsPipeline() != null && task.getIsPipeline() == 1 ? "是" : "否");
|
||||
vo.setCreateTime(task.getCreateTime() != null ? task.getCreateTime().format(DATE_FORMATTER) : "");
|
||||
vo.setDeadline(task.getDeadline() != null ? task.getDeadline().format(DATE_FORMATTER) : "");
|
||||
|
||||
// 🔥 添加任务明细和积分明细
|
||||
List<TaskItem> items = taskItemsMap.get(task.getId());
|
||||
if (items != null && !items.isEmpty()) {
|
||||
StringBuilder taskDetails = new StringBuilder();
|
||||
StringBuilder scoreDetails = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
TaskItem item = items.get(i);
|
||||
if (i > 0) {
|
||||
taskDetails.append("\n");
|
||||
scoreDetails.append("\n");
|
||||
}
|
||||
|
||||
// 解析typeDetails JSON
|
||||
if (items != null) {
|
||||
for (TaskItem item : items) {
|
||||
if (item.getTypeDetails() != null && !item.getTypeDetails().isEmpty()) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> typeDetails = objectMapper.readValue(item.getTypeDetails(), List.class);
|
||||
StringBuilder itemDetail = new StringBuilder();
|
||||
StringBuilder itemScore = new StringBuilder();
|
||||
|
||||
for (int j = 0; j < typeDetails.size(); j++) {
|
||||
Map<String, Object> detail = typeDetails.get(j);
|
||||
for (Map<String, Object> detail : typeDetails) {
|
||||
String typeName = String.valueOf(detail.get("typeName"));
|
||||
Object qtyObj = detail.get("quantity");
|
||||
Object scoreObj = detail.get("totalScore");
|
||||
int qty = qtyObj instanceof Number ? ((Number) qtyObj).intValue() : 1;
|
||||
String score = scoreObj != null ? String.valueOf(scoreObj) : "0";
|
||||
|
||||
if (j > 0) {
|
||||
itemDetail.append("; ");
|
||||
itemScore.append("; ");
|
||||
if (typeName != null && !typeName.equals("null")) {
|
||||
allTypeNames.add(typeName);
|
||||
}
|
||||
itemDetail.append(typeName).append(" x").append(qty);
|
||||
itemScore.append(typeName).append(": ").append(score).append("分");
|
||||
}
|
||||
|
||||
// 如果有多个子任务组,添加组号前缀
|
||||
if (items.size() > 1) {
|
||||
taskDetails.append("第").append(item.getGroupNo()).append("组: ");
|
||||
scoreDetails.append("第").append(item.getGroupNo()).append("组: ");
|
||||
}
|
||||
taskDetails.append(itemDetail);
|
||||
scoreDetails.append(itemScore);
|
||||
} catch (Exception e) {
|
||||
log.warn("解析任务明细失败: taskId={}, itemId={}, error={}",
|
||||
task.getId(), item.getId(), e.getMessage());
|
||||
log.warn("解析任务类型失败: itemId={}", item.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
List<String> typeNameList = new ArrayList<>(allTypeNames);
|
||||
log.info("导出任务大厅数据,发现 {} 种任务类型: {}", typeNameList.size(), typeNameList);
|
||||
|
||||
// 转换为导出数据(使用Map存储动态列)
|
||||
List<Map<String, Object>> exportList = new ArrayList<>();
|
||||
for (Task task : tasks) {
|
||||
Map<String, Object> row = new java.util.LinkedHashMap<>();
|
||||
row.put("taskNo", task.getTaskNo());
|
||||
row.put("title", task.getTitle());
|
||||
row.put("taskType", taskTypeMap.getOrDefault(task.getTaskTypeId(), ""));
|
||||
row.put("demandType", task.getTaskSubType() != null ? task.getTaskSubType() : "");
|
||||
row.put("brand", brandMap.getOrDefault(task.getBrandId(), ""));
|
||||
row.put("category", categoryMap.getOrDefault(task.getCategoryId(), ""));
|
||||
row.put("platform", platformMap.getOrDefault(task.getPlatformId(), ""));
|
||||
row.put("spuInfo", task.getSpuInfo() != null ? task.getSpuInfo() : "");
|
||||
row.put("score", task.getScore() != null ? task.getScore().toString() : "0");
|
||||
row.put("estimatedHours", task.getEstimatedHours() != null ? task.getEstimatedHours().toString() : "0");
|
||||
row.put("quantity", task.getQuantity() != null ? task.getQuantity() : 1);
|
||||
|
||||
// 🔥 初始化所有任务类型列为空(数量和积分都初始化)
|
||||
for (String typeName : typeNameList) {
|
||||
row.put("qty_" + typeName, "");
|
||||
row.put("score_" + typeName, "");
|
||||
}
|
||||
|
||||
// 🔥 填充该任务的各任务类型数量和积分
|
||||
List<TaskItem> items = taskItemsMap.get(task.getId());
|
||||
if (items != null) {
|
||||
// 汇总同一任务所有子任务的类型数据
|
||||
Map<String, Integer> typeQtyMap = new HashMap<>();
|
||||
Map<String, Double> typeScoreMap = new HashMap<>();
|
||||
|
||||
for (TaskItem item : items) {
|
||||
if (item.getTypeDetails() != null && !item.getTypeDetails().isEmpty()) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> typeDetails = objectMapper.readValue(item.getTypeDetails(), List.class);
|
||||
for (Map<String, Object> detail : typeDetails) {
|
||||
String typeName = String.valueOf(detail.get("typeName"));
|
||||
if (typeName != null && !typeName.equals("null")) {
|
||||
Object qtyObj = detail.get("quantity");
|
||||
Object scoreObj = detail.get("totalScore");
|
||||
int qty = qtyObj instanceof Number ? ((Number) qtyObj).intValue() : 0;
|
||||
double score = scoreObj instanceof Number ? ((Number) scoreObj).doubleValue() : 0;
|
||||
|
||||
typeQtyMap.merge(typeName, qty, Integer::sum);
|
||||
typeScoreMap.merge(typeName, score, Double::sum);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析任务明细失败: taskId={}, itemId={}", task.getId(), item.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vo.setTaskDetails(taskDetails.toString());
|
||||
vo.setScoreDetails(scoreDetails.toString());
|
||||
} else {
|
||||
vo.setTaskDetails("");
|
||||
vo.setScoreDetails("");
|
||||
// 填入汇总数据
|
||||
for (Map.Entry<String, Integer> entry : typeQtyMap.entrySet()) {
|
||||
row.put("qty_" + entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Map.Entry<String, Double> entry : typeScoreMap.entrySet()) {
|
||||
row.put("score_" + entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
exportList.add(vo);
|
||||
row.put("publisher", userMap.getOrDefault(task.getPublisherId(), ""));
|
||||
row.put("publisherDept", deptMap.getOrDefault(task.getPublisherDeptId(), ""));
|
||||
row.put("receiver", userMap.getOrDefault(task.getReceiverId(), ""));
|
||||
row.put("receiverDept", deptMap.getOrDefault(task.getReceiverDeptId(), ""));
|
||||
row.put("status", getStatusText(task.getStatus()));
|
||||
row.put("releaseType", getReleaseTypeText(task.getReleaseType()));
|
||||
row.put("isUrgent", task.getIsUrgent() != null && task.getIsUrgent() == 1 ? "是" : "否");
|
||||
row.put("isPipeline", task.getIsPipeline() != null && task.getIsPipeline() == 1 ? "是" : "否");
|
||||
row.put("createTime", task.getCreateTime() != null ? task.getCreateTime().format(DATE_FORMATTER) : "");
|
||||
row.put("deadline", task.getDeadline() != null ? task.getDeadline().format(DATE_FORMATTER) : "");
|
||||
|
||||
exportList.add(row);
|
||||
}
|
||||
|
||||
// 定义表头
|
||||
String[] headers = {
|
||||
"任务编号", "任务标题", "任务类型", "需求类型", "品牌", "类目", "平台",
|
||||
"SPU信息", "任务积分", "积分明细", "任务明细", "预估工时(小时)", "数量",
|
||||
"发布人", "发布部门", "接收人", "接收部门", "状态", "发布类型",
|
||||
"是否紧急", "是否流水线", "创建时间", "截止时间"
|
||||
};
|
||||
// 🔥 动态构建表头和字段名
|
||||
List<String> headerList = new ArrayList<>();
|
||||
List<String> fieldList = new ArrayList<>();
|
||||
|
||||
// 定义字段名
|
||||
String[] fieldNames = {
|
||||
"taskNo", "title", "taskType", "demandType", "brand", "category", "platform",
|
||||
"spuInfo", "score", "scoreDetails", "taskDetails", "estimatedHours", "quantity",
|
||||
"publisher", "publisherDept", "receiver", "receiverDept", "status", "releaseType",
|
||||
"isUrgent", "isPipeline", "createTime", "deadline"
|
||||
};
|
||||
// 基本信息列
|
||||
headerList.add("任务编号"); fieldList.add("taskNo");
|
||||
headerList.add("任务标题"); fieldList.add("title");
|
||||
headerList.add("任务类型"); fieldList.add("taskType");
|
||||
headerList.add("需求类型"); fieldList.add("demandType");
|
||||
headerList.add("品牌"); fieldList.add("brand");
|
||||
headerList.add("类目"); fieldList.add("category");
|
||||
headerList.add("平台"); fieldList.add("platform");
|
||||
headerList.add("SPU信息"); fieldList.add("spuInfo");
|
||||
headerList.add("任务积分"); fieldList.add("score");
|
||||
headerList.add("预估工时(小时)"); fieldList.add("estimatedHours");
|
||||
headerList.add("数量"); fieldList.add("quantity");
|
||||
|
||||
// 🔥 动态添加任务类型列(数量和积分分开)
|
||||
for (String typeName : typeNameList) {
|
||||
headerList.add(typeName + "(数量)"); fieldList.add("qty_" + typeName);
|
||||
headerList.add(typeName + "(积分)"); fieldList.add("score_" + typeName);
|
||||
}
|
||||
|
||||
// 其他信息列
|
||||
headerList.add("发布人"); fieldList.add("publisher");
|
||||
headerList.add("发布部门"); fieldList.add("publisherDept");
|
||||
headerList.add("接收人"); fieldList.add("receiver");
|
||||
headerList.add("接收部门"); fieldList.add("receiverDept");
|
||||
headerList.add("状态"); fieldList.add("status");
|
||||
headerList.add("发布类型"); fieldList.add("releaseType");
|
||||
headerList.add("是否紧急"); fieldList.add("isUrgent");
|
||||
headerList.add("是否流水线"); fieldList.add("isPipeline");
|
||||
headerList.add("创建时间"); fieldList.add("createTime");
|
||||
headerList.add("截止时间"); fieldList.add("deadline");
|
||||
|
||||
String[] headers = headerList.toArray(new String[0]);
|
||||
String[] fieldNames = fieldList.toArray(new String[0]);
|
||||
|
||||
// 生成文件名
|
||||
String fileName = "任务大厅数据_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||
@ -318,7 +353,7 @@ public class ExportService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务大厅导出VO
|
||||
* 任务大厅导出VO(保留用于兼容,实际使用Map动态列)
|
||||
*/
|
||||
@lombok.Data
|
||||
public static class TaskHallExportVO {
|
||||
@ -331,8 +366,6 @@ public class ExportService {
|
||||
private String platform;
|
||||
private String spuInfo;
|
||||
private String score;
|
||||
private String scoreDetails; // 积分明细
|
||||
private String taskDetails; // 任务明细
|
||||
private String estimatedHours;
|
||||
private Integer quantity;
|
||||
private String publisher;
|
||||
@ -345,6 +378,7 @@ public class ExportService {
|
||||
private String isPipeline;
|
||||
private String createTime;
|
||||
private String deadline;
|
||||
// 动态任务类型列通过Map处理,不在此定义
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -136,9 +136,16 @@ public class ExcelExportUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过反射获取字段值
|
||||
* 通过反射获取字段值(支持Map和普通对象)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Object getFieldValue(Object obj, String fieldName) {
|
||||
// 🔥 如果是Map类型,直接通过key获取值
|
||||
if (obj instanceof java.util.Map) {
|
||||
return ((java.util.Map<String, Object>) obj).get(fieldName);
|
||||
}
|
||||
|
||||
// 普通对象通过反射获取
|
||||
try {
|
||||
Field field = findField(obj.getClass(), fieldName);
|
||||
if (field != null) {
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
### 导出功能
|
||||
- 修复导出功能报错问题
|
||||
- 导出数据现在正确显示需求类型(新品/优化等)
|
||||
- 任务大厅导出数据新增"任务明细"和"积分明细"列
|
||||
|
||||
---
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user