“单号”改为多行输入,每行一个,支持最多 2000 个号码。

后端支持换行、空格、逗号、分号分隔。
自动去重、忽略空行。
同时匹配订单号、运单号、转单号:
This commit is contained in:
caojia
2026-09-23 11:28:55 +08:00
parent 67c9d28c8c
commit c92c8c0a8e
6 changed files with 81 additions and 33 deletions
@@ -17,7 +17,7 @@ public class ArBillGenerateQuery
private String currency;
/** 订单号、运单号或转单号关键词,按 OR 条件模糊查询。 */
/** 订单号、运单号或转单号;支持换行、逗号、分号或空格分隔多个号码。 */
private String orderOrTrackingNo;
/** 全选模式下,排除弹窗使用的附加订单号、运单号或转单号关键词。 */
@@ -36,7 +36,7 @@ public class ArBillGenerateRequest
@JsonDeserialize(using = StrictDateDeserializer.class)
private Date billDate;
private String currency = "CNY";
/** 订单号、运单号或转单号关键词,生成时用于再次校验筛选条件。 */
/** 订单号、运单号或转单号原始输入,生成时会拆分并再次校验筛选条件。 */
private String orderOrTrackingNo;
private String bankAccountName;
private String bankAccountNo;
@@ -114,6 +114,8 @@ 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;
/**
* 模板明细行使用的边框、字体和换行样式;样式定义来自 ar_bill_template.xlsx。
*/
@@ -216,13 +218,14 @@ public class ArBillServiceImpl implements IArBillService {
}
/**
* 分页预览可生成订单;订单号和运单号关键字在 SQL 中使用 OR 条件。
* 分页预览可生成订单;多个订单号、运单号或转单号按 OR 条件精确匹配。
*/
@Override
public List<PrcOrderBill> previewBill(ArBillGenerateQuery query) {
validatePreviewQuery(query);
List<String> orderIdentifiers = normalizeOrderIdentifiers(query.getOrderOrTrackingNo());
return sourceBillMapper.selectPrcOrderBillByCustomerPeriod(query.getCustomerId(),
query.getCustomerCode(), StringUtils.trim(query.getOrderOrTrackingNo()),
query.getCustomerCode(), orderIdentifiers,
StringUtils.trim(query.getExcludeOrderOrTrackingNo()), query.getBillPeriodEnd(), query.getCurrency(),
eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode(), null);
}
@@ -233,8 +236,9 @@ public class ArBillServiceImpl implements IArBillService {
@Override
public BigDecimal sumPreviewBill(ArBillGenerateQuery query) {
validatePreviewQuery(query);
List<String> orderIdentifiers = normalizeOrderIdentifiers(query.getOrderOrTrackingNo());
return nvl(sourceBillMapper.sumPrcOrderBillIncomeByCustomerPeriod(query.getCustomerId(),
query.getCustomerCode(), StringUtils.trim(query.getOrderOrTrackingNo()),
query.getCustomerCode(), orderIdentifiers,
StringUtils.trim(query.getExcludeOrderOrTrackingNo()), query.getBillPeriodEnd(), query.getCurrency(),
eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode()));
}
@@ -422,7 +426,8 @@ public class ArBillServiceImpl implements IArBillService {
if (task.getTotalCount() == null || task.getTotalCount() < 0) {
log.info("开始统计应收账单生成范围,taskId={}", taskId);
int totalCount = sourceBillMapper.countPrcOrderBillByCustomerPeriod(
request.getCustomerId(), request.getCustomerCode(), StringUtils.trim(request.getOrderOrTrackingNo()),
request.getCustomerId(), request.getCustomerCode(),
normalizeOrderIdentifiers(request.getOrderOrTrackingNo()),
request.getBillPeriodEnd(), request.getCurrency(), eligibleOrderBillStatuses(),
ArIncomeBillFeeStatus.UNBILLED.getCode(),
task.getSnapshotCreateTime(), null, excludedSourceBillIds);
@@ -546,7 +551,8 @@ public class ArBillServiceImpl implements IArBillService {
List<String> explicitIds = selectionMode == ArBillSelectionMode.EXPLICIT
? sourceBillIds : null;
List<PrcOrderBill> sources = sourceBillMapper.selectPrcOrderBillByCustomerPeriodCursor(
request.getCustomerId(), request.getCustomerCode(), StringUtils.trim(request.getOrderOrTrackingNo()),
request.getCustomerId(), request.getCustomerCode(),
normalizeOrderIdentifiers(request.getOrderOrTrackingNo()),
request.getBillPeriodEnd(), StringUtils.isEmpty(request.getCurrency()) ? "CNY" : request.getCurrency(),
eligibleOrderBillStatuses(), ArIncomeBillFeeStatus.UNBILLED.getCode(),
task.getSnapshotCreateTime(), task.getLastSourceBillId(),
@@ -1661,6 +1667,8 @@ public class ArBillServiceImpl implements IArBillService {
if (StringUtils.isNotEmpty(request.getRemark()) && request.getRemark().trim().length() > 500) {
throw new ServiceException("备注不能超过500个字符");
}
// 生成任务会保存原始请求快照,先在入任务前校验号码数量,避免后台任务创建后才失败。
normalizeOrderIdentifiers(request.getOrderOrTrackingNo());
}
private void validatePreviewQuery(ArBillGenerateQuery query) {
@@ -1696,4 +1704,26 @@ public class ArBillServiceImpl implements IArBillService {
}
return new ArrayList<>(uniqueIds);
}
/**
* 将前端多行输入的订单号、运单号和转单号拆分为去重列表。
* 支持换行、空格、英文/中文逗号和英文/中文分号作为分隔符。
*/
private List<String> normalizeOrderIdentifiers(String rawIdentifiers) {
LinkedHashSet<String> uniqueIdentifiers = new LinkedHashSet<>();
if (StringUtils.isEmpty(rawIdentifiers)) {
return new ArrayList<>();
}
String[] identifiers = rawIdentifiers.split("[\\s,,;;]+");
for (String identifier : identifiers) {
String value = StringUtils.trim(identifier);
if (!StringUtils.isEmpty(value)) {
uniqueIdentifiers.add(value);
}
}
if (uniqueIdentifiers.size() > ORDER_IDENTIFIER_LIMIT) {
throw new ServiceException("单号最多输入 " + ORDER_IDENTIFIER_LIMIT + " 个");
}
return new ArrayList<>(uniqueIdentifiers);
}
}
@@ -31,7 +31,7 @@ public interface PrcOrderBillMapper
/** 应收账单生成读取指定客户截止日期前仍存在未出账费用的订单计费快照。 */
public List<PrcOrderBill> selectPrcOrderBillByCustomerPeriod(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderOrTrackingNo") String orderOrTrackingNo,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("excludeOrderOrTrackingNo") String excludeOrderOrTrackingNo,
@Param("cutoffDate") Date cutoffDate, @Param("currency") String currency,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus,
@@ -39,14 +39,14 @@ public interface PrcOrderBillMapper
/** 统计应收账单预览结果金额,供全选模式展示。 */
BigDecimal sumPrcOrderBillIncomeByCustomerPeriod(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderOrTrackingNo") String orderOrTrackingNo,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("excludeOrderOrTrackingNo") String excludeOrderOrTrackingNo,
@Param("cutoffDate") Date cutoffDate, @Param("currency") String currency,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus);
/** 异步生成账单按 bill_id 游标读取一批来源订单。 */
List<PrcOrderBill> selectPrcOrderBillByCustomerPeriodCursor(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderOrTrackingNo") String orderOrTrackingNo,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("cutoffDate") Date cutoffDate, @Param("currency") String currency,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus,
@Param("snapshotCreateTime") Date snapshotCreateTime,
@@ -54,7 +54,7 @@ public interface PrcOrderBillMapper
@Param("excludedBillIds") List<String> excludedBillIds, @Param("limit") int limit);
int countPrcOrderBillByCustomerPeriod(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderOrTrackingNo") String orderOrTrackingNo,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("cutoffDate") Date cutoffDate, @Param("currency") String currency,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus,
@Param("snapshotCreateTime") Date snapshotCreateTime,
@@ -62,7 +62,7 @@ public interface PrcOrderBillMapper
/** 按生成账单时用户勾选的订单读取,并再次校验账单筛选条件。 */
public List<PrcOrderBill> selectPrcOrderBillByCustomerCutoffAndIds(@Param("customerId") Long customerId,
@Param("customerCode") String customerCode, @Param("orderOrTrackingNo") String orderOrTrackingNo,
@Param("customerCode") String customerCode, @Param("orderIdentifiers") List<String> orderIdentifiers,
@Param("cutoffDate") Date cutoffDate,
@Param("currency") String currency, @Param("billIds") List<String> billIds,
@Param("arBillStatuses") List<String> arBillStatuses, @Param("feeArBillStatus") String feeArBillStatus);