fix: 增加下载excel接口

This commit is contained in:
liu.zixi
2025-11-25 10:47:11 +08:00
parent 8d7cfac081
commit 24576a4fd1
3 changed files with 117 additions and 128 deletions

View File

@@ -8,8 +8,6 @@ import com.xboe.module.boecase.service.ICaseAiChatService;
import com.xboe.module.boecase.service.ICaseAiPermissionService; import com.xboe.module.boecase.service.ICaseAiPermissionService;
import com.xboe.module.boecase.service.IElasticSearchIndexService; import com.xboe.module.boecase.service.IElasticSearchIndexService;
import com.xboe.module.boecase.vo.CaseAiMessageVo; import com.xboe.module.boecase.vo.CaseAiMessageVo;
import com.xboe.module.excel.ExportsExcelSenderUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; 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 org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
/** /**
@@ -110,32 +104,9 @@ public class CaseAiChatApi extends ApiBaseController {
public void downloadConversationExcel(@RequestParam String startTime, public void downloadConversationExcel(@RequestParam String startTime,
@RequestParam String endTime, @RequestParam String endTime,
HttpServletResponse response) { HttpServletResponse response) {
try { LocalDateTime start = LocalDateTime.parse(startTime);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime end = LocalDateTime.parse(endTime);
LocalDateTime start = LocalDateTime.parse(startTime, formatter); caseAiChatService.getConversationExcel(start, end, response);
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<String, String> headers = new LinkedHashMap<>();
headers.put("会话ID", "conversationId");
headers.put("会话名称", "conversationName");
headers.put("用户", "user");
headers.put("开始时间", "startTime");
headers.put("会话时长", "duration");
List<ConversationExcelVo> dataList = new ArrayList<>();
// 这里应该填充实际数据
ExportsExcelSenderUtil.export(headers, dataList, response.getOutputStream(), "yyyy-MM-dd HH:mm:ss");
} catch (Exception e) {
log.error("导出会话记录为Excel异常", e);
}
} }
/** /**
@@ -191,16 +162,4 @@ public class CaseAiChatApi extends ApiBaseController {
} }
return error("创建失败"); return error("创建失败");
} }
/**
* 用于Excel导出的VO类
*/
@Data
static class ConversationExcelVo {
private String conversationId;
private String conversationName;
private String user;
private String startTime;
private String duration;
}
} }

View File

@@ -6,6 +6,7 @@ import com.xboe.module.boecase.entity.CaseAiConversations;
import com.xboe.module.boecase.vo.CaseAiMessageVo; import com.xboe.module.boecase.vo.CaseAiMessageVo;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@@ -40,6 +41,14 @@ public interface ICaseAiChatService {
*/ */
List<CaseAiMessageVo> getConversationMessages(String conversationId); List<CaseAiMessageVo> getConversationMessages(String conversationId);
/**
* 导出会话记录为Excel
* @param startTime 开始时间
* @param endTime 结束时间
* @param response
*/
void getConversationExcel(LocalDateTime startTime, LocalDateTime endTime, HttpServletResponse response);
/** /**
* 导出会话记录为Excel * 导出会话记录为Excel
* *

View File

@@ -61,6 +61,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.servlet.http.HttpServletResponse;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@@ -390,92 +391,24 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
return elasticSearchIndexService.queryData(conversationId); 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 @Override
public void downloadConversationExcel(LocalDateTime startTime, LocalDateTime endTime) { public void downloadConversationExcel(LocalDateTime startTime, LocalDateTime endTime) {
// 1. 根据startTime和endTime查询在这个时间区间内的CaseAiConversations数据 Workbook workbook = getChatMessageExcel(startTime, endTime);
List<CaseAiConversations> conversations = caseAiConversationsDao.getGenericDao().findList( // 创建Excel文件并保存
CaseAiConversations.class,
FieldFilters.ge("sysCreateTime", startTime),
FieldFilters.le("sysCreateTime", endTime)
);
// 准备Excel数据
List<ConversationExcelVo> excelDataList = new ArrayList<>();
// 2. 遍历这组数据根据aiConversationId从es中查询数据可调用getConversationMessages()方法)
for (CaseAiConversations conversation : conversations) {
String aiConversationId = conversation.getAiConversationId();
String conversationName = conversation.getConversationName();
String conversationUser = conversation.getConversationUser();
List<CaseAiMessageVo> 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<CaseAiMessageVo> 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文件并保存
if (caseAiProperties.isAiChatDataSendEmail()) { if (caseAiProperties.isAiChatDataSendEmail()) {
// TODO 发送邮件附件 // TODO 发送邮件附件
} else { } else {
@@ -814,4 +747,92 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
return false; return false;
} }
private Workbook getChatMessageExcel(LocalDateTime startTime, LocalDateTime endTime) {
// 1. 根据startTime和endTime查询在这个时间区间内的CaseAiConversations数据
List<CaseAiConversations> conversations = caseAiConversationsDao.getGenericDao().findList(
CaseAiConversations.class,
FieldFilters.ge("sysCreateTime", startTime),
FieldFilters.le("sysCreateTime", endTime)
);
// 准备Excel数据
List<ConversationExcelVo> excelDataList = new ArrayList<>();
// 2. 遍历这组数据根据aiConversationId从es中查询数据可调用getConversationMessages()方法)
for (CaseAiConversations conversation : conversations) {
String aiConversationId = conversation.getAiConversationId();
String conversationName = conversation.getConversationName();
String conversationUser = conversation.getConversationUser();
List<CaseAiMessageVo> 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<CaseAiMessageVo> 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;
}
} }