diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/monitor/TabOrderMonitorController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/monitor/TabOrderMonitorController.java index ca55c27a..64ae8328 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/monitor/TabOrderMonitorController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/monitor/TabOrderMonitorController.java @@ -37,6 +37,16 @@ import com.bms.price.search.EsLogType; import com.bms.price.search.IBillSearchStore; import com.bms.price.search.TabOrderSyncEsLog; import com.bms.price.task.TabOrderCompareAsyncRunner; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import jakarta.servlet.http.HttpServletResponse; +import com.bms.common.config.BmsConfig; +import com.bms.common.utils.DateUtils; +import com.bms.common.utils.file.FileUtils; +import com.bms.common.utils.uuid.IdUtils; +import com.bms.price.domain.vo.TabOrderExportTask; +import com.bms.price.task.TabOrderExportAsyncRunner; import com.bms.price.task.TabOrderSyncAsyncRunner; /** @@ -58,6 +68,9 @@ public class TabOrderMonitorController extends BaseController @Autowired private TabOrderCompareAsyncRunner tabOrderCompareAsyncRunner; + @Autowired + private TabOrderExportAsyncRunner tabOrderExportAsyncRunner; + @Autowired private IBillSearchStore billSearchStore; @@ -320,6 +333,78 @@ public class TabOrderMonitorController extends BaseController /** * 列表查询:有任一单号即可查询;无单号时必须客户(名称或代码)+提货时间。 */ + + /** + * 异步导出订单数源:按当前筛选(须有单号,或客户+提货时间)。 + */ + @PreAuthorize("@ss.hasPermi('monitor:orderSource:export')") + @Log(title = "订单数源", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public AjaxResult export(@RequestBody(required = false) TabOrderMonitorQuery query) + { + if (query == null) + { + query = new TabOrderMonitorQuery(); + } + if (!hasListFilters(query)) + { + return error("请先设置列表查询条件后再导出"); + } + customerKeywordResolver.resolve(query); + String taskId = IdUtils.fastSimpleUUID(); + String fileName = "订单数源_" + DateUtils.dateTimeNow() + ".xlsx"; + tabOrderExportAsyncRunner.put(taskId, TabOrderExportTask.STATUS_PENDING, 0, "queued", null, + fileName, null, 0); + tabOrderExportAsyncRunner.run(taskId, query, fileName); + Map data = new HashMap(); + data.put("taskId", taskId); + return success(data); + } + + @PreAuthorize("@ss.hasPermi('monitor:orderSource:export')") + @GetMapping("/export/task/{taskId}") + public AjaxResult exportTask(@PathVariable("taskId") String taskId) + { + TabOrderExportTask task = tabOrderExportAsyncRunner.get(taskId); + if (task == null) + { + return error("export task not found or expired"); + } + return success(task); + } + + @PreAuthorize("@ss.hasPermi('monitor:orderSource:export')") + @GetMapping("/export/download/{taskId}") + public void exportDownload(@PathVariable("taskId") String taskId, HttpServletResponse response) + throws Exception + { + TabOrderExportTask task = tabOrderExportAsyncRunner.get(taskId); + if (task == null) + { + throw new com.bms.common.exception.ServiceException("export task not found or expired"); + } + if (!TabOrderExportTask.STATUS_SUCCESS.equals(task.getStatus()) + || StringUtils.isEmpty(task.getStorageKey())) + { + throw new com.bms.common.exception.ServiceException("export file not ready"); + } + if (!FileUtils.checkAllowDownload(task.getStorageKey())) + { + throw new com.bms.common.exception.ServiceException("export file missing"); + } + Path downloadRoot = Paths.get(BmsConfig.getDownloadPath()).toAbsolutePath().normalize(); + Path filePath = downloadRoot.resolve(task.getStorageKey()).normalize(); + if (!filePath.startsWith(downloadRoot) || !Files.isRegularFile(filePath)) + { + throw new com.bms.common.exception.ServiceException("export file missing"); + } + String fileName = StringUtils.isNotEmpty(task.getFileName()) ? task.getFileName() : (taskId + ".xlsx"); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + FileUtils.setAttachmentResponseHeader(response, fileName); + FileUtils.writeBytes(filePath.toString(), response.getOutputStream()); + } + + private static boolean hasListFilters(TabOrderMonitorQuery query) { return hasRequiredFilters(query) || hasNonBlankItem(query.getOrderIdentifiers()); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcOrderBill.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcOrderBill.java index 6330f8c1..da3c69ef 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcOrderBill.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcOrderBill.java @@ -132,4 +132,7 @@ public class PrcOrderBill extends BaseEntity private List incomeFees; private List payFees; + + /** Excel export fields (Java props; export only). */ + private List exportFields; } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderExportTask.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderExportTask.java new file mode 100644 index 00000000..77d89475 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderExportTask.java @@ -0,0 +1,41 @@ +package com.bms.price.domain.vo; + +import java.io.Serializable; + +/** 订单数源异步 Excel 导出进度(Redis)。 */ +public class TabOrderExportTask implements Serializable +{ + private static final long serialVersionUID = 1L; + + public static final String STATUS_PENDING = "PENDING"; + public static final String STATUS_RUNNING = "RUNNING"; + public static final String STATUS_SUCCESS = "SUCCESS"; + public static final String STATUS_FAIL = "FAIL"; + + private String taskId; + private String status; + private int percent; + private String message; + private String error; + private String fileName; + /** Relative path under download root. */ + private String storageKey; + private int rowCount; + + public String getTaskId() { return taskId; } + public void setTaskId(String taskId) { this.taskId = taskId; } + public String getStatus() { return status; } + public void setStatus(String status) { this.status = status; } + public int getPercent() { return percent; } + public void setPercent(int percent) { this.percent = percent; } + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } + public String getError() { return error; } + public void setError(String error) { this.error = error; } + public String getFileName() { return fileName; } + public void setFileName(String fileName) { this.fileName = fileName; } + public String getStorageKey() { return storageKey; } + public void setStorageKey(String storageKey) { this.storageKey = storageKey; } + public int getRowCount() { return rowCount; } + public void setRowCount(int rowCount) { this.rowCount = rowCount; } +} diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorListExportRow.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorListExportRow.java new file mode 100644 index 00000000..c50e7572 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorListExportRow.java @@ -0,0 +1,53 @@ +package com.bms.price.domain.vo; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import com.bms.common.annotation.Excel; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +/** 订单数源列表 Excel 导出行。 */ +@Data +public class TabOrderMonitorListExportRow implements Serializable +{ + private static final long serialVersionUID = 1L; + + @Excel(name = "客户订单号", width = 22) + private String orderId; + @Excel(name = "运单号", width = 20) + private String orgOrderId; + @Excel(name = "转单号", width = 20) + private String transferOrderId; + @Excel(name = "轨迹ID", width = 16) + private String trackId; + @Excel(name = "订单状态", width = 12) + private String orderStatusLabel; + @Excel(name = "客户代码", width = 14) + private String customerCode; + @Excel(name = "客户名称", width = 20) + private String customerName; + @Excel(name = "产品代码", width = 14) + private String productCode; + @Excel(name = "产品名称", width = 22) + private String productName; + @Excel(name = "产品底级代码", width = 16) + private String productFloorCode; + @Excel(name = "国家代码", width = 12) + private String country; + @Excel(name = "国家/地区", width = 16) + private String countryName; + @Excel(name = "收件人邮编", width = 14) + private String consigneePostcode; + @Excel(name = "客户确认重", scale = 3, width = 12) + private BigDecimal confirmWeight; + @Excel(name = "计费重", scale = 3, width = 12) + private BigDecimal dimensionalWeightFactor; + @Excel(name = "体积重", scale = 3, width = 12) + private BigDecimal volumeWeight; + @Excel(name = "实重", scale = 3, width = 12) + private BigDecimal weight; + @Excel(name = "提货时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date pickupDate; +} diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java index 59eb4e02..0d712110 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java @@ -45,4 +45,6 @@ public class TabOrderMonitorQuery implements Serializable private List orderStatuses; /** 分批同步计费每批条数 */ private Integer batchSize; + /** Excel export field names (Java props; export only). */ + private List exportFields; } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/support/OrderBillExportSupport.java b/bms-back/bms-system/src/main/java/com/bms/price/service/support/OrderBillExportSupport.java index 2bb1ae56..8353e01b 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/support/OrderBillExportSupport.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/support/OrderBillExportSupport.java @@ -64,6 +64,31 @@ public final class OrderBillExportSupport return false; } + + /** Null/empty => export all columns; otherwise only named Java props. */ + public static String[] toExportFieldArray(List exportFields) + { + if (exportFields == null || exportFields.isEmpty()) + { + return null; + } + List cleaned = new ArrayList(); + for (String f : exportFields) + { + if (f == null) + { + continue; + } + String t = f.trim(); + if (t.isEmpty() || cleaned.contains(t)) + { + continue; + } + cleaned.add(t); + } + return cleaned.isEmpty() ? null : cleaned.toArray(new String[cleaned.size()]); + } + private static boolean hasTexts(List list) { if (list == null || list.isEmpty()) diff --git a/bms-back/bms-system/src/main/java/com/bms/price/task/PrcOrderBillExportAsyncRunner.java b/bms-back/bms-system/src/main/java/com/bms/price/task/PrcOrderBillExportAsyncRunner.java index 1f9d8273..e7217345 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/task/PrcOrderBillExportAsyncRunner.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/task/PrcOrderBillExportAsyncRunner.java @@ -83,14 +83,28 @@ public class PrcOrderBillExportAsyncRunner if (PrcOrderBillExportTask.TYPE_BILLING.equals(exportType)) { List exportRows = OrderBillExportSupport.toBillingListRows(list); - new ExcelUtil(PrcBillingBillListExportRow.class) - .exportExcelToStream(exportRows, "\u8ba1\u8d39\u5217\u8868", out); + ExcelUtil billingUtil = + new ExcelUtil(PrcBillingBillListExportRow.class); + String[] billingFields = OrderBillExportSupport.toExportFieldArray( + query == null ? null : query.getExportFields()); + if (billingFields != null) + { + billingUtil.showColumn(billingFields); + } + billingUtil.exportExcelToStream(exportRows, "\u8ba1\u8d39\u5217\u8868", out); } else { List exportRows = OrderBillExportSupport.toOrderListRows(list); - new ExcelUtil(PrcOrderBillListExportRow.class) - .exportExcelToStream(exportRows, "\u8ba2\u5355\u5217\u8868", out); + ExcelUtil orderUtil = + new ExcelUtil(PrcOrderBillListExportRow.class); + String[] orderFields = OrderBillExportSupport.toExportFieldArray( + query == null ? null : query.getExportFields()); + if (orderFields != null) + { + orderUtil.showColumn(orderFields); + } + orderUtil.exportExcelToStream(exportRows, "\u8ba2\u5355\u5217\u8868", out); } } String storageKey = REL_DIR + "/" + taskId + ".xlsx"; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/task/TabOrderExportAsyncRunner.java b/bms-back/bms-system/src/main/java/com/bms/price/task/TabOrderExportAsyncRunner.java new file mode 100644 index 00000000..0c6e193f --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/price/task/TabOrderExportAsyncRunner.java @@ -0,0 +1,228 @@ +package com.bms.price.task; + +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +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.Component; +import com.bms.common.config.BmsConfig; +import com.bms.common.core.redis.RedisCache; +import com.bms.common.utils.StringUtils; +import com.bms.common.utils.poi.ExcelUtil; +import com.bms.price.service.support.OrderBillExportSupport; +import com.bms.price.domain.vo.TabOrderExportTask; +import com.bms.price.domain.vo.TabOrderMonitorListExportRow; +import com.bms.price.domain.vo.TabOrderMonitorQuery; +import com.bms.price.domain.vo.TabOrderMonitorVo; +import com.bms.price.oracle.TabOrderMonitorService; +import com.bms.price.oracle.TabOrderPageResult; + +/** + * 订单数源异步 Excel 导出:按当前筛选分页拉取上游列表。 + */ +@Component +public class TabOrderExportAsyncRunner +{ + private static final Logger log = LoggerFactory.getLogger(TabOrderExportAsyncRunner.class); + + public static final String CACHE_KEY_PREFIX = "monitor:orderSource:export:task:"; + public static final int TTL_MINUTES = 60; + public static final String REL_DIR = "orderSourceExport"; + public static final int PAGE_SIZE = 500; + /** 单次导出行数上限(防 OOM) */ + public static final int EXPORT_MAX = 20000; + + private static final Map ORDER_STATUS_LABEL = new HashMap(); + static + { + ORDER_STATUS_LABEL.put(Integer.valueOf(0), "预报订单"); + ORDER_STATUS_LABEL.put(Integer.valueOf(1), "确认订单"); + ORDER_STATUS_LABEL.put(Integer.valueOf(2), "已中转"); + ORDER_STATUS_LABEL.put(Integer.valueOf(3), "已收货"); + ORDER_STATUS_LABEL.put(Integer.valueOf(4), "已装箱"); + ORDER_STATUS_LABEL.put(Integer.valueOf(5), "已出库"); + ORDER_STATUS_LABEL.put(Integer.valueOf(6), "转运中"); + ORDER_STATUS_LABEL.put(Integer.valueOf(7), "已上网"); + ORDER_STATUS_LABEL.put(Integer.valueOf(8), "已签收"); + ORDER_STATUS_LABEL.put(Integer.valueOf(9), "已退件"); + ORDER_STATUS_LABEL.put(Integer.valueOf(10), "已删除"); + ORDER_STATUS_LABEL.put(Integer.valueOf(11), "已复核"); + } + + @Autowired + private TabOrderMonitorService tabOrderMonitorService; + + @Autowired + private RedisCache redisCache; + + @Async("threadPoolTaskExecutor") + public void run(String taskId, TabOrderMonitorQuery query, String fileName) + { + Path file = null; + try + { + put(taskId, TabOrderExportTask.STATUS_RUNNING, 5, "querying", null, fileName, null, 0); + List all = new ArrayList(); + int pageNum = 1; + long total = -1L; + while (true) + { + TabOrderPageResult page = tabOrderMonitorService.searchPage(query, pageNum, PAGE_SIZE); + if (page == null) + { + break; + } + if (total < 0L) + { + total = page.getTotal(); + if (total > EXPORT_MAX) + { + throw new IllegalStateException("导出数量超过上限 " + EXPORT_MAX + + "(当前 " + total + "),请缩小筛选范围"); + } + if (total <= 0L) + { + throw new IllegalStateException("当前筛选无匹配数据"); + } + } + List rows = page.getRows(); + if (rows == null || rows.isEmpty()) + { + break; + } + all.addAll(rows); + int pct = Math.min(70, 5 + (int) ((all.size() * 65L) / Math.max(total, 1L))); + put(taskId, TabOrderExportTask.STATUS_RUNNING, pct, "querying " + all.size() + "/" + total, + null, fileName, null, all.size()); + if (all.size() >= total || rows.size() < PAGE_SIZE || all.size() >= EXPORT_MAX) + { + break; + } + pageNum++; + } + put(taskId, TabOrderExportTask.STATUS_RUNNING, 80, "building excel", null, fileName, null, all.size()); + + Path dir = Paths.get(BmsConfig.getDownloadPath(), REL_DIR).toAbsolutePath().normalize(); + Files.createDirectories(dir); + file = dir.resolve(taskId + ".xlsx").normalize(); + if (!file.startsWith(dir)) + { + throw new IllegalStateException("invalid export path"); + } + List exportRows = toExportRows(all); + try (OutputStream out = Files.newOutputStream(file)) + { + ExcelUtil util = + new ExcelUtil(TabOrderMonitorListExportRow.class); + String[] fields = OrderBillExportSupport.toExportFieldArray( + query == null ? null : query.getExportFields()); + if (fields != null) + { + util.showColumn(fields); + } + util.exportExcelToStream(exportRows, "订单数源", out); + } + String storageKey = REL_DIR + "/" + taskId + ".xlsx"; + put(taskId, TabOrderExportTask.STATUS_SUCCESS, 100, "done", null, fileName, storageKey, exportRows.size()); + } + catch (Exception e) + { + log.error("orderSource export failed taskId={}", taskId, e); + if (file != null) + { + try { Files.deleteIfExists(file); } catch (Exception ignore) { } + } + put(taskId, TabOrderExportTask.STATUS_FAIL, 100, "failed", errorMessage(e), fileName, null, 0); + } + } + + public void put(String taskId, String status, int percent, String message, String error, + String fileName, String storageKey, int rowCount) + { + TabOrderExportTask task = new TabOrderExportTask(); + task.setTaskId(taskId); + task.setStatus(status); + task.setPercent(percent); + task.setMessage(message); + task.setError(error); + task.setFileName(fileName); + task.setStorageKey(storageKey); + task.setRowCount(rowCount); + redisCache.setCacheObject(CACHE_KEY_PREFIX + taskId, task, TTL_MINUTES, TimeUnit.MINUTES); + } + + public TabOrderExportTask get(String taskId) + { + return redisCache.getCacheObject(CACHE_KEY_PREFIX + taskId); + } + + private static List toExportRows(List list) + { + List rows = new ArrayList(); + if (list == null) + { + return rows; + } + for (TabOrderMonitorVo vo : list) + { + if (vo == null) + { + continue; + } + TabOrderMonitorListExportRow row = new TabOrderMonitorListExportRow(); + row.setOrderId(vo.getOrderId()); + row.setOrgOrderId(vo.getOrgOrderId()); + row.setTransferOrderId(vo.getTransferOrderId()); + row.setTrackId(vo.getTrackId()); + row.setOrderStatusLabel(statusLabel(vo.getOrderStatus())); + row.setCustomerCode(vo.getCustomerCode()); + row.setCustomerName(vo.getCustomerName()); + row.setProductCode(vo.getProductCode()); + row.setProductName(vo.getProductName()); + row.setProductFloorCode(vo.getProductFloorCode()); + row.setCountry(vo.getCountry()); + row.setCountryName(vo.getCountryName()); + row.setConsigneePostcode(vo.getConsigneePostcode()); + row.setConfirmWeight(vo.getConfirmWeight()); + row.setDimensionalWeightFactor(vo.getDimensionalWeightFactor()); + row.setVolumeWeight(vo.getVolumeWeight()); + row.setWeight(vo.getWeight()); + row.setPickupDate(vo.getPickupDate()); + rows.add(row); + } + return rows; + } + + private static String statusLabel(Integer status) + { + if (status == null) + { + return ""; + } + String label = ORDER_STATUS_LABEL.get(status); + return label == null ? String.valueOf(status) : label; + } + + private static String errorMessage(Exception e) + { + String msg = e.getMessage(); + if (StringUtils.isEmpty(msg)) + { + msg = e.getClass().getSimpleName(); + } + if (msg.length() > 500) + { + msg = msg.substring(0, 500); + } + return msg; + } +} diff --git a/bms-back/sql/monitor/order_source_export_menu.sql b/bms-back/sql/monitor/order_source_export_menu.sql new file mode 100644 index 00000000..04699c88 --- /dev/null +++ b/bms-back/sql/monitor/order_source_export_menu.sql @@ -0,0 +1,27 @@ +-- 订单数源导出 +SET NAMES utf8mb4; + +INSERT INTO sys_menu ( + menu_id, menu_name, parent_id, order_num, path, component, + is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark +) +SELECT 2329, N'导出', 2325, 4, '', NULL, + 1, 0, 'F', '0', '0', 'monitor:orderSource:export', '#', 'admin', sysdate(), + N'订单数源导出 Excel' + FROM DUAL + WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2329 OR perms = 'monitor:orderSource:export'); + +INSERT INTO sys_role_menu (role_id, menu_id) +SELECT 1, 2329 + FROM DUAL + WHERE EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2329) + AND NOT EXISTS (SELECT 1 FROM sys_role_menu WHERE role_id = 1 AND menu_id = 2329); + +INSERT INTO sys_role_menu (role_id, menu_id) +SELECT DISTINCT rm.role_id, 2329 + FROM sys_role_menu rm + WHERE rm.menu_id = 2325 + AND EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2329) + AND NOT EXISTS ( + SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = 2329 + ); diff --git a/bms-front/src/api/monitor/orderSource.js b/bms-front/src/api/monitor/orderSource.js index 8c311414..21a650b7 100644 --- a/bms-front/src/api/monitor/orderSource.js +++ b/bms-front/src/api/monitor/orderSource.js @@ -100,3 +100,30 @@ export function listOrderSourceOrdersByProduct(data) { }) } + +/** 异步导出:提交任务 */ +export function exportOrderSource(data) { + return request({ + url: '/monitor/orderSource/export', + method: 'post', + data, + timeout: 120000, + headers: { repeatSubmit: false } + }) +} + +export function getOrderSourceExportTask(taskId) { + return request({ + url: '/monitor/orderSource/export/task/' + taskId, + method: 'get' + }) +} + +export function downloadOrderSourceExport(taskId) { + return request({ + url: '/monitor/orderSource/export/download/' + taskId, + method: 'get', + responseType: 'blob', + timeout: 120000 + }) +} diff --git a/bms-front/src/components/ExcelExportFieldDialog/index.vue b/bms-front/src/components/ExcelExportFieldDialog/index.vue new file mode 100644 index 00000000..9c1d6626 --- /dev/null +++ b/bms-front/src/components/ExcelExportFieldDialog/index.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/bms-front/src/utils/excelExport.js b/bms-front/src/utils/excelExport.js index 10f8407a..4ca5508e 100644 --- a/bms-front/src/utils/excelExport.js +++ b/bms-front/src/utils/excelExport.js @@ -142,7 +142,7 @@ export async function exportAsync(options = {}) { const extraIgnore = (options.filterOpts && options.filterOpts.ignoreKeys) || [] const filterOpts = { ...(options.filterOpts || {}), - ignoreKeys: ['orderStatuses', ...extraIgnore] + ignoreKeys: ['orderStatuses', 'exportFields', ...extraIgnore] } if (!hasListFilter(query, filterOpts)) { ElMessage.warning(options.filterMessage || '\u8bf7\u5148\u8bbe\u7f6e\u5217\u8868\u67e5\u8be2\u6761\u4ef6\u540e\u518d\u5bfc\u51fa') diff --git a/bms-front/src/utils/exportFieldDefs.js b/bms-front/src/utils/exportFieldDefs.js new file mode 100644 index 00000000..fcdf24c1 --- /dev/null +++ b/bms-front/src/utils/exportFieldDefs.js @@ -0,0 +1,74 @@ +/** Excel export field options (prop must match backend export-row Java field names). */ + +export const ORDER_SOURCE_EXPORT_FIELDS = [ + { prop: 'orderId', label: '客户订单号' }, + { prop: 'orgOrderId', label: '运单号' }, + { prop: 'transferOrderId', label: '转单号' }, + { prop: 'trackId', label: '轨迹ID' }, + { prop: 'orderStatusLabel', label: '订单状态' }, + { prop: 'customerCode', label: '客户代码' }, + { prop: 'customerName', label: '客户名称' }, + { prop: 'productCode', label: '产品代码' }, + { prop: 'productName', label: '产品名称' }, + { prop: 'productFloorCode', label: '产品底级代码' }, + { prop: 'country', label: '国家代码' }, + { prop: 'countryName', label: '国家/地区' }, + { prop: 'consigneePostcode', label: '收件人邮编' }, + { prop: 'confirmWeight', label: '客户确认重' }, + { prop: 'dimensionalWeightFactor', label: '计费重' }, + { prop: 'volumeWeight', label: '体积重' }, + { prop: 'weight', label: '实重' }, + { prop: 'pickupDate', label: '提货时间' } +] + +export const ORDER_BILL_EXPORT_FIELDS = [ + { prop: 'orderNo', label: '订单号' }, + { prop: 'trackingNo', label: '运单号' }, + { prop: 'transferNo', label: '转单号' }, + { prop: 'customerName', label: '客户' }, + { prop: 'customerCode', label: '客户代码' }, + { prop: 'productCode', label: '产品代码' }, + { prop: 'productName', label: '产品名称' }, + { prop: 'countryCode', label: '国家代码' }, + { prop: 'countryName', label: '国家/地区' }, + { prop: 'pieces', label: '件数' }, + { prop: 'weight', label: '计费重' }, + { prop: 'volumeWeight', label: '体积重' }, + { prop: 'receiveWeight', label: '实重' }, + { prop: 'destPostcode', label: '收件人邮编' }, + { prop: 'orderStatusLabel', label: '订单状态' }, + { prop: 'billingFailStatusLabel', label: '计费状态' }, + { prop: 'bizDate', label: '计费时间' }, + { prop: 'orderTime', label: '下单时间' }, + { prop: 'pickupDate', label: '提货时间' }, + { prop: 'belongSaler', label: '销售员' }, + { prop: 'settlementMan', label: '结算员' }, + { prop: 'serviceMan', label: '客服员' } +] + +export const BILLING_BILL_EXPORT_FIELDS = [ + { prop: 'orderNo', label: '订单号' }, + { prop: 'trackingNo', label: '运单号' }, + { prop: 'transferNo', label: '转单号' }, + { prop: 'customerName', label: '客户' }, + { prop: 'customerCode', label: '客户代码' }, + { prop: 'productCode', label: '产品代码' }, + { prop: 'productName', label: '产品名称' }, + { prop: 'countryCode', label: '国家代码' }, + { prop: 'countryName', label: '国家/地区' }, + { prop: 'pieces', label: '件数' }, + { prop: 'chargeWeight', label: '计费重' }, + { prop: 'weight', label: '原计费重' }, + { prop: 'receiveWeight', label: '收货重' }, + { prop: 'incomeTotal', label: '应收总额' }, + { prop: 'payTotal', label: '应付总额' }, + { prop: 'matchSourceLabel', label: '计价来源' }, + { prop: 'billingFailStatusLabel', label: '计费状态' }, + { prop: 'customerActiveStatusLabel', label: '客户状态' }, + { prop: 'creditArrearsStatusLabel', label: '额度欠费' }, + { prop: 'bizDate', label: '计费时间' }, + { prop: 'orderTime', label: '下单时间' }, + { prop: 'belongSaler', label: '销售员' }, + { prop: 'settlementMan', label: '结算员' }, + { prop: 'serviceMan', label: '客服员' } +] diff --git a/bms-front/src/views/monitor/orderSource/index.vue b/bms-front/src/views/monitor/orderSource/index.vue index 5a9d6526..8cb13f79 100644 --- a/bms-front/src/views/monitor/orderSource/index.vue +++ b/bms-front/src/views/monitor/orderSource/index.vue @@ -65,6 +65,15 @@ @click="logDrawerRef.open()" >操作记录 + + 导出 + + +