From 143a9e90beffef3f4e511de391fa4df143453cc5 Mon Sep 17 00:00:00 2001 From: MerCry Date: Sat, 7 Mar 2026 18:49:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BB=9F=E8=AE=A1=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- excel-handle/pom.xml | 4 + .../wecom/domain/CustomerExportData.java | 3 + .../excel/wecom/helper/HandleAllData.java | 48 +++- .../wecom/helper/StatisticsAccumulator.java | 30 +++ .../mapper/CustomerExportDataMapper.java | 38 +++ .../CustomerDataChangeTrackingService.java | 1 + .../service/CustomerExportAsyncService.java | 250 ++++++++++++++++++ .../wecom/service/CustomerExportService.java | 79 +++++- .../mapper/wecom/CustomerExportDataMapper.xml | 128 +++++++++ .../wocom/CustomerExportDataController.java | 164 +++++++++++- .../ruoyi/system/domain/SysExportTask.java | 209 +++++++++++++++ .../system/mapper/SysExportTaskMapper.java | 66 +++++ .../system/service/ISysExportTaskService.java | 93 +++++++ .../impl/SysExportTaskServiceImpl.java | 107 ++++++++ .../mapper/system/SysExportTaskMapper.xml | 134 ++++++++++ ruoyi-ui/src/api/wecom/customerExport.js | 34 +++ .../src/views/wecom/customerExport/index.vue | 200 ++++++++++++-- sql/sys_export_task.sql | 24 ++ 18 files changed, 1581 insertions(+), 31 deletions(-) create mode 100644 excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerExportAsyncService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysExportTask.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysExportTaskMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysExportTaskService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysExportTaskServiceImpl.java create mode 100644 ruoyi-system/src/main/resources/mapper/system/SysExportTaskMapper.xml create mode 100644 sql/sys_export_task.sql diff --git a/excel-handle/pom.xml b/excel-handle/pom.xml index ade6b58..4784242 100644 --- a/excel-handle/pom.xml +++ b/excel-handle/pom.xml @@ -59,6 +59,10 @@ fastjson 1.2.83 + + com.ruoyi + ruoyi-system + diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/domain/CustomerExportData.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/domain/CustomerExportData.java index 8d30fe0..0b70e56 100644 --- a/excel-handle/src/main/java/com/ruoyi/excel/wecom/domain/CustomerExportData.java +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/domain/CustomerExportData.java @@ -66,6 +66,9 @@ public class CustomerExportData implements Serializable { */ private Date addDate; + //成交日期 + private Date finishDate; + /** * 来源 */ diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllData.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllData.java index b64d3b7..a3778cc 100644 --- a/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllData.java +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/HandleAllData.java @@ -519,6 +519,20 @@ import java.util.concurrent.atomic.AtomicInteger; GROUP_FIELD_MAP.put("AE组", "tagGroup18"); } + private static final Map GROUP_ATTR_MAP = new LinkedHashMap<>(); + static { + GROUP_ATTR_MAP.put("N组", "tag_group1"); + GROUP_ATTR_MAP.put("O组", "tag_group2"); + GROUP_ATTR_MAP.put("P组", "tag_group3"); + GROUP_ATTR_MAP.put("W组", "tag_group10"); + GROUP_ATTR_MAP.put("X组", "tag_group11"); + GROUP_ATTR_MAP.put("Y组", "tag_group12"); + GROUP_ATTR_MAP.put("Z组", "tag_group13"); + GROUP_ATTR_MAP.put("AA组", "tag_group14"); + GROUP_ATTR_MAP.put("AC组", "tag_group16"); + GROUP_ATTR_MAP.put("AD组", "tag_group17"); + GROUP_ATTR_MAP.put("AE组", "tag_group18"); + } /** * 字段反射缓存 */ @@ -729,7 +743,6 @@ import java.util.concurrent.atomic.AtomicInteger; String customerAttr = data.getTagGroup6(); if (customerAttr != null && !customerAttr.trim().isEmpty()) { stats.setTotalCustomerAttr(stats.getTotalCustomerAttr() + 1); - if (customerAttr.contains("家长")) { stats.setParentCount(stats.getParentCount() + 1); //todo 存在订单未完成 但是有标签的场景 @@ -751,9 +764,24 @@ import java.util.concurrent.atomic.AtomicInteger; if (matchesQValue(data, date) && isTimelyOrder(data)) { stats.setStudentDailyOrderCount(stats.getStudentDailyOrderCount() + 1); } + } else if (customerAttr.contains("老师")) { + stats.setTeacherCount(stats.getTeacherCount() + 1); + stats.setTeacherOrderCount(stats.getTeacherOrderCount() + 1); - } else { - stats.setUnknownAttrCount(stats.getUnknownAttrCount() + 1); + // 新增:N组老师出单率统计(当日) + stats.setTeacherDailyCount(stats.getTeacherDailyCount() + 1); + if (matchesQValue(data, date) && isTimelyOrder(data)) { + stats.setTeacherDailyOrderCount(stats.getTeacherDailyOrderCount() + 1); + } + } + } else { + stats.setUnknownAttrCount(stats.getUnknownAttrCount() + 1); + stats.setUnkownOrderCount(stats.getUnkownOrderCount() + 1); + + // 新增:N组未知出单率统计(当日) + stats.setUnkownDailyCount(stats.getUnkownDailyCount() + 1); + if (matchesQValue(data, date) && isTimelyOrder(data)) { + stats.setUnkownDailyOrderCount(stats.getUnkownDailyOrderCount() + 1); } } @@ -825,6 +853,7 @@ import java.util.concurrent.atomic.AtomicInteger; int sortNo = 0; // 为每个组生成23个统计指标 for (Map.Entry entry : accumulator.getGroupStatsMap().entrySet()) { + String groupName = entry.getKey(); StatisticsAccumulator.GroupStatistics stats = entry.getValue(); @@ -834,7 +863,9 @@ import java.util.concurrent.atomic.AtomicInteger; setIndicatorValue(corpId,indicatorMap,curDate, "成单成本(当日)", groupName, "需手工填写",(10*sortNo++)); // 1. 成单数 - setIndicatorValue(corpId,indicatorMap,curDate, "成单数(当日)", groupName, String.valueOf(stats.getOrderCount()),(10*sortNo++)); + //成单数 需要从历史的所有数据中获取 成交日期 = date的数据 + Long finishCount = customerExportDataMapper.selectByFinishDate(corpId,curDate,GROUP_ATTR_MAP.get(groupName)); + setIndicatorValue(corpId,indicatorMap,curDate, "成单数(当日)", groupName, String.valueOf(finishCount),(10*sortNo++)); // 2. 进粉数 setIndicatorValue(corpId,indicatorMap,curDate, "进粉数(当日)", groupName, String.valueOf(stats.getCustomerCount()),(10*sortNo++)); @@ -866,6 +897,11 @@ import java.util.concurrent.atomic.AtomicInteger; setIndicatorValue(corpId,indicatorMap,curDate, "学生占比(当日)", groupName, studentRate,(10*sortNo++)); setIndicatorValue(corpId,indicatorMap,curDate, "学生数量(当日)", groupName, String.valueOf(stats.getStudentCount()),(10*sortNo++),true); + // 8. 老师占比 + String teacherRate = calculateRate(stats.getTeacherCount(), stats.getTotalCustomerAttr()); + setIndicatorValue(corpId,indicatorMap,curDate, "老师占比(当日)", groupName, teacherRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "老师数量(当日)", groupName, String.valueOf(stats.getTeacherCount()),(10*sortNo++),true); + // 9. 未知占比 String unknownRate = calculateRate(stats.getUnknownAttrCount(), stats.getTotalCustomerAttr()); setIndicatorValue(corpId,indicatorMap,curDate, "未知占比(当日)", groupName, unknownRate,(10*sortNo++)); @@ -914,12 +950,12 @@ import java.util.concurrent.atomic.AtomicInteger; // 19. 家长出单占比 String parentOrderRate = calculateRate(stats.getParentOrderCount(), stats.getParentCount()); - setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比(当日)", groupName, parentOrderRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比(当日)", groupName, parentOrderRate,(10*sortNo++),true); setIndicatorValue(corpId,indicatorMap,curDate, "家长出单数量(当日)", groupName, String.valueOf(stats.getParentOrderCount()),(10*sortNo++),true); // 20. 学生出单占比 String studentOrderRate = calculateRate(stats.getStudentOrderCount(), stats.getStudentCount()); - setIndicatorValue(corpId,indicatorMap,curDate, "学生出单占比(当日)", groupName, studentOrderRate,(10*sortNo++)); + setIndicatorValue(corpId,indicatorMap,curDate, "学生出单占比(当日)", groupName, studentOrderRate,(10*sortNo++),true); setIndicatorValue(corpId,indicatorMap,curDate, "学生出单数量(当日)", groupName, String.valueOf(stats.getStudentOrderCount()),(10*sortNo++),true); // 21. 家长出单率(当日) diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/StatisticsAccumulator.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/StatisticsAccumulator.java index 2ef4c58..ea37654 100644 --- a/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/StatisticsAccumulator.java +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/helper/StatisticsAccumulator.java @@ -78,6 +78,10 @@ public class StatisticsAccumulator { * 学生数 */ private int studentCount = 0; + /** + * 老师 + */ + private int teacherCount = 0; /** * 未知(空白)数 @@ -141,6 +145,13 @@ public class StatisticsAccumulator { * 学生出单数 */ private int studentOrderCount = 0; + /** + * 老师出单数 + * + */ + private int teacherOrderCount = 0; + + private int unkownOrderCount = 0; // ========== 新增:家长/学生出单率统计(当日) ========== /** @@ -158,10 +169,29 @@ public class StatisticsAccumulator { */ private int studentDailyOrderCount = 0; + /** * 学生总数(当日进粉)- 用于出单率分母 */ private int studentDailyCount = 0; + /** + * 老师总数(当日进粉)- 用于出单率分母 + */ + private int teacherDailyCount = 0; + /** + * 未知总数(当日进粉)- 用于出单率分母 + */ + private int unkownDailyCount = 0; + + /** + * 学生出单数(当日成交)- 满足Q列=当日 AND T列=已成交及时单9元+ + */ + private int teacherDailyOrderCount = 0; + + /** + * 学生出单数(当日成交)- 满足Q列=当日 AND T列=已成交及时单9元+ + */ + private int unkownDailyOrderCount = 0; // ========== 成本数据 ========== /** diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/mapper/CustomerExportDataMapper.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/mapper/CustomerExportDataMapper.java index de61cc1..f33cb29 100644 --- a/excel-handle/src/main/java/com/ruoyi/excel/wecom/mapper/CustomerExportDataMapper.java +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/mapper/CustomerExportDataMapper.java @@ -57,4 +57,42 @@ public interface CustomerExportDataMapper extends BaseMapper @Param("addUserAccount") String addUserAccount, @Param("addTime") Date addTime ); + + Long selectByFinishDate( + @Param("corpId") String corpId,@Param("date") Date date,@Param("attr") String attr); + + /** + * 统计客户导出数据VO数量(用于异步导出) + * @param corpId 企业ID + * @param startDate 开始日期 + * @param endDate 结束日期 + * @param customerName 客户名称(可选) + * @return 数据总数 + */ + int countCustomerExportDataVOList( + @Param("corpId") String corpId, + @Param("startDate") Date startDate, + @Param("endDate") Date endDate, + @Param("customerName") String customerName + ); + + /** + * 分页查询客户导出数据VO列表(用于异步导出) + * @param corpId 企业ID + * @param startDate 开始日期 + * @param endDate 结束日期 + * @param customerName 客户名称(可选) + * @param offset 偏移量 + * @param limit 每页数量 + * @return 客户导出数据VO列表 + */ + List selectCustomerExportDataVOListByPage( + @Param("corpId") String corpId, + @Param("startDate") Date startDate, + @Param("endDate") Date endDate, + @Param("customerName") String customerName, + @Param("offset") int offset, + @Param("limit") int limit + ); } + diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerDataChangeTrackingService.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerDataChangeTrackingService.java index 6897a33..d267b47 100644 --- a/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerDataChangeTrackingService.java +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerDataChangeTrackingService.java @@ -116,6 +116,7 @@ public class CustomerDataChangeTrackingService { sb.append(data.getTagGroup15()).append("|"); sb.append(data.getTagGroup16()).append("|"); sb.append(data.getTagGroup17()).append("|"); + sb.append(data.getFinishDate()).append("|"); sb.append(data.getTagGroup18()); // 计算MD5 diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerExportAsyncService.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerExportAsyncService.java new file mode 100644 index 0000000..3e6306f --- /dev/null +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerExportAsyncService.java @@ -0,0 +1,250 @@ +package com.ruoyi.excel.wecom.service; + +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.excel.wecom.mapper.CustomerExportDataMapper; +import com.ruoyi.excel.wecom.vo.CustomerExportDataVO; +import com.ruoyi.system.service.ISysExportTaskService; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.Date; +import java.util.List; + +/** + * 客户数据异步导出服务 + */ +@Service +public class CustomerExportAsyncService +{ + private static final Logger log = LoggerFactory.getLogger(CustomerExportAsyncService.class); + + private static final int BATCH_SIZE = 5000; + private static final int ROW_ACCESS_WINDOW = 1000; + + @Autowired + private CustomerExportDataMapper customerExportDataMapper; + + @Autowired + private ISysExportTaskService exportTaskService; + + @Async("threadPoolTaskExecutor") + public void executeExport(Long taskId, String corpId, Date startDate, Date endDate, String customerName) + { + log.info("开始执行异步导出任务,taskId: {}, corpId: {}", taskId, corpId); + String filePath = null; + String fileName = null; + File file = null; + SXSSFWorkbook workbook = null; + FileOutputStream fos = null; + + try + { + int totalCount = customerExportDataMapper.countCustomerExportDataVOList(corpId, startDate, endDate, customerName); + log.info("导出任务 taskId: {}, 总数据量: {}", taskId, totalCount); + + if (totalCount == 0) + { + exportTaskService.markSuccess(taskId, "", "无数据.xlsx", 0L); + return; + } + + exportTaskService.updateProgress(taskId, 0, totalCount); + + String dateStr = DateUtils.dateTimeNow("yyyyMMddHHmmss"); + fileName = "客户统计数据_" + dateStr + ".xlsx"; + String downloadPath = RuoYiConfig.getDownloadPath(); + File dir = new File(downloadPath); + if (!dir.exists()) + { + dir.mkdirs(); + } + filePath = downloadPath + fileName; + file = new File(filePath); + + workbook = new SXSSFWorkbook(ROW_ACCESS_WINDOW); + Sheet sheet = workbook.createSheet("客户统计数据"); + + CellStyle headerStyle = createHeaderStyle(workbook); + CellStyle dataStyle = createDataStyle(workbook); + + String[] headers = { + "客户名称", "描述", "添加人", "添加人账号", "添加人所属部门", "添加时间", "来源", + "手机", "企业", "邮箱", "地址", "职务", "电话", + "标签组1(投放)", "标签组2(公司孵化)", "标签组3(商务)", "标签组4(成交日期)", "标签组5(年级组)", + "标签组6(客户属性)", "标签组7(成交)", "标签组8(成交品牌)", "标签组9(线索通标签)", "标签组10(A1组)", + "标签组11(B1组)", "标签组12(C1组)", "标签组13(D1组)", "标签组14(E1组)", "标签组15(意向度)", + "标签组16(自然流)", "标签组17(F1组)", "标签组18(G1组)" + }; + + Row headerRow = sheet.createRow(0); + for (int i = 0; i < headers.length; i++) + { + Cell cell = headerRow.createCell(i); + cell.setCellValue(headers[i]); + cell.setCellStyle(headerStyle); + sheet.setColumnWidth(i, 20 * 256); + } + + int processedCount = 0; + int rowIndex = 1; + int offset = 0; + + while (offset < totalCount) + { + List dataList = customerExportDataMapper.selectCustomerExportDataVOListByPage( + corpId, startDate, endDate, customerName, offset, BATCH_SIZE); + + if (dataList == null || dataList.isEmpty()) + { + break; + } + + for (CustomerExportDataVO data : dataList) + { + Row row = sheet.createRow(rowIndex++); + fillRowData(row, data, dataStyle); + processedCount++; + } + + offset += BATCH_SIZE; + + exportTaskService.updateProgress(taskId, processedCount, totalCount); + } + + fos = new FileOutputStream(file); + workbook.write(fos); + fos.flush(); + + long fileSize = file.length(); + exportTaskService.markSuccess(taskId, filePath, fileName, fileSize); + log.info("导出任务完成,taskId: {}, 文件: {}, 大小: {} bytes", taskId, fileName, fileSize); + } + catch (Exception e) + { + log.error("导出任务执行失败,taskId: {}", taskId, e); + exportTaskService.markFailed(taskId, "导出失败:" + e.getMessage()); + } + finally + { + try + { + if (fos != null) + { + fos.close(); + } + if (workbook != null) + { + workbook.dispose(); + workbook.close(); + } + } + catch (Exception e) + { + log.error("关闭资源失败", e); + } + } + } + + private CellStyle createHeaderStyle(Workbook workbook) + { + CellStyle style = workbook.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font font = workbook.createFont(); + font.setBold(true); + font.setFontName("Arial"); + font.setFontHeightInPoints((short) 10); + style.setFont(font); + return style; + } + + private CellStyle createDataStyle(Workbook workbook) + { + CellStyle style = workbook.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font font = workbook.createFont(); + font.setFontName("Arial"); + font.setFontHeightInPoints((short) 10); + style.setFont(font); + return style; + } + + private void fillRowData(Row row, CustomerExportDataVO data, CellStyle style) + { + int col = 0; + createCell(row, col++, data.getCustomerName(), style); + createCell(row, col++, data.getDescription(), style); + createCell(row, col++, data.getAddUserName(), style); + createCell(row, col++, data.getAddUserAccount(), style); + createCell(row, col++, data.getAddUserDepartment(), style); + createCell(row, col++, formatDate(data.getAddTime()), style); + createCell(row, col++, data.getSource(), style); + createCell(row, col++, data.getMobile(), style); + createCell(row, col++, data.getCompany(), style); + createCell(row, col++, data.getEmail(), style); + createCell(row, col++, data.getAddress(), style); + createCell(row, col++, data.getPosition(), style); + createCell(row, col++, data.getPhone(), style); + createCell(row, col++, data.getTagGroup1(), style); + createCell(row, col++, data.getTagGroup2(), style); + createCell(row, col++, data.getTagGroup3(), style); + createCell(row, col++, data.getTagGroup4(), style); + createCell(row, col++, data.getTagGroup5(), style); + createCell(row, col++, data.getTagGroup6(), style); + createCell(row, col++, data.getTagGroup7(), style); + createCell(row, col++, data.getTagGroup8(), style); + createCell(row, col++, data.getTagGroup9(), style); + createCell(row, col++, data.getTagGroup10(), style); + createCell(row, col++, data.getTagGroup11(), style); + createCell(row, col++, data.getTagGroup12(), style); + createCell(row, col++, data.getTagGroup13(), style); + createCell(row, col++, data.getTagGroup14(), style); + createCell(row, col++, data.getTagGroup15(), style); + createCell(row, col++, data.getTagGroup16(), style); + createCell(row, col++, data.getTagGroup17(), style); + createCell(row, col++, data.getTagGroup18(), style); + } + + private void createCell(Row row, int column, String value, CellStyle style) + { + Cell cell = row.createCell(column); + cell.setCellValue(value == null ? "" : value); + cell.setCellStyle(style); + } + + private String formatDate(Date date) + { + if (date == null) + { + return ""; + } + return DateUtils.parseDateToStr("yyyy-MM-dd", date); + } +} diff --git a/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerExportService.java b/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerExportService.java index 5c18864..8b9a7f9 100644 --- a/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerExportService.java +++ b/excel-handle/src/main/java/com/ruoyi/excel/wecom/service/CustomerExportService.java @@ -235,6 +235,79 @@ public class CustomerExportService { return exportData; } + private Date parseCompleteDate(String orderDate, Date addDate) { + if (orderDate == null || orderDate.trim().isEmpty()) { + return null; + } + + if (addDate == null) { + log.warn("parseCompleteDate: addDate is null, orderDate: {}", orderDate); + return null; + } + + try { + String[] dates = orderDate.trim().split(","); + String lastDateStr = dates[dates.length - 1].trim(); + log.debug("parseCompleteDate: input orderDate: {}, lastDateStr: {}", orderDate, lastDateStr); + + Calendar orderCal = Calendar.getInstance(); + orderCal.setTime(addDate); + orderCal.set(Calendar.HOUR_OF_DAY, 0); + orderCal.set(Calendar.MINUTE, 0); + orderCal.set(Calendar.SECOND, 0); + orderCal.set(Calendar.MILLISECOND, 0); + + boolean parsed = false; + + java.util.regex.Pattern fullDatePattern = java.util.regex.Pattern.compile("(\\d{4})[/\\-](\\d{1,2})[/\\-](\\d{1,2})"); + java.util.regex.Matcher fullDateMatcher = fullDatePattern.matcher(lastDateStr); + if (fullDateMatcher.find()) { + int year = Integer.parseInt(fullDateMatcher.group(1)); + int month = Integer.parseInt(fullDateMatcher.group(2)); + int day = Integer.parseInt(fullDateMatcher.group(3)); + orderCal.set(Calendar.YEAR, year); + orderCal.set(Calendar.MONTH, month - 1); + orderCal.set(Calendar.DAY_OF_MONTH, day); + parsed = true; + log.info("parseCompleteDate: matched full date pattern, input: {}, result: {}-{}-{}", lastDateStr, year, month, day); + } + + if (!parsed) { + java.util.regex.Pattern monthDayPattern = java.util.regex.Pattern.compile("^(\\d{1,2})[.\\-/](\\d{1,2})"); + java.util.regex.Matcher monthDayMatcher = monthDayPattern.matcher(lastDateStr); + if (monthDayMatcher.find()) { + int month = Integer.parseInt(monthDayMatcher.group(1)); + int day = Integer.parseInt(monthDayMatcher.group(2)); + orderCal.set(Calendar.MONTH, month - 1); + orderCal.set(Calendar.DAY_OF_MONTH, day); + Calendar tempCal = Calendar.getInstance(); + tempCal.setTime(addDate); + tempCal.set(Calendar.MONTH, month - 1); + tempCal.set(Calendar.DAY_OF_MONTH, day); + tempCal.set(Calendar.HOUR_OF_DAY, 0); + tempCal.set(Calendar.MINUTE, 0); + tempCal.set(Calendar.SECOND, 0); + tempCal.set(Calendar.MILLISECOND, 0); + if (tempCal.getTime().before(addDate)) { + orderCal.add(Calendar.YEAR, 1); + } + parsed = true; + log.info("parseCompleteDate: matched month-day pattern, input: {}, result: {}-{}-{}", lastDateStr, orderCal.get(Calendar.YEAR), month, day); + } + } + + if (!parsed) { + log.warn("parseCompleteDate: no pattern matched, input: {}", lastDateStr); + return null; + } + return orderCal.getTime(); + } catch (Exception e) { + log.error("parseCompleteDate error, orderDate: {}, addDate: {}", orderDate, addDate, e); + return null; + } + } + + /** * 处理客户标签,按标签组分类填充到对应字段 * @@ -277,8 +350,7 @@ public class CustomerExportService { * @param tagNames 标签名称(逗号分隔) */ private void fillTagGroupField(CustomerExportData exportData, String groupName, String tagNames) { - // 根据标签组名称映射到对应字段 - // 这里的映射关系需要根据实际业务调整 + if (groupName.contains("投放")) { exportData.setTagGroup1(tagNames); } else if (groupName.contains("公司孵化")) { @@ -287,12 +359,15 @@ public class CustomerExportService { exportData.setTagGroup3(tagNames); } else if (groupName.contains("成交日期")) { exportData.setTagGroup4(tagNames); + Date finishDate = parseCompleteDate(tagNames, exportData.getAddTime()); + exportData.setFinishDate(finishDate); } else if (groupName.contains("年级组")) { exportData.setTagGroup5(tagNames); } else if (groupName.contains("客户属性")) { exportData.setTagGroup6(tagNames); } else if (groupName.contains("成交") && !groupName.contains("日期") && !groupName.contains("品牌")) { exportData.setTagGroup7(tagNames); + } else if (groupName.contains("成交品牌")) { exportData.setTagGroup8(tagNames); } else if (groupName.contains("线索通")) { diff --git a/excel-handle/src/main/resources/mapper/wecom/CustomerExportDataMapper.xml b/excel-handle/src/main/resources/mapper/wecom/CustomerExportDataMapper.xml index 384ecd7..a58e19d 100644 --- a/excel-handle/src/main/resources/mapper/wecom/CustomerExportDataMapper.xml +++ b/excel-handle/src/main/resources/mapper/wecom/CustomerExportDataMapper.xml @@ -1,6 +1,22 @@ + + + + + + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wocom/CustomerExportDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wocom/CustomerExportDataController.java index 9079a00..f51a7e5 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wocom/CustomerExportDataController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wocom/CustomerExportDataController.java @@ -2,19 +2,26 @@ package com.ruoyi.web.controller.wocom; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.CorpContextHolder; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.excel.wecom.domain.CustomerExportData; +import com.ruoyi.excel.wecom.service.CustomerExportAsyncService; import com.ruoyi.excel.wecom.service.ICustomerExportDataService; import com.ruoyi.excel.wecom.vo.CustomerExportDataVO; +import com.ruoyi.system.domain.SysExportTask; +import com.ruoyi.system.service.ISysExportTaskService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.List; @@ -23,11 +30,17 @@ import java.util.List; */ @RestController @RequestMapping("/wecom/customerExport") -public class CustomerExportDataController extends BaseController { - +public class CustomerExportDataController extends BaseController +{ @Autowired private ICustomerExportDataService customerExportDataService; + @Autowired + private CustomerExportAsyncService customerExportAsyncService; + + @Autowired + private ISysExportTaskService exportTaskService; + /** * 查询客户统计数据列表 */ @@ -36,16 +49,17 @@ public class CustomerExportDataController extends BaseController { public TableDataInfo list( @RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, @RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate, - @RequestParam(value = "customerName", required = false) String customerName) { + @RequestParam(value = "customerName", required = false) String customerName) + { String corpId = CorpContextHolder.getCurrentCorpId(); startPage(); - List list = customerExportDataService.selectCustomerExportDataList(corpId,startDate, endDate, customerName); + List list = customerExportDataService.selectCustomerExportDataList(corpId, startDate, endDate, customerName); return getDataTable(list); } /** - * 导出客户统计数据列表 + * 导出客户统计数据列表(同步方式,保留兼容) */ @PreAuthorize("@ss.hasPermi('wecom:customerExport:export')") @Log(title = "客户统计数据", businessType = BusinessType.EXPORT) @@ -53,13 +67,149 @@ public class CustomerExportDataController extends BaseController { public void export(HttpServletResponse response, @RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, @RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate, - @RequestParam(value = "customerName", required = false) String customerName) { + @RequestParam(value = "customerName", required = false) String customerName) + { String corpId = CorpContextHolder.getCurrentCorpId(); - List list = customerExportDataService.selectCustomerExportDataVOList(corpId,startDate, endDate, customerName); + List list = customerExportDataService.selectCustomerExportDataVOList(corpId, startDate, endDate, customerName); ExcelUtil util = new ExcelUtil<>(CustomerExportDataVO.class); util.exportExcel(response, list, "客户统计数据"); } + /** + * 异步导出客户统计数据列表 + */ + @PreAuthorize("@ss.hasPermi('wecom:customerExport:export')") + @Log(title = "客户统计数据-异步导出", businessType = BusinessType.EXPORT) + @PostMapping("/exportAsync") + public AjaxResult exportAsync( + @RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, + @RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate, + @RequestParam(value = "customerName", required = false) String customerName) + { + String corpId = CorpContextHolder.getCurrentCorpId(); + SysExportTask task = new SysExportTask(); + task.setTaskName("客户统计数据导出"); + task.setTaskType("customer_export"); + task.setCorpId(corpId); + task.setCreateBy(getUsername()); + + Long taskId = exportTaskService.createExportTask(task); + + customerExportAsyncService.executeExport(taskId, corpId, startDate, endDate, customerName); + + return AjaxResult.success("导出任务已创建,请稍后查看进度", taskId); + } + + /** + * 查询导出任务状态 + */ + @PreAuthorize("@ss.hasPermi('wecom:customerExport:export')") + @GetMapping("/export/status/{taskId}") + public AjaxResult getExportStatus(@PathVariable Long taskId) + { + SysExportTask task = exportTaskService.selectExportTaskById(taskId); + if (task == null) + { + return AjaxResult.error("任务不存在"); + } + return AjaxResult.success(task); + } + + /** + * 下载导出文件 + */ + @PreAuthorize("@ss.hasPermi('wecom:customerExport:export')") + @GetMapping("/export/download/{taskId}") + public void downloadExportFile(@PathVariable Long taskId, HttpServletResponse response) + { + SysExportTask task = exportTaskService.selectExportTaskById(taskId); + if (task == null) + { + return; + } + + if (!SysExportTask.STATUS_SUCCESS.equals(task.getStatus())) + { + return; + } + + String filePath = task.getFilePath(); + if (filePath == null || filePath.isEmpty()) + { + return; + } + + File file = new File(filePath); + if (!file.exists()) + { + return; + } + + try + { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fileName = URLEncoder.encode(task.getFileName(), StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20"); + response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ";filename*=utf-8''" + fileName); + response.setHeader("Content-Length", String.valueOf(file.length())); + + java.io.FileInputStream fis = new java.io.FileInputStream(file); + java.io.OutputStream os = response.getOutputStream(); + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = fis.read(buffer)) != -1) + { + os.write(buffer, 0, bytesRead); + } + fis.close(); + os.flush(); + } + catch (Exception e) + { + logger.error("下载文件失败", e); + } + } + + /** + * 查询导出任务列表 + */ + @PreAuthorize("@ss.hasPermi('wecom:customerExport:export')") + @GetMapping("/export/list") + public TableDataInfo exportTaskList(SysExportTask task) + { + String corpId = CorpContextHolder.getCurrentCorpId(); + task.setCorpId(corpId); + task.setCreateBy(getUsername()); + startPage(); + List list = exportTaskService.selectExportTaskList(task); + return getDataTable(list); + } + + /** + * 删除导出任务 + */ + @PreAuthorize("@ss.hasPermi('wecom:customerExport:export')") + @Log(title = "客户统计数据-删除导出任务", businessType = BusinessType.DELETE) + @DeleteMapping("/export/{taskId}") + public AjaxResult deleteExportTask(@PathVariable Long taskId) + { + SysExportTask task = exportTaskService.selectExportTaskById(taskId); + if (task == null) + { + return AjaxResult.error("任务不存在"); + } + + if (task.getFilePath() != null && !task.getFilePath().isEmpty()) + { + File file = new File(task.getFilePath()); + if (file.exists()) + { + file.delete(); + } + } + + return toAjax(exportTaskService.deleteExportTaskById(taskId)); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysExportTask.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysExportTask.java new file mode 100644 index 0000000..7a4c0bf --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysExportTask.java @@ -0,0 +1,209 @@ +package com.ruoyi.system.domain; + +import com.alibaba.fastjson2.annotation.JSONField; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.annotation.Excel.ColumnType; +import com.ruoyi.common.core.domain.BaseEntity; + +import java.util.Date; + +/** + * 导出任务表 sys_export_task + */ +public class SysExportTask extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + public static final String STATUS_PENDING = "0"; + public static final String STATUS_PROCESSING = "1"; + public static final String STATUS_SUCCESS = "2"; + public static final String STATUS_FAILED = "3"; + + @Excel(name = "任务ID", cellType = ColumnType.NUMERIC) + private Long taskId; + + @Excel(name = "任务名称") + private String taskName; + + @Excel(name = "任务类型") + private String taskType; + + private String corpId; + + private String queryParams; + + @Excel(name = "状态", readConverterExp = "0=待处理,1=处理中,2=成功,3=失败") + private String status; + + @Excel(name = "进度") + private Integer progress; + + @Excel(name = "总数据量") + private Integer totalCount; + + @Excel(name = "已处理数量") + private Integer processedCount; + + private String filePath; + + @Excel(name = "文件名") + private String fileName; + + private Long fileSize; + + private String errorMsg; + + @JSONField(format = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "完成时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date finishTime; + + public Long getTaskId() + { + return taskId; + } + + public void setTaskId(Long taskId) + { + this.taskId = taskId; + } + + public String getTaskName() + { + return taskName; + } + + public void setTaskName(String taskName) + { + this.taskName = taskName; + } + + public String getTaskType() + { + return taskType; + } + + public void setTaskType(String taskType) + { + this.taskType = taskType; + } + + public String getCorpId() + { + return corpId; + } + + public void setCorpId(String corpId) + { + this.corpId = corpId; + } + + public String getQueryParams() + { + return queryParams; + } + + public void setQueryParams(String params) + { + this.queryParams = params; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public Integer getProgress() + { + return progress; + } + + public void setProgress(Integer progress) + { + this.progress = progress; + } + + public Integer getTotalCount() + { + return totalCount; + } + + public void setTotalCount(Integer totalCount) + { + this.totalCount = totalCount; + } + + public Integer getProcessedCount() + { + return processedCount; + } + + public void setProcessedCount(Integer processedCount) + { + this.processedCount = processedCount; + } + + public String getFilePath() + { + return filePath; + } + + public void setFilePath(String filePath) + { + this.filePath = filePath; + } + + public String getFileName() + { + return fileName; + } + + public void setFileName(String fileName) + { + this.fileName = fileName; + } + + public Long getFileSize() + { + return fileSize; + } + + public void setFileSize(Long fileSize) + { + this.fileSize = fileSize; + } + + public String getErrorMsg() + { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) + { + this.errorMsg = errorMsg; + } + + public Date getFinishTime() + { + return finishTime; + } + + public void setFinishTime(Date finishTime) + { + this.finishTime = finishTime; + } + + public boolean isFinished() + { + return STATUS_SUCCESS.equals(status) || STATUS_FAILED.equals(status); + } + + public boolean isSuccess() + { + return STATUS_SUCCESS.equals(status); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysExportTaskMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysExportTaskMapper.java new file mode 100644 index 0000000..7a33d80 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysExportTaskMapper.java @@ -0,0 +1,66 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.SysExportTask; + +/** + * 导出任务 数据层 + */ +public interface SysExportTaskMapper +{ + /** + * 新增导出任务 + * + * @param task 导出任务对象 + * @return 结果 + */ + public int insertExportTask(SysExportTask task); + + /** + * 修改导出任务 + * + * @param task 导出任务对象 + * @return 结果 + */ + public int updateExportTask(SysExportTask task); + + /** + * 根据ID查询导出任务 + * + * @param taskId 任务ID + * @return 导出任务对象 + */ + public SysExportTask selectExportTaskById(Long taskId); + + /** + * 查询导出任务列表 + * + * @param task 导出任务对象 + * @return 导出任务集合 + */ + public List selectExportTaskList(SysExportTask task); + + /** + * 删除导出任务 + * + * @param taskId 任务ID + * @return 结果 + */ + public int deleteExportTaskById(Long taskId); + + /** + * 批量删除导出任务 + * + * @param taskIds 任务ID数组 + * @return 结果 + */ + public int deleteExportTaskByIds(Long[] taskIds); + + /** + * 查询过期的导出任务 + * + * @param expireDays 过期天数 + * @return 导出任务集合 + */ + public List selectExpiredExportTasks(int expireDays); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysExportTaskService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysExportTaskService.java new file mode 100644 index 0000000..43240c6 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysExportTaskService.java @@ -0,0 +1,93 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.domain.SysExportTask; + +/** + * 导出任务Service接口 + */ +public interface ISysExportTaskService +{ + /** + * 创建导出任务 + * + * @param task 导出任务对象 + * @return 任务ID + */ + public Long createExportTask(SysExportTask task); + + /** + * 更新导出任务 + * + * @param task 导出任务对象 + * @return 结果 + */ + public int updateExportTask(SysExportTask task); + + /** + * 根据ID查询导出任务 + * + * @param taskId 任务ID + * @return 导出任务对象 + */ + public SysExportTask selectExportTaskById(Long taskId); + + /** + * 查询导出任务列表 + * + * @param task 导出任务对象 + * @return 导出任务集合 + */ + public List selectExportTaskList(SysExportTask task); + + /** + * 删除导出任务 + * + * @param taskId 任务ID + * @return 结果 + */ + public int deleteExportTaskById(Long taskId); + + /** + * 批量删除导出任务 + * + * @param taskIds 任务ID数组 + * @return 结果 + */ + public int deleteExportTaskByIds(Long[] taskIds); + + /** + * 更新任务进度 + * + * @param taskId 任务ID + * @param processedCount 已处理数量 + * @param totalCount 总数量 + */ + public void updateProgress(Long taskId, int processedCount, int totalCount); + + /** + * 标记任务成功 + * + * @param taskId 任务ID + * @param filePath 文件路径 + * @param fileName 文件名 + * @param fileSize 文件大小 + */ + public void markSuccess(Long taskId, String filePath, String fileName, Long fileSize); + + /** + * 标记任务失败 + * + * @param taskId 任务ID + * @param errorMsg 错误信息 + */ + public void markFailed(Long taskId, String errorMsg); + + /** + * 查询过期的导出任务 + * + * @param expireDays 过期天数 + * @return 导出任务集合 + */ + public List selectExpiredExportTasks(int expireDays); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysExportTaskServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysExportTaskServiceImpl.java new file mode 100644 index 0000000..2b7c9ff --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysExportTaskServiceImpl.java @@ -0,0 +1,107 @@ +package com.ruoyi.system.service.impl; + +import java.util.Date; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.system.domain.SysExportTask; +import com.ruoyi.system.mapper.SysExportTaskMapper; +import com.ruoyi.system.service.ISysExportTaskService; + +/** + * 导出任务Service业务层处理 + */ +@Service +public class SysExportTaskServiceImpl implements ISysExportTaskService +{ + @Autowired + private SysExportTaskMapper exportTaskMapper; + + @Override + public Long createExportTask(SysExportTask task) + { + task.setStatus(SysExportTask.STATUS_PENDING); + task.setProgress(0); + task.setCreateTime(DateUtils.getNowDate()); + exportTaskMapper.insertExportTask(task); + return task.getTaskId(); + } + + @Override + public int updateExportTask(SysExportTask task) + { + return exportTaskMapper.updateExportTask(task); + } + + @Override + public SysExportTask selectExportTaskById(Long taskId) + { + return exportTaskMapper.selectExportTaskById(taskId); + } + + @Override + public List selectExportTaskList(SysExportTask task) + { + return exportTaskMapper.selectExportTaskList(task); + } + + @Override + public int deleteExportTaskById(Long taskId) + { + return exportTaskMapper.deleteExportTaskById(taskId); + } + + @Override + public int deleteExportTaskByIds(Long[] taskIds) + { + return exportTaskMapper.deleteExportTaskByIds(taskIds); + } + + @Override + public void updateProgress(Long taskId, int processedCount, int totalCount) + { + SysExportTask task = new SysExportTask(); + task.setTaskId(taskId); + task.setProcessedCount(processedCount); + task.setTotalCount(totalCount); + if (totalCount > 0) + { + int progress = (int) ((processedCount * 100.0) / totalCount); + task.setProgress(Math.min(progress, 99)); + } + task.setStatus(SysExportTask.STATUS_PROCESSING); + exportTaskMapper.updateExportTask(task); + } + + @Override + public void markSuccess(Long taskId, String filePath, String fileName, Long fileSize) + { + SysExportTask task = new SysExportTask(); + task.setTaskId(taskId); + task.setStatus(SysExportTask.STATUS_SUCCESS); + task.setProgress(100); + task.setFilePath(filePath); + task.setFileName(fileName); + task.setFileSize(fileSize); + task.setFinishTime(new Date()); + exportTaskMapper.updateExportTask(task); + } + + @Override + public void markFailed(Long taskId, String errorMsg) + { + SysExportTask task = new SysExportTask(); + task.setTaskId(taskId); + task.setStatus(SysExportTask.STATUS_FAILED); + task.setErrorMsg(errorMsg); + task.setFinishTime(new Date()); + exportTaskMapper.updateExportTask(task); + } + + @Override + public List selectExpiredExportTasks(int expireDays) + { + return exportTaskMapper.selectExpiredExportTasks(expireDays); + } +} diff --git a/ruoyi-system/src/main/resources/mapper/system/SysExportTaskMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysExportTaskMapper.xml new file mode 100644 index 0000000..e39fd91 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/SysExportTaskMapper.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + select task_id, task_name, task_type, corp_id, query_params, status, progress, total_count, processed_count, + file_path, file_name, file_size, error_msg, create_by, create_time, finish_time + from sys_export_task + + + + + + + + + + insert into sys_export_task + + task_name, + task_type, + corp_id, + query_params, + status, + progress, + total_count, + processed_count, + file_path, + file_name, + file_size, + error_msg, + create_by, + create_time, + finish_time, + + + #{taskName}, + #{taskType}, + #{corpId}, + #{queryParams}, + #{status}, + #{progress}, + #{totalCount}, + #{processedCount}, + #{filePath}, + #{fileName}, + #{fileSize}, + #{errorMsg}, + #{createBy}, + #{createTime}, + #{finishTime}, + + + + + update sys_export_task + + task_name = #{taskName}, + task_type = #{taskType}, + corp_id = #{corpId}, + query_params = #{queryParams}, + status = #{status}, + progress = #{progress}, + total_count = #{totalCount}, + processed_count = #{processedCount}, + file_path = #{filePath}, + file_name = #{fileName}, + file_size = #{fileSize}, + error_msg = #{errorMsg}, + finish_time = #{finishTime}, + + where task_id = #{taskId} + + + + delete from sys_export_task where task_id = #{taskId} + + + + delete from sys_export_task where task_id in + + #{taskId} + + + + diff --git a/ruoyi-ui/src/api/wecom/customerExport.js b/ruoyi-ui/src/api/wecom/customerExport.js index 32b2598..0437cf9 100644 --- a/ruoyi-ui/src/api/wecom/customerExport.js +++ b/ruoyi-ui/src/api/wecom/customerExport.js @@ -52,3 +52,37 @@ export function exportCustomerExport(query) { responseType: 'blob' }) } + +// 异步导出客户导出数据 +export function exportAsync(query) { + return request({ + url: '/wecom/customerExport/exportAsync', + method: 'post', + params: query + }) +} + +// 查询导出任务状态 +export function getExportStatus(taskId) { + return request({ + url: '/wecom/customerExport/export/status/' + taskId, + method: 'get' + }) +} + +// 查询导出任务列表 +export function listExportTask(query) { + return request({ + url: '/wecom/customerExport/export/list', + method: 'get', + params: query + }) +} + +// 删除导出任务 +export function delExportTask(taskId) { + return request({ + url: '/wecom/customerExport/export/' + taskId, + method: 'delete' + }) +} diff --git a/ruoyi-ui/src/views/wecom/customerExport/index.vue b/ruoyi-ui/src/views/wecom/customerExport/index.vue index 4ecb9a2..e084fca 100644 --- a/ruoyi-ui/src/views/wecom/customerExport/index.vue +++ b/ruoyi-ui/src/views/wecom/customerExport/index.vue @@ -42,7 +42,27 @@ size="mini" @click="handleExport" v-hasPermi="['wecom:customerExport:export']" - >导出 + >同步导出 + + + 异步导出 + + + 导出任务 @@ -99,45 +119,105 @@ :limit.sync="queryParams.pageSize" @pagination="getList" /> + + + + + + + + + + + + + + + + + + + + + + + +