diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/ar/ArBillController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/ar/ArBillController.java index 39b240f6..a08821a4 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/ar/ArBillController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/ar/ArBillController.java @@ -6,6 +6,7 @@ import java.util.Date; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; +import com.github.pagehelper.PageHelper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.WebDataBinder; @@ -120,10 +121,10 @@ public class ArBillController extends BaseController { * 查询生成账单前的订单计费结果。 */ @PreAuthorize("@ss.hasPermi('ar:bill:generate')") - @GetMapping("/generate/preview") - public AjaxResult preview(ArBillGenerateQuery query, HttpServletRequest request) { - rejectMultiValueParameter(request, "customerId"); - startPage(); + @PostMapping("/generate/preview") + public AjaxResult preview(@RequestBody ArBillGenerateQuery query) { + PageHelper.startPage(query == null || query.getPageNum() == null ? 1 : query.getPageNum(), + query == null || query.getPageSize() == null ? 10 : query.getPageSize()).setReasonable(true); List list = billService.previewBill(query); TableDataInfo pageData = getDataTable(list); AjaxResult result = success(); diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateQuery.java b/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateQuery.java index 02cd5f85..bc36a885 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateQuery.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/domain/vo/ArBillGenerateQuery.java @@ -1,6 +1,9 @@ package com.bms.ar.domain.vo; import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.bms.common.config.serializer.StrictDateDeserializer; import org.springframework.format.annotation.DateTimeFormat; import lombok.Data; @@ -8,11 +11,17 @@ import lombok.Data; @Data public class ArBillGenerateQuery { + private Integer pageNum; + + private Integer pageSize; + private Long customerId; private String customerCode; @DateTimeFormat(pattern = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + @JsonDeserialize(using = StrictDateDeserializer.class) private Date billPeriodEnd; private String currency; diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java index f108455e..bdf2f3c7 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java @@ -135,7 +135,10 @@ public class ArBillServiceImpl implements IArBillService { private static final int EXPLICIT_SOURCE_ID_LIMIT = 10000; private static final int EXCLUDED_SOURCE_ID_LIMIT = 10000; /** 单次生成查询最多接收的订单号、运单号或转单号数量。 */ - private static final int ORDER_IDENTIFIER_LIMIT = 2000; + private static final int ORDER_IDENTIFIER_LIMIT = 20000; + /** 订单号会分别匹配订单号、运单号和转单号列;预留其他 SQL 参数空间后控制 MySQL 参数总数。 */ + private static final int ORDER_IDENTIFIER_SQL_BIND_COUNT = 3; + private static final int MAX_SQL_PARAMETER_COUNT = 65000; /** * 模板明细行使用的边框、字体和换行样式;样式定义来自 ar_bill_template.xlsx。 */ @@ -351,6 +354,9 @@ public class ArBillServiceImpl implements IArBillService { throw new ServiceException("全选模式最多排除 " + EXCLUDED_SOURCE_ID_LIMIT + " 条订单,请缩小查询条件后再生成"); } + validateOrderIdentifierParameterCount( + normalizeOrderIdentifiers(request.getOrderOrTrackingNo()).size(), + allMatched ? excludedSourceBillIds.size() : sourceBillIds.size()); request.setSelectionMode(selectionMode); String currency = StringUtils.isEmpty(request.getCurrency()) ? "CNY" : request.getCurrency().trim(); @@ -1990,6 +1996,12 @@ public class ArBillServiceImpl implements IArBillService { || query.getBillPeriodEnd() == null) { throw new ServiceException("客户和账单截止日不能为空"); } + int identifierCount = normalizeOrderIdentifiers(query.getOrderOrTrackingNo()).size() + + normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()).size(); + if (identifierCount > ORDER_IDENTIFIER_LIMIT) { + throw new ServiceException("筛选单号和排除单号合计最多输入 " + ORDER_IDENTIFIER_LIMIT + " 个"); + } + validateOrderIdentifierParameterCount(identifierCount, 0); } /** 可参与本次应收生成的订单状态;PARTIAL 只生成其中仍为 UNBILLED 的费用。 */ @@ -2041,6 +2053,14 @@ public class ArBillServiceImpl implements IArBillService { return new ArrayList<>(uniqueIdentifiers); } + /** 校验重复用于三列精确匹配的单号参数及选择/排除订单 ID 不会超过数据库参数预算。 */ + private void validateOrderIdentifierParameterCount(int orderIdentifierCount, int billIdCount) { + long parameterCount = (long) orderIdentifierCount * ORDER_IDENTIFIER_SQL_BIND_COUNT + billIdCount; + if (parameterCount > MAX_SQL_PARAMETER_COUNT) { + throw new ServiceException("单号筛选与订单选择/排除条件过多,请减少单号或选择/排除订单数量后重试"); + } + } + private long elapsedMillis(long startedAt) { return (System.nanoTime() - startedAt) / 1_000_000L; } diff --git a/bms-front/src/api/ar/bill.js b/bms-front/src/api/ar/bill.js index f228421c..d995f845 100644 --- a/bms-front/src/api/ar/bill.js +++ b/bms-front/src/api/ar/bill.js @@ -42,7 +42,12 @@ export function retryArBillGenerateTask(taskId) { } export function previewArBill(query) { - return request({ url: '/ar/bill/generate/preview', method: 'get', params: query }) + return request({ + url: '/ar/bill/generate/preview', + method: 'post', + data: query, + timeout: 60000 + }) } export function confirmArBill(arBillId, data = {}) {