package com.gxwebsoft.ai.controller; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletResponse; import org.apache.poi.openxml4j.util.ZipSecureFile; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.alibaba.fastjson.JSONObject; import com.gxwebsoft.ai.config.TemplateConfig; import com.gxwebsoft.ai.dto.AuditReportRequest; import com.gxwebsoft.ai.dto.KnowledgeBaseRequest; import com.gxwebsoft.ai.enums.AuditReportEnum; import com.gxwebsoft.ai.service.KnowledgeBaseService; import com.gxwebsoft.ai.util.AuditReportUtil; import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.BaseController; import com.gxwebsoft.common.system.entity.User; import cn.afterturn.easypoi.word.WordExportUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; /** * 审计报告控制器 * @author GIIT-YC * */ @Tag(name = "审计报告") @RestController @RequestMapping("/api/ai/auditReport") public class AuditReportController extends BaseController { @Autowired private TemplateConfig templateConfig; @Autowired private KnowledgeBaseService knowledgeBaseService; private String invok(String query, String knowledge, String history, String suggestion, String title, String userName) { // 构建请求体 JSONObject requestBody = new JSONObject(); JSONObject inputs = new JSONObject(); inputs.put("query", query); inputs.put("knowledge", knowledge); inputs.put("history", history); inputs.put("suggestion", suggestion); inputs.put("title", title); requestBody.put("inputs", inputs); requestBody.put("response_mode", "blocking"); requestBody.put("user", userName); // 发送 POST 请求 String result = HttpUtil.createPost("http://1.14.159.185:8180/v1/workflows/run") .header("Authorization", "Bearer app-d7Ok9FECVZG2Ybw9wpg7tGu9") .header("Content-Type", "application/json") .body(requestBody.toString()) .timeout(600000) .execute() .body(); // 解析返回的JSON字符串 JSONObject jsonResponse = JSONObject.parseObject(result); // 获取data字段 JSONObject data = jsonResponse.getJSONObject("data"); // 获取outputs字段 JSONObject outputs = data.getJSONObject("outputs"); // 获取outputs中的result字符串 String resultStr = outputs.getString("result"); return resultStr; } /** * 生成审计报告-单一模块 */ @Operation(summary = "生成审计报告-单一模块") @PostMapping("/generate") public ApiResult generateAuditReport(@RequestBody AuditReportRequest req) { final User loginUser = getLoginUser(); Set kbIdSet = new HashSet<>(); List kbIdList = StrUtil.split(req.getKbIds(), ','); for(String kbId : kbIdList) { KnowledgeBaseRequest knowledgeBaseRequest = new KnowledgeBaseRequest(); knowledgeBaseRequest.setKbId(kbId); //召回切片数上限 knowledgeBaseRequest.setTopK(10); knowledgeBaseRequest.setFormCommit((req.getFormCommit() >= 10) ? req.getFormCommit() / 10 : req.getFormCommit()); kbIdSet.addAll(knowledgeBaseService.queryKnowledgeBase(knowledgeBaseRequest)); } String knowledge = kbIdSet.toString(); String query = AuditReportEnum.getByCode(req.getFormCommit()).getDesc(); // String ret = this.invok(query, knowledge, AuditReportUtil.generateReportContent(req), req.getSuggestion(), loginUser.getUsername()); String ret = this.invok(query, knowledge, AuditReportUtil.generateReportContentByFormCommit(req), req.getSuggestion(), req.getFrom00(), loginUser.getUsername()); return success(ret); } /** * 生成并下载审计报告 */ @Operation(summary = "生成并下载审计报告") @PostMapping("/download") public void downloadAuditReport(@RequestBody AuditReportRequest req, HttpServletResponse response) { double originalMinInflateRatio = ZipSecureFile.getMinInflateRatio(); try { ZipSecureFile.setMinInflateRatio(0.001); // 准备模板数据 Map map = new HashMap<>(); map.put(AuditReportEnum.TITLE.getCode().toString(), req.getFrom00()); map.put(AuditReportEnum.BASIS.getCode().toString(), req.getFrom10()); map.put(AuditReportEnum.OBJECTIVE.getCode().toString(), req.getFrom20()); map.put(AuditReportEnum.SCOPE.getCode().toString(), req.getFrom30()); map.put(AuditReportEnum.UNIT_OVERVIEW.getCode().toString(), req.getFrom41()); map.put(AuditReportEnum.ORG_PERSONNEL.getCode().toString(), req.getFrom42()); map.put(AuditReportEnum.FINANCIAL_ACCOUNTING.getCode().toString(), req.getFrom43()); map.put(AuditReportEnum.ANNUAL_BUSINESS.getCode().toString(), req.getFrom44()); map.put(AuditReportEnum.INTERNAL_CONTROL.getCode().toString(), req.getFrom45()); map.put(AuditReportEnum.ECONOMIC_POLICIES.getCode().toString(), req.getFrom51()); map.put(AuditReportEnum.DEV_STRATEGY.getCode().toString(), req.getFrom52()); map.put(AuditReportEnum.MAJOR_ECONOMIC.getCode().toString(), req.getFrom53()); map.put(AuditReportEnum.CORP_GOVERNANCE.getCode().toString(), req.getFrom54()); map.put(AuditReportEnum.FINANCIAL_LEGAL.getCode().toString(), req.getFrom55()); map.put(AuditReportEnum.INTEGRITY_COMPLIANCE.getCode().toString(), req.getFrom56()); map.put(AuditReportEnum.PREV_AUDIT_ISSUES.getCode().toString(), req.getFrom57()); map.put(AuditReportEnum.OTHER_MATTERS.getCode().toString(), req.getFrom58()); map.put(AuditReportEnum.RISK_IDENTIFY.getCode().toString(), req.getFrom61()); map.put(AuditReportEnum.RISK_RESPONSE.getCode().toString(), req.getFrom62()); map.put(AuditReportEnum.TECHNIQUES.getCode().toString(), req.getFrom70()); map.put(AuditReportEnum.SCHEDULE.getCode().toString(), req.getFrom80()); map.put(AuditReportEnum.ORGANIZATION.getCode().toString(), req.getFrom90()); // 使用 Easypoi 的 Word 模板功能 XWPFDocument document = WordExportUtil.exportWord07(templateConfig.getWordTemplatePath(), map); // 处理换行,确保 \n 转为硬回车(新段落) processParagraphs(document); response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); response.setHeader("Content-Disposition", "attachment; filename=audit_report.docx"); try (OutputStream out = response.getOutputStream()) { document.write(out); out.flush(); } } catch (Exception e) { throw new RuntimeException("生成审计报告失败", e); } finally { ZipSecureFile.setMinInflateRatio(originalMinInflateRatio); } } private void processParagraphs(XWPFDocument document) { List originalParas = new ArrayList<>(document.getParagraphs()); for (XWPFParagraph para : originalParas) { String text = para.getText(); if (text == null || !text.contains("\n")) { continue; } String[] parts = text.replace("\r\n", "\n").replace("\r", "\n").split("\n"); // 在原段落位置之前插入新段落 int pos = document.getPosOfParagraph(para); // 修正:按正序插入(从前往后) for (int i = 0; i < parts.length; i++) { // 创建新段落 XWPFParagraph newPara = document.insertNewParagraph(para.getCTP().newCursor()); // 复制样式 newPara.getCTP().setPPr(para.getCTP().getPPr()); XWPFRun newRun = newPara.createRun(); newRun.setText(parts[i].trim()); if (!para.getRuns().isEmpty()) { newRun.getCTR().setRPr(para.getRuns().get(0).getCTR().getRPr()); } } // 删除原段落 document.removeBodyElement(pos + parts.length); } } }