✨ 优化主数据校验与运单导入空值处理

电报略码改为选填且填写时唯一;用户支持账号姓名手机模糊查询;合同名称允许重复;项目情况说明扩至1000字;导入运单未填里程费用不再落库-1。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-09 17:07:56 +08:00
parent 5ed2a5c0fc
commit ef9eab737f
19 changed files with 164 additions and 54 deletions
@@ -670,7 +670,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
private void validateDraft(ContractManage contractManage) {
TransportBusinessSupport.validateRequired(contractManage.getContractName(), "请输入合同名称");
TransportBusinessSupport.validateRequired(contractManage.getContractCategory(), "请选择合同类别");
validateContractNameUnique(contractManage);
// 合同名称允许重复,唯一性由合同编号保证。
TransportBusinessSupport.validateLength(contractManage.getRemark(), 2000, "备注不能超过2000字");
}
@@ -787,16 +787,6 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
}
}
private void validateContractNameUnique(ContractManage contractManage) {
Long count = count(Wrappers.<ContractManage>lambdaQuery()
.eq(ContractManage::getIsDeleted, 0)
.eq(ContractManage::getContractName, contractManage.getContractName())
.ne(Func.isNotEmpty(contractManage.getId()), ContractManage::getId, contractManage.getId()));
if (count > 0) {
throw new ServiceException("合同名称已存在");
}
}
private void validateContractPartyCombinationUnique(ContractManage contractManage) {
if (Func.isEmpty(contractManage.getContractCategory())
|| Func.isEmpty(contractManage.getPartyA())
@@ -770,6 +770,34 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl<ProjectApplyMapper,
TransportBusinessSupport.validateLength(projectApply.getSourceRemark(), 300, "项目由来说明不能超过300个字");
TransportBusinessSupport.validateLength(projectApply.getCargoQuantity(), 100, "预估货物数量不能超过100个字");
TransportBusinessSupport.validateLength(projectApply.getTransportRoute(), 100, "运输线路不能超过100个字");
validateSituationRemarkLength(projectApply.getSituationRemark());
}
/**
* 校验项目情况说明各字段长度(JSON:项目简介/盈利模式/风险点/应急预案)。
*/
@SuppressWarnings("unchecked")
private void validateSituationRemarkLength(String situationRemark) {
if (Func.isBlank(situationRemark)) {
return;
}
Object parsed;
try {
parsed = JsonUtil.parse(situationRemark, Object.class);
} catch (Exception exception) {
// 历史纯文本按整段校验。
TransportBusinessSupport.validateLength(situationRemark, 1000, "项目情况说明不能超过1000个字");
return;
}
if (!(parsed instanceof Map<?, ?> situationMap)) {
TransportBusinessSupport.validateLength(situationRemark, 1000, "项目情况说明不能超过1000个字");
return;
}
Map<String, Object> data = (Map<String, Object>) situationMap;
TransportBusinessSupport.validateLength(Func.toStr(data.get("projectIntro")), 1000, "项目简介不能超过1000个字");
TransportBusinessSupport.validateLength(Func.toStr(data.get("profitRemark")), 1000, "盈利模式及利润测算情况说明不能超过1000个字");
TransportBusinessSupport.validateLength(Func.toStr(data.get("riskPoint")), 1000, "项目风险点不能超过1000个字");
TransportBusinessSupport.validateLength(Func.toStr(data.get("emergencyPlan")), 1000, "风险防范措施及应急预案不能超过1000个字");
}
private void validateChange(ProjectApply projectApply, String changeType) {
@@ -455,12 +455,12 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
waybill.setTrailerVehicleNo(stringValue(row, "trailerVehicleNo"));
waybill.setEscortName(stringValue(row, "escortName"));
waybill.setEscortPhone(stringValue(row, "escortPhone"));
waybill.setMileage(normalizeImportMileage(decimalValue(
waybill.setMileage(normalizeImportOptionalDecimal(decimalValue(
row, "mileage", "里程", "里程(km)", "里程(公里)"
)));
waybill.setUnitPrice(decimalValue(row, "unitPrice", "单价"));
waybill.setUnitPrice(normalizeImportOptionalDecimal(decimalValue(row, "unitPrice", "单价")));
waybill.setPriceUnit(stringValue(row, "priceUnit"));
waybill.setOtherFeeTotal(decimalValue(row, "otherFeeTotal", "其他费用合计"));
waybill.setOtherFeeTotal(normalizeImportOptionalDecimal(decimalValue(row, "otherFeeTotal", "其他费用合计")));
waybill.setRemark(stringValue(row, "remark"));
waybill.setRelationNo(stringValue(row, "waybillIdentifier", "同一运单标识号"));
waybill.setProjectId(batch.getProjectId());
@@ -516,7 +516,9 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
private BigDecimal decimalValue(Map<String, Object> row, String field, String fieldName, String... aliases) {
String value = stringValue(row, field, aliases);
if (Func.isEmpty(value)) return null;
if (Func.isEmpty(value) || isImportOptionalNumberEmpty(value)) {
return null;
}
try {
return new BigDecimal(value);
} catch (NumberFormatException exception) {
@@ -524,8 +526,32 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
}
}
private BigDecimal normalizeImportMileage(BigDecimal mileage) {
return mileage != null && mileage.compareTo(BigDecimal.ONE.negate()) == 0 ? null : mileage;
/**
* BladeX 数字 null 常被序列化为 -1;导入未填的可选金额/里程不得按 -1 落库。
*/
private BigDecimal normalizeImportOptionalDecimal(BigDecimal value) {
return isImportOptionalNumberEmpty(value) ? null : value;
}
private boolean isImportOptionalNumberEmpty(Object value) {
if (value == null) {
return true;
}
if (value instanceof BigDecimal bigDecimal) {
return bigDecimal.compareTo(BigDecimal.ONE.negate()) == 0;
}
if (value instanceof Number number) {
return Double.compare(number.doubleValue(), -1D) == 0;
}
String text = String.valueOf(value).trim();
if (Func.isEmpty(text)) {
return true;
}
try {
return new BigDecimal(text).compareTo(BigDecimal.ONE.negate()) == 0;
} catch (NumberFormatException exception) {
return false;
}
}
private LocalDate parseDate(Object value, String fieldName, boolean required, String... aliases) {
@@ -809,7 +835,7 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
private void validatePositiveNumber(Map<String, Object> row, String field, String fieldName, List<String> errors) {
String value = stringValue(row, field, fieldName);
if (Func.isEmpty(value)) {
if (Func.isEmpty(value) || isImportOptionalNumberEmpty(value)) {
return;
}
@@ -836,7 +862,7 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
private void validateFreightTotal(Map<String, Object> row, List<String> errors) {
String freightTotalStr = stringValue(row, "freightTotal", "运费合计");
if (Func.isEmpty(freightTotalStr)) {
if (Func.isEmpty(freightTotalStr) || isImportOptionalNumberEmpty(freightTotalStr)) {
return;
}
@@ -845,8 +871,10 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
String freightStr = stringValue(row, "freight", "运费");
String otherFeeTotalStr = stringValue(row, "otherFeeTotal", "其他费用合计");
BigDecimal freight = Func.isNotEmpty(freightStr) ? new BigDecimal(freightStr) : BigDecimal.ZERO;
BigDecimal otherFeeTotal = Func.isNotEmpty(otherFeeTotalStr) ? new BigDecimal(otherFeeTotalStr) : BigDecimal.ZERO;
BigDecimal freight = Func.isNotEmpty(freightStr) && !isImportOptionalNumberEmpty(freightStr)
? new BigDecimal(freightStr) : BigDecimal.ZERO;
BigDecimal otherFeeTotal = Func.isNotEmpty(otherFeeTotalStr) && !isImportOptionalNumberEmpty(otherFeeTotalStr)
? new BigDecimal(otherFeeTotalStr) : BigDecimal.ZERO;
BigDecimal calculatedTotal = freight.add(otherFeeTotal);
if (freightTotal.compareTo(calculatedTotal) != 0) {
@@ -2211,9 +2211,20 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
}
private void putIfNotEmpty(Map<String, Object> map, String key, Object value) {
if (Func.isNotEmpty(value)) {
map.put(key, value);
if (Func.isEmpty(value) || isSentinelMinusOneValue(value)) {
return;
}
map.put(key, value);
}
private boolean isSentinelMinusOneValue(Object value) {
if (value instanceof BigDecimal bigDecimal) {
return isSentinelMinusOne(bigDecimal);
}
if (value instanceof Number number) {
return Double.compare(number.doubleValue(), -1D) == 0;
}
return false;
}
private synchronized String nextCode() {
@@ -62,7 +62,7 @@ public class WaybillWrapper extends BaseEntityWrapper<Waybill, WaybillVO> {
waybillVO.setBusinessStatusName(businessStatusName(displayStatus));
waybillVO.setTransportTypeName(transportTypeName(waybill.getTransportType()));
waybillVO.setRequireAccept(WaybillProcessSupport.requiresDriverAcceptConfirmation(waybill.getProcessJson()));
// 未维护里程等占位值 -1 对外展示为空
// 未维护里程/费用等占位值 -1 对外展示为空
if (isSentinelMinusOne(waybillVO.getMileage())) {
waybillVO.setMileage(null);
}
@@ -72,6 +72,9 @@ public class WaybillWrapper extends BaseEntityWrapper<Waybill, WaybillVO> {
if (isSentinelMinusOne(waybillVO.getUnitPrice())) {
waybillVO.setUnitPrice(null);
}
if (isSentinelMinusOne(waybillVO.getOtherFeeTotal())) {
waybillVO.setOtherFeeTotal(null);
}
// 计划未选时 planId 可能为库内 -1 或序列化占位,统一清空避免前端回显 -1
if (waybillVO.getPlanId() != null && waybillVO.getPlanId() <= 0L) {
waybillVO.setPlanId(null);