From 24576a4fd1976f891a8cfe111e6a89a9bb875cb3 Mon Sep 17 00:00:00 2001 From: "liu.zixi" Date: Tue, 25 Nov 2025 10:47:11 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=E4=B8=8B=E8=BD=BDexce?= =?UTF-8?q?l=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/boecase/api/CaseAiChatApi.java | 47 +---- .../boecase/service/ICaseAiChatService.java | 9 + .../service/impl/CaseAiChatServiceImpl.java | 189 ++++++++++-------- 3 files changed, 117 insertions(+), 128 deletions(-) diff --git a/servers/boe-server-all/src/main/java/com/xboe/module/boecase/api/CaseAiChatApi.java b/servers/boe-server-all/src/main/java/com/xboe/module/boecase/api/CaseAiChatApi.java index e71c6aae..2ebd58f0 100644 --- a/servers/boe-server-all/src/main/java/com/xboe/module/boecase/api/CaseAiChatApi.java +++ b/servers/boe-server-all/src/main/java/com/xboe/module/boecase/api/CaseAiChatApi.java @@ -8,8 +8,6 @@ import com.xboe.module.boecase.service.ICaseAiChatService; import com.xboe.module.boecase.service.ICaseAiPermissionService; import com.xboe.module.boecase.service.IElasticSearchIndexService; import com.xboe.module.boecase.vo.CaseAiMessageVo; -import com.xboe.module.excel.ExportsExcelSenderUtil; -import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; @@ -17,12 +15,8 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; /** @@ -110,32 +104,9 @@ public class CaseAiChatApi extends ApiBaseController { public void downloadConversationExcel(@RequestParam String startTime, @RequestParam String endTime, HttpServletResponse response) { - try { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - LocalDateTime start = LocalDateTime.parse(startTime, formatter); - LocalDateTime end = LocalDateTime.parse(endTime, formatter); - - // TODO: 这里需要修改为实际返回数据的方法 - caseAiChatService.downloadConversationExcel(start, end); - - response.setContentType("application/vnd.ms-excel"); - response.setHeader("Content-Disposition", "attachment; filename=conversations.xls"); - - // 示例数据,实际应该从Service获取 - LinkedHashMap headers = new LinkedHashMap<>(); - headers.put("会话ID", "conversationId"); - headers.put("会话名称", "conversationName"); - headers.put("用户", "user"); - headers.put("开始时间", "startTime"); - headers.put("会话时长", "duration"); - - List dataList = new ArrayList<>(); - // 这里应该填充实际数据 - - ExportsExcelSenderUtil.export(headers, dataList, response.getOutputStream(), "yyyy-MM-dd HH:mm:ss"); - } catch (Exception e) { - log.error("导出会话记录为Excel异常", e); - } + LocalDateTime start = LocalDateTime.parse(startTime); + LocalDateTime end = LocalDateTime.parse(endTime); + caseAiChatService.getConversationExcel(start, end, response); } /** @@ -191,16 +162,4 @@ public class CaseAiChatApi extends ApiBaseController { } return error("创建失败"); } - - /** - * 用于Excel导出的VO类 - */ - @Data - static class ConversationExcelVo { - private String conversationId; - private String conversationName; - private String user; - private String startTime; - private String duration; - } } \ No newline at end of file diff --git a/servers/boe-server-all/src/main/java/com/xboe/module/boecase/service/ICaseAiChatService.java b/servers/boe-server-all/src/main/java/com/xboe/module/boecase/service/ICaseAiChatService.java index c04d2bd8..87e401e5 100644 --- a/servers/boe-server-all/src/main/java/com/xboe/module/boecase/service/ICaseAiChatService.java +++ b/servers/boe-server-all/src/main/java/com/xboe/module/boecase/service/ICaseAiChatService.java @@ -6,6 +6,7 @@ import com.xboe.module.boecase.entity.CaseAiConversations; import com.xboe.module.boecase.vo.CaseAiMessageVo; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import javax.servlet.http.HttpServletResponse; import java.time.LocalDateTime; import java.util.List; @@ -40,6 +41,14 @@ public interface ICaseAiChatService { */ List getConversationMessages(String conversationId); + /** + * 导出会话记录为Excel + * @param startTime 开始时间 + * @param endTime 结束时间 + * @param response + */ + void getConversationExcel(LocalDateTime startTime, LocalDateTime endTime, HttpServletResponse response); + /** * 导出会话记录为Excel * diff --git a/servers/boe-server-all/src/main/java/com/xboe/module/boecase/service/impl/CaseAiChatServiceImpl.java b/servers/boe-server-all/src/main/java/com/xboe/module/boecase/service/impl/CaseAiChatServiceImpl.java index a6712e1b..0888852e 100644 --- a/servers/boe-server-all/src/main/java/com/xboe/module/boecase/service/impl/CaseAiChatServiceImpl.java +++ b/servers/boe-server-all/src/main/java/com/xboe/module/boecase/service/impl/CaseAiChatServiceImpl.java @@ -61,6 +61,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -390,92 +391,24 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService { return elasticSearchIndexService.queryData(conversationId); } + @Override + public void getConversationExcel(LocalDateTime startTime, LocalDateTime endTime, HttpServletResponse response) { + Workbook workbook = getChatMessageExcel(startTime, endTime); + // 写入response.getOutputStream() + try (OutputStream out = response.getOutputStream()) { + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=chat_message.xlsx"); + workbook.write(out); + out.flush(); + } catch (Exception e) { + log.error("导出Excel异常", e); + } + } + @Override public void downloadConversationExcel(LocalDateTime startTime, LocalDateTime endTime) { - // 1. 根据startTime和endTime,查询在这个时间区间内的CaseAiConversations数据 - List conversations = caseAiConversationsDao.getGenericDao().findList( - CaseAiConversations.class, - FieldFilters.ge("sysCreateTime", startTime), - FieldFilters.le("sysCreateTime", endTime) - ); - - // 准备Excel数据 - List excelDataList = new ArrayList<>(); - - // 2. 遍历这组数据,根据aiConversationId从es中查询数据(可调用getConversationMessages()方法) - for (CaseAiConversations conversation : conversations) { - String aiConversationId = conversation.getAiConversationId(); - String conversationName = conversation.getConversationName(); - String conversationUser = conversation.getConversationUser(); - - List messages = getConversationMessages(aiConversationId); - - // 计算会话时长 - long duration = 0; // 默认为0,如果需要精确计算,需要从消息中提取时间信息 - - // 3. 写入Excel,包括每个会话的用户,会话标题,会话内的问答记录,每次对话时长等 - ConversationExcelVo excelData = new ConversationExcelVo(); - excelData.setConversationId(aiConversationId); - excelData.setConversationName(conversationName); - excelData.setUser(conversationUser); - excelData.setMessages(messages); - - excelDataList.add(excelData); - } - - // 写入Excel文件 - Workbook workbook = new XSSFWorkbook(); - Sheet sheet = workbook.createSheet("AI会话数据"); - // 标题行 - Row headerRow = sheet.createRow(0); - headerRow.createCell(0).setCellValue("会话ID"); - headerRow.createCell(1).setCellValue("会话名称"); - headerRow.createCell(2).setCellValue("用户"); - headerRow.createCell(3).setCellValue("提问"); - headerRow.createCell(4).setCellValue("回答"); - headerRow.createCell(5).setCellValue("开始时间"); - headerRow.createCell(6).setCellValue("问答时长(秒)"); - - // 内容行 - if (!excelDataList.isEmpty()) { - int rowNum = 1; // 从第二行开始写入数据 - for (ConversationExcelVo excelData : excelDataList) { - List messages = excelData.getMessages(); - - if (messages != null && !messages.isEmpty()) { - // 记录起始行号,用于后续合并单元格 - int startRow = rowNum; - - // 遍历每个消息 - for (CaseAiMessageVo message : messages) { - Row row = sheet.createRow(rowNum++); - // 填充每行数据 - row.createCell(0).setCellValue(excelData.getConversationId()); - row.createCell(1).setCellValue(excelData.getConversationName()); - row.createCell(2).setCellValue(excelData.getUser()); - row.createCell(3).setCellValue(message.getQuery() != null ? message.getQuery() : ""); - row.createCell(4).setCellValue(message.getAnswer() != null ? message.getAnswer() : ""); - row.createCell(5).setCellValue(""); // 开始时间字段暂留空 - row.createCell(6).setCellValue(message.getDurationSeconds() != null ? message.getDurationSeconds() : 0); - } - - // 合并单元格(会话ID、会话名称、用户三列) - // 参数说明:起始行号,结束行号,起始列号,结束列号 - if (rowNum > startRow + 1) { // 只有当有多行时才合并 - sheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 0, 0)); - sheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 1, 1)); - sheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 2, 2)); - } - } else { - // 如果没有消息,则仍然创建一行显示基本信息 - Row row = sheet.createRow(rowNum++); - row.createCell(0).setCellValue(excelData.getConversationId()); - row.createCell(1).setCellValue(excelData.getConversationName()); - row.createCell(2).setCellValue(excelData.getUser()); - } - } - } - // 3. 创建Excel文件并保存 + Workbook workbook = getChatMessageExcel(startTime, endTime); + // 创建Excel文件并保存 if (caseAiProperties.isAiChatDataSendEmail()) { // TODO 发送邮件附件 } else { @@ -814,4 +747,92 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService { return false; } + + private Workbook getChatMessageExcel(LocalDateTime startTime, LocalDateTime endTime) { + // 1. 根据startTime和endTime,查询在这个时间区间内的CaseAiConversations数据 + List conversations = caseAiConversationsDao.getGenericDao().findList( + CaseAiConversations.class, + FieldFilters.ge("sysCreateTime", startTime), + FieldFilters.le("sysCreateTime", endTime) + ); + + // 准备Excel数据 + List excelDataList = new ArrayList<>(); + + // 2. 遍历这组数据,根据aiConversationId从es中查询数据(可调用getConversationMessages()方法) + for (CaseAiConversations conversation : conversations) { + String aiConversationId = conversation.getAiConversationId(); + String conversationName = conversation.getConversationName(); + String conversationUser = conversation.getConversationUser(); + + List messages = getConversationMessages(aiConversationId); + + // 计算会话时长 + long duration = 0; // 默认为0,如果需要精确计算,需要从消息中提取时间信息 + + // 3. 写入Excel,包括每个会话的用户,会话标题,会话内的问答记录,每次对话时长等 + ConversationExcelVo excelData = new ConversationExcelVo(); + excelData.setConversationId(aiConversationId); + excelData.setConversationName(conversationName); + excelData.setUser(conversationUser); + excelData.setMessages(messages); + + excelDataList.add(excelData); + } + + // 写入Excel文件 + Workbook workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet("AI会话数据"); + // 标题行 + Row headerRow = sheet.createRow(0); + headerRow.createCell(0).setCellValue("会话ID"); + headerRow.createCell(1).setCellValue("会话名称"); + headerRow.createCell(2).setCellValue("用户"); + headerRow.createCell(3).setCellValue("提问"); + headerRow.createCell(4).setCellValue("回答"); + headerRow.createCell(5).setCellValue("开始时间"); + headerRow.createCell(6).setCellValue("问答时长(秒)"); + + // 内容行 + if (!excelDataList.isEmpty()) { + int rowNum = 1; // 从第二行开始写入数据 + for (ConversationExcelVo excelData : excelDataList) { + List messages = excelData.getMessages(); + + if (messages != null && !messages.isEmpty()) { + // 记录起始行号,用于后续合并单元格 + int startRow = rowNum; + + // 遍历每个消息 + for (CaseAiMessageVo message : messages) { + Row row = sheet.createRow(rowNum++); + // 填充每行数据 + row.createCell(0).setCellValue(excelData.getConversationId()); + row.createCell(1).setCellValue(excelData.getConversationName()); + row.createCell(2).setCellValue(excelData.getUser()); + row.createCell(3).setCellValue(message.getQuery() != null ? message.getQuery() : ""); + row.createCell(4).setCellValue(message.getAnswer() != null ? message.getAnswer() : ""); + row.createCell(5).setCellValue(""); // 开始时间字段暂留空 + row.createCell(6).setCellValue(message.getDurationSeconds() != null ? message.getDurationSeconds() : 0); + } + + // 合并单元格(会话ID、会话名称、用户三列) + // 参数说明:起始行号,结束行号,起始列号,结束列号 + if (rowNum > startRow + 1) { // 只有当有多行时才合并 + sheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 0, 0)); + sheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 1, 1)); + sheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 2, 2)); + } + } else { + // 如果没有消息,则仍然创建一行显示基本信息 + Row row = sheet.createRow(rowNum++); + row.createCell(0).setCellValue(excelData.getConversationId()); + row.createCell(1).setCellValue(excelData.getConversationName()); + row.createCell(2).setCellValue(excelData.getUser()); + } + } + } + + return workbook; + } }