Compare commits

...

3 Commits

  1. 35
      src/main/java/com/biutag/supervision/pojo/vo/ExportNegativeReturnVo.java
  2. 3
      src/main/java/com/biutag/supervision/pojo/vo/ExportNegativeVo.java
  3. 49
      src/main/java/com/biutag/supervision/service/MailBoxCaptureService.java
  4. 79
      src/main/java/com/biutag/supervision/service/ModifiedVerifyContentCellWriteHandler.java
  5. 165
      src/main/java/com/biutag/supervision/service/NegativeReturnExportService.java
  6. 16
      src/main/java/com/biutag/supervision/service/NegativeTaskService.java

35
src/main/java/com/biutag/supervision/pojo/vo/ExportNegativeReturnVo.java

@ -0,0 +1,35 @@
package com.biutag.supervision.pojo.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
@Setter
@Getter
public class ExportNegativeReturnVo {
@ExcelProperty("问题编号")
private String id;
@ExcelProperty("样本源头编号")
private String originId;
@ExcelProperty("退回次数")
private Integer returnCount;
@ExcelProperty(value = "退回时间", format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime returnTime;
@ExcelProperty("退回人员")
private String returnUser;
@ExcelProperty("退回意见")
private String returnOpinion;
@ExcelProperty("修改核查内容")
@ColumnWidth(80)
private String modifiedVerifyContent;
}

3
src/main/java/com/biutag/supervision/pojo/vo/ExportNegativeVo.java

@ -144,5 +144,8 @@ public class ExportNegativeVo {
@ExcelProperty({"核办情况","市局审批时长"})
private String firstApproveTime;
@ExcelProperty({"核办情况","退回次数"})
private Integer returnCount;
}

49
src/main/java/com/biutag/supervision/service/MailBoxCaptureService.java

@ -4,6 +4,8 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.biutag.supervision.constants.enums.AccountabilityTargetEnum;
import com.biutag.supervision.constants.enums.BusinessTypeEnum;
@ -50,9 +52,11 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -110,6 +114,7 @@ public class MailBoxCaptureService {
log.info("【局长信箱抓取新信件】查询到投诉举报信件信件数量:{}", mailList.size());
Map<String, String> involveProblemMapping = loadMayorMailboxInvolveProblemMapping();
Set<String> mergedMailboxOriginIds = loadMergedMailboxOriginIds();
// 3. 遍历处理
int successCount = 0;
@ -118,6 +123,11 @@ public class MailBoxCaptureService {
for (Mail mail : mailList) {
try {
if (mergedMailboxOriginIds.contains(mail.getId())) {
skipCount++;
log.info("【局长信箱抓取新信件】跳过已合并源件: mailId={}", mail.getId());
continue;
}
// 每条记录在独立事务中执行
boolean success = Boolean.TRUE.equals(transactionTemplate.execute(status -> {
return doCaptureSingleMail(mail, involveProblemMapping);
@ -262,6 +272,45 @@ public class MailBoxCaptureService {
return exists;
}
/**
* 从合并历史中提取已合并的局长信箱源件编号供抓取任务排除
*/
private Set<String> loadMergedMailboxOriginIds() {
Set<String> originIds = new HashSet<>();
List<ComplaintCollection> mergedRecords = complaintCollectionMapper.selectList(
new LambdaQueryWrapper<ComplaintCollection>()
.select(ComplaintCollection::getMergeHistory)
.isNotNull(ComplaintCollection::getMergeHistory)
.ne(ComplaintCollection::getMergeHistory, "")
);
for (ComplaintCollection record : mergedRecords) {
try {
JSONObject history = JSON.parseObject(record.getMergeHistory());
JSONArray merges = history == null ? null : history.getJSONArray("merges");
if (CollectionUtil.isEmpty(merges)) {
continue;
}
for (Object merge : merges) {
JSONObject mergeRecord = JSON.parseObject(JSON.toJSONString(merge));
if (mergeRecord == null) {
continue;
}
if (ComplaintCollectionSourceTableEnum.MAYOR_MAILBOX.getCode()
.equals(mergeRecord.getString("sourceTable"))) {
String originId = mergeRecord.getString("originId");
if (StrUtil.isNotBlank(originId)) {
originIds.add(originId);
}
}
}
} catch (Exception e) {
log.warn("【局长信箱抓取新信件】解析合并历史失败,已跳过该记录: {}", e.getMessage());
}
}
return originIds;
}
// ==================== 单位查询 ====================
/**

79
src/main/java/com/biutag/supervision/service/ModifiedVerifyContentCellWriteHandler.java

@ -0,0 +1,79 @@
package com.biutag.supervision.service;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Workbook;
public class ModifiedVerifyContentCellWriteHandler implements CellWriteHandler {
private static final int MODIFIED_VERIFY_CONTENT_COLUMN_INDEX = 6;
private Font labelFont;
private Font arrowFont;
private CellStyle wrappedStyle;
@Override
public void afterCellDispose(CellWriteHandlerContext context) {
if (Boolean.TRUE.equals(context.getHead())
|| !Integer.valueOf(MODIFIED_VERIFY_CONTENT_COLUMN_INDEX).equals(context.getColumnIndex())) {
return;
}
Cell cell = context.getCell();
String content = cell.getStringCellValue();
if (StrUtil.isBlank(content)) {
return;
}
Workbook workbook = cell.getSheet().getWorkbook();
applyWrappedStyle(workbook, cell);
RichTextString richText = workbook.getCreationHelper().createRichTextString(content);
String[] lines = content.split("\\n", -1);
int offset = 0;
for (String line : lines) {
int separatorIndex = line.indexOf(':');
if (separatorIndex > 0) {
richText.applyFont(offset, offset + separatorIndex, getLabelFont(workbook));
}
int arrowIndex = line.indexOf('→', separatorIndex + 1);
if (arrowIndex >= 0) {
richText.applyFont(offset + arrowIndex, offset + arrowIndex + 1, getArrowFont(workbook));
}
offset += line.length() + 1;
}
float requiredHeight = Math.max(cell.getRow().getHeightInPoints(), lines.length * 18F);
cell.getRow().setHeightInPoints(requiredHeight);
cell.setCellValue(richText);
}
private Font getLabelFont(Workbook workbook) {
if (labelFont == null) {
labelFont = workbook.createFont();
labelFont.setBold(true);
labelFont.setColor(IndexedColors.BLACK.getIndex());
}
return labelFont;
}
private Font getArrowFont(Workbook workbook) {
if (arrowFont == null) {
arrowFont = workbook.createFont();
arrowFont.setBold(true);
arrowFont.setColor(IndexedColors.RED.getIndex());
}
return arrowFont;
}
private void applyWrappedStyle(Workbook workbook, Cell cell) {
if (wrappedStyle == null) {
wrappedStyle = workbook.createCellStyle();
wrappedStyle.cloneStyleFrom(cell.getCellStyle());
wrappedStyle.setWrapText(true);
}
cell.setCellStyle(wrappedStyle);
}
}

165
src/main/java/com/biutag/supervision/service/NegativeReturnExportService.java

@ -0,0 +1,165 @@
package com.biutag.supervision.service;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.biutag.supervision.pojo.entity.NegativeHistory;
import com.biutag.supervision.pojo.vo.ExportNegativeReturnVo;
import com.biutag.supervision.pojo.vo.NegativeQueryVo;
import com.biutag.supervision.util.JSON;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@Service
public class NegativeReturnExportService {
private final NegativeHistoryService negativeHistoryService;
public ExportData build(List<NegativeQueryVo> data) {
if (data.isEmpty()) {
return new ExportData(Collections.emptyMap(), Collections.emptyList());
}
List<String> negativeIds = data.stream().map(NegativeQueryVo::getId).toList();
List<NegativeHistory> histories = negativeHistoryService.list(new LambdaQueryWrapper<NegativeHistory>()
.in(NegativeHistory::getNegativeId, negativeIds)
.orderByAsc(NegativeHistory::getNegativeId)
.orderByAsc(NegativeHistory::getCrtTime));
Map<String, List<NegativeHistory>> historyMap = histories.stream()
.collect(Collectors.groupingBy(NegativeHistory::getNegativeId, LinkedHashMap::new, Collectors.toList()));
Map<String, Integer> returnCountMap = new HashMap<>();
List<ExportNegativeReturnVo> returnRecords = new ArrayList<>();
for (NegativeQueryVo negative : data) {
List<NegativeHistory> negativeHistories = historyMap.getOrDefault(negative.getId(), Collections.emptyList());
VerifySnapshot latestSnapshot = null;
PendingReturn pendingReturn = null;
int returnCount = 0;
for (NegativeHistory history : negativeHistories) {
ParsedHistory parsedHistory = parseHistory(history);
if (parsedHistory.snapshot() != null) {
latestSnapshot = parsedHistory.snapshot();
}
if (isReturnAction(parsedHistory.actionKey())) {
returnCount++;
ExportNegativeReturnVo returnVo = new ExportNegativeReturnVo();
returnVo.setId(negative.getId());
returnVo.setOriginId(negative.getOriginId());
returnVo.setReturnCount(returnCount);
returnVo.setReturnTime(history.getCrtTime());
returnVo.setReturnUser(history.getCrtName());
returnVo.setReturnOpinion(parsedHistory.comments());
returnVo.setModifiedVerifyContent("尚未再次提交");
returnRecords.add(returnVo);
pendingReturn = new PendingReturn(parsedHistory.actionKey(), latestSnapshot, returnVo);
} else if (pendingReturn != null && parsedHistory.snapshot() != null) {
pendingReturn.returnVo().setModifiedVerifyContent(
buildVerifyDiff(pendingReturn.beforeSnapshot(), latestSnapshot));
} else if (pendingReturn != null && isResubmitAction(pendingReturn.returnActionKey(), parsedHistory.actionKey())) {
pendingReturn.returnVo().setModifiedVerifyContent(buildVerifyDiff(pendingReturn.beforeSnapshot(), latestSnapshot));
}
}
returnCountMap.put(negative.getId(), returnCount);
}
return new ExportData(returnCountMap, returnRecords);
}
private ParsedHistory parseHistory(NegativeHistory history) {
if (StrUtil.isBlank(history.getDataJson())) {
return new ParsedHistory(null, null, null);
}
try {
JsonNode root = JSON.readTree(history.getDataJson());
String actionKey = textValue(root, "actionKey");
JsonNode actionData = root.path("data");
String comments = actionData.isObject() ? textValue(actionData, "comments") : null;
VerifySnapshot snapshot = hasVerifyData(actionData)
? new VerifySnapshot(
textValue(actionData, "checkStatusName"),
textValue(actionData, "isRectifyName"),
textValue(actionData, "checkStatusDesc"),
textValue(actionData, "rectifyDesc"))
: null;
return new ParsedHistory(actionKey, comments, snapshot);
} catch (RuntimeException ignored) {
return new ParsedHistory(null, null, null);
}
}
private boolean hasVerifyData(JsonNode actionData) {
return actionData.isObject() && (actionData.has("checkStatusName")
|| actionData.has("isRectifyName")
|| actionData.has("checkStatusDesc")
|| actionData.has("rectifyDesc"));
}
private String textValue(JsonNode node, String fieldName) {
JsonNode value = node.path(fieldName);
return value.isMissingNode() || value.isNull() ? null : value.asText();
}
private boolean isReturnAction(String actionKey) {
return "second_approve_return".equals(actionKey) || "first_approve_return".equals(actionKey);
}
private boolean isResubmitAction(String returnActionKey, String actionKey) {
if ("second_approve_return".equals(returnActionKey)) {
return "apply_completion".equals(actionKey);
}
if ("first_approve_return".equals(returnActionKey)) {
return "second_approve".equals(actionKey) || "apply_completion".equals(actionKey);
}
return false;
}
private String buildVerifyDiff(VerifySnapshot before, VerifySnapshot after) {
if (before == null || after == null) {
return "无法获取核查办理内容";
}
List<String> diffs = new ArrayList<>();
addVerifyDiff(diffs, "核查结论", before.checkStatusName(), after.checkStatusName());
addVerifyDiff(diffs, "是否整改", before.isRectifyName(), after.isRectifyName());
addVerifyDiff(diffs, "问题核查情况", before.checkStatusDesc(), after.checkStatusDesc());
addVerifyDiff(diffs, "问题整改情况", before.rectifyDesc(), after.rectifyDesc());
return diffs.isEmpty() ? null : String.join("\n", diffs);
}
private void addVerifyDiff(List<String> diffs, String label, String before, String after) {
String beforeText = normalizeCellText(before);
String afterText = normalizeCellText(after);
if (!Objects.equals(beforeText, afterText)) {
diffs.add(String.format("%s:%s → %s", label, beforeText, afterText));
}
}
private String normalizeCellText(String text) {
if (StrUtil.isBlank(text)) {
return "无";
}
return text.replaceAll("[\\r\\n]+", " ").trim();
}
public record ExportData(Map<String, Integer> returnCountMap,
List<ExportNegativeReturnVo> returnRecords) {
}
private record ParsedHistory(String actionKey, String comments, VerifySnapshot snapshot) {
}
private record VerifySnapshot(String checkStatusName, String isRectifyName,
String checkStatusDesc, String rectifyDesc) {
}
private record PendingReturn(String returnActionKey, VerifySnapshot beforeSnapshot,
ExportNegativeReturnVo returnVo) {
}
}

16
src/main/java/com/biutag/supervision/service/NegativeTaskService.java

@ -23,6 +23,7 @@ import com.biutag.supervision.pojo.param.NegativeQueryParam;
import com.biutag.supervision.pojo.param.NegativeTaskQueryParam;
import com.biutag.supervision.pojo.vo.ExportNegativeBlameLeaderVo;
import com.biutag.supervision.pojo.vo.ExportNegativeBlameVo;
import com.biutag.supervision.pojo.vo.ExportNegativeReturnVo;
import com.biutag.supervision.pojo.vo.ExportNegativeVo;
import com.biutag.supervision.pojo.vo.NegativeQueryVo;
import com.biutag.supervision.util.TimeUtil;
@ -66,6 +67,8 @@ public class NegativeTaskService extends ServiceImpl<NegativeTaskMapper, Negativ
private final ConfinementService confinementService;
private final NegativeReturnExportService negativeReturnExportService;
public Page<NegativeTask> page(NegativeTaskQueryParam param) {
LambdaQueryWrapper<NegativeTask> queryWrapper = new LambdaQueryWrapper<NegativeTask>()
@ -135,6 +138,7 @@ public class NegativeTaskService extends ServiceImpl<NegativeTaskMapper, Negativ
List<SupDictData> specialSupervisionDict = dictDataService.listByDictType("specialSupervision");
List<ExportNegativeVo> list = new ArrayList<>();
List<ExportNegativeBlameVo> blameVoList = new ArrayList<>();
NegativeReturnExportService.ExportData returnHistoryExportData = negativeReturnExportService.build(data);
if (!data.isEmpty()) {
List<NegativeProblemRelation> negativeProblemRelations = negativeProblemRelationService.list(new LambdaQueryWrapper<NegativeProblemRelation>().in(NegativeProblemRelation::getNegativeId, data.stream().map(NegativeQueryVo::getId).toList()));
List<NegativeBlame> blames = negativeBlameService.list(new LambdaQueryWrapper<NegativeBlame>().in(NegativeBlame::getNegativeId, data.stream().map(NegativeQueryVo::getId).toList()));
@ -142,6 +146,7 @@ public class NegativeTaskService extends ServiceImpl<NegativeTaskMapper, Negativ
list = data.stream().map(item -> {
ExportNegativeVo vo = new ExportNegativeVo();
BeanUtils.copyProperties(item, vo);
vo.setReturnCount(returnHistoryExportData.returnCountMap().getOrDefault(item.getId(), 0));
if (StrUtil.isNotBlank(item.getInvolveProblem())) {
String involveProblem = Arrays.stream(item.getInvolveProblem().split(","))
.map(val -> suspectProblem.stream().filter(problem -> val.equals(problem.getDictValue())).findFirst().map(SupDictData::getDictLabel).orElse(""))
@ -265,10 +270,15 @@ public class NegativeTaskService extends ServiceImpl<NegativeTaskMapper, Negativ
.head(ExportNegativeBlameLeaderVo.class).build();
WriteSheet sheet4 = EasyExcel.writerSheet(3, "单位问题涉及台账")
.head(ExportNegativeBlameVo.class).build();
WriteSheet sheet5 = EasyExcel.writerSheet(4, "退回修改记录")
.head(ExportNegativeReturnVo.class)
.registerWriteHandler(new ModifiedVerifyContentCellWriteHandler())
.build();
excelWriter.write(list, sheet1);
excelWriter.write(blameVoList, sheet2);
excelWriter.write(blameLeaderVoList, sheet3);
excelWriter.write(departBlameLeaderVoList, sheet4);
excelWriter.write(returnHistoryExportData.returnRecords(), sheet5);
excelWriter.finish();
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
@ -281,10 +291,15 @@ public class NegativeTaskService extends ServiceImpl<NegativeTaskMapper, Negativ
.head(ExportNegativeBlameLeaderVo.class).build();
WriteSheet sheet4 = EasyExcel.writerSheet(3, "单位问题涉及台账")
.head(ExportNegativeBlameVo.class).build();
WriteSheet sheet5 = EasyExcel.writerSheet(4, "退回修改记录")
.head(ExportNegativeReturnVo.class)
.registerWriteHandler(new ModifiedVerifyContentCellWriteHandler())
.build();
excelWriter.write(list, sheet1);
excelWriter.write(blameVoList, sheet2);
excelWriter.write(blameLeaderVoList, sheet3);
excelWriter.write(departBlameLeaderVoList, sheet4);
excelWriter.write(returnHistoryExportData.returnRecords(), sheet5);
excelWriter.finish();
}
String filePath = fileService.upload(new ByteArrayInputStream(os.toByteArray()), os.size(), ".xlsx");
@ -294,7 +309,6 @@ public class NegativeTaskService extends ServiceImpl<NegativeTaskMapper, Negativ
.set(NegativeTask::getUpdTime, LocalDateTime.now()));
}
private void fillBlameAndLeaderAges(ExportNegativeBlameVo vo) {
if (vo == null) {
return;

Loading…
Cancel
Save