org.springblade
blade-core-auto
diff --git a/blade-common/src/main/java/org/springblade/common/excel/LenientDateParser.java b/blade-common/src/main/java/org/springblade/common/excel/LenientDateParser.java
new file mode 100644
index 0000000..750c101
--- /dev/null
+++ b/blade-common/src/main/java/org/springblade/common/excel/LenientDateParser.java
@@ -0,0 +1,198 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ *
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ *
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ *
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ *
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software remains with BladeX.
+ *
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ *
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.excel;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 批量导入宽容日期解析器(口径见根工作区 docs/import-spec.md)。
+ *
+ * 解析规则:
+ *
+ * 分隔符 {@code -}、{@code /}、{@code .} 均接受;补零与否均可(2026-08-02 ≡ 2026-8-2)
+ * 日期时间:日期部分同上,时间 HH:mm:ss,可省略秒或秒+分(2026-8-2 12:3 可解析)
+ * 拒绝:两位年份(26-8-2)、日在前(2/8/2026)、无分隔符(20260802)
+ *
+ *
+ * @author Chill
+ */
+public final class LenientDateParser {
+
+ /**
+ * 日期部分:4 位年 + 分隔符 + 1~2 位月 + 同一分隔符 + 1~2 位日(年在前,拒绝两位年份与日在前)。
+ */
+ private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4})([-/.])(\\d{1,2})\\2(\\d{1,2})");
+
+ /**
+ * 时间部分:1~2 位时[:1~2 位分[:1~2 位秒]],逐级可省略。
+ */
+ private static final Pattern TIME_PATTERN = Pattern.compile("(\\d{1,2})(?::(\\d{1,2})(?::(\\d{1,2}))?)?");
+
+ private LenientDateParser() {
+ }
+
+ /**
+ * 解析日期文本,失败返回 {@code null}。
+ *
+ * @param value 单元格原始文本
+ * @return 日期;无法识别时返回 null
+ */
+ public static LocalDate parseDateOrNull(String value) {
+ String normalized = normalize(value);
+ if (normalized == null) {
+ return null;
+ }
+ Matcher matcher = DATE_PATTERN.matcher(normalized);
+ if (!matcher.matches()) {
+ return null;
+ }
+ try {
+ return LocalDate.of(Integer.parseInt(matcher.group(1)),
+ Integer.parseInt(matcher.group(3)), Integer.parseInt(matcher.group(4)));
+ } catch (NumberFormatException | java.time.DateTimeException exception) {
+ return null;
+ }
+ }
+
+ /**
+ * 解析日期文本;允许携带合法时间部分并截断(如 2026-9-1 8:0:0 按 2026-09-01 解析,
+ * 与 fastexcel 内置 LocalDate 转换的既有宽容度保持一致),失败返回 {@code null}。
+ *
+ * @param value 单元格原始文本
+ * @return 日期;无法识别时返回 null
+ */
+ public static LocalDate parseDateLenientlyOrNull(String value) {
+ LocalDate date = parseDateOrNull(value);
+ if (date != null) {
+ return date;
+ }
+ LocalDateTime dateTime = parseDateTimeOrNull(value);
+ return dateTime == null ? null : dateTime.toLocalDate();
+ }
+
+ /**
+ * 解析日期时间文本;纯日期按当日零点处理,失败返回 {@code null}。
+ *
+ * @param value 单元格原始文本
+ * @return 日期时间;无法识别时返回 null
+ */
+ public static LocalDateTime parseDateTimeOrNull(String value) {
+ String normalized = normalize(value);
+ if (normalized == null) {
+ return null;
+ }
+ // 拆出日期与时间两部分;中间允许 1 个及以上空白或小写 t(2026-8-2t12:3 亦接受)。
+ String[] parts = normalized.split("[ \\t]+|(?<=\\d)t", 2);
+ if (parts.length == 0) {
+ return null;
+ }
+ LocalDate date = parseDateOrNull(parts[0]);
+ if (date == null) {
+ return null;
+ }
+ if (parts.length == 1) {
+ return date.atStartOfDay();
+ }
+ Matcher matcher = TIME_PATTERN.matcher(parts[1]);
+ if (!matcher.matches()) {
+ return null;
+ }
+ try {
+ int hour = Integer.parseInt(matcher.group(1));
+ int minute = matcher.group(2) == null ? 0 : Integer.parseInt(matcher.group(2));
+ int second = matcher.group(3) == null ? 0 : Integer.parseInt(matcher.group(3));
+ return LocalDateTime.of(date, LocalTime.of(hour, minute, second));
+ } catch (NumberFormatException | java.time.DateTimeException exception) {
+ return null;
+ }
+ }
+
+ /**
+ * 解析日期文本,失败抛出携带口径文案的 {@link org.springblade.core.log.exception.ServiceException}。
+ * 空白与 {@code null} 返回 {@code null}(可选字段由业务校验决定是否必填)。
+ *
+ * @param value 单元格原始文本
+ * @param columnName 导入模板列名(用于失败原因文案与失败明细标红定位)
+ * @return 日期
+ */
+ public static LocalDate parseDate(String value, String columnName) {
+ if (value == null || value.trim().isEmpty()) {
+ return null;
+ }
+ LocalDate date = parseDateLenientlyOrNull(value);
+ if (date == null) {
+ throw unrecognizedDate(value, columnName);
+ }
+ return date;
+ }
+
+ /**
+ * 解析日期时间文本,失败抛出携带口径文案的 {@link org.springblade.core.log.exception.ServiceException}。
+ * 空白与 {@code null} 返回 {@code null}(可选字段由业务校验决定是否必填)。
+ *
+ * @param value 单元格原始文本
+ * @param columnName 导入模板列名(用于失败原因文案与失败明细标红定位)
+ * @return 日期时间
+ */
+ public static LocalDateTime parseDateTime(String value, String columnName) {
+ if (value == null || value.trim().isEmpty()) {
+ return null;
+ }
+ LocalDateTime dateTime = parseDateTimeOrNull(value);
+ if (dateTime == null) {
+ throw unrecognizedDate(value, columnName);
+ }
+ return dateTime;
+ }
+
+ /**
+ * 按口径构造「日期格式无法识别」错误。
+ *
+ * @param value 单元格原始文本
+ * @param columnName 导入模板列名
+ * @return 业务异常
+ */
+ public static org.springblade.core.log.exception.ServiceException unrecognizedDate(String value, String columnName) {
+ String displayName = columnName == null || columnName.isBlank() ? "日期" : columnName;
+ return new org.springblade.core.log.exception.ServiceException(
+ displayName + " 日期格式无法识别:" + (value == null ? "" : value.trim()));
+ }
+
+ /**
+ * 归一化输入:去首尾空白,跳过空白值。
+ */
+ private static String normalize(String value) {
+ if (value == null) {
+ return null;
+ }
+ String normalized = value.trim();
+ return normalized.isEmpty() ? null : normalized;
+ }
+
+}
diff --git a/blade-common/src/main/java/org/springblade/common/excel/LenientDateStringConverter.java b/blade-common/src/main/java/org/springblade/common/excel/LenientDateStringConverter.java
new file mode 100644
index 0000000..970dde7
--- /dev/null
+++ b/blade-common/src/main/java/org/springblade/common/excel/LenientDateStringConverter.java
@@ -0,0 +1,75 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ *
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ *
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ *
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ *
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software remains with BladeX.
+ *
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ *
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.excel;
+
+import cn.idev.excel.converters.Converter;
+import cn.idev.excel.enums.CellDataTypeEnum;
+import cn.idev.excel.metadata.GlobalConfiguration;
+import cn.idev.excel.metadata.data.ReadCellData;
+import cn.idev.excel.metadata.data.WriteCellData;
+import cn.idev.excel.metadata.property.ExcelContentProperty;
+import cn.idev.excel.util.DateUtils;
+
+import java.time.LocalDate;
+
+/**
+ * 批量导入宽容日期转换器(String 承载):Excel 数值日期(序列号)转 ISO 文本,文本原样透传。
+ *
+ * 文本的宽容解析由服务层调用 {@link LenientDateParser} 完成,不在此处抛错——
+ * 转换器阶段抛出的异常会被 fastexcel 包装成 ExcelDataConvertException 直接中断读取,
+ * 无法进入导入失败明细流程。口径见根工作区 docs/import-spec.md。
+ *
+ * @author Chill
+ */
+public class LenientDateStringConverter implements Converter {
+
+ @Override
+ public Class> supportJavaTypeKey() {
+ return String.class;
+ }
+
+ @Override
+ public CellDataTypeEnum supportExcelTypeKey() {
+ return CellDataTypeEnum.STRING;
+ }
+
+ @Override
+ public String convertToJavaData(ReadCellData> cellData, ExcelContentProperty contentProperty,
+ GlobalConfiguration globalConfiguration) {
+ if (cellData.getType() == CellDataTypeEnum.NUMBER) {
+ LocalDate date = DateUtils.getLocalDateTime(cellData.getNumberValue().doubleValue(),
+ globalConfiguration.getUse1904windowing()).toLocalDate();
+ return date.toString();
+ }
+ return cellData.getStringValue();
+ }
+
+ @Override
+ public WriteCellData> convertToExcelData(String value, ExcelContentProperty contentProperty,
+ GlobalConfiguration globalConfiguration) {
+ return new WriteCellData<>(value);
+ }
+
+}
diff --git a/blade-common/src/main/java/org/springblade/common/excel/LenientDateTimeStringConverter.java b/blade-common/src/main/java/org/springblade/common/excel/LenientDateTimeStringConverter.java
new file mode 100644
index 0000000..bcb070a
--- /dev/null
+++ b/blade-common/src/main/java/org/springblade/common/excel/LenientDateTimeStringConverter.java
@@ -0,0 +1,82 @@
+/**
+ * BladeX Commercial License Agreement
+ * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
+ *
+ * Use of this software is governed by the Commercial License Agreement
+ * obtained after purchasing a license from BladeX.
+ *
+ * 1. This software is for development use only under a valid license
+ * from BladeX.
+ *
+ * 2. Redistribution of this software's source code to any third party
+ * without a commercial license is strictly prohibited.
+ *
+ * 3. Licensees may copyright their own code but cannot use segments
+ * from this software for such purposes. Copyright of this software remains with BladeX.
+ *
+ * Using this software signifies agreement to this License, and the software
+ * must not be used for illegal purposes.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
+ * not liable for any claims arising from secondary or illegal development.
+ *
+ * Author: Chill Zhuang (bladejava@qq.com)
+ */
+package org.springblade.common.excel;
+
+import cn.idev.excel.converters.Converter;
+import cn.idev.excel.enums.CellDataTypeEnum;
+import cn.idev.excel.metadata.GlobalConfiguration;
+import cn.idev.excel.metadata.data.ReadCellData;
+import cn.idev.excel.metadata.data.WriteCellData;
+import cn.idev.excel.metadata.property.ExcelContentProperty;
+import cn.idev.excel.util.DateUtils;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 批量导入宽容日期时间转换器(String 承载):Excel 数值日期(序列号)转
+ * {@code yyyy-MM-dd HH:mm:ss} 文本,文本原样透传。
+ *
+ * 文本的宽容解析由服务层调用 {@link LenientDateParser} 完成,不在此处抛错——
+ * 转换器阶段抛出的异常会被 fastexcel 包装成 ExcelDataConvertException 直接中断读取,
+ * 无法进入导入失败明细流程。口径见根工作区 docs/import-spec.md。
+ *
+ * @author Chill
+ */
+public class LenientDateTimeStringConverter implements Converter {
+
+ /**
+ * 数值日期序列号转文本的输出格式,与导入模板展示格式保持一致。
+ */
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+ @Override
+ public Class> supportJavaTypeKey() {
+ return String.class;
+ }
+
+ @Override
+ public CellDataTypeEnum supportExcelTypeKey() {
+ return CellDataTypeEnum.STRING;
+ }
+
+ @Override
+ public String convertToJavaData(ReadCellData> cellData, ExcelContentProperty contentProperty,
+ GlobalConfiguration globalConfiguration) {
+ if (cellData.getType() == CellDataTypeEnum.NUMBER) {
+ LocalDateTime dateTime = DateUtils.getLocalDateTime(cellData.getNumberValue().doubleValue(),
+ globalConfiguration.getUse1904windowing());
+ return dateTime.format(DATE_TIME_FORMATTER);
+ }
+ return cellData.getStringValue();
+ }
+
+ @Override
+ public WriteCellData> convertToExcelData(String value, ExcelContentProperty contentProperty,
+ GlobalConfiguration globalConfiguration) {
+ return new WriteCellData<>(value);
+ }
+
+}
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/excel/CurrencyExcel.java b/blade-service/blade-system/src/main/java/org/springblade/system/excel/CurrencyExcel.java
index 941b7eb..b59573d 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/excel/CurrencyExcel.java
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/excel/CurrencyExcel.java
@@ -35,7 +35,6 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
-import java.time.LocalDate;
/**
* 币种汇率 Excel
@@ -62,8 +61,8 @@ public class CurrencyExcel implements Serializable {
@ExcelProperty("汇率")
private BigDecimal exchangeRate;
- @ExcelProperty("生效日期")
- private LocalDate effectiveDate;
+ @ExcelProperty(value = "生效日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String effectiveDate;
@ExcelProperty("状态")
private String statusName;
@@ -71,8 +70,8 @@ public class CurrencyExcel implements Serializable {
@ExcelProperty("来源")
private String dataSource;
- @ExcelProperty("失效日期")
- private LocalDate expiryDate;
+ @ExcelProperty(value = "失效日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String expiryDate;
@ExcelProperty("备注")
private String remark;
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/excel/UserExcel.java b/blade-service/blade-system/src/main/java/org/springblade/system/excel/UserExcel.java
index 1dd71ac..306e144 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/excel/UserExcel.java
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/excel/UserExcel.java
@@ -34,7 +34,6 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
-import java.util.Date;
/**
* UserExcel
@@ -102,7 +101,7 @@ public class UserExcel implements Serializable {
private String postName;
@ColumnWidth(20)
- @ExcelProperty("生日")
- private Date birthday;
+ @ExcelProperty(value = "生日", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String birthday;
}
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/mapper/UserMapper.xml b/blade-service/blade-system/src/main/java/org/springblade/system/mapper/UserMapper.xml
index 6a4dd47..70dd2e9 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/mapper/UserMapper.xml
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/mapper/UserMapper.xml
@@ -95,7 +95,7 @@
- SELECT id, tenant_id, user_type, account, name, real_name, email, phone, birthday, role_id, dept_id, post_id FROM blade_user ${ew.customSqlSegment}
+ SELECT id, tenant_id, user_type, account, name, real_name, email, phone, DATE_FORMAT(birthday, '%Y-%m-%d') AS birthday, role_id, dept_id, post_id FROM blade_user ${ew.customSqlSegment}
diff --git a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/CurrencyServiceImpl.java b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/CurrencyServiceImpl.java
index 9e329b3..dea6d26 100644
--- a/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/CurrencyServiceImpl.java
+++ b/blade-service/blade-system/src/main/java/org/springblade/system/service/impl/CurrencyServiceImpl.java
@@ -125,6 +125,8 @@ public class CurrencyServiceImpl extends BaseServiceImpl implement
*/
private User buildImportUser(UserExcel userExcel, String tenantId) {
User user = Objects.requireNonNull(BeanUtil.copyProperties(userExcel, User.class));
+ // 宽容解析生日文本(2026-8-2 等写法),User.birthday 为 java.util.Date 需转换
+ java.time.LocalDate birthday = org.springblade.common.excel.LenientDateParser.parseDate(userExcel.getBirthday(), "生日");
+ user.setBirthday(birthday == null ? null : java.sql.Date.valueOf(birthday));
user.setTenantId(tenantId);
user.setUserType(Func.toInt(DictCache.getKey(DictEnum.USER_TYPE, userExcel.getUserTypeName()), 1));
user.setDeptId(Func.toStrWithEmpty(SysCache.getDeptIds(tenantId, userExcel.getDeptName()), StringPool.EMPTY));
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/AccidentRecordExcel.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/AccidentRecordExcel.java
index 0ae2d2d..322825c 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/AccidentRecordExcel.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/AccidentRecordExcel.java
@@ -36,7 +36,6 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
-import java.time.LocalDate;
/**
* 事故记录 Excel
@@ -60,8 +59,8 @@ public class AccidentRecordExcel implements Serializable {
@ExcelProperty("*车牌号/船号")
private String vehicleNo;
- @ExcelProperty("*事故发生日期")
- private LocalDate accidentDate;
+ @ExcelProperty(value = "*事故发生日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String accidentDate;
@ExcelProperty("事故发生地点")
private String accidentLocation;
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/AnnualInspectionRecordExcel.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/AnnualInspectionRecordExcel.java
index 3f9f1af..74b087b 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/AnnualInspectionRecordExcel.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/AnnualInspectionRecordExcel.java
@@ -35,7 +35,6 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
-import java.time.LocalDate;
/**
* 年检记录 Excel
@@ -59,11 +58,11 @@ public class AnnualInspectionRecordExcel implements Serializable {
@ExcelProperty("*车牌号/船号")
private String vehicleNo;
- @ExcelProperty("*检测评定日期")
- private LocalDate inspectionAssessmentDate;
+ @ExcelProperty(value = "*检测评定日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String inspectionAssessmentDate;
- @ExcelProperty("*有效期截止日")
- private LocalDate validUntilDate;
+ @ExcelProperty(value = "*有效期截止日", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String validUntilDate;
@ExcelProperty("*车辆技术等级")
private String vehicleTechnicalLevel;
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/EquipmentLedgerExcel.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/EquipmentLedgerExcel.java
index b80123e..f849960 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/EquipmentLedgerExcel.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/EquipmentLedgerExcel.java
@@ -7,12 +7,10 @@ package org.springblade.transport.excel;
import cn.idev.excel.annotation.ExcelIgnore;
import cn.idev.excel.annotation.ExcelProperty;
-import cn.idev.excel.annotation.format.DateTimeFormat;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
-import java.time.LocalDate;
/**
* 设备台账 Excel
@@ -29,7 +27,7 @@ public class EquipmentLedgerExcel implements Serializable {
@ExcelProperty("设备品牌") private String equipmentBrand;
@ExcelProperty("设备类型") private String equipmentType;
@ExcelProperty("规格型号") private String specificationModel;
- @ExcelProperty("出厂日期") @DateTimeFormat("yyyy-MM-dd") private LocalDate factoryDate;
+ @ExcelProperty(value = "出厂日期", converter = org.springblade.common.excel.LenientDateStringConverter.class) private String factoryDate;
@ExcelProperty("备注") private String remark;
@ExcelIgnore private String errorMessage;
}
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/InsuranceRecordExcel.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/InsuranceRecordExcel.java
index e6b8701..6c18af3 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/InsuranceRecordExcel.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/InsuranceRecordExcel.java
@@ -35,7 +35,6 @@ import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
-import java.time.LocalDate;
/**
* 保险记录 Excel
@@ -68,11 +67,11 @@ public class InsuranceRecordExcel implements Serializable {
@ExcelProperty("*保单号")
private String policyNo;
- @ExcelProperty("*开始日期")
- private LocalDate startDate;
+ @ExcelProperty(value = "*开始日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String startDate;
- @ExcelProperty("*结束日期")
- private LocalDate endDate;
+ @ExcelProperty(value = "*结束日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String endDate;
@ExcelProperty("保额")
private BigDecimal insuredAmount;
@@ -83,8 +82,8 @@ public class InsuranceRecordExcel implements Serializable {
@ExcelProperty("发票号")
private String invoiceNo;
- @ExcelProperty("开票日期")
- private LocalDate invoiceDate;
+ @ExcelProperty(value = "开票日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String invoiceDate;
@ExcelProperty("备注")
private String remark;
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/MaintenancePlanDateTimeConverter.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/MaintenancePlanDateTimeConverter.java
index f3f1cab..713ba63 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/MaintenancePlanDateTimeConverter.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/MaintenancePlanDateTimeConverter.java
@@ -33,22 +33,20 @@ import cn.idev.excel.metadata.data.WriteCellData;
import cn.idev.excel.metadata.property.ExcelContentProperty;
import cn.idev.excel.util.DateUtils;
-import java.time.LocalDate;
import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeParseException;
/**
* 保养记录日期转换器,兼容日期文本、日期时间文本和 Excel 数值日期。
+ *
+ * 文本解析委托公共宽容解析器(支持 2026-8-2、2026/8/2 等写法,口径见根工作区
+ * docs/import-spec.md);无法识别的文本按既有行为抛出转换异常,
+ * 文案带原值,与「日期格式无法识别」口径一致。
*
* @author Chill
*/
public class MaintenancePlanDateTimeConverter implements Converter {
private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
- private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
- private static final DateTimeFormatter DATE_TIME_MINUTE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
- private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT);
@Override
public Class> supportJavaTypeKey() {
@@ -71,16 +69,14 @@ public class MaintenancePlanDateTimeConverter implements Converter
+ * 数值日期序列号转 ISO 文本,文本原样透传;文本的宽容解析由服务层委托
+ * {@link org.springblade.common.excel.LenientDateParser} 完成(支持 2026-8-2 等写法,
+ * 口径见根工作区 docs/import-spec.md)。
*
* @author Chill
*/
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/WaybillExcel.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/WaybillExcel.java
index 75d5e0f..c093fdd 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/WaybillExcel.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/excel/WaybillExcel.java
@@ -108,10 +108,10 @@ public class WaybillExcel implements Serializable {
private String escortPhone;
@ExcelProperty("里程(km)")
private BigDecimal mileage;
- @ExcelProperty("预计发货日期")
- private LocalDate estimatedStartTime;
- @ExcelProperty("预计完成日期")
- private LocalDate estimatedEndTime;
+ @ExcelProperty(value = "预计发货日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String estimatedStartTime;
+ @ExcelProperty(value = "预计完成日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String estimatedEndTime;
@ExcelProperty("单价")
private BigDecimal unitPrice;
@ExcelProperty("计价单位")
@@ -126,10 +126,10 @@ public class WaybillExcel implements Serializable {
private String businessStatus;
@ExcelProperty("数据来源")
private String dataSource;
- @ExcelProperty("开始日期")
- private LocalDate startDate;
- @ExcelProperty("结束日期")
- private LocalDate endDate;
+ @ExcelProperty(value = "开始日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String startDate;
+ @ExcelProperty(value = "结束日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
+ private String endDate;
@ExcelProperty("计划名称")
private String planName;
@ExcelProperty("多联总单")
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AccidentRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AccidentRecordServiceImpl.java
index 0568120..70b0401 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AccidentRecordServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AccidentRecordServiceImpl.java
@@ -94,6 +94,7 @@ public class AccidentRecordServiceImpl extends BaseServiceImpl validationErrors = validateImportAccidentRecord(accidentRecord);
if (Func.isNotEmpty(validationErrors)) {
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AnnualInspectionRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AnnualInspectionRecordServiceImpl.java
index 563555b..0e45f28 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AnnualInspectionRecordServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/AnnualInspectionRecordServiceImpl.java
@@ -113,6 +113,8 @@ public class AnnualInspectionRecordServiceImpl extends BaseServiceImpl validationErrors = validateImportAnnualInspectionRecord(annualInspectionRecord);
if (Func.isNotEmpty(validationErrors)) {
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EquipmentLedgerServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EquipmentLedgerServiceImpl.java
index 19ad162..cd1eccb 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EquipmentLedgerServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/EquipmentLedgerServiceImpl.java
@@ -91,6 +91,7 @@ public class EquipmentLedgerServiceImpl extends BaseServiceImpl validationErrors = validateImportInsuranceRecord(insuranceRecord);
if (Func.isNotEmpty(insuranceRecord.getVehicleType()) && Func.isNotEmpty(insuranceRecord.getInsuranceType()) && Func.isNotEmpty(insuranceRecord.getPolicyNo())) {
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OtherExpenseRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OtherExpenseRecordServiceImpl.java
index e854595..6a20467 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OtherExpenseRecordServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/OtherExpenseRecordServiceImpl.java
@@ -75,6 +75,7 @@ public class OtherExpenseRecordServiceImpl extends BaseServiceImpl validationErrors = validateImportOtherExpenseRecord(otherExpenseRecord);
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TireReplacementRecordServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TireReplacementRecordServiceImpl.java
index a6d9c2e..28c01fe 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TireReplacementRecordServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/TireReplacementRecordServiceImpl.java
@@ -43,8 +43,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -64,7 +62,6 @@ public class TireReplacementRecordServiceImpl extends BaseServiceImpl selectTireReplacementRecordPage(IPage page, TireReplacementRecordVO tireReplacementRecord) {
@@ -144,9 +141,9 @@ public class TireReplacementRecordServiceImpl extends BaseServiceImpl implements IWaybillImportBatchService {
- private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/** 批量导入状态仅保留草稿与导入完成两种。 */
private static final String STATUS_DRAFT = "draft";
private static final String STATUS_COMPLETED = "completed";
@@ -467,11 +465,12 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl loadTransportTypeOptions() {
diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java
index 2b85c8f..e53e35d 100644
--- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java
+++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java
@@ -885,6 +885,10 @@ public class WaybillServiceImpl extends BaseServiceImpl
WaybillExcel excel = data.get(index);
try {
Waybill waybill = Objects.requireNonNull(BeanUtil.copyProperties(excel, Waybill.class));
+ waybill.setEstimatedStartTime(org.springblade.common.excel.LenientDateParser.parseDate(excel.getEstimatedStartTime(), "预计发货日期"));
+ waybill.setEstimatedEndTime(org.springblade.common.excel.LenientDateParser.parseDate(excel.getEstimatedEndTime(), "预计完成日期"));
+ waybill.setStartDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getStartDate(), "开始日期"));
+ waybill.setEndDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getEndDate(), "结束日期"));
waybill.setDataSource("批量导入");
waybill.setCreateTime(null);
waybill.setUpdateTime(null);