|
|
@ -308,12 +308,12 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
for (Long taskId : ids) { |
|
|
|
DocumentTasksVo documentTasksVo = documentTasksService.queryById(taskId); |
|
|
|
if (documentTasksVo == null) continue; |
|
|
|
|
|
|
|
|
|
|
|
String documentName = documentTasksVo.getDocumentName(); |
|
|
|
String taskName = documentTasksVo.getTaskName(); |
|
|
|
String taskType = documentTasksVo.getTaskType(); |
|
|
|
String label = dictTypeService.getDictLabel(taskType, taskName); |
|
|
|
|
|
|
|
|
|
|
|
// 获取详细的任务结果
|
|
|
|
List<DocumentTaskResultVO> resultDetails = getDetailResultsByTaskId(String.valueOf(taskId)); |
|
|
|
if (resultDetails != null && !resultDetails.isEmpty()) { |
|
|
@ -322,12 +322,12 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
if (allCategory.getResults() != null && !allCategory.getResults().isEmpty()) { |
|
|
|
// 获取任务类型对应的字段配置
|
|
|
|
List<FieldConfig> fieldConfigs = getFieldConfigsByTaskType(taskName); |
|
|
|
|
|
|
|
|
|
|
|
// 将结果转换为Markdown
|
|
|
|
StringBuilder markdown = new StringBuilder(); |
|
|
|
for (DocumentTaskResultVO.ResultItem item : allCategory.getResults()) { |
|
|
|
markdown.append("## ").append(item.getSerialNumber()).append(". ").append(item.getExistingIssues()).append("\n\n"); |
|
|
|
|
|
|
|
|
|
|
|
// 根据配置添加各字段内容
|
|
|
|
for (FieldConfig config : fieldConfigs) { |
|
|
|
String fieldValue = getFieldValue(item, config.getField()); |
|
|
@ -335,31 +335,31 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
markdown.append("### ").append(config.getTitle()).append("\n\n").append(fieldValue).append("\n\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 添加分隔线
|
|
|
|
markdown.append("---\n\n"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 为每个结果创建PDF文件
|
|
|
|
String pdfFileName = label + "_" + documentName + "_" + ".pdf"; |
|
|
|
String pdfPath = tempDir + File.separator + pdfFileName; |
|
|
|
|
|
|
|
|
|
|
|
// 转换Markdown为PDF
|
|
|
|
convertMarkdownToPdf(markdown.toString(), pdfPath); |
|
|
|
|
|
|
|
|
|
|
|
// 添加到ZIP
|
|
|
|
addToZip(pdfPath, pdfFileName, zos); |
|
|
|
|
|
|
|
|
|
|
|
// 删除临时PDF文件
|
|
|
|
new File(pdfPath).delete(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 下载ZIP文件
|
|
|
|
downloadFile(response, zipFilePath, zipFileName); |
|
|
|
|
|
|
|
|
|
|
|
// 删除临时ZIP文件
|
|
|
|
new File(zipFilePath).delete(); |
|
|
|
} else { |
|
|
@ -369,30 +369,30 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
if (documentTasksVo == null) { |
|
|
|
throw new RuntimeException("未找到相关任务"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String documentName = documentTasksVo.getDocumentName(); |
|
|
|
String taskName = documentTasksVo.getTaskName(); |
|
|
|
String taskType = documentTasksVo.getTaskType(); |
|
|
|
String label = dictTypeService.getDictLabel(taskType, taskName); |
|
|
|
|
|
|
|
|
|
|
|
// 获取详细的任务结果
|
|
|
|
List<DocumentTaskResultVO> resultDetails = getDetailResultsByTaskId(String.valueOf(taskId)); |
|
|
|
if (resultDetails == null || resultDetails.isEmpty() || |
|
|
|
if (resultDetails == null || resultDetails.isEmpty() || |
|
|
|
resultDetails.get(0).getResults() == null || resultDetails.get(0).getResults().isEmpty()) { |
|
|
|
throw new RuntimeException("未找到相关结果"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 第一个是"全部"分类
|
|
|
|
DocumentTaskResultVO allCategory = resultDetails.get(0); |
|
|
|
|
|
|
|
|
|
|
|
// 获取任务类型对应的字段配置
|
|
|
|
List<FieldConfig> fieldConfigs = getFieldConfigsByTaskType(taskName); |
|
|
|
|
|
|
|
|
|
|
|
// 将结果转换为Markdown
|
|
|
|
StringBuilder markdown = new StringBuilder(); |
|
|
|
for (DocumentTaskResultVO.ResultItem item : allCategory.getResults()) { |
|
|
|
markdown.append("## ").append(item.getSerialNumber()).append(". ").append(item.getExistingIssues()).append("\n\n"); |
|
|
|
|
|
|
|
|
|
|
|
// 根据配置添加各字段内容
|
|
|
|
for (FieldConfig config : fieldConfigs) { |
|
|
|
String fieldValue = getFieldValue(item, config.getField()); |
|
|
@ -400,21 +400,21 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
markdown.append("### ").append(config.getTitle()).append("\n\n").append(fieldValue).append("\n\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 添加分隔线
|
|
|
|
markdown.append("---\n\n"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String pdfFileName = label + "_" + documentName + "_" + ".pdf"; |
|
|
|
String tempDir = System.getProperty("java.io.tmpdir"); |
|
|
|
String pdfPath = tempDir + File.separator + pdfFileName; |
|
|
|
|
|
|
|
|
|
|
|
// 转换Markdown为PDF
|
|
|
|
convertMarkdownToPdf(markdown.toString(), pdfPath); |
|
|
|
|
|
|
|
|
|
|
|
// 下载PDF文件
|
|
|
|
downloadFile(response, pdfPath, pdfFileName); |
|
|
|
|
|
|
|
|
|
|
|
// 删除临时PDF文件
|
|
|
|
new File(pdfPath).delete(); |
|
|
|
} |
|
|
@ -494,12 +494,6 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
|
|
|
|
// Markdown转PDF方法
|
|
|
|
private void convertMarkdownToPdf(String markdown, String outputPath) throws Exception { |
|
|
|
// 使用flexmark-java解析Markdown
|
|
|
|
// MutableDataSet options = new MutableDataSet();
|
|
|
|
// Parser parser = Parser.builder(options).build();
|
|
|
|
// HtmlRenderer renderer = HtmlRenderer.builder(options).build();
|
|
|
|
// Node document = parser.parse(markdown);
|
|
|
|
// String htmlContent = renderer.render(document);
|
|
|
|
MutableDataSet options = new MutableDataSet(); |
|
|
|
// 启用表格解析
|
|
|
|
options.set(Parser.EXTENSIONS, Arrays.asList( |
|
|
@ -523,14 +517,12 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
|
|
|
|
// 配置允许的标签
|
|
|
|
Safelist safelist = Safelist.relaxed() |
|
|
|
// .addTags("em", "strong", "div", "span","br")
|
|
|
|
// .addAttributes(":all", "style", "class");
|
|
|
|
.addTags("em", "strong", "div", "span", "br", "table", "thead", "tbody", "tr", "th", "td") |
|
|
|
.addTags("em", "strong", "div", "span", "br", "table", "thead", "tbody", "tr", "th", "td", "img") |
|
|
|
.addAttributes(":all", "style", "class") |
|
|
|
.addAttributes("table", "border", "cellpadding", "cellspacing"); |
|
|
|
.addAttributes("table", "border", "cellpadding", "cellspacing") |
|
|
|
.addAttributes("img", "src", "alt", "width", "height"); // 允许img标签及其属性
|
|
|
|
htmlContent = Jsoup.clean(htmlContent, "", safelist, settings); |
|
|
|
|
|
|
|
// 使用 NekoHTML 进一步处理
|
|
|
|
// 创建完整的HTML文档,使用微软雅黑
|
|
|
|
String html = String.format(""" |
|
|
|
<!DOCTYPE html> |
|
|
@ -573,6 +565,14 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
tr { |
|
|
|
page-break-inside: avoid; |
|
|
|
} |
|
|
|
img { |
|
|
|
width: 600px; |
|
|
|
max-width: 100%%; |
|
|
|
height: auto; |
|
|
|
display: block; |
|
|
|
margin: 20px auto; |
|
|
|
page-break-inside: avoid; |
|
|
|
} |
|
|
|
</style> |
|
|
|
</head> |
|
|
|
<body> |
|
|
@ -581,9 +581,8 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
</html> |
|
|
|
""", |
|
|
|
htmlContent.replace("<br>", "\n")); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 处理图片标签,将markdown的图片语法转换为HTML的img标签
|
|
|
|
html = handleImageTags(html); |
|
|
|
// 配置Flying Saucer
|
|
|
|
ITextRenderer pdfRenderer = new ITextRenderer(); |
|
|
|
|
|
|
@ -610,6 +609,104 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 处理Markdown中的图片标签 |
|
|
|
* @param content Markdown内容 |
|
|
|
* @return 处理后的HTML内容 |
|
|
|
*/ |
|
|
|
private String handleImageTags(String content) { |
|
|
|
// 使用非贪婪模式匹配alt文本,使用平衡组模式匹配路径
|
|
|
|
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("!\\[(.*?)\\]\\(([^()]*(?:\\([^()]*\\)[^()]*)*?)\\)"); |
|
|
|
java.util.regex.Matcher matcher = pattern.matcher(content); |
|
|
|
StringBuffer sb = new StringBuffer(); |
|
|
|
|
|
|
|
while (matcher.find()) { |
|
|
|
String alt = matcher.group(1); |
|
|
|
String imagePath = matcher.group(2); |
|
|
|
|
|
|
|
// 检查图片文件是否存在
|
|
|
|
File imageFile = new File(imagePath); |
|
|
|
if (!imageFile.exists() && imagePath.contains("(")) { |
|
|
|
// 如果文件不存在且路径中包含括号,尝试修正路径
|
|
|
|
String correctedPath = correctImagePath(imagePath); |
|
|
|
imageFile = new File(correctedPath); |
|
|
|
if (imageFile.exists()) { |
|
|
|
imagePath = correctedPath; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (imageFile.exists()) { |
|
|
|
try { |
|
|
|
// 将图片转换为Base64编码
|
|
|
|
byte[] imageBytes = Files.readAllBytes(imageFile.toPath()); |
|
|
|
String base64Image = java.util.Base64.getEncoder().encodeToString(imageBytes); |
|
|
|
String imageType = getImageMimeType(imagePath); |
|
|
|
|
|
|
|
// 创建data URL,使用固定的宽度来确保图片在页面内显示
|
|
|
|
String imgTag = String.format("<img src=\"data:%s;base64,%s\" alt=\"%s\" style=\"width: 600px; max-width: 100%%; height: auto; display: block; margin: 10px auto;\"/>", |
|
|
|
imageType, base64Image, alt); |
|
|
|
|
|
|
|
// 替换markdown图片语法为HTML img标签
|
|
|
|
matcher.appendReplacement(sb, imgTag.replace("$", "\\$")); |
|
|
|
} catch (IOException e) { |
|
|
|
log.error("处理图片失败: " + imagePath, e); |
|
|
|
// 如果处理失败,保留原始文本
|
|
|
|
matcher.appendReplacement(sb, matcher.group(0).replace("$", "\\$")); |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.warn("图片文件不存在: " + imagePath); |
|
|
|
// 如果图片不存在,保留原始文本
|
|
|
|
matcher.appendReplacement(sb, matcher.group(0).replace("$", "\\$")); |
|
|
|
} |
|
|
|
} |
|
|
|
matcher.appendTail(sb); |
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 修正包含括号的图片路径 |
|
|
|
* @param originalPath 原始路径 |
|
|
|
* @return 修正后的路径 |
|
|
|
*/ |
|
|
|
private String correctImagePath(String originalPath) { |
|
|
|
// 如果路径中包含多个括号,取最后一个右括号之前的内容
|
|
|
|
int lastRightBracket = originalPath.lastIndexOf(")"); |
|
|
|
if (lastRightBracket != -1) { |
|
|
|
// 找到对应的左括号
|
|
|
|
int count = 1; |
|
|
|
int leftBracket = lastRightBracket - 1; |
|
|
|
while (leftBracket >= 0 && count > 0) { |
|
|
|
if (originalPath.charAt(leftBracket) == ')') { |
|
|
|
count++; |
|
|
|
} else if (originalPath.charAt(leftBracket) == '(') { |
|
|
|
count--; |
|
|
|
} |
|
|
|
leftBracket--; |
|
|
|
} |
|
|
|
if (count == 0) { |
|
|
|
// 找到匹配的括号对,返回不包含最外层括号的路径
|
|
|
|
return originalPath.substring(0, leftBracket + 1) + originalPath.substring(lastRightBracket + 1); |
|
|
|
} |
|
|
|
} |
|
|
|
return originalPath; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 根据文件扩展名获取MIME类型 |
|
|
|
* @param filePath 文件路径 |
|
|
|
* @return MIME类型 |
|
|
|
*/ |
|
|
|
private String getImageMimeType(String filePath) { |
|
|
|
String extension = filePath.substring(filePath.lastIndexOf(".") + 1).toLowerCase(); |
|
|
|
return switch (extension) { |
|
|
|
case "png" -> "image/png"; |
|
|
|
case "jpg", "jpeg" -> "image/jpeg"; |
|
|
|
case "gif" -> "image/gif"; |
|
|
|
case "bmp" -> "image/bmp"; |
|
|
|
default -> "image/jpeg"; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// 添加文件到ZIP
|
|
|
|
private void addToZip(String filePath, String fileName, ZipOutputStream zos) throws IOException { |
|
|
|
byte[] buffer = new byte[1024]; |
|
|
@ -770,21 +867,21 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
private static class FieldConfig { |
|
|
|
private String field; |
|
|
|
private String title; |
|
|
|
|
|
|
|
|
|
|
|
public FieldConfig(String field, String title) { |
|
|
|
this.field = field; |
|
|
|
this.title = title; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public String getField() { |
|
|
|
return field; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public String getTitle() { |
|
|
|
return title; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 根据任务类型获取对应的字段配置 |
|
|
|
* |
|
|
@ -793,7 +890,7 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
*/ |
|
|
|
private List<FieldConfig> getFieldConfigsByTaskType(String taskName) { |
|
|
|
List<FieldConfig> configs = new java.util.ArrayList<>(); |
|
|
|
|
|
|
|
|
|
|
|
// 根据任务类型返回不同的字段配置
|
|
|
|
switch (taskName) { |
|
|
|
case "checkCompanyName": |
|
|
@ -824,10 +921,10 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi |
|
|
|
configs.add(new FieldConfig("modificationDisplay", "修改情况")); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return configs; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 获取对象的字段值 |
|
|
|
* |
|
|
|