Compare commits
5 Commits
6b97685165
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 0797785176 | |||
| 86adb47392 | |||
| 780cd56ffe | |||
| 8cf9140f56 | |||
| 2f56ca07cb |
@@ -22,15 +22,6 @@
|
|||||||
<groupId>org.springblade</groupId>
|
<groupId>org.springblade</groupId>
|
||||||
<artifactId>blade-starter-loadbalancer</artifactId>
|
<artifactId>blade-starter-loadbalancer</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springblade</groupId>
|
|
||||||
<artifactId>blade-starter-log</artifactId>
|
|
||||||
<!-- provided:LenientDateParser 编译期需要 ServiceException(位于 starter-log),
|
|
||||||
但 provided 不向下游传递——否则网关会经 common 拿到 blade-core-tool 的
|
|
||||||
BladeConverterConfiguration(implements WebMvcConfigurer),在无 spring-webmvc
|
|
||||||
的 WebFlux 网关里启动即崩。业务服务经 blade-core-boot 自带 starter-log,运行时不受影响。 -->
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springblade</groupId>
|
<groupId>org.springblade</groupId>
|
||||||
<artifactId>blade-core-auto</artifactId>
|
<artifactId>blade-core-auto</artifactId>
|
||||||
|
|||||||
+5
-133
@@ -46,11 +46,9 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入失败明细 Excel 导出工具类
|
* 导入失败明细 Excel 导出工具类
|
||||||
@@ -97,7 +95,7 @@ public class ImportFailureExcelUtil {
|
|||||||
* @param excelClass 原导入 Excel 类型
|
* @param excelClass 原导入 Excel 类型
|
||||||
*/
|
*/
|
||||||
public static void export(HttpServletResponse response, String fileName, String sheetName, List<?> data, Class<?> excelClass) {
|
public static void export(HttpServletResponse response, String fileName, String sheetName, List<?> data, Class<?> excelClass) {
|
||||||
export(response, fileName, sheetName, data, excelClass, true);
|
exportFailureReasonOnly(response, fileName, sheetName, data, excelClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,16 +109,6 @@ public class ImportFailureExcelUtil {
|
|||||||
*/
|
*/
|
||||||
public static void exportFailureReasonOnly(HttpServletResponse response, String fileName, String sheetName,
|
public static void exportFailureReasonOnly(HttpServletResponse response, String fileName, String sheetName,
|
||||||
List<?> data, Class<?> excelClass) {
|
List<?> data, Class<?> excelClass) {
|
||||||
export(response, fileName, sheetName, data, excelClass, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出导入失败明细
|
|
||||||
*
|
|
||||||
* @param markErrorColumns 是否按失败原因里出现的列名,标红对应字段单元格
|
|
||||||
*/
|
|
||||||
private static void export(HttpServletResponse response, String fileName, String sheetName,
|
|
||||||
List<?> data, Class<?> excelClass, boolean markErrorColumns) {
|
|
||||||
response.setContentType("application/vnd.ms-excel");
|
response.setContentType("application/vnd.ms-excel");
|
||||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||||
String encodeFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
|
String encodeFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
|
||||||
@@ -130,7 +118,7 @@ public class ImportFailureExcelUtil {
|
|||||||
List<List<Object>> rows = buildRows(data, excelFields);
|
List<List<Object>> rows = buildRows(data, excelFields);
|
||||||
try {
|
try {
|
||||||
FastExcel.write(response.getOutputStream())
|
FastExcel.write(response.getOutputStream())
|
||||||
.registerWriteHandler(new ImportFailureCellStyleHandler(excelFields, rows, markErrorColumns))
|
.registerWriteHandler(new ImportFailureCellStyleHandler(excelFields.size()))
|
||||||
.head(head)
|
.head(head)
|
||||||
.sheet(sheetName)
|
.sheet(sheetName)
|
||||||
.doWrite(rows);
|
.doWrite(rows);
|
||||||
@@ -216,59 +204,15 @@ public class ImportFailureExcelUtil {
|
|||||||
throw new NoSuchFieldException(String.join(",", fieldNames));
|
throw new NoSuchFieldException(String.join(",", fieldNames));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 文本归一化:去掉空白、星号与中英文标点并统一小写
|
|
||||||
* <p>
|
|
||||||
* 目的是让「失败原因里写的列名」与「表头列名」能直接做包含匹配,
|
|
||||||
* 不受「*」「/」「:」等写法差异影响。
|
|
||||||
*/
|
|
||||||
private static String normalize(String value) {
|
|
||||||
return value == null ? "" : value.replaceAll("[\\s*_::,,。;;()()\\[\\]【】<>《》//、-]", "").toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取某一列用于定位的候选关键词
|
|
||||||
* <p>
|
|
||||||
* 包含表头列名、字段名,以及列名按分隔符拆出的片段
|
|
||||||
* (如「车牌号/船号」拆出「车牌号」「船号」,失败原因只写其中一段时也能定位)。
|
|
||||||
*/
|
|
||||||
private static List<String> columnKeywords(Field field) {
|
|
||||||
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
|
|
||||||
String[] value = excelProperty.value();
|
|
||||||
String columnName = value.length == 0 ? field.getName() : value[0];
|
|
||||||
List<String> keywords = new ArrayList<>();
|
|
||||||
keywords.add(columnName);
|
|
||||||
keywords.add(field.getName());
|
|
||||||
keywords.addAll(Arrays.asList(columnName.replace("*", "").split("[//、()()\\s]+")));
|
|
||||||
return keywords.stream()
|
|
||||||
.map(ImportFailureExcelUtil::normalize)
|
|
||||||
.filter(keyword -> keyword.length() >= 2)
|
|
||||||
.distinct()
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ImportFailureCellStyleHandler implements CellWriteHandler {
|
private static class ImportFailureCellStyleHandler implements CellWriteHandler {
|
||||||
|
|
||||||
private final int failureReasonColumnIndex;
|
private final int failureReasonColumnIndex;
|
||||||
private final boolean markErrorColumns;
|
|
||||||
private final List<List<Object>> rows;
|
|
||||||
private final Map<Integer, Set<Integer>> redColumnsByRow = new HashMap<>();
|
|
||||||
private final Map<Short, CellStyle> redStyleCache = new HashMap<>();
|
private final Map<Short, CellStyle> redStyleCache = new HashMap<>();
|
||||||
private final Map<Short, CellStyle> noWrapStyleCache = new HashMap<>();
|
private final Map<Short, CellStyle> noWrapStyleCache = new HashMap<>();
|
||||||
private final Map<Integer, Integer> columnWidthCache = new HashMap<>();
|
private final Map<Integer, Integer> columnWidthCache = new HashMap<>();
|
||||||
|
|
||||||
private ImportFailureCellStyleHandler(List<Field> excelFields, List<List<Object>> rows, boolean markErrorColumns) {
|
private ImportFailureCellStyleHandler(int failureReasonColumnIndex) {
|
||||||
this.failureReasonColumnIndex = excelFields.size();
|
this.failureReasonColumnIndex = failureReasonColumnIndex;
|
||||||
this.markErrorColumns = markErrorColumns;
|
|
||||||
this.rows = rows;
|
|
||||||
if (markErrorColumns) {
|
|
||||||
List<List<String>> columnKeywords = excelFields.stream()
|
|
||||||
.map(ImportFailureExcelUtil::columnKeywords)
|
|
||||||
.toList();
|
|
||||||
for (int rowIndex = 0; rowIndex < rows.size(); rowIndex++) {
|
|
||||||
redColumnsByRow.put(rowIndex, resolveRedColumns(rows.get(rowIndex), columnKeywords));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -286,83 +230,11 @@ public class ImportFailureExcelUtil {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
adjustColumnWidth(cell);
|
adjustColumnWidth(cell);
|
||||||
if (relativeRowIndex == null || relativeRowIndex < 0 || relativeRowIndex >= rows.size()) {
|
if (cell.getColumnIndex() == failureReasonColumnIndex) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (shouldMarkRed(relativeRowIndex, cell.getColumnIndex())) {
|
|
||||||
markRed(cell);
|
markRed(cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算某一行需要标红的列
|
|
||||||
* <p>
|
|
||||||
* 失败原因里出现的列名即视为出错列;但当某个命中片段被另一列更长的命中
|
|
||||||
* 片段完全覆盖时(如原因「车船类型不能为空」同时命中「车船类型」和它的
|
|
||||||
* 子串「类型」),只保留更长的那一列,避免把无关列一起标红。
|
|
||||||
*/
|
|
||||||
private Set<Integer> resolveRedColumns(List<Object> row, List<List<String>> columnKeywords) {
|
|
||||||
Set<Integer> redColumns = new LinkedHashSet<>();
|
|
||||||
redColumns.add(failureReasonColumnIndex);
|
|
||||||
String failureReason = normalize(String.valueOf(row.get(failureReasonColumnIndex)));
|
|
||||||
if (failureReason.isEmpty()) {
|
|
||||||
return redColumns;
|
|
||||||
}
|
|
||||||
List<int[]> matches = new ArrayList<>();
|
|
||||||
for (int column = 0; column < columnKeywords.size(); column++) {
|
|
||||||
for (String keyword : columnKeywords.get(column)) {
|
|
||||||
int fromIndex = 0;
|
|
||||||
while (true) {
|
|
||||||
int index = failureReason.indexOf(keyword, fromIndex);
|
|
||||||
if (index < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
matches.add(new int[]{index, index + keyword.length(), column});
|
|
||||||
fromIndex = index + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int[] match : matches) {
|
|
||||||
if (!isSubsumed(match, matches)) {
|
|
||||||
redColumns.add(match[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return redColumns;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断该命中片段是否被另一列更长的命中片段完全覆盖
|
|
||||||
*/
|
|
||||||
private boolean isSubsumed(int[] match, List<int[]> matches) {
|
|
||||||
int matchLength = match[1] - match[0];
|
|
||||||
for (int[] other : matches) {
|
|
||||||
if (other[2] == match[2]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((other[1] - other[0]) > matchLength && other[0] <= match[0] && other[1] >= match[1]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldMarkRed(int rowIndex, int columnIndex) {
|
|
||||||
if (columnIndex == failureReasonColumnIndex) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!markErrorColumns) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Set<Integer> redColumns = redColumnsByRow.get(rowIndex);
|
|
||||||
return redColumns != null && redColumns.contains(columnIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标红单元格
|
|
||||||
* <p>
|
|
||||||
* 统一只改字体颜色,不加底纹;空单元格的红色字体在屏幕上不可见,
|
|
||||||
* 这类错误依靠失败原因列的文字定位。
|
|
||||||
*/
|
|
||||||
private void markRed(Cell cell) {
|
private void markRed(Cell cell) {
|
||||||
CellStyle currentStyle = cell.getCellStyle();
|
CellStyle currentStyle = cell.getCellStyle();
|
||||||
CellStyle redStyle = redStyleCache.computeIfAbsent(currentStyle.getIndex(), styleIndex -> {
|
CellStyle redStyle = redStyleCache.computeIfAbsent(currentStyle.getIndex(), styleIndex -> {
|
||||||
|
|||||||
@@ -1,198 +0,0 @@
|
|||||||
/**
|
|
||||||
* BladeX Commercial License Agreement
|
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
|
||||||
* <p>
|
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
|
||||||
* obtained after purchasing a license from BladeX.
|
|
||||||
* <p>
|
|
||||||
* 1. This software is for development use only under a valid license
|
|
||||||
* from BladeX.
|
|
||||||
* <p>
|
|
||||||
* 2. Redistribution of this software's source code to any third party
|
|
||||||
* without a commercial license is strictly prohibited.
|
|
||||||
* <p>
|
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
|
||||||
* from this software for such purposes. Copyright of this software remains with BladeX.
|
|
||||||
* <p>
|
|
||||||
* Using this software signifies agreement to this License, and the software
|
|
||||||
* must not be used for illegal purposes.
|
|
||||||
* <p>
|
|
||||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
|
||||||
* not liable for any claims arising from secondary or illegal development.
|
|
||||||
* <p>
|
|
||||||
* 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)。
|
|
||||||
* <p>
|
|
||||||
* 解析规则:
|
|
||||||
* <ul>
|
|
||||||
* <li>分隔符 {@code -}、{@code /}、{@code .} 均接受;补零与否均可(2026-08-02 ≡ 2026-8-2)</li>
|
|
||||||
* <li>日期时间:日期部分同上,时间 HH:mm:ss,可省略秒或秒+分(2026-8-2 12:3 可解析)</li>
|
|
||||||
* <li>拒绝:两位年份(26-8-2)、日在前(2/8/2026)、无分隔符(20260802)</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-75
@@ -1,75 +0,0 @@
|
|||||||
/**
|
|
||||||
* BladeX Commercial License Agreement
|
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
|
||||||
* <p>
|
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
|
||||||
* obtained after purchasing a license from BladeX.
|
|
||||||
* <p>
|
|
||||||
* 1. This software is for development use only under a valid license
|
|
||||||
* from BladeX.
|
|
||||||
* <p>
|
|
||||||
* 2. Redistribution of this software's source code to any third party
|
|
||||||
* without a commercial license is strictly prohibited.
|
|
||||||
* <p>
|
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
|
||||||
* from this software for such purposes. Copyright of this software remains with BladeX.
|
|
||||||
* <p>
|
|
||||||
* Using this software signifies agreement to this License, and the software
|
|
||||||
* must not be used for illegal purposes.
|
|
||||||
* <p>
|
|
||||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
|
||||||
* not liable for any claims arising from secondary or illegal development.
|
|
||||||
* <p>
|
|
||||||
* 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 文本,文本原样透传。
|
|
||||||
* <p>
|
|
||||||
* 文本的宽容解析由服务层调用 {@link LenientDateParser} 完成,不在此处抛错——
|
|
||||||
* 转换器阶段抛出的异常会被 fastexcel 包装成 ExcelDataConvertException 直接中断读取,
|
|
||||||
* 无法进入导入失败明细流程。口径见根工作区 docs/import-spec.md。
|
|
||||||
*
|
|
||||||
* @author Chill
|
|
||||||
*/
|
|
||||||
public class LenientDateStringConverter implements Converter<String> {
|
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-82
@@ -1,82 +0,0 @@
|
|||||||
/**
|
|
||||||
* BladeX Commercial License Agreement
|
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
|
||||||
* <p>
|
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
|
||||||
* obtained after purchasing a license from BladeX.
|
|
||||||
* <p>
|
|
||||||
* 1. This software is for development use only under a valid license
|
|
||||||
* from BladeX.
|
|
||||||
* <p>
|
|
||||||
* 2. Redistribution of this software's source code to any third party
|
|
||||||
* without a commercial license is strictly prohibited.
|
|
||||||
* <p>
|
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
|
||||||
* from this software for such purposes. Copyright of this software remains with BladeX.
|
|
||||||
* <p>
|
|
||||||
* Using this software signifies agreement to this License, and the software
|
|
||||||
* must not be used for illegal purposes.
|
|
||||||
* <p>
|
|
||||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
|
||||||
* not liable for any claims arising from secondary or illegal development.
|
|
||||||
* <p>
|
|
||||||
* 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} 文本,文本原样透传。
|
|
||||||
* <p>
|
|
||||||
* 文本的宽容解析由服务层调用 {@link LenientDateParser} 完成,不在此处抛错——
|
|
||||||
* 转换器阶段抛出的异常会被 fastexcel 包装成 ExcelDataConvertException 直接中断读取,
|
|
||||||
* 无法进入导入失败明细流程。口径见根工作区 docs/import-spec.md。
|
|
||||||
*
|
|
||||||
* @author Chill
|
|
||||||
*/
|
|
||||||
public class LenientDateTimeStringConverter implements Converter<String> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数值日期序列号转文本的输出格式,与导入模板展示格式保持一致。
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+12
@@ -39,6 +39,7 @@ public interface IBusinessProcessClient {
|
|||||||
String QUERY_BUSINESS_PROCESS_SNAPSHOT = API_PREFIX + "/queryBusinessProcessSnapshot";
|
String QUERY_BUSINESS_PROCESS_SNAPSHOT = API_PREFIX + "/queryBusinessProcessSnapshot";
|
||||||
String QUERY_APPROVED_RECORD_LIST = API_PREFIX + "/queryApprovedRecordsNoAttachments";
|
String QUERY_APPROVED_RECORD_LIST = API_PREFIX + "/queryApprovedRecordsNoAttachments";
|
||||||
String GET_CURRENT_NODES = API_PREFIX + "/getCurrentNodes";
|
String GET_CURRENT_NODES = API_PREFIX + "/getCurrentNodes";
|
||||||
|
String GET_PROCESS_INFO = API_PREFIX + "/getProcessInfo";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交业务流程
|
* 提交业务流程
|
||||||
@@ -114,4 +115,15 @@ public interface IBusinessProcessClient {
|
|||||||
@GetMapping(GET_CURRENT_NODES)
|
@GetMapping(GET_CURRENT_NODES)
|
||||||
FR<Object> getCurrentNodes(@RequestParam("processInstanceId") String processInstanceId,
|
FR<Object> getCurrentNodes(@RequestParam("processInstanceId") String processInstanceId,
|
||||||
@RequestParam(value = "loginName", required = false) String loginName);
|
@RequestParam(value = "loginName", required = false) String loginName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程实例详情
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @param loginName MK登录名(手机号)
|
||||||
|
* @return 流程实例详情
|
||||||
|
*/
|
||||||
|
@GetMapping(GET_PROCESS_INFO)
|
||||||
|
FR<Object> getProcessInfo(@RequestParam("processInstanceId") String processInstanceId,
|
||||||
|
@RequestParam(value = "loginName", required = false) String loginName);
|
||||||
}
|
}
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package org.springblade.transport.feign;
|
||||||
|
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.transport.pojo.dto.CustomerProcessNodeSyncDTO;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客商档案 Feign接口
|
||||||
|
*/
|
||||||
|
@FeignClient(value = "blade-transport")
|
||||||
|
public interface ICustomerArchiveClient {
|
||||||
|
|
||||||
|
String API_PREFIX = "/feign/client/customerArchive";
|
||||||
|
String SYNC_PROCESS_NODE = API_PREFIX + "/syncProcessNode";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 MK 当前节点同步客商当前节点、当前处理人和审批状态
|
||||||
|
*
|
||||||
|
* @param param 同步参数
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
@PostMapping(SYNC_PROCESS_NODE)
|
||||||
|
FR<Boolean> syncProcessNode(@RequestBody CustomerProcessNodeSyncDTO param);
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package org.springblade.transport.feign;
|
||||||
|
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.transport.pojo.dto.MkProcessSyncDTO;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 业务流程同步 Feign
|
||||||
|
*/
|
||||||
|
@FeignClient(value = "blade-transport")
|
||||||
|
public interface IMkProcessClient {
|
||||||
|
|
||||||
|
String API_PREFIX = "/feign/client/mkProcess";
|
||||||
|
String APPLY = API_PREFIX + "/apply";
|
||||||
|
|
||||||
|
@PostMapping(APPLY)
|
||||||
|
FR<Boolean> apply(@RequestBody MkProcessSyncDTO param);
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package org.springblade.transport.pojo.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客商流程当前节点同步参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "客商流程当前节点同步参数")
|
||||||
|
public class CustomerProcessNodeSyncDTO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "客商ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "当前节点")
|
||||||
|
private String currentNode;
|
||||||
|
|
||||||
|
@Schema(description = "当前处理人")
|
||||||
|
private String currentProcessor;
|
||||||
|
|
||||||
|
@Schema(description = "审批状态")
|
||||||
|
private String approvalStatus;
|
||||||
|
|
||||||
|
@Schema(description = "MK 流程实例详情,传入后按 currentHandlers.fdName 和 handlerInfos.nodeName 回写")
|
||||||
|
private Object processInfo;
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package org.springblade.transport.pojo.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 流程节点同步参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "MK 流程节点同步参数")
|
||||||
|
public class MkProcessSyncDTO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "业务类型,如 project-apply")
|
||||||
|
private String bizType;
|
||||||
|
|
||||||
|
@Schema(description = "业务主键")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "动作:sync / approve / reject")
|
||||||
|
private String action;
|
||||||
|
|
||||||
|
@Schema(description = "处理人姓名")
|
||||||
|
private String processorName;
|
||||||
|
|
||||||
|
@Schema(description = "MK 流程实例详情")
|
||||||
|
private Object processInfo;
|
||||||
|
}
|
||||||
@@ -62,6 +62,10 @@
|
|||||||
<groupId>org.springblade</groupId>
|
<groupId>org.springblade</groupId>
|
||||||
<artifactId>blade-mk-api</artifactId>
|
<artifactId>blade-mk-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springblade</groupId>
|
||||||
|
<artifactId>blade-transport-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 其他依赖 -->
|
<!-- 其他依赖 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
+6
@@ -60,6 +60,12 @@ public class BusinessProcessController extends BladeController {
|
|||||||
return R.data(businessProcessService.processSubmit(param));
|
return R.data(businessProcessService.processSubmit(param));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/processDelete")
|
||||||
|
@ApiOperationSupport(order = 7)
|
||||||
|
public R<Boolean> processDelete(@RequestBody MKProcessCreateDTO param) {
|
||||||
|
return R.data(businessProcessService.processDelete(param == null ? null : param.getFormInstanceId()));
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/isEditView")
|
@GetMapping("/isEditView")
|
||||||
@ApiOperationSupport(order = 3)
|
@ApiOperationSupport(order = 3)
|
||||||
@Operation(summary = "是否编辑页", description = "传入业务id")
|
@Operation(summary = "是否编辑页", description = "传入业务id")
|
||||||
|
|||||||
+8
@@ -86,4 +86,12 @@ public class BusinessProcessClient implements IBusinessProcessClient {
|
|||||||
@RequestParam(value = "loginName", required = false) String loginName) {
|
@RequestParam(value = "loginName", required = false) String loginName) {
|
||||||
return FR.data(businessProcessService.getCurrentNodes(processInstanceId, loginName));
|
return FR.data(businessProcessService.getCurrentNodes(processInstanceId, loginName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@GetMapping(GET_PROCESS_INFO)
|
||||||
|
@Override
|
||||||
|
public FR<Object> getProcessInfo(@RequestParam("processInstanceId") String processInstanceId,
|
||||||
|
@RequestParam(value = "loginName", required = false) String loginName) {
|
||||||
|
return FR.data(businessProcessService.getProcessInfo(processInstanceId, loginName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -34,6 +34,14 @@ public interface IBusinessProcessService extends IService<BusinessProcess> {
|
|||||||
*/
|
*/
|
||||||
String processSubmit(MKProcessCreateDTO param);
|
String processSubmit(MKProcessCreateDTO param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按业务表单实例 id 删除 MK 流程(不删除本地业务流程记录,供驳回后重新提交使用)
|
||||||
|
*
|
||||||
|
* @param formInstanceId 业务表单实例 id
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean processDelete(String formInstanceId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取流程当前节点详情
|
* 获取流程当前节点详情
|
||||||
*
|
*
|
||||||
@@ -43,6 +51,15 @@ public interface IBusinessProcessService extends IService<BusinessProcess> {
|
|||||||
*/
|
*/
|
||||||
List<?> getCurrentNodes(String processInstanceId, String loginName);
|
List<?> getCurrentNodes(String processInstanceId, String loginName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程实例详情
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @param loginName MK登录名(手机号),可为空,为空时按流程发起人解析
|
||||||
|
* @return 流程实例详情
|
||||||
|
*/
|
||||||
|
Object getProcessInfo(String processInstanceId, String loginName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改业务流程状态
|
* 修改业务流程状态
|
||||||
* @param param
|
* @param param
|
||||||
|
|||||||
+166
-2
@@ -15,6 +15,7 @@ import org.springblade.process.pojo.enums.ApproveStatusEnum;
|
|||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.log.utils.AssertUtils;
|
import org.springblade.core.log.utils.AssertUtils;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
import org.springblade.core.tool.utils.StringUtil;
|
import org.springblade.core.tool.utils.StringUtil;
|
||||||
import org.springblade.process.convert.ApprovalConvert;
|
import org.springblade.process.convert.ApprovalConvert;
|
||||||
import org.springblade.process.convert.BusinessProcessConvert;
|
import org.springblade.process.convert.BusinessProcessConvert;
|
||||||
@@ -41,12 +42,17 @@ import org.springblade.thirdparty.mk.pojo.dto.approval.MKProcessDTO;
|
|||||||
import org.springblade.thirdparty.mk.pojo.dto.sort.*;
|
import org.springblade.thirdparty.mk.pojo.dto.sort.*;
|
||||||
import org.springblade.thirdparty.mk.pojo.vo.*;
|
import org.springblade.thirdparty.mk.pojo.vo.*;
|
||||||
import org.springblade.thirdparty.mk.service.IMKService;
|
import org.springblade.thirdparty.mk.service.IMKService;
|
||||||
|
import org.springblade.transport.feign.ICustomerArchiveClient;
|
||||||
|
import org.springblade.transport.feign.IMkProcessClient;
|
||||||
|
import org.springblade.transport.pojo.dto.CustomerProcessNodeSyncDTO;
|
||||||
|
import org.springblade.transport.pojo.dto.MkProcessSyncDTO;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 业务流程关联表 服务实现类
|
* 业务流程关联表 服务实现类
|
||||||
@@ -64,6 +70,8 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
|||||||
private final MKProperties mkProperties;
|
private final MKProperties mkProperties;
|
||||||
private final ApprovalConvert approvalConvert;
|
private final ApprovalConvert approvalConvert;
|
||||||
private final IUserService userService;
|
private final IUserService userService;
|
||||||
|
private final ICustomerArchiveClient customerArchiveClient;
|
||||||
|
private final IMkProcessClient mkProcessClient;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
@@ -128,8 +136,17 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
|||||||
AssertUtils.notBlank(loginName, "当前用户手机号为空,无法提交审核流");
|
AssertUtils.notBlank(loginName, "当前用户手机号为空,无法提交审核流");
|
||||||
param.setSubmitIdentity(loginName);
|
param.setSubmitIdentity(loginName);
|
||||||
param.setLoginName(loginName);
|
param.setLoginName(loginName);
|
||||||
log.info("调用mk processSubmit 参数:{}", JSON.toJSONString(param));
|
String bizType = param.getBizType();
|
||||||
String processInstanceId = mkService.processSubmit(param);
|
MKProcessCreateDTO mkParam = new MKProcessCreateDTO();
|
||||||
|
mkParam.setFormInstanceId(param.getFormInstanceId());
|
||||||
|
mkParam.setSubject(param.getSubject());
|
||||||
|
mkParam.setSubmitIdentity(loginName);
|
||||||
|
mkParam.setLoginName(loginName);
|
||||||
|
mkParam.setTemplateCode(param.getTemplateCode());
|
||||||
|
mkParam.setFormValues(param.getFormValues());
|
||||||
|
mkParam.setTempVarData(param.getTempVarData());
|
||||||
|
log.info("调用mk processSubmit 参数:{}", JSON.toJSONString(mkParam));
|
||||||
|
String processInstanceId = mkService.processSubmit(mkParam);
|
||||||
AssertUtils.notBlank(processInstanceId, "提交流程失败,未返回流程实例id");
|
AssertUtils.notBlank(processInstanceId, "提交流程失败,未返回流程实例id");
|
||||||
|
|
||||||
Long bizId;
|
Long bizId;
|
||||||
@@ -164,9 +181,42 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
|||||||
businessProcess.setApproveStatus(ApproveStatusEnum.APPROVING.getValue());
|
businessProcess.setApproveStatus(ApproveStatusEnum.APPROVING.getValue());
|
||||||
this.saveOrUpdate(businessProcess);
|
this.saveOrUpdate(businessProcess);
|
||||||
this.getCurrentNodes(processInstanceId, loginName);
|
this.getCurrentNodes(processInstanceId, loginName);
|
||||||
|
Object processInfo = this.getProcessInfo(processInstanceId, loginName);
|
||||||
|
this.syncBizFromProcessInfo(bizType, param.getFormInstanceId(), processInfo);
|
||||||
return processInstanceId;
|
return processInstanceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public boolean processDelete(String formInstanceId) {
|
||||||
|
AssertUtils.notBlank(formInstanceId, "表单实例id不能为空");
|
||||||
|
Long bizId;
|
||||||
|
try {
|
||||||
|
bizId = Long.valueOf(formInstanceId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new ServiceException("表单实例id格式不正确");
|
||||||
|
}
|
||||||
|
BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
|
||||||
|
.eq(BusinessProcess::getBizId, bizId)
|
||||||
|
);
|
||||||
|
if (businessProcess == null || StringUtil.isBlank(businessProcess.getProcessInstanceId())) {
|
||||||
|
log.warn("客商驳回后删除流程跳过,未找到流程实例 formInstanceId={}", formInstanceId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String loginName = businessProcess.getPromoterLoginName();
|
||||||
|
if (StringUtil.isBlank(loginName)) {
|
||||||
|
loginName = resolveCurrentUserPhone();
|
||||||
|
}
|
||||||
|
AssertUtils.notBlank(loginName, "当前用户手机号为空,无法删除审核流");
|
||||||
|
log.info("调用mk processDelete processInstanceId={} loginName={} formInstanceId={}",
|
||||||
|
businessProcess.getProcessInstanceId(), loginName, formInstanceId);
|
||||||
|
boolean deleted = mkService.processDelete(businessProcess.getProcessInstanceId(), loginName);
|
||||||
|
if (!deleted) {
|
||||||
|
throw new ServiceException("删除MK流程失败");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<?> getCurrentNodes(String processInstanceId, String loginName) {
|
public List<?> getCurrentNodes(String processInstanceId, String loginName) {
|
||||||
if (StringUtils.isBlank(processInstanceId)) {
|
if (StringUtils.isBlank(processInstanceId)) {
|
||||||
@@ -193,6 +243,120 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getProcessInfo(String processInstanceId, String loginName) {
|
||||||
|
if (StringUtils.isBlank(processInstanceId)) {
|
||||||
|
log.warn("查询流程实例详情失败,processInstanceId为空");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String resolvedLoginName = loginName;
|
||||||
|
if (StringUtils.isBlank(resolvedLoginName)) {
|
||||||
|
BusinessProcess businessProcess = this.getBusinessProcessByProcessInstanceId(processInstanceId);
|
||||||
|
resolvedLoginName = resolvePromoterLoginName(businessProcess, null);
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(resolvedLoginName)) {
|
||||||
|
log.warn("查询流程实例详情失败,loginName为空 processInstanceId={}", processInstanceId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object processInfo = mkService.getProcessInfo(processInstanceId, resolvedLoginName);
|
||||||
|
log.info("获取流程实例详情 processInstanceId={} loginName={} result={}",
|
||||||
|
processInstanceId, resolvedLoginName, JSON.toJSONString(processInfo));
|
||||||
|
return processInfo;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("查询流程实例详情异常 processInstanceId={} loginName={}", processInstanceId, resolvedLoginName, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncBizFromProcessInfo(String bizType, String formInstanceId, Object processInfo) {
|
||||||
|
if (StringUtils.isBlank(formInstanceId) || processInfo == null) {
|
||||||
|
log.warn("同步业务当前节点跳过,formInstanceId或流程实例详情为空 formInstanceId={}", formInstanceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Long bizId;
|
||||||
|
try {
|
||||||
|
bizId = Long.valueOf(formInstanceId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("同步业务当前节点失败,表单实例id不是数字:{}", formInstanceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String resolvedBizType = StringUtils.isBlank(bizType) ? "customer-archive" : bizType;
|
||||||
|
if ("customer-archive".equals(resolvedBizType)) {
|
||||||
|
this.syncCustomerArchiveFromProcessInfo(formInstanceId, processInfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MkProcessSyncDTO param = new MkProcessSyncDTO();
|
||||||
|
param.setBizType(resolvedBizType);
|
||||||
|
param.setId(bizId);
|
||||||
|
param.setAction("sync");
|
||||||
|
param.setProcessInfo(processInfo);
|
||||||
|
try {
|
||||||
|
FR<Boolean> result = mkProcessClient.apply(param);
|
||||||
|
log.info("同步业务当前节点完成 bizType={} bizId={} result={}",
|
||||||
|
resolvedBizType, bizId, JSON.toJSONString(result));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("同步业务当前节点异常 bizType={} bizId={}", resolvedBizType, bizId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncCustomerArchiveFromProcessInfo(String formInstanceId, Object processInfo) {
|
||||||
|
if (StringUtils.isBlank(formInstanceId) || processInfo == null) {
|
||||||
|
log.warn("同步客商当前节点跳过,formInstanceId或流程实例详情为空 formInstanceId={}", formInstanceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Long customerId;
|
||||||
|
try {
|
||||||
|
customerId = Long.valueOf(formInstanceId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("同步客商当前节点失败,表单实例id不是数字:{}", formInstanceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CustomerProcessNodeSyncDTO param = new CustomerProcessNodeSyncDTO();
|
||||||
|
param.setId(customerId);
|
||||||
|
param.setProcessInfo(processInfo);
|
||||||
|
param.setApprovalStatus("reviewing");
|
||||||
|
try {
|
||||||
|
FR<Boolean> result = customerArchiveClient.syncProcessNode(param);
|
||||||
|
log.info("同步客商当前节点完成 customerId={} result={}", customerId, JSON.toJSONString(result));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("同步客商当前节点异常 customerId={}", customerId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readMkNodeName(Object node) {
|
||||||
|
if (node instanceof MKNodeVO vo) {
|
||||||
|
return vo.getNodeName();
|
||||||
|
}
|
||||||
|
if (node instanceof Map<?, ?> map) {
|
||||||
|
Object value = map.get("nodeName");
|
||||||
|
return value == null ? null : String.valueOf(value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<String> readMkHandlerNames(Object node) {
|
||||||
|
List<MKNodeHandlerVO> handlers = null;
|
||||||
|
if (node instanceof MKNodeVO vo) {
|
||||||
|
handlers = vo.getNodeHandlers();
|
||||||
|
} else if (node instanceof Map<?, ?> map && map.get("nodeHandlers") instanceof List<?> list) {
|
||||||
|
return list.stream().map(item -> {
|
||||||
|
if (item instanceof MKNodeHandlerVO handler) {
|
||||||
|
return handler.getHandlerName();
|
||||||
|
}
|
||||||
|
if (item instanceof Map<?, ?> handlerMap) {
|
||||||
|
Object value = handlerMap.get("handlerName");
|
||||||
|
return value == null ? null : String.valueOf(value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (CollectionUtil.isEmpty(handlers)) {
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
return handlers.stream().map(MKNodeHandlerVO::getHandlerName);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从当前登录用户实体读取真实手机号(绕过接口返回脱敏)
|
* 从当前登录用户实体读取真实手机号(绕过接口返回脱敏)
|
||||||
*/
|
*/
|
||||||
|
|||||||
+263
-276
@@ -1,276 +1,263 @@
|
|||||||
/**
|
/**
|
||||||
* BladeX Commercial License Agreement
|
* BladeX Commercial License Agreement
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
* <p>
|
* <p>
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
* obtained after purchasing a license from BladeX.
|
* obtained after purchasing a license from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 1. This software is for development use only under a valid license
|
* 1. This software is for development use only under a valid license
|
||||||
* from BladeX.
|
* from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 2. Redistribution of this software's source code to any third party
|
* 2. Redistribution of this software's source code to any third party
|
||||||
* without a commercial license is strictly prohibited.
|
* without a commercial license is strictly prohibited.
|
||||||
* <p>
|
* <p>
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
* from this software for such purposes. Copyright of this software
|
* from this software for such purposes. Copyright of this software
|
||||||
* remains with BladeX.
|
* remains with BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* Using this software signifies agreement to this License, and the software
|
* Using this software signifies agreement to this License, and the software
|
||||||
* must not be used for illegal purposes.
|
* must not be used for illegal purposes.
|
||||||
* <p>
|
* <p>
|
||||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
* not liable for any claims arising from secondary or illegal development.
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
* <p>
|
* <p>
|
||||||
* Author: Chill Zhuang (bladejava@qq.com)
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
*/
|
*/
|
||||||
package org.springblade.system.controller;
|
package org.springblade.system.controller;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.springblade.core.boot.ctrl.BladeController;
|
import org.springblade.core.boot.ctrl.BladeController;
|
||||||
import org.springblade.core.excel.util.ExcelUtil;
|
import org.springblade.core.excel.util.ExcelUtil;
|
||||||
import org.springblade.core.mp.support.Condition;
|
import org.springblade.core.mp.support.Condition;
|
||||||
import org.springblade.core.mp.support.Query;
|
import org.springblade.core.mp.support.Query;
|
||||||
import org.springblade.core.secure.annotation.PreAuth;
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
import org.springblade.core.tenant.annotation.NonDS;
|
import org.springblade.core.tenant.annotation.NonDS;
|
||||||
import org.springblade.core.tool.api.R;
|
import org.springblade.core.tool.api.R;
|
||||||
import org.springblade.core.tool.utils.DateUtil;
|
import org.springblade.core.tool.utils.DateUtil;
|
||||||
import org.springblade.core.tool.utils.Func;
|
import org.springblade.core.tool.utils.Func;
|
||||||
import org.springblade.common.excel.ImportFailureExcelUtil;
|
import org.springblade.system.excel.PortTerminalExcel;
|
||||||
import org.springblade.system.excel.ImportFailureException;
|
import org.springblade.system.excel.PortTerminalExportExcel;
|
||||||
import org.springblade.system.excel.PortTerminalExcel;
|
import org.springblade.system.excel.PortTerminalImporter;
|
||||||
import org.springblade.system.excel.PortTerminalExportExcel;
|
import org.springblade.system.pojo.entity.PortTerminal;
|
||||||
import org.springblade.system.excel.PortTerminalImporter;
|
import org.springblade.system.pojo.vo.PortTerminalVO;
|
||||||
import org.springblade.system.pojo.entity.PortTerminal;
|
import org.springblade.system.service.IPortTerminalService;
|
||||||
import org.springblade.system.pojo.vo.PortTerminalVO;
|
import org.springblade.system.wrapper.PortTerminalWrapper;
|
||||||
import org.springblade.system.service.IPortTerminalService;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springblade.system.wrapper.PortTerminalWrapper;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.Map;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
/**
|
||||||
|
* 港口码头主数据 控制器
|
||||||
/**
|
*
|
||||||
* 港口码头主数据 控制器
|
* @author Chill
|
||||||
*
|
*/
|
||||||
* @author Chill
|
@NonDS
|
||||||
*/
|
@RestController
|
||||||
@NonDS
|
@AllArgsConstructor
|
||||||
@RestController
|
@PreAuth(menu = "port_terminal")
|
||||||
@AllArgsConstructor
|
@RequestMapping("/port-terminal")
|
||||||
@PreAuth(menu = "port_terminal")
|
@Tag(name = "港口码头主数据", description = "港口码头主数据")
|
||||||
@RequestMapping("/port-terminal")
|
public class PortTerminalController extends BladeController {
|
||||||
@Tag(name = "港口码头主数据", description = "港口码头主数据")
|
|
||||||
public class PortTerminalController extends BladeController {
|
private static final int DEFAULT_CURRENT = 1;
|
||||||
|
private static final int DEFAULT_SIZE = 10;
|
||||||
private static final int DEFAULT_CURRENT = 1;
|
private static final int MAX_SIZE = 100;
|
||||||
private static final int DEFAULT_SIZE = 10;
|
private static final String SOURCE_INITIAL = "初始化录入";
|
||||||
private static final int MAX_SIZE = 100;
|
private static final String SOURCE_INITIAL_IMPORT = "初始化导入";
|
||||||
private static final String SOURCE_INITIAL = "初始化录入";
|
private static final String SOURCE_INITIAL_OLD = "初始导入";
|
||||||
private static final String SOURCE_INITIAL_IMPORT = "初始化导入";
|
private static final String SOURCE_MANUAL = "手动录入";
|
||||||
private static final String SOURCE_INITIAL_OLD = "初始导入";
|
private static final String SOURCE_MANUAL_OLD = "手工导入";
|
||||||
private static final String SOURCE_MANUAL = "手动录入";
|
|
||||||
private static final String SOURCE_MANUAL_OLD = "手工导入";
|
private final IPortTerminalService portTerminalService;
|
||||||
|
|
||||||
private final IPortTerminalService portTerminalService;
|
/**
|
||||||
|
* 详情
|
||||||
/**
|
*/
|
||||||
* 详情
|
@GetMapping("/detail")
|
||||||
*/
|
@ApiOperationSupport(order = 1)
|
||||||
@GetMapping("/detail")
|
@Operation(summary = "详情", description = "传入portTerminal")
|
||||||
@ApiOperationSupport(order = 1)
|
public R<PortTerminalVO> detail(PortTerminal portTerminal) {
|
||||||
@Operation(summary = "详情", description = "传入portTerminal")
|
if (Func.isEmpty(portTerminal.getId())) {
|
||||||
public R<PortTerminalVO> detail(PortTerminal portTerminal) {
|
return R.fail("主键不能为空");
|
||||||
if (Func.isEmpty(portTerminal.getId())) {
|
}
|
||||||
return R.fail("主键不能为空");
|
PortTerminal detail = portTerminalService.getById(portTerminal.getId());
|
||||||
}
|
if (Func.isEmpty(detail)) {
|
||||||
PortTerminal detail = portTerminalService.getById(portTerminal.getId());
|
return R.fail("港口码头不存在");
|
||||||
if (Func.isEmpty(detail)) {
|
}
|
||||||
return R.fail("港口码头不存在");
|
detail.setDataSource(normalizeDataSource(detail.getDataSource()));
|
||||||
}
|
return R.data(PortTerminalWrapper.build().entityVO(detail));
|
||||||
detail.setDataSource(normalizeDataSource(detail.getDataSource()));
|
}
|
||||||
return R.data(PortTerminalWrapper.build().entityVO(detail));
|
|
||||||
}
|
/**
|
||||||
|
* 分页
|
||||||
/**
|
*/
|
||||||
* 分页
|
@GetMapping("/list")
|
||||||
*/
|
@ApiOperationSupport(order = 2)
|
||||||
@GetMapping("/list")
|
@Operation(summary = "分页", description = "传入portTerminal")
|
||||||
@ApiOperationSupport(order = 2)
|
public R<IPage<PortTerminalVO>> list(PortTerminalVO portTerminal, Query query) {
|
||||||
@Operation(summary = "分页", description = "传入portTerminal")
|
IPage<PortTerminalVO> pages = portTerminalService.selectPortTerminalPage(Condition.getPage(normalizeQuery(query)), portTerminal);
|
||||||
public R<IPage<PortTerminalVO>> list(PortTerminalVO portTerminal, Query query) {
|
return R.data(pages);
|
||||||
IPage<PortTerminalVO> pages = portTerminalService.selectPortTerminalPage(Condition.getPage(normalizeQuery(query)), portTerminal);
|
}
|
||||||
return R.data(pages);
|
|
||||||
}
|
/**
|
||||||
|
* 新增或修改
|
||||||
/**
|
*/
|
||||||
* 新增或修改
|
@PostMapping("/submit")
|
||||||
*/
|
@ApiOperationSupport(order = 3)
|
||||||
@PostMapping("/submit")
|
@Operation(summary = "新增或修改", description = "传入portTerminal")
|
||||||
@ApiOperationSupport(order = 3)
|
public R submit(@Valid @RequestBody PortTerminal portTerminal) {
|
||||||
@Operation(summary = "新增或修改", description = "传入portTerminal")
|
return R.status(portTerminalService.submit(portTerminal));
|
||||||
public R submit(@Valid @RequestBody PortTerminal portTerminal) {
|
}
|
||||||
return R.status(portTerminalService.submit(portTerminal));
|
|
||||||
}
|
/**
|
||||||
|
* 删除
|
||||||
/**
|
*/
|
||||||
* 删除
|
@PostMapping("/remove")
|
||||||
*/
|
@ApiOperationSupport(order = 4)
|
||||||
@PostMapping("/remove")
|
@Operation(summary = "逻辑删除", description = "传入ids")
|
||||||
@ApiOperationSupport(order = 4)
|
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
|
||||||
@Operation(summary = "逻辑删除", description = "传入ids")
|
if (Func.isEmpty(ids)) {
|
||||||
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
|
return R.fail("主键不能为空");
|
||||||
if (Func.isEmpty(ids)) {
|
}
|
||||||
return R.fail("主键不能为空");
|
return R.status(portTerminalService.deleteLogic(Func.toLongList(ids)));
|
||||||
}
|
}
|
||||||
return R.status(portTerminalService.deleteLogic(Func.toLongList(ids)));
|
|
||||||
}
|
/**
|
||||||
|
* 启用或停用
|
||||||
/**
|
*/
|
||||||
* 启用或停用
|
@PostMapping("/status")
|
||||||
*/
|
@ApiOperationSupport(order = 5)
|
||||||
@PostMapping("/status")
|
@Operation(summary = "启用或停用", description = "传入id和status")
|
||||||
@ApiOperationSupport(order = 5)
|
public R status(@Parameter(description = "主键", required = true) @RequestParam Long id,
|
||||||
@Operation(summary = "启用或停用", description = "传入id和status")
|
@Parameter(description = "状态", required = true) @RequestParam Integer status) {
|
||||||
public R status(@Parameter(description = "主键", required = true) @RequestParam Long id,
|
return R.status(portTerminalService.changeStatus(id, status));
|
||||||
@Parameter(description = "状态", required = true) @RequestParam Integer status) {
|
}
|
||||||
return R.status(portTerminalService.changeStatus(id, status));
|
|
||||||
}
|
/**
|
||||||
|
* 上级港口下拉数据源
|
||||||
/**
|
*/
|
||||||
* 上级港口下拉数据源
|
@GetMapping("/port-select")
|
||||||
*/
|
@ApiOperationSupport(order = 6)
|
||||||
@GetMapping("/port-select")
|
@Operation(summary = "上级港口下拉数据源")
|
||||||
@ApiOperationSupport(order = 6)
|
public R<List<PortTerminal>> portSelect() {
|
||||||
@Operation(summary = "上级港口下拉数据源")
|
List<PortTerminal> ports = portTerminalService.selectEnabledPorts();
|
||||||
public R<List<PortTerminal>> portSelect() {
|
ports.forEach(port -> port.setDataSource(normalizeDataSource(port.getDataSource())));
|
||||||
List<PortTerminal> ports = portTerminalService.selectEnabledPorts();
|
return R.data(ports);
|
||||||
ports.forEach(port -> port.setDataSource(normalizeDataSource(port.getDataSource())));
|
}
|
||||||
return R.data(ports);
|
|
||||||
}
|
/**
|
||||||
|
* 导入港口码头主数据
|
||||||
/**
|
*/
|
||||||
* 导入港口码头主数据
|
@PostMapping("/import-port-terminal")
|
||||||
*/
|
@ApiOperationSupport(order = 7)
|
||||||
@PostMapping("/import-port-terminal")
|
@Operation(summary = "导入港口码头主数据", description = "传入excel")
|
||||||
@ApiOperationSupport(order = 7)
|
public R importPortTerminal(MultipartFile file, HttpServletResponse response) {
|
||||||
@Operation(summary = "导入港口码头主数据", description = "传入excel")
|
if (file == null || file.isEmpty()) {
|
||||||
public R importPortTerminal(MultipartFile file, HttpServletResponse response) {
|
return R.fail("上传文件不能为空");
|
||||||
if (file == null || file.isEmpty()) {
|
}
|
||||||
return R.fail("上传文件不能为空");
|
String fileName = Func.toStrWithEmpty(file.getOriginalFilename(), "").toLowerCase();
|
||||||
}
|
if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
|
||||||
String fileName = Func.toStrWithEmpty(file.getOriginalFilename(), "").toLowerCase();
|
return R.fail("请上传 .xls,.xlsx 标准格式文件");
|
||||||
if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
|
}
|
||||||
return R.fail("请上传 .xls,.xlsx 标准格式文件");
|
List<PortTerminalExcel> failureList = portTerminalService.importPortTerminal(ExcelUtil.read(file, PortTerminalExcel.class));
|
||||||
}
|
if (Func.isNotEmpty(failureList)) {
|
||||||
try {
|
org.springblade.common.excel.ImportFailureExcelUtil.exportFailureReasonOnly(response, "港口码头主数据导入失败明细" + DateUtil.time(), "导入失败明细", failureList, PortTerminalExcel.class);
|
||||||
portTerminalService.importPortTerminal(ExcelUtil.read(file, PortTerminalExcel.class));
|
return null;
|
||||||
} catch (ImportFailureException exception) {
|
}
|
||||||
// 全失败即整批回滚,导出原表全部数据并标注错误,用户修正后重新导入。
|
return R.success("操作成功");
|
||||||
exportFailure(response, exception.getFailureList());
|
}
|
||||||
return null;
|
|
||||||
}
|
/**
|
||||||
return R.success("操作成功");
|
* 导出港口码头主数据
|
||||||
}
|
*/
|
||||||
|
@GetMapping("/export-port-terminal")
|
||||||
/**
|
@ApiOperationSupport(order = 8)
|
||||||
* 导出导入失败明细,内容为原表全部数据并在末尾追加失败原因列。
|
@Operation(summary = "导出港口码头主数据")
|
||||||
* <p>
|
public void exportPortTerminal(@Parameter(hidden = true) @RequestParam Map<String, Object> portTerminal, HttpServletResponse response) {
|
||||||
* 失败数据仅标红出错单元格与失败原因列,表头保持默认样式。
|
Object ids = portTerminal.remove("ids");
|
||||||
*/
|
Object dataSource = portTerminal.remove("dataSource");
|
||||||
private void exportFailure(HttpServletResponse response, List<?> failureList) {
|
portTerminal.remove("Blade-Auth");
|
||||||
ImportFailureExcelUtil.exportFailureReasonOnly(response, "港口码头主数据导入失败明细" + DateUtil.time(), "导入失败明细", failureList, PortTerminalExcel.class);
|
portTerminal.remove("Authorization");
|
||||||
}
|
portTerminal.remove("access_token");
|
||||||
|
normalizeRegionCodeCondition(portTerminal);
|
||||||
/**
|
QueryWrapper<PortTerminal> queryWrapper = Condition.getQueryWrapper(portTerminal, PortTerminal.class);
|
||||||
* 导出港口码头主数据
|
applyDataSourceCondition(queryWrapper, dataSource);
|
||||||
*/
|
if (Func.isNotEmpty(ids)) {
|
||||||
@GetMapping("/export-port-terminal")
|
queryWrapper.lambda().in(PortTerminal::getId, Func.toLongList(ids.toString()));
|
||||||
@ApiOperationSupport(order = 8)
|
}
|
||||||
@Operation(summary = "导出港口码头主数据")
|
List<PortTerminalExportExcel> list = portTerminalService.exportPortTerminal(queryWrapper);
|
||||||
public void exportPortTerminal(@Parameter(hidden = true) @RequestParam Map<String, Object> portTerminal, HttpServletResponse response) {
|
ExcelUtil.export(response, "港口码头主数据" + DateUtil.time(), "港口码头主数据表", list, PortTerminalExportExcel.class);
|
||||||
Object ids = portTerminal.remove("ids");
|
}
|
||||||
Object dataSource = portTerminal.remove("dataSource");
|
|
||||||
portTerminal.remove("Blade-Auth");
|
/**
|
||||||
portTerminal.remove("Authorization");
|
* 导出模板
|
||||||
portTerminal.remove("access_token");
|
*/
|
||||||
normalizeRegionCodeCondition(portTerminal);
|
@GetMapping("/export-template")
|
||||||
QueryWrapper<PortTerminal> queryWrapper = Condition.getQueryWrapper(portTerminal, PortTerminal.class);
|
@ApiOperationSupport(order = 9)
|
||||||
applyDataSourceCondition(queryWrapper, dataSource);
|
@Operation(summary = "导出模板")
|
||||||
if (Func.isNotEmpty(ids)) {
|
public void exportTemplate(HttpServletResponse response) {
|
||||||
queryWrapper.lambda().in(PortTerminal::getId, Func.toLongList(ids.toString()));
|
List<PortTerminalExcel> list = new ArrayList<>();
|
||||||
}
|
ExcelUtil.export(response, "港口码头主数据模板", "港口码头主数据表", list, PortTerminalExcel.class);
|
||||||
List<PortTerminalExportExcel> list = portTerminalService.exportPortTerminal(queryWrapper);
|
}
|
||||||
ExcelUtil.export(response, "港口码头主数据" + DateUtil.time(), "港口码头主数据表", list, PortTerminalExportExcel.class);
|
|
||||||
}
|
private Query normalizeQuery(Query query) {
|
||||||
|
if (query == null) {
|
||||||
/**
|
query = new Query();
|
||||||
* 导出模板
|
}
|
||||||
*/
|
if (query.getCurrent() == null || query.getCurrent() < DEFAULT_CURRENT) {
|
||||||
@GetMapping("/export-template")
|
query.setCurrent(DEFAULT_CURRENT);
|
||||||
@ApiOperationSupport(order = 9)
|
}
|
||||||
@Operation(summary = "导出模板")
|
if (query.getSize() == null || query.getSize() <= 0) {
|
||||||
public void exportTemplate(HttpServletResponse response) {
|
query.setSize(DEFAULT_SIZE);
|
||||||
List<PortTerminalExcel> list = new ArrayList<>();
|
}
|
||||||
ExcelUtil.export(response, "港口码头主数据模板", "港口码头主数据表", list, PortTerminalExcel.class);
|
if (query.getSize() > MAX_SIZE) {
|
||||||
}
|
query.setSize(MAX_SIZE);
|
||||||
|
}
|
||||||
private Query normalizeQuery(Query query) {
|
return query;
|
||||||
if (query == null) {
|
}
|
||||||
query = new Query();
|
|
||||||
}
|
private void normalizeRegionCodeCondition(Map<String, Object> params) {
|
||||||
if (query.getCurrent() == null || query.getCurrent() < DEFAULT_CURRENT) {
|
Object regionCode = params.remove("regionCode");
|
||||||
query.setCurrent(DEFAULT_CURRENT);
|
if (Func.isNotEmpty(regionCode) && Func.isEmpty(params.get("districtCode"))) {
|
||||||
}
|
params.put("districtCode", regionCode);
|
||||||
if (query.getSize() == null || query.getSize() <= 0) {
|
}
|
||||||
query.setSize(DEFAULT_SIZE);
|
}
|
||||||
}
|
|
||||||
if (query.getSize() > MAX_SIZE) {
|
private void applyDataSourceCondition(QueryWrapper<PortTerminal> queryWrapper, Object dataSource) {
|
||||||
query.setSize(MAX_SIZE);
|
String value = Func.toStrWithEmpty(dataSource, "");
|
||||||
}
|
if (Func.isEmpty(value)) {
|
||||||
return query;
|
return;
|
||||||
}
|
}
|
||||||
|
if (SOURCE_INITIAL.equals(value)) {
|
||||||
private void normalizeRegionCodeCondition(Map<String, Object> params) {
|
queryWrapper.in("data_source", SOURCE_INITIAL, SOURCE_INITIAL_IMPORT, SOURCE_INITIAL_OLD);
|
||||||
Object regionCode = params.remove("regionCode");
|
} else if (SOURCE_MANUAL.equals(value)) {
|
||||||
if (Func.isNotEmpty(regionCode) && Func.isEmpty(params.get("districtCode"))) {
|
queryWrapper.in("data_source", SOURCE_MANUAL, SOURCE_MANUAL_OLD);
|
||||||
params.put("districtCode", regionCode);
|
} else {
|
||||||
}
|
queryWrapper.eq("data_source", value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private void applyDataSourceCondition(QueryWrapper<PortTerminal> queryWrapper, Object dataSource) {
|
|
||||||
String value = Func.toStrWithEmpty(dataSource, "");
|
private String normalizeDataSource(String dataSource) {
|
||||||
if (Func.isEmpty(value)) {
|
if (SOURCE_INITIAL_IMPORT.equals(dataSource) || SOURCE_INITIAL_OLD.equals(dataSource)) {
|
||||||
return;
|
return SOURCE_INITIAL;
|
||||||
}
|
}
|
||||||
if (SOURCE_INITIAL.equals(value)) {
|
return SOURCE_MANUAL_OLD.equals(dataSource) ? SOURCE_MANUAL : dataSource;
|
||||||
queryWrapper.in("data_source", SOURCE_INITIAL, SOURCE_INITIAL_IMPORT, SOURCE_INITIAL_OLD);
|
}
|
||||||
} else if (SOURCE_MANUAL.equals(value)) {
|
|
||||||
queryWrapper.in("data_source", SOURCE_MANUAL, SOURCE_MANUAL_OLD);
|
}
|
||||||
} else {
|
|
||||||
queryWrapper.eq("data_source", value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String normalizeDataSource(String dataSource) {
|
|
||||||
if (SOURCE_INITIAL_IMPORT.equals(dataSource) || SOURCE_INITIAL_OLD.equals(dataSource)) {
|
|
||||||
return SOURCE_INITIAL;
|
|
||||||
}
|
|
||||||
return SOURCE_MANUAL_OLD.equals(dataSource) ? SOURCE_MANUAL : dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
+5
-4
@@ -35,6 +35,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 币种汇率 Excel
|
* 币种汇率 Excel
|
||||||
@@ -61,8 +62,8 @@ public class CurrencyExcel implements Serializable {
|
|||||||
@ExcelProperty("汇率")
|
@ExcelProperty("汇率")
|
||||||
private BigDecimal exchangeRate;
|
private BigDecimal exchangeRate;
|
||||||
|
|
||||||
@ExcelProperty(value = "生效日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("生效日期")
|
||||||
private String effectiveDate;
|
private LocalDate effectiveDate;
|
||||||
|
|
||||||
@ExcelProperty("状态")
|
@ExcelProperty("状态")
|
||||||
private String statusName;
|
private String statusName;
|
||||||
@@ -70,8 +71,8 @@ public class CurrencyExcel implements Serializable {
|
|||||||
@ExcelProperty("来源")
|
@ExcelProperty("来源")
|
||||||
private String dataSource;
|
private String dataSource;
|
||||||
|
|
||||||
@ExcelProperty(value = "失效日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("失效日期")
|
||||||
private String expiryDate;
|
private LocalDate expiryDate;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
-60
@@ -1,60 +0,0 @@
|
|||||||
/**
|
|
||||||
* BladeX Commercial License Agreement
|
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
|
||||||
* <p>
|
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
|
||||||
* obtained after purchasing a license from BladeX.
|
|
||||||
* <p>
|
|
||||||
* 1. This software is for development use only under a valid license
|
|
||||||
* from BladeX.
|
|
||||||
* <p>
|
|
||||||
* 2. Redistribution of this software's source code to any third party
|
|
||||||
* without a commercial license is strictly prohibited.
|
|
||||||
* <p>
|
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
|
||||||
* from this software for such purposes. Copyright of this software
|
|
||||||
* remains with BladeX.
|
|
||||||
* <p>
|
|
||||||
* Using this software signifies agreement to this License, and the software
|
|
||||||
* must not be used for illegal purposes.
|
|
||||||
* <p>
|
|
||||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
|
||||||
* not liable for any claims arising from secondary or illegal development.
|
|
||||||
* <p>
|
|
||||||
* Author: Chill Zhuang (bladejava@qq.com)
|
|
||||||
*/
|
|
||||||
package org.springblade.system.excel;
|
|
||||||
|
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导入失败异常,携带失败明细用于导出原表并标注错误。
|
|
||||||
* <p>
|
|
||||||
* 批量导入采用「全失败即整批回滚」语义:任一行校验失败都会抛出本异常触发事务回滚,
|
|
||||||
* 失败明细在抛异常前已收集完毕,因此回滚不影响明细的内容。
|
|
||||||
*
|
|
||||||
* @author Chill
|
|
||||||
*/
|
|
||||||
public class ImportFailureException extends ServiceException {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 失败明细,包含原表全部数据,错误行已标注错误原因。
|
|
||||||
*/
|
|
||||||
private final transient List<?> failureList;
|
|
||||||
|
|
||||||
public ImportFailureException(List<?> failureList) {
|
|
||||||
super("导入失败,已回滚全部数据");
|
|
||||||
this.failureList = failureList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<?> getFailureList() {
|
|
||||||
return failureList;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+3
-2
@@ -34,6 +34,7 @@ import lombok.Data;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UserExcel
|
* UserExcel
|
||||||
@@ -101,7 +102,7 @@ public class UserExcel implements Serializable {
|
|||||||
private String postName;
|
private String postName;
|
||||||
|
|
||||||
@ColumnWidth(20)
|
@ColumnWidth(20)
|
||||||
@ExcelProperty(value = "生日", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("生日")
|
||||||
private String birthday;
|
private Date birthday;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -95,7 +95,7 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="exportUser" resultType="org.springblade.system.excel.UserExcel">
|
<select id="exportUser" resultType="org.springblade.system.excel.UserExcel">
|
||||||
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}
|
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>
|
</select>
|
||||||
|
|
||||||
<select id="selectCustomerOptions" resultType="java.util.HashMap">
|
<select id="selectCustomerOptions" resultType="java.util.HashMap">
|
||||||
|
|||||||
-2
@@ -125,8 +125,6 @@ public class CurrencyServiceImpl extends BaseServiceImpl<CurrencyMapper, Currenc
|
|||||||
CurrencyExcel excel = data.get(index);
|
CurrencyExcel excel = data.get(index);
|
||||||
try {
|
try {
|
||||||
Currency currency = Objects.requireNonNull(BeanUtil.copyProperties(excel, Currency.class));
|
Currency currency = Objects.requireNonNull(BeanUtil.copyProperties(excel, Currency.class));
|
||||||
currency.setEffectiveDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getEffectiveDate(), "生效日期"));
|
|
||||||
currency.setExpiryDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getExpiryDate(), "失效日期"));
|
|
||||||
currency.setDataSource(SOURCE_BATCH);
|
currency.setDataSource(SOURCE_BATCH);
|
||||||
currency.setStatus(STATUS_ENABLED);
|
currency.setStatus(STATUS_ENABLED);
|
||||||
prepare(currency, SOURCE_BATCH);
|
prepare(currency, SOURCE_BATCH);
|
||||||
|
|||||||
+694
-640
File diff suppressed because it is too large
Load Diff
-3
@@ -689,9 +689,6 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
|
|||||||
*/
|
*/
|
||||||
private User buildImportUser(UserExcel userExcel, String tenantId) {
|
private User buildImportUser(UserExcel userExcel, String tenantId) {
|
||||||
User user = Objects.requireNonNull(BeanUtil.copyProperties(userExcel, User.class));
|
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.setTenantId(tenantId);
|
||||||
user.setUserType(Func.toInt(DictCache.getKey(DictEnum.USER_TYPE, userExcel.getUserTypeName()), 1));
|
user.setUserType(Func.toInt(DictCache.getKey(DictEnum.USER_TYPE, userExcel.getUserTypeName()), 1));
|
||||||
user.setDeptId(Func.toStrWithEmpty(SysCache.getDeptIds(tenantId, userExcel.getDeptName()), StringPool.EMPTY));
|
user.setDeptId(Func.toStrWithEmpty(SysCache.getDeptIds(tenantId, userExcel.getDeptName()), StringPool.EMPTY));
|
||||||
|
|||||||
-6
@@ -6,20 +6,14 @@ package org.springblade.transport.config;
|
|||||||
|
|
||||||
import io.minio.MinioClient;
|
import io.minio.MinioClient;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 凭证图片 MinIO 客户端配置。
|
* 凭证图片 MinIO 客户端配置。
|
||||||
* <p>
|
|
||||||
* 连接参数由 Nacos 的 file.storage.minio 配置提供。
|
* 连接参数由 Nacos 的 file.storage.minio 配置提供。
|
||||||
* 未配置 {@code file.storage.minio.endpoint} 时不注册该客户端,
|
|
||||||
* 以免凭证上传功能缺失配置导致整个 blade-transport 服务无法启动;
|
|
||||||
* 此时凭证相关接口会在调用时给出明确提示,而非启动即失败。
|
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnProperty(prefix = "file.storage.minio", name = "endpoint")
|
|
||||||
public class VoucherMinioConfig {
|
public class VoucherMinioConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
+5
-55
@@ -35,13 +35,11 @@ import org.springblade.core.mp.support.Query;
|
|||||||
import org.springblade.core.secure.annotation.PreAuth;
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
import org.springblade.core.secure.constant.AuthConstant;
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
import org.springblade.core.tenant.annotation.TenantIgnore;
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
import org.springblade.core.tool.api.FR;
|
|
||||||
import org.springblade.core.tool.api.R;
|
import org.springblade.core.tool.api.R;
|
||||||
import org.springblade.core.tool.utils.StringUtil;
|
|
||||||
import org.springblade.process.feign.IBusinessProcessClient;
|
|
||||||
import org.springblade.transport.pojo.vo.CustomerArchiveVO;
|
import org.springblade.transport.pojo.vo.CustomerArchiveVO;
|
||||||
import org.springblade.transport.pojo.vo.CustomerChangeRecordVO;
|
import org.springblade.transport.pojo.vo.CustomerChangeRecordVO;
|
||||||
import org.springblade.transport.service.ICustomerArchiveService;
|
import org.springblade.transport.service.ICustomerArchiveService;
|
||||||
|
import org.springblade.transport.service.impl.CustomerArchivePublicProcessService;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
@@ -49,8 +47,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,7 +64,7 @@ import java.util.Map;
|
|||||||
public class CustomerArchivePublicController {
|
public class CustomerArchivePublicController {
|
||||||
|
|
||||||
private final ICustomerArchiveService customerArchiveService;
|
private final ICustomerArchiveService customerArchiveService;
|
||||||
private final IBusinessProcessClient businessProcessClient;
|
private final CustomerArchivePublicProcessService customerArchivePublicProcessService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 公开详情
|
* 公开详情
|
||||||
@@ -92,61 +88,15 @@ public class CustomerArchivePublicController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 公开接收流程页 postMessage 数据(当前仅打印,便于联调)
|
* 公开接收流程页 postMessage 数据
|
||||||
*/
|
*/
|
||||||
@PostMapping("/process-message")
|
@PostMapping("/process-message")
|
||||||
@ApiOperationSupport(order = 3)
|
@ApiOperationSupport(order = 3)
|
||||||
@Operation(summary = "公开接收流程消息", description = "无需登录,接收后查询当前节点并打印")
|
@Operation(summary = "公开接收流程消息", description = "无需登录,立即查询当前节点,5秒后查询流程实例详情并同步客商")
|
||||||
public R processMessage(@RequestBody Map<String, Object> body) {
|
public R processMessage(@RequestBody Map<String, Object> body) {
|
||||||
log.info("客商公开页收到流程消息:{}", JSON.toJSONString(body));
|
log.info("客商公开页收到流程消息:{}", JSON.toJSONString(body));
|
||||||
Map<String, Object> formValues = asMap(body == null ? null : body.get("formValues"));
|
customerArchivePublicProcessService.handleProcessMessage(body);
|
||||||
String processId = firstText(formValues, "processId");
|
|
||||||
if (StringUtil.isBlank(processId) && body != null) {
|
|
||||||
processId = firstText(body, "processId");
|
|
||||||
}
|
|
||||||
String loginName = firstText(formValues, "mkLoginName", "loginName");
|
|
||||||
if (StringUtil.isBlank(processId)) {
|
|
||||||
log.warn("客商公开页流程消息未找到 processId,跳过查询当前节点");
|
|
||||||
return R.success("ok");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
FR<Object> result = businessProcessClient.getCurrentNodes(processId, loginName);
|
|
||||||
log.info("客商公开页流程消息当前节点详情 processId={} loginName={} result={}",
|
|
||||||
processId, loginName, JSON.toJSONString(result == null ? null : result.getData()));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("客商公开页查询当前节点失败 processId={} loginName={}", processId, loginName, e);
|
|
||||||
}
|
|
||||||
return R.success("ok");
|
return R.success("ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, Object> asMap(Object value) {
|
|
||||||
if (!(value instanceof Map<?, ?> map)) {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
Map<String, Object> result = new HashMap<>();
|
|
||||||
map.forEach((key, nested) -> {
|
|
||||||
if (key != null) {
|
|
||||||
result.put(String.valueOf(key), nested);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String firstText(Map<String, Object> source, String... keys) {
|
|
||||||
if (source == null || keys == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (String key : keys) {
|
|
||||||
Object value = source.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String text = String.valueOf(value).trim();
|
|
||||||
if (StringUtil.isNotBlank(text) && !"null".equalsIgnoreCase(text)) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
package org.springblade.transport.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.R;
|
||||||
|
import org.springblade.transport.mk.MkProcessMessageService;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 业务流程公开查看
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
@TenantIgnore
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@RequestMapping("/mk-process/public")
|
||||||
|
@Tag(name = "MK业务流程公开查看", description = "MK业务流程公开查看")
|
||||||
|
public class MkProcessPublicController {
|
||||||
|
|
||||||
|
private final MkProcessMessageService mkProcessMessageService;
|
||||||
|
|
||||||
|
@GetMapping("/{bizType}/detail")
|
||||||
|
@ApiOperationSupport(order = 1)
|
||||||
|
@Operation(summary = "公开详情", description = "无需登录")
|
||||||
|
public R detail(@PathVariable String bizType,
|
||||||
|
@Parameter(description = "主键", required = true) @RequestParam Long id) {
|
||||||
|
return R.data(mkProcessMessageService.handler(bizType).publicDetail(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{bizType}/process-message")
|
||||||
|
@ApiOperationSupport(order = 2)
|
||||||
|
@Operation(summary = "公开接收流程消息", description = "无需登录,立即查询当前节点,5秒后查询流程实例详情并同步业务")
|
||||||
|
public R processMessage(@PathVariable String bizType, @RequestBody Map<String, Object> body) {
|
||||||
|
log.info("公开页收到流程消息 bizType={} body={}", bizType, JSON.toJSONString(body));
|
||||||
|
mkProcessMessageService.handleProcessMessage(bizType, body);
|
||||||
|
return R.success("ok");
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-20
@@ -52,7 +52,6 @@ import org.springblade.transport.pojo.entity.Waybill;
|
|||||||
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
||||||
import org.springblade.transport.pojo.vo.ProcessConfigVO;
|
import org.springblade.transport.pojo.vo.ProcessConfigVO;
|
||||||
import org.springblade.transport.service.IProcessConfigService;
|
import org.springblade.transport.service.IProcessConfigService;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@@ -84,34 +83,20 @@ public class ProcessConfigController extends BladeController {
|
|||||||
private final VoucherFileMapper voucherFileMapper;
|
private final VoucherFileMapper voucherFileMapper;
|
||||||
private final VoucherImageMapper voucherImageMapper;
|
private final VoucherImageMapper voucherImageMapper;
|
||||||
private final VoucherManageMapper voucherManageMapper;
|
private final VoucherManageMapper voucherManageMapper;
|
||||||
private final ObjectProvider<MinioClient> minioClientProvider;
|
private final MinioClient minioClient;
|
||||||
@Value("${file.storage.minio.bucket-name:${minio.bucket-name:}}")
|
@Value("${file.storage.minio.bucket-name:${minio.bucket-name:}}")
|
||||||
private String minioBucketName;
|
private String minioBucketName;
|
||||||
|
|
||||||
public ProcessConfigController(IProcessConfigService processConfigService, WaybillMapper waybillMapper,
|
public ProcessConfigController(IProcessConfigService processConfigService, WaybillMapper waybillMapper,
|
||||||
VoucherFileMapper voucherFileMapper, VoucherImageMapper voucherImageMapper,
|
VoucherFileMapper voucherFileMapper, VoucherImageMapper voucherImageMapper,
|
||||||
VoucherManageMapper voucherManageMapper,
|
VoucherManageMapper voucherManageMapper,
|
||||||
ObjectProvider<MinioClient> minioClientProvider) {
|
MinioClient minioClient) {
|
||||||
this.processConfigService = processConfigService;
|
this.processConfigService = processConfigService;
|
||||||
this.waybillMapper = waybillMapper;
|
this.waybillMapper = waybillMapper;
|
||||||
this.voucherFileMapper = voucherFileMapper;
|
this.voucherFileMapper = voucherFileMapper;
|
||||||
this.voucherImageMapper = voucherImageMapper;
|
this.voucherImageMapper = voucherImageMapper;
|
||||||
this.voucherManageMapper = voucherManageMapper;
|
this.voucherManageMapper = voucherManageMapper;
|
||||||
this.minioClientProvider = minioClientProvider;
|
this.minioClient = minioClient;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 MinIO 客户端。
|
|
||||||
* <p>
|
|
||||||
* 未配置 file.storage.minio.endpoint 时该客户端不会被注册,
|
|
||||||
* 此时凭证预览地址无法生成,抛出明确提示而非启动即失败。
|
|
||||||
*/
|
|
||||||
private MinioClient minioClient() {
|
|
||||||
MinioClient minioClient = minioClientProvider.getIfAvailable();
|
|
||||||
if (minioClient == null) {
|
|
||||||
throw new IllegalStateException("Nacos 未配置 file.storage.minio.endpoint,凭证文件功能不可用");
|
|
||||||
}
|
|
||||||
return minioClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/detail")
|
@GetMapping("/detail")
|
||||||
@@ -162,7 +147,7 @@ public class ProcessConfigController extends BladeController {
|
|||||||
result.put("waybillNo", image.getWaybillNo());
|
result.put("waybillNo", image.getWaybillNo());
|
||||||
result.put("objectKey", image.getObjectKey());
|
result.put("objectKey", image.getObjectKey());
|
||||||
try {
|
try {
|
||||||
result.put("url", minioClient().getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
|
result.put("url", minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
|
||||||
.method(Method.GET).bucket(minioBucketName).object(image.getObjectKey())
|
.method(Method.GET).bucket(minioBucketName).object(image.getObjectKey())
|
||||||
.expiry(1, TimeUnit.HOURS).build()));
|
.expiry(1, TimeUnit.HOURS).build()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -285,7 +270,7 @@ public class ProcessConfigController extends BladeController {
|
|||||||
result.put("objectKey", image.objectKey());
|
result.put("objectKey", image.objectKey());
|
||||||
result.put("matched", image.matched());
|
result.put("matched", image.matched());
|
||||||
try {
|
try {
|
||||||
result.put("url", minioClient().getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
|
result.put("url", minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
|
||||||
.method(Method.GET).bucket(minioBucketName).object(image.objectKey())
|
.method(Method.GET).bucket(minioBucketName).object(image.objectKey())
|
||||||
.expiry(1, TimeUnit.HOURS).build()));
|
.expiry(1, TimeUnit.HOURS).build()));
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
|
|||||||
+1
-1
@@ -105,7 +105,7 @@ public class ProjectApplyController extends BladeController {
|
|||||||
@ApiOperationSupport(order = 4)
|
@ApiOperationSupport(order = 4)
|
||||||
@Operation(summary = "新增或修改", description = "传入projectApply")
|
@Operation(summary = "新增或修改", description = "传入projectApply")
|
||||||
public R submit(@RequestBody ProjectApply projectApply) {
|
public R submit(@RequestBody ProjectApply projectApply) {
|
||||||
return R.status(projectApplyService.submit(projectApply));
|
return projectApplyService.submit(projectApply) ? R.data(projectApply) : R.fail("保存失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/submit-approval")
|
@PostMapping("/submit-approval")
|
||||||
|
|||||||
+1
-1
@@ -213,7 +213,7 @@ public class WaybillController extends BladeController {
|
|||||||
@ApiOperationSupport(order = 9)
|
@ApiOperationSupport(order = 9)
|
||||||
@Operation(summary = "新增或修改", description = "传入waybill")
|
@Operation(summary = "新增或修改", description = "传入waybill")
|
||||||
public R submit(@RequestBody Waybill waybill) {
|
public R submit(@RequestBody Waybill waybill) {
|
||||||
return R.status(waybillService.submit(waybill));
|
return waybillService.submit(waybill) ? R.data(waybill) : R.fail("保存失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/save-draft")
|
@PostMapping("/save-draft")
|
||||||
|
|||||||
+3
-2
@@ -36,6 +36,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事故记录 Excel
|
* 事故记录 Excel
|
||||||
@@ -59,8 +60,8 @@ public class AccidentRecordExcel implements Serializable {
|
|||||||
@ExcelProperty("*车牌号/船号")
|
@ExcelProperty("*车牌号/船号")
|
||||||
private String vehicleNo;
|
private String vehicleNo;
|
||||||
|
|
||||||
@ExcelProperty(value = "*事故发生日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("*事故发生日期")
|
||||||
private String accidentDate;
|
private LocalDate accidentDate;
|
||||||
|
|
||||||
@ExcelProperty("事故发生地点")
|
@ExcelProperty("事故发生地点")
|
||||||
private String accidentLocation;
|
private String accidentLocation;
|
||||||
|
|||||||
+3
-3
@@ -37,7 +37,7 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事故记录导出 Excel
|
* 事故记录导出 Excel
|
||||||
@@ -83,14 +83,14 @@ public class AccidentRecordExportExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+5
-4
@@ -35,6 +35,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 年检记录 Excel
|
* 年检记录 Excel
|
||||||
@@ -58,11 +59,11 @@ public class AnnualInspectionRecordExcel implements Serializable {
|
|||||||
@ExcelProperty("*车牌号/船号")
|
@ExcelProperty("*车牌号/船号")
|
||||||
private String vehicleNo;
|
private String vehicleNo;
|
||||||
|
|
||||||
@ExcelProperty(value = "*检测评定日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("*检测评定日期")
|
||||||
private String inspectionAssessmentDate;
|
private LocalDate inspectionAssessmentDate;
|
||||||
|
|
||||||
@ExcelProperty(value = "*有效期截止日", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("*有效期截止日")
|
||||||
private String validUntilDate;
|
private LocalDate validUntilDate;
|
||||||
|
|
||||||
@ExcelProperty("*车辆技术等级")
|
@ExcelProperty("*车辆技术等级")
|
||||||
private String vehicleTechnicalLevel;
|
private String vehicleTechnicalLevel;
|
||||||
|
|||||||
+3
-3
@@ -36,7 +36,7 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 年检记录导出 Excel
|
* 年检记录导出 Excel
|
||||||
@@ -83,14 +83,14 @@ public class AnnualInspectionRecordExportExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+96
-99
@@ -1,99 +1,96 @@
|
|||||||
/**
|
/**
|
||||||
* BladeX Commercial License Agreement
|
* BladeX Commercial License Agreement
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
* <p>
|
* <p>
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
* obtained after purchasing a license from BladeX.
|
* obtained after purchasing a license from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 1. This software is for development use only under a valid license
|
* 1. This software is for development use only under a valid license
|
||||||
* from BladeX.
|
* from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 2. Redistribution of this software's source code to any third party
|
* 2. Redistribution of this software's source code to any third party
|
||||||
* without a commercial license is strictly prohibited.
|
* without a commercial license is strictly prohibited.
|
||||||
* <p>
|
* <p>
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
* from this software for such purposes. Copyright of this software
|
* from this software for such purposes. Copyright of this software
|
||||||
* remains with BladeX.
|
* remains with BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* Using this software signifies agreement to this License, and the software
|
* Using this software signifies agreement to this License, and the software
|
||||||
* must not be used for illegal purposes.
|
* must not be used for illegal purposes.
|
||||||
* <p>
|
* <p>
|
||||||
* Author: Chill Zhuang (bladejava@qq.com)
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
*/
|
*/
|
||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelIgnore;
|
import cn.idev.excel.annotation.ExcelIgnore;
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import lombok.Data;
|
||||||
import lombok.Data;
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.io.Serial;
|
import java.io.Serializable;
|
||||||
import java.io.Serializable;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigDecimal;
|
import java.util.Date;
|
||||||
import java.util.Date;
|
|
||||||
|
/**
|
||||||
/**
|
* 常用地址导出 Excel
|
||||||
* 常用地址导出 Excel
|
*
|
||||||
*
|
* @author Chill
|
||||||
* @author Chill
|
*/
|
||||||
*/
|
@Data
|
||||||
@Data
|
@ColumnWidth(18)
|
||||||
@ColumnWidth(18)
|
@HeadRowHeight(20)
|
||||||
@HeadRowHeight(20)
|
@ContentRowHeight(18)
|
||||||
@ContentRowHeight(18)
|
public class CommonAddressExportExcel implements Serializable {
|
||||||
public class CommonAddressExportExcel implements Serializable {
|
|
||||||
|
@Serial
|
||||||
@Serial
|
private static final long serialVersionUID = 1L;
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
@ExcelIgnore
|
||||||
@ExcelIgnore
|
private Long id;
|
||||||
private Long id;
|
|
||||||
|
@ExcelProperty("地址名称")
|
||||||
@ExcelProperty("地址名称")
|
private String addressName;
|
||||||
private String addressName;
|
|
||||||
|
@ExcelProperty("地址编号")
|
||||||
@ExcelProperty("地址编号")
|
private String addressCode;
|
||||||
private String addressCode;
|
|
||||||
|
@ExcelProperty("类型")
|
||||||
@ExcelProperty("类型")
|
private String addressType;
|
||||||
private String addressType;
|
|
||||||
|
@ExcelProperty("站点编码")
|
||||||
@ExcelProperty("站点编码")
|
private String siteCodeDisplay;
|
||||||
private String siteCodeDisplay;
|
|
||||||
|
@ExcelProperty("详细地址")
|
||||||
@ExcelProperty("详细地址")
|
private String detailAddress;
|
||||||
private String detailAddress;
|
|
||||||
|
@ExcelProperty("经度")
|
||||||
@ExcelProperty("经度")
|
private BigDecimal longitude;
|
||||||
private BigDecimal longitude;
|
|
||||||
|
@ExcelProperty("纬度")
|
||||||
@ExcelProperty("纬度")
|
private BigDecimal latitude;
|
||||||
private BigDecimal latitude;
|
|
||||||
|
@ExcelProperty("行政区划")
|
||||||
@ExcelProperty("行政区划")
|
private String regionName;
|
||||||
private String regionName;
|
|
||||||
|
@ExcelProperty("联系人")
|
||||||
@ExcelProperty("联系人")
|
private String contactName;
|
||||||
private String contactName;
|
|
||||||
|
@ExcelProperty("联系方式")
|
||||||
@ExcelProperty("联系方式")
|
private String contactPhone;
|
||||||
private String contactPhone;
|
|
||||||
|
@ExcelProperty("组织")
|
||||||
@ExcelProperty("组织")
|
private String deptName;
|
||||||
private String deptName;
|
|
||||||
|
@ExcelProperty("备注")
|
||||||
@ExcelProperty("备注")
|
private String remark;
|
||||||
private String remark;
|
|
||||||
|
@ExcelProperty("更新时间")
|
||||||
@ExcelProperty("更新时间")
|
private Date updateTime;
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Date updateTime;
|
@ExcelProperty("创建时间")
|
||||||
|
private Date createTime;
|
||||||
@ExcelProperty("创建时间")
|
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
}
|
||||||
private Date createTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
+101
-104
@@ -1,104 +1,101 @@
|
|||||||
/**
|
/**
|
||||||
* BladeX Commercial License Agreement
|
* BladeX Commercial License Agreement
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
* <p>
|
* <p>
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
* obtained after purchasing a license from BladeX.
|
* obtained after purchasing a license from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 1. This software is for development use only under a valid license
|
* 1. This software is for development use only under a valid license
|
||||||
* from BladeX.
|
* from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 2. Redistribution of this software's source code to any third party
|
* 2. Redistribution of this software's source code to any third party
|
||||||
* without a commercial license is strictly prohibited.
|
* without a commercial license is strictly prohibited.
|
||||||
* <p>
|
* <p>
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
* from this software for such purposes. Copyright of this software
|
* from this software for such purposes. Copyright of this software
|
||||||
* remains with BladeX.
|
* remains with BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* Using this software signifies agreement to this License, and the software
|
* Using this software signifies agreement to this License, and the software
|
||||||
* must not be used for illegal purposes.
|
* must not be used for illegal purposes.
|
||||||
* <p>
|
* <p>
|
||||||
* Author: Chill Zhuang (bladejava@qq.com)
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
import cn.idev.excel.annotation.format.NumberFormat;
|
||||||
import cn.idev.excel.annotation.format.NumberFormat;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import lombok.Data;
|
||||||
import lombok.Data;
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.io.Serial;
|
import java.io.Serializable;
|
||||||
import java.io.Serializable;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigDecimal;
|
import java.util.Date;
|
||||||
import java.util.Date;
|
|
||||||
|
/**
|
||||||
/**
|
* 常用货物导出 Excel
|
||||||
* 常用货物导出 Excel
|
*
|
||||||
*
|
* @author Chill
|
||||||
* @author Chill
|
*/
|
||||||
*/
|
@Data
|
||||||
@Data
|
@ColumnWidth(24)
|
||||||
@ColumnWidth(24)
|
@HeadRowHeight(20)
|
||||||
@HeadRowHeight(20)
|
@ContentRowHeight(18)
|
||||||
@ContentRowHeight(18)
|
public class CommonCargoExportExcel implements Serializable {
|
||||||
public class CommonCargoExportExcel implements Serializable {
|
|
||||||
|
@Serial
|
||||||
@Serial
|
private static final long serialVersionUID = 1L;
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
@ExcelProperty("货物名称")
|
||||||
@ExcelProperty("货物名称")
|
private String cargoName;
|
||||||
private String cargoName;
|
|
||||||
|
@ExcelProperty("货物编号后缀")
|
||||||
@ExcelProperty("货物编号后缀")
|
private String cargoCodeSuffix;
|
||||||
private String cargoCodeSuffix;
|
|
||||||
|
@ExcelProperty("一级货物类型")
|
||||||
@ExcelProperty("一级货物类型")
|
private String firstCargoTypeName;
|
||||||
private String firstCargoTypeName;
|
|
||||||
|
@ExcelProperty("二级货物类型")
|
||||||
@ExcelProperty("二级货物类型")
|
private String secondCargoTypeName;
|
||||||
private String secondCargoTypeName;
|
|
||||||
|
@ExcelProperty("二级货物类型编码")
|
||||||
@ExcelProperty("二级货物类型编码")
|
private String secondCargoTypeCode;
|
||||||
private String secondCargoTypeCode;
|
|
||||||
|
@ExcelProperty("包装")
|
||||||
@ExcelProperty("包装")
|
private String packageType;
|
||||||
private String packageType;
|
|
||||||
|
@ExcelProperty("品牌")
|
||||||
@ExcelProperty("品牌")
|
private String brand;
|
||||||
private String brand;
|
|
||||||
|
@ExcelProperty("规格")
|
||||||
@ExcelProperty("规格")
|
private String specification;
|
||||||
private String specification;
|
|
||||||
|
@ExcelProperty("型号")
|
||||||
@ExcelProperty("型号")
|
private String model;
|
||||||
private String model;
|
|
||||||
|
@ExcelProperty("单价")
|
||||||
@ExcelProperty("单价")
|
@NumberFormat("0.00")
|
||||||
@NumberFormat("0.00")
|
private BigDecimal cargoValue;
|
||||||
private BigDecimal cargoValue;
|
|
||||||
|
@ExcelProperty("计价单位")
|
||||||
@ExcelProperty("计价单位")
|
private String priceUnit;
|
||||||
private String priceUnit;
|
|
||||||
|
@ExcelProperty("说明")
|
||||||
@ExcelProperty("说明")
|
private String descriptionOne;
|
||||||
private String descriptionOne;
|
|
||||||
|
@ExcelProperty("备注")
|
||||||
@ExcelProperty("备注")
|
private String remark;
|
||||||
private String remark;
|
|
||||||
|
@ExcelProperty("组织")
|
||||||
@ExcelProperty("组织")
|
private String deptName;
|
||||||
private String deptName;
|
|
||||||
|
@ExcelProperty("更新时间")
|
||||||
@ExcelProperty("更新时间")
|
private Date updateTime;
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Date updateTime;
|
@ExcelProperty("创建时间")
|
||||||
|
private Date createTime;
|
||||||
@ExcelProperty("创建时间")
|
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
}
|
||||||
private Date createTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
+82
-85
@@ -1,85 +1,82 @@
|
|||||||
/**
|
/**
|
||||||
* BladeX Commercial License Agreement
|
* BladeX Commercial License Agreement
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
* <p>
|
* <p>
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
* obtained after purchasing a license from BladeX.
|
* obtained after purchasing a license from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 1. This software is for development use only under a valid license
|
* 1. This software is for development use only under a valid license
|
||||||
* from BladeX.
|
* from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 2. Redistribution of this software's source code to any third party
|
* 2. Redistribution of this software's source code to any third party
|
||||||
* without a commercial license is strictly prohibited.
|
* without a commercial license is strictly prohibited.
|
||||||
* <p>
|
* <p>
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
* from this software for such purposes. Copyright of this software
|
* from this software for such purposes. Copyright of this software
|
||||||
* remains with BladeX.
|
* remains with BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* Using this software signifies agreement to this License, and the software
|
* Using this software signifies agreement to this License, and the software
|
||||||
* must not be used for illegal purposes.
|
* must not be used for illegal purposes.
|
||||||
* <p>
|
* <p>
|
||||||
* Author: Chill Zhuang (bladejava@qq.com)
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
*/
|
*/
|
||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import lombok.Data;
|
||||||
import lombok.Data;
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.io.Serial;
|
import java.io.Serializable;
|
||||||
import java.io.Serializable;
|
import java.util.Date;
|
||||||
import java.util.Date;
|
|
||||||
|
/**
|
||||||
/**
|
* 常用线路导出 Excel
|
||||||
* 常用线路导出 Excel
|
*
|
||||||
*
|
* @author Chill
|
||||||
* @author Chill
|
*/
|
||||||
*/
|
@Data
|
||||||
@Data
|
@ColumnWidth(22)
|
||||||
@ColumnWidth(22)
|
@HeadRowHeight(20)
|
||||||
@HeadRowHeight(20)
|
@ContentRowHeight(18)
|
||||||
@ContentRowHeight(18)
|
public class CommonRouteExportExcel implements Serializable {
|
||||||
public class CommonRouteExportExcel implements Serializable {
|
|
||||||
|
@Serial
|
||||||
@Serial
|
private static final long serialVersionUID = 1L;
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
@ExcelProperty("线路编号")
|
||||||
@ExcelProperty("线路编号")
|
private String routeCode;
|
||||||
private String routeCode;
|
@ExcelProperty("线路名称")
|
||||||
@ExcelProperty("线路名称")
|
private String routeName;
|
||||||
private String routeName;
|
@ExcelProperty("发货地")
|
||||||
@ExcelProperty("发货地")
|
private String departureName;
|
||||||
private String departureName;
|
@ExcelProperty("发货地址")
|
||||||
@ExcelProperty("发货地址")
|
private String departureAddress;
|
||||||
private String departureAddress;
|
@ExcelProperty("发货联系人")
|
||||||
@ExcelProperty("发货联系人")
|
private String departureContact;
|
||||||
private String departureContact;
|
@ExcelProperty("发货联系方式")
|
||||||
@ExcelProperty("发货联系方式")
|
private String departurePhone;
|
||||||
private String departurePhone;
|
@ExcelProperty("收货地")
|
||||||
@ExcelProperty("收货地")
|
private String arrivalName;
|
||||||
private String arrivalName;
|
@ExcelProperty("收货地址")
|
||||||
@ExcelProperty("收货地址")
|
private String arrivalAddress;
|
||||||
private String arrivalAddress;
|
@ExcelProperty("收货联系人")
|
||||||
@ExcelProperty("收货联系人")
|
private String arrivalContact;
|
||||||
private String arrivalContact;
|
@ExcelProperty("收货联系方式")
|
||||||
@ExcelProperty("收货联系方式")
|
private String arrivalPhone;
|
||||||
private String arrivalPhone;
|
@ExcelProperty("所属组织")
|
||||||
@ExcelProperty("所属组织")
|
private String deptName;
|
||||||
private String deptName;
|
@ExcelProperty("备注")
|
||||||
@ExcelProperty("备注")
|
private String remark;
|
||||||
private String remark;
|
@ExcelProperty("创建人")
|
||||||
@ExcelProperty("创建人")
|
private String createUserName;
|
||||||
private String createUserName;
|
@ExcelProperty("更新人")
|
||||||
@ExcelProperty("更新人")
|
private String updateUserName;
|
||||||
private String updateUserName;
|
@ExcelProperty("更新时间")
|
||||||
@ExcelProperty("更新时间")
|
private Date updateTime;
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@ExcelProperty("创建时间")
|
||||||
private Date updateTime;
|
private Date createTime;
|
||||||
@ExcelProperty("创建时间")
|
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
}
|
||||||
private Date createTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
+118
-121
@@ -1,121 +1,118 @@
|
|||||||
/**
|
/**
|
||||||
* BladeX Commercial License Agreement
|
* BladeX Commercial License Agreement
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
* <p>
|
* <p>
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
* obtained after purchasing a license from BladeX.
|
* obtained after purchasing a license from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 1. This software is for development use only under a valid license
|
* 1. This software is for development use only under a valid license
|
||||||
* from BladeX.
|
* from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 2. Redistribution of this software's source code to any third party
|
* 2. Redistribution of this software's source code to any third party
|
||||||
* without a commercial license is strictly prohibited.
|
* without a commercial license is strictly prohibited.
|
||||||
* <p>
|
* <p>
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
* from this software for such purposes. Copyright of this software
|
* from this software for such purposes. Copyright of this software
|
||||||
* remains with BladeX.
|
* remains with BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* Using this software signifies agreement to this License, and the software
|
* Using this software signifies agreement to this License, and the software
|
||||||
* must not be used for illegal purposes.
|
* must not be used for illegal purposes.
|
||||||
* <p>
|
* <p>
|
||||||
* Author: Chill Zhuang (bladejava@qq.com)
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
*/
|
*/
|
||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
import cn.idev.excel.annotation.format.NumberFormat;
|
||||||
import cn.idev.excel.annotation.format.NumberFormat;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import lombok.Data;
|
||||||
import lombok.Data;
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.io.Serial;
|
import java.io.Serializable;
|
||||||
import java.io.Serializable;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigDecimal;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
|
||||||
|
/**
|
||||||
/**
|
* 合同管理 Excel
|
||||||
* 合同管理 Excel
|
*
|
||||||
*
|
* @author Chill
|
||||||
* @author Chill
|
*/
|
||||||
*/
|
@Data
|
||||||
@Data
|
@ColumnWidth(22)
|
||||||
@ColumnWidth(22)
|
@HeadRowHeight(20)
|
||||||
@HeadRowHeight(20)
|
@ContentRowHeight(18)
|
||||||
@ContentRowHeight(18)
|
public class ContractManageExcel implements Serializable {
|
||||||
public class ContractManageExcel implements Serializable {
|
|
||||||
|
@Serial
|
||||||
@Serial
|
private static final long serialVersionUID = 1L;
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
@ExcelProperty("合同编号")
|
||||||
@ExcelProperty("合同编号")
|
private String contractNo;
|
||||||
private String contractNo;
|
@ExcelProperty("合同名称")
|
||||||
@ExcelProperty("合同名称")
|
private String contractName;
|
||||||
private String contractName;
|
@ExcelProperty("所属项目")
|
||||||
@ExcelProperty("所属项目")
|
private String projectName;
|
||||||
private String projectName;
|
@ExcelProperty("所属组织")
|
||||||
@ExcelProperty("所属组织")
|
private String organizationName;
|
||||||
private String organizationName;
|
@ExcelProperty("合同类别")
|
||||||
@ExcelProperty("合同类别")
|
private String contractCategory;
|
||||||
private String contractCategory;
|
@ExcelProperty("签约类型")
|
||||||
@ExcelProperty("签约类型")
|
private String signType;
|
||||||
private String signType;
|
@ExcelProperty("甲方")
|
||||||
@ExcelProperty("甲方")
|
private String partyA;
|
||||||
private String partyA;
|
@ExcelProperty("乙方")
|
||||||
@ExcelProperty("乙方")
|
private String partyB;
|
||||||
private String partyB;
|
@ExcelProperty("开始日期")
|
||||||
@ExcelProperty("开始日期")
|
private LocalDate startDate;
|
||||||
private LocalDate startDate;
|
@ExcelProperty("结束日期")
|
||||||
@ExcelProperty("结束日期")
|
private LocalDate endDate;
|
||||||
private LocalDate endDate;
|
@ExcelProperty("临时效力起")
|
||||||
@ExcelProperty("临时效力起")
|
private LocalDate temporaryStartDate;
|
||||||
private LocalDate temporaryStartDate;
|
@ExcelProperty("临时效力止")
|
||||||
@ExcelProperty("临时效力止")
|
private LocalDate temporaryEndDate;
|
||||||
private LocalDate temporaryEndDate;
|
@ExcelProperty("经办人")
|
||||||
@ExcelProperty("经办人")
|
private String handlerUserName;
|
||||||
private String handlerUserName;
|
@ExcelProperty("合同阶段")
|
||||||
@ExcelProperty("合同阶段")
|
private String contractStage;
|
||||||
private String contractStage;
|
@ExcelProperty("审核状态")
|
||||||
@ExcelProperty("审核状态")
|
private String approvalStatus;
|
||||||
private String approvalStatus;
|
@ExcelProperty("归档状态")
|
||||||
@ExcelProperty("归档状态")
|
private String archiveStatus;
|
||||||
private String archiveStatus;
|
@ExcelProperty("结算币种")
|
||||||
@ExcelProperty("结算币种")
|
private String settlementCurrency;
|
||||||
private String settlementCurrency;
|
@ExcelProperty("结算方式")
|
||||||
@ExcelProperty("结算方式")
|
private String settlementMode;
|
||||||
private String settlementMode;
|
@ExcelProperty("开票周期(天)")
|
||||||
@ExcelProperty("开票周期(天)")
|
private Integer invoiceCycle;
|
||||||
private Integer invoiceCycle;
|
@ExcelProperty("一式份数")
|
||||||
@ExcelProperty("一式份数")
|
private Integer copyCount;
|
||||||
private Integer copyCount;
|
@ExcelProperty("回款账期(天)")
|
||||||
@ExcelProperty("回款账期(天)")
|
private Integer paymentDays;
|
||||||
private Integer paymentDays;
|
@ExcelProperty("合同金额")
|
||||||
@ExcelProperty("合同金额")
|
@NumberFormat("0.00")
|
||||||
@NumberFormat("0.00")
|
private BigDecimal contractAmount;
|
||||||
private BigDecimal contractAmount;
|
@ExcelProperty("是否范本")
|
||||||
@ExcelProperty("是否范本")
|
private Integer templateFlag;
|
||||||
private Integer templateFlag;
|
@ExcelProperty("原件合同编号")
|
||||||
@ExcelProperty("原件合同编号")
|
private String originalContractNo;
|
||||||
private String originalContractNo;
|
@ExcelProperty("是否电子章")
|
||||||
@ExcelProperty("是否电子章")
|
private Integer electronicSealFlag;
|
||||||
private Integer electronicSealFlag;
|
@ExcelProperty("当前节点")
|
||||||
@ExcelProperty("当前节点")
|
private String currentNode;
|
||||||
private String currentNode;
|
@ExcelProperty("当前处理人")
|
||||||
@ExcelProperty("当前处理人")
|
private String currentProcessor;
|
||||||
private String currentProcessor;
|
@ExcelProperty("备注")
|
||||||
@ExcelProperty("备注")
|
private String remark;
|
||||||
private String remark;
|
@ExcelProperty("创建人")
|
||||||
@ExcelProperty("创建人")
|
private String createUserName;
|
||||||
private String createUserName;
|
@ExcelProperty("更新人")
|
||||||
@ExcelProperty("更新人")
|
private String updateUserName;
|
||||||
private String updateUserName;
|
@ExcelProperty("创建时间")
|
||||||
@ExcelProperty("创建时间")
|
private LocalDateTime createTime;
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@ExcelProperty("更新时间")
|
||||||
private Date createTime;
|
private LocalDateTime updateTime;
|
||||||
@ExcelProperty("更新时间")
|
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
}
|
||||||
private Date updateTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
+3
-1
@@ -7,10 +7,12 @@ package org.springblade.transport.excel;
|
|||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelIgnore;
|
import cn.idev.excel.annotation.ExcelIgnore;
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
|
import cn.idev.excel.annotation.format.DateTimeFormat;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备台账 Excel
|
* 设备台账 Excel
|
||||||
@@ -27,7 +29,7 @@ public class EquipmentLedgerExcel implements Serializable {
|
|||||||
@ExcelProperty("设备品牌") private String equipmentBrand;
|
@ExcelProperty("设备品牌") private String equipmentBrand;
|
||||||
@ExcelProperty("设备类型") private String equipmentType;
|
@ExcelProperty("设备类型") private String equipmentType;
|
||||||
@ExcelProperty("规格型号") private String specificationModel;
|
@ExcelProperty("规格型号") private String specificationModel;
|
||||||
@ExcelProperty(value = "出厂日期", converter = org.springblade.common.excel.LenientDateStringConverter.class) private String factoryDate;
|
@ExcelProperty("出厂日期") @DateTimeFormat("yyyy-MM-dd") private LocalDate factoryDate;
|
||||||
@ExcelProperty("备注") private String remark;
|
@ExcelProperty("备注") private String remark;
|
||||||
@ExcelIgnore private String errorMessage;
|
@ExcelIgnore private String errorMessage;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -11,7 +11,6 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ETC记录导出 Excel
|
* ETC记录导出 Excel
|
||||||
@@ -51,14 +50,14 @@ public class EtcRecordExportExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+7
-6
@@ -35,6 +35,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保险记录 Excel
|
* 保险记录 Excel
|
||||||
@@ -67,11 +68,11 @@ public class InsuranceRecordExcel implements Serializable {
|
|||||||
@ExcelProperty("*保单号")
|
@ExcelProperty("*保单号")
|
||||||
private String policyNo;
|
private String policyNo;
|
||||||
|
|
||||||
@ExcelProperty(value = "*开始日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("*开始日期")
|
||||||
private String startDate;
|
private LocalDate startDate;
|
||||||
|
|
||||||
@ExcelProperty(value = "*结束日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("*结束日期")
|
||||||
private String endDate;
|
private LocalDate endDate;
|
||||||
|
|
||||||
@ExcelProperty("保额")
|
@ExcelProperty("保额")
|
||||||
private BigDecimal insuredAmount;
|
private BigDecimal insuredAmount;
|
||||||
@@ -82,8 +83,8 @@ public class InsuranceRecordExcel implements Serializable {
|
|||||||
@ExcelProperty("发票号")
|
@ExcelProperty("发票号")
|
||||||
private String invoiceNo;
|
private String invoiceNo;
|
||||||
|
|
||||||
@ExcelProperty(value = "开票日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("开票日期")
|
||||||
private String invoiceDate;
|
private LocalDate invoiceDate;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+3
-3
@@ -36,7 +36,7 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保险记录导出 Excel
|
* 保险记录导出 Excel
|
||||||
@@ -83,14 +83,14 @@ public class InsuranceRecordExportExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+15
-11
@@ -33,20 +33,22 @@ import cn.idev.excel.metadata.data.WriteCellData;
|
|||||||
import cn.idev.excel.metadata.property.ExcelContentProperty;
|
import cn.idev.excel.metadata.property.ExcelContentProperty;
|
||||||
import cn.idev.excel.util.DateUtils;
|
import cn.idev.excel.util.DateUtils;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保养记录日期转换器,兼容日期文本、日期时间文本和 Excel 数值日期。
|
* 保养记录日期转换器,兼容日期文本、日期时间文本和 Excel 数值日期。
|
||||||
* <p>
|
|
||||||
* 文本解析委托公共宽容解析器(支持 2026-8-2、2026/8/2 等写法,口径见根工作区
|
|
||||||
* docs/import-spec.md);无法识别的文本按既有行为抛出转换异常,
|
|
||||||
* 文案带原值,与「日期格式无法识别」口径一致。
|
|
||||||
*
|
*
|
||||||
* @author Chill
|
* @author Chill
|
||||||
*/
|
*/
|
||||||
public class MaintenancePlanDateTimeConverter implements Converter<LocalDateTime> {
|
public class MaintenancePlanDateTimeConverter implements Converter<LocalDateTime> {
|
||||||
|
|
||||||
private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
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
|
@Override
|
||||||
public Class<?> supportJavaTypeKey() {
|
public Class<?> supportJavaTypeKey() {
|
||||||
@@ -69,14 +71,16 @@ public class MaintenancePlanDateTimeConverter implements Converter<LocalDateTime
|
|||||||
if (value == null || value.trim().isEmpty()) {
|
if (value == null || value.trim().isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
LocalDateTime parsed = org.springblade.common.excel.LenientDateParser.parseDateTimeOrNull(value);
|
String normalizedValue = value.trim();
|
||||||
if (parsed != null) {
|
try {
|
||||||
return parsed;
|
return LocalDateTime.parse(normalizedValue, DATE_TIME_FORMATTER);
|
||||||
|
} catch (DateTimeParseException ignored) {
|
||||||
|
try {
|
||||||
|
return LocalDateTime.parse(normalizedValue, DATE_TIME_MINUTE_FORMATTER);
|
||||||
|
} catch (DateTimeParseException ignoredMinute) {
|
||||||
|
return LocalDate.parse(normalizedValue, DATE_FORMATTER).atStartOfDay();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 无法识别的文本:与既有行为一致抛出转换异常(ExcelDataConvertException 是 RuntimeException,
|
|
||||||
// 会带上本文案一路抛到 Controller,由全局异常处理返回给前端提示)。
|
|
||||||
throw new cn.idev.excel.exception.ExcelDataConvertException(-1, -1, cellData, contentProperty,
|
|
||||||
value.trim() + " 日期格式无法识别");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+3
-3
@@ -11,7 +11,7 @@ import lombok.Data;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 车辆保养记录导出 Excel
|
* 车辆保养记录导出 Excel
|
||||||
@@ -26,12 +26,12 @@ public class MaintenancePlanExportExcel extends MaintenancePlanExcel {
|
|||||||
|
|
||||||
@ExcelProperty(value = "创建时间", index = 12)
|
@ExcelProperty(value = "创建时间", index = 12)
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty(value = "更新人", index = 13)
|
@ExcelProperty(value = "更新人", index = 13)
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty(value = "更新时间", index = 14)
|
@ExcelProperty(value = "更新时间", index = 14)
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -38,7 +38,6 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 车辆维修记录 Excel
|
* 车辆维修记录 Excel
|
||||||
@@ -96,16 +95,16 @@ public class MaintenanceRecordExcel implements Serializable {
|
|||||||
@NumberFormat("0.00")
|
@NumberFormat("0.00")
|
||||||
private BigDecimal mileage;
|
private BigDecimal mileage;
|
||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty(value = "创建时间", converter = MaintenancePlanDateTimeConverter.class)
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty(value = "更新时间", converter = MaintenancePlanDateTimeConverter.class)
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("里程单位")
|
@ExcelProperty("里程单位")
|
||||||
private String mileageUnit;
|
private String mileageUnit;
|
||||||
|
|||||||
+4
@@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@@ -41,4 +42,7 @@ public class MaintenanceRecordExportExcel extends MaintenanceRecordExcel {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "导出失败原因", index = 17)
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -36,7 +36,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 里程记录导出 Excel
|
* 里程记录导出 Excel
|
||||||
@@ -72,14 +72,14 @@ public class MileageRecordExportExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+2
-3
@@ -11,7 +11,6 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 油电记录导出 Excel
|
* 油电记录导出 Excel
|
||||||
@@ -62,14 +61,14 @@ public class OilElectricRecordExportExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+3
-2
@@ -16,6 +16,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 其他费用记录 Excel
|
* 其他费用记录 Excel
|
||||||
@@ -39,8 +40,8 @@ public class OtherExpenseRecordExcel implements Serializable {
|
|||||||
@ExcelProperty("*车牌号/船号")
|
@ExcelProperty("*车牌号/船号")
|
||||||
private String vehicleNo;
|
private String vehicleNo;
|
||||||
|
|
||||||
@ExcelProperty(value = "*费用日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("*费用日期")
|
||||||
private String expenseDate;
|
private LocalDate expenseDate;
|
||||||
|
|
||||||
@ExcelProperty("*费用类型")
|
@ExcelProperty("*费用类型")
|
||||||
private String expenseType;
|
private String expenseType;
|
||||||
|
|||||||
+3
-3
@@ -11,7 +11,7 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 其他费用记录导出 Excel
|
* 其他费用记录导出 Excel
|
||||||
@@ -43,14 +43,14 @@ public class OtherExpenseRecordExportExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+76
-79
@@ -1,79 +1,76 @@
|
|||||||
/**
|
/**
|
||||||
* BladeX Commercial License Agreement
|
* BladeX Commercial License Agreement
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
* <p>
|
* <p>
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
* obtained after purchasing a license from BladeX.
|
* obtained after purchasing a license from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 1. This software is for development use only under a valid license
|
* 1. This software is for development use only under a valid license
|
||||||
* from BladeX.
|
* from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 2. Redistribution of this software's source code to any third party
|
* 2. Redistribution of this software's source code to any third party
|
||||||
* without a commercial license is strictly prohibited.
|
* without a commercial license is strictly prohibited.
|
||||||
* <p>
|
* <p>
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
* from this software for such purposes. Copyright of this software
|
* from this software for such purposes. Copyright of this software
|
||||||
* remains with BladeX.
|
* remains with BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* Using this software signifies agreement to this License, and the software
|
* Using this software signifies agreement to this License, and the software
|
||||||
* must not be used for illegal purposes.
|
* must not be used for illegal purposes.
|
||||||
* <p>
|
* <p>
|
||||||
* Author: Chill Zhuang (bladejava@qq.com)
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
*/
|
*/
|
||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import lombok.Data;
|
||||||
import lombok.Data;
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.io.Serial;
|
import java.io.Serializable;
|
||||||
import java.io.Serializable;
|
import java.util.Date;
|
||||||
import java.util.Date;
|
|
||||||
|
/**
|
||||||
/**
|
* 过程配置导出 Excel
|
||||||
* 过程配置导出 Excel
|
*
|
||||||
*
|
* @author Chill
|
||||||
* @author Chill
|
*/
|
||||||
*/
|
@Data
|
||||||
@Data
|
@ColumnWidth(22)
|
||||||
@ColumnWidth(22)
|
@HeadRowHeight(20)
|
||||||
@HeadRowHeight(20)
|
@ContentRowHeight(18)
|
||||||
@ContentRowHeight(18)
|
public class ProcessConfigExportExcel implements Serializable {
|
||||||
public class ProcessConfigExportExcel implements Serializable {
|
|
||||||
|
@Serial
|
||||||
@Serial
|
private static final long serialVersionUID = 1L;
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
@ExcelProperty("配置编号")
|
||||||
@ExcelProperty("配置编号")
|
private String configCode;
|
||||||
private String configCode;
|
@ExcelProperty("配置名称")
|
||||||
@ExcelProperty("配置名称")
|
private String configName;
|
||||||
private String configName;
|
@ExcelProperty("项目ID集合")
|
||||||
@ExcelProperty("项目ID集合")
|
private String projectIds;
|
||||||
private String projectIds;
|
@ExcelProperty("项目")
|
||||||
@ExcelProperty("项目")
|
private String projectNames;
|
||||||
private String projectNames;
|
@ExcelProperty("包含过程节点")
|
||||||
@ExcelProperty("包含过程节点")
|
private String includedNodes;
|
||||||
private String includedNodes;
|
@ExcelProperty("默认后台完成运输天数")
|
||||||
@ExcelProperty("默认后台完成运输天数")
|
private Integer defaultFinishDays;
|
||||||
private Integer defaultFinishDays;
|
@ExcelProperty("状态")
|
||||||
@ExcelProperty("状态")
|
private Integer status;
|
||||||
private Integer status;
|
@ExcelProperty("所属组织")
|
||||||
@ExcelProperty("所属组织")
|
private String deptName;
|
||||||
private String deptName;
|
@ExcelProperty("备注")
|
||||||
@ExcelProperty("备注")
|
private String remark;
|
||||||
private String remark;
|
@ExcelProperty("创建人")
|
||||||
@ExcelProperty("创建人")
|
private String createUserName;
|
||||||
private String createUserName;
|
@ExcelProperty("更新人")
|
||||||
@ExcelProperty("更新人")
|
private String updateUserName;
|
||||||
private String updateUserName;
|
@ExcelProperty("更新时间")
|
||||||
@ExcelProperty("更新时间")
|
private Date updateTime;
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@ExcelProperty("创建时间")
|
||||||
private Date updateTime;
|
private Date createTime;
|
||||||
@ExcelProperty("创建时间")
|
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
}
|
||||||
private Date createTime;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
+2
-6
@@ -23,7 +23,6 @@
|
|||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
@@ -34,7 +33,6 @@ import java.io.Serializable;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 项目立项 Excel
|
* 项目立项 Excel
|
||||||
@@ -125,10 +123,8 @@ public class ProjectApplyExcel implements Serializable {
|
|||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
private LocalDateTime createTime;
|
||||||
private Date createTime;
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
private LocalDateTime updateTime;
|
||||||
private Date updateTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-6
@@ -23,7 +23,6 @@
|
|||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
@@ -31,7 +30,7 @@ import lombok.Data;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发货模板 Excel
|
* 发货模板 Excel
|
||||||
@@ -60,10 +59,8 @@ public class ShippingTemplateExcel implements Serializable {
|
|||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
private LocalDateTime updateTime;
|
||||||
private Date updateTime;
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
private LocalDateTime createTime;
|
||||||
private Date createTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-6
@@ -23,7 +23,6 @@
|
|||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
@@ -33,7 +32,7 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 临时额度申请 Excel
|
* 临时额度申请 Excel
|
||||||
@@ -82,10 +81,8 @@ public class TemporaryCreditLimitExcel implements Serializable {
|
|||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
private LocalDateTime createTime;
|
||||||
private Date createTime;
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
private LocalDateTime updateTime;
|
||||||
private Date updateTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-4
@@ -38,10 +38,6 @@ import java.time.format.DateTimeFormatter;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 换胎日期文本转换器,保留非法日期原值并兼容 Excel 数值日期。
|
* 换胎日期文本转换器,保留非法日期原值并兼容 Excel 数值日期。
|
||||||
* <p>
|
|
||||||
* 数值日期序列号转 ISO 文本,文本原样透传;文本的宽容解析由服务层委托
|
|
||||||
* {@link org.springblade.common.excel.LenientDateParser} 完成(支持 2026-8-2 等写法,
|
|
||||||
* 口径见根工作区 docs/import-spec.md)。
|
|
||||||
*
|
*
|
||||||
* @author Chill
|
* @author Chill
|
||||||
*/
|
*/
|
||||||
|
|||||||
+3
-3
@@ -37,7 +37,7 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 换胎记录导出 Excel
|
* 换胎记录导出 Excel
|
||||||
@@ -76,14 +76,14 @@ public class TireReplacementRecordExportExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+3
-3
@@ -28,7 +28,7 @@ import lombok.Data;
|
|||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 变更记录导出 Excel
|
* 变更记录导出 Excel
|
||||||
@@ -57,14 +57,14 @@ public class TransportChangeRecordExportExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|||||||
+3
-6
@@ -23,7 +23,6 @@
|
|||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
@@ -32,7 +31,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Date;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 运输计划 Excel
|
* 运输计划 Excel
|
||||||
@@ -93,10 +92,8 @@ public class TransportPlanExcel implements Serializable {
|
|||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
private LocalDateTime createTime;
|
||||||
private Date createTime;
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
private LocalDateTime updateTime;
|
||||||
private Date updateTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -37,7 +37,6 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 违章记录 Excel
|
* 违章记录 Excel
|
||||||
@@ -96,14 +95,14 @@ public class ViolationRecordExcel implements Serializable {
|
|||||||
|
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
|
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
@ExcelIgnore
|
@ExcelIgnore
|
||||||
private String errorMessage;
|
private String errorMessage;
|
||||||
|
|||||||
+2
-5
@@ -60,11 +60,8 @@ public class ViolationRecordImportExcel implements Serializable {
|
|||||||
@ExcelProperty("*驾驶人")
|
@ExcelProperty("*驾驶人")
|
||||||
private String driverName;
|
private String driverName;
|
||||||
|
|
||||||
@ExcelProperty("*类型")
|
@ExcelProperty("*类型/事项")
|
||||||
private String violationType;
|
private String violationTypeOrItem;
|
||||||
|
|
||||||
@ExcelProperty("*事项")
|
|
||||||
private String violationItem;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "*时间", converter = MaintenancePlanDateTimeConverter.class)
|
@ExcelProperty(value = "*时间", converter = MaintenancePlanDateTimeConverter.class)
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
|
|||||||
+163
-163
@@ -1,163 +1,163 @@
|
|||||||
/**
|
/**
|
||||||
* BladeX Commercial License Agreement
|
* BladeX Commercial License Agreement
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
* <p>
|
* <p>
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
* obtained after purchasing a license from BladeX.
|
* obtained after purchasing a license from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 1. This software is for development use only under a valid license
|
* 1. This software is for development use only under a valid license
|
||||||
* from BladeX.
|
* from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 2. Redistribution of this software's source code to any third party
|
* 2. Redistribution of this software's source code to any third party
|
||||||
* without a commercial license is strictly prohibited.
|
* without a commercial license is strictly prohibited.
|
||||||
* <p>
|
* <p>
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
* from this software for such purposes. Copyright of this software
|
* from this software for such purposes. Copyright of this software
|
||||||
* remains with BladeX.
|
* remains with BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* Using this software signifies agreement to this License, and the software
|
* Using this software signifies agreement to this License, and the software
|
||||||
* must not be used for illegal purposes.
|
* must not be used for illegal purposes.
|
||||||
* <p>
|
* <p>
|
||||||
* Author: Chill Zhuang (bladejava@qq.com)
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
*/
|
*/
|
||||||
package org.springblade.transport.excel;
|
package org.springblade.transport.excel;
|
||||||
|
|
||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.idev.excel.annotation.ExcelIgnore;
|
import cn.idev.excel.annotation.ExcelIgnore;
|
||||||
import cn.idev.excel.annotation.format.DateTimeFormat;
|
import cn.idev.excel.annotation.format.DateTimeFormat;
|
||||||
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
import cn.idev.excel.annotation.write.style.ColumnWidth;
|
||||||
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
import cn.idev.excel.annotation.write.style.ContentRowHeight;
|
||||||
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
import cn.idev.excel.annotation.write.style.HeadRowHeight;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 运单管理 Excel
|
* 运单管理 Excel
|
||||||
*
|
*
|
||||||
* @author Chill
|
* @author Chill
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@ColumnWidth(22)
|
@ColumnWidth(22)
|
||||||
@HeadRowHeight(20)
|
@HeadRowHeight(20)
|
||||||
@ContentRowHeight(18)
|
@ContentRowHeight(18)
|
||||||
public class WaybillExcel implements Serializable {
|
public class WaybillExcel implements Serializable {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@ExcelProperty("运单号")
|
@ExcelProperty("运单号")
|
||||||
private String waybillNo;
|
private String waybillNo;
|
||||||
@ExcelProperty("项目")
|
@ExcelProperty("项目")
|
||||||
private String projectName;
|
private String projectName;
|
||||||
@ExcelProperty("客户合同")
|
@ExcelProperty("客户合同")
|
||||||
private String contractName;
|
private String contractName;
|
||||||
@ExcelProperty("客户名称")
|
@ExcelProperty("客户名称")
|
||||||
private String customerName;
|
private String customerName;
|
||||||
@ExcelProperty("运输类型")
|
@ExcelProperty("运输类型")
|
||||||
private String transportType;
|
private String transportType;
|
||||||
@ExcelProperty("货物名称")
|
@ExcelProperty("货物名称")
|
||||||
private String cargoName;
|
private String cargoName;
|
||||||
@ExcelProperty("货物类型")
|
@ExcelProperty("货物类型")
|
||||||
private String cargoType;
|
private String cargoType;
|
||||||
@ExcelProperty("规格")
|
@ExcelProperty("规格")
|
||||||
private String specification;
|
private String specification;
|
||||||
@ExcelProperty("型号")
|
@ExcelProperty("型号")
|
||||||
private String model;
|
private String model;
|
||||||
@ExcelProperty("数量")
|
@ExcelProperty("数量")
|
||||||
private BigDecimal quantity;
|
private BigDecimal quantity;
|
||||||
@ExcelProperty("数量单位")
|
@ExcelProperty("数量单位")
|
||||||
private String quantityUnit;
|
private String quantityUnit;
|
||||||
@ExcelProperty("发货地")
|
@ExcelProperty("发货地")
|
||||||
private String departureName;
|
private String departureName;
|
||||||
@ExcelProperty("发货地址")
|
@ExcelProperty("发货地址")
|
||||||
private String departureAddress;
|
private String departureAddress;
|
||||||
@ExcelProperty("发货联系人")
|
@ExcelProperty("发货联系人")
|
||||||
private String departureContact;
|
private String departureContact;
|
||||||
@ExcelProperty("发货联系方式")
|
@ExcelProperty("发货联系方式")
|
||||||
private String departurePhone;
|
private String departurePhone;
|
||||||
@ExcelProperty("收货地")
|
@ExcelProperty("收货地")
|
||||||
private String arrivalName;
|
private String arrivalName;
|
||||||
@ExcelProperty("收货地址")
|
@ExcelProperty("收货地址")
|
||||||
private String arrivalAddress;
|
private String arrivalAddress;
|
||||||
@ExcelProperty("收货联系人")
|
@ExcelProperty("收货联系人")
|
||||||
private String arrivalContact;
|
private String arrivalContact;
|
||||||
@ExcelProperty("收货联系方式")
|
@ExcelProperty("收货联系方式")
|
||||||
private String arrivalPhone;
|
private String arrivalPhone;
|
||||||
@ExcelProperty("任务录入模式")
|
@ExcelProperty("任务录入模式")
|
||||||
private String taskEntryMode;
|
private String taskEntryMode;
|
||||||
@ExcelProperty("承运类型")
|
@ExcelProperty("承运类型")
|
||||||
private String carrierType;
|
private String carrierType;
|
||||||
@ExcelProperty("承运商名称")
|
@ExcelProperty("承运商名称")
|
||||||
private String carrierName;
|
private String carrierName;
|
||||||
@ExcelProperty("司机姓名")
|
@ExcelProperty("司机姓名")
|
||||||
private String driverName;
|
private String driverName;
|
||||||
@ExcelProperty("司机手机号")
|
@ExcelProperty("司机手机号")
|
||||||
private String driverPhone;
|
private String driverPhone;
|
||||||
@ExcelProperty("车/船/航班/班列号")
|
@ExcelProperty("车/船/航班/班列号")
|
||||||
private String vehicleNo;
|
private String vehicleNo;
|
||||||
@ExcelProperty("挂车车牌号")
|
@ExcelProperty("挂车车牌号")
|
||||||
private String trailerVehicleNo;
|
private String trailerVehicleNo;
|
||||||
@ExcelProperty("押运人")
|
@ExcelProperty("押运人")
|
||||||
private String escortName;
|
private String escortName;
|
||||||
@ExcelProperty("押运人手机号")
|
@ExcelProperty("押运人手机号")
|
||||||
private String escortPhone;
|
private String escortPhone;
|
||||||
@ExcelProperty("里程(km)")
|
@ExcelProperty("里程(km)")
|
||||||
private BigDecimal mileage;
|
private BigDecimal mileage;
|
||||||
@ExcelProperty(value = "预计发货日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("预计发货日期")
|
||||||
private String estimatedStartTime;
|
private LocalDate estimatedStartTime;
|
||||||
@ExcelProperty(value = "预计完成日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("预计完成日期")
|
||||||
private String estimatedEndTime;
|
private LocalDate estimatedEndTime;
|
||||||
@ExcelProperty("单价")
|
@ExcelProperty("单价")
|
||||||
private BigDecimal unitPrice;
|
private BigDecimal unitPrice;
|
||||||
@ExcelProperty("计价单位")
|
@ExcelProperty("计价单位")
|
||||||
private String priceUnit;
|
private String priceUnit;
|
||||||
@ExcelProperty("其他费用合计")
|
@ExcelProperty("其他费用合计")
|
||||||
private BigDecimal otherFeeTotal;
|
private BigDecimal otherFeeTotal;
|
||||||
@ExcelProperty("任务备注")
|
@ExcelProperty("任务备注")
|
||||||
private String taskRemark;
|
private String taskRemark;
|
||||||
@ExcelProperty("原始单号")
|
@ExcelProperty("原始单号")
|
||||||
private String originalNo;
|
private String originalNo;
|
||||||
@ExcelProperty("业务状态")
|
@ExcelProperty("业务状态")
|
||||||
private String businessStatus;
|
private String businessStatus;
|
||||||
@ExcelProperty("数据来源")
|
@ExcelProperty("数据来源")
|
||||||
private String dataSource;
|
private String dataSource;
|
||||||
@ExcelProperty(value = "开始日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("开始日期")
|
||||||
private String startDate;
|
private LocalDate startDate;
|
||||||
@ExcelProperty(value = "结束日期", converter = org.springblade.common.excel.LenientDateStringConverter.class)
|
@ExcelProperty("结束日期")
|
||||||
private String endDate;
|
private LocalDate endDate;
|
||||||
@ExcelProperty("计划名称")
|
@ExcelProperty("计划名称")
|
||||||
private String planName;
|
private String planName;
|
||||||
@ExcelProperty("多联总单")
|
@ExcelProperty("多联总单")
|
||||||
private String masterNo;
|
private String masterNo;
|
||||||
@ExcelProperty("配载单号")
|
@ExcelProperty("配载单号")
|
||||||
private String loadingNo;
|
private String loadingNo;
|
||||||
@ExcelProperty("运单批次号")
|
@ExcelProperty("运单批次号")
|
||||||
private String batchNo;
|
private String batchNo;
|
||||||
@ExcelProperty("关联单号")
|
@ExcelProperty("关联单号")
|
||||||
private String relationNo;
|
private String relationNo;
|
||||||
@ExcelProperty("当前过程节点")
|
@ExcelProperty("当前过程节点")
|
||||||
private String currentProcessNode;
|
private String currentProcessNode;
|
||||||
@ExcelProperty("所属组织")
|
@ExcelProperty("所属组织")
|
||||||
private String deptName;
|
private String deptName;
|
||||||
@ExcelProperty("备注")
|
@ExcelProperty("备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
@ExcelProperty("创建人")
|
@ExcelProperty("创建人")
|
||||||
private String createUserName;
|
private String createUserName;
|
||||||
@ExcelProperty("更新人")
|
@ExcelProperty("更新人")
|
||||||
private String updateUserName;
|
private String updateUserName;
|
||||||
@ExcelProperty("创建时间")
|
@ExcelProperty("创建时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
@ExcelProperty("更新时间")
|
@ExcelProperty("更新时间")
|
||||||
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
|
|
||||||
@ExcelIgnore
|
@ExcelIgnore
|
||||||
private String errorMessage;
|
private String errorMessage;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
package org.springblade.transport.feign;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.transport.pojo.dto.CustomerProcessNodeSyncDTO;
|
||||||
|
import org.springblade.transport.service.ICustomerArchiveService;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客商档案 Feign实现
|
||||||
|
*/
|
||||||
|
@Hidden
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class CustomerArchiveClient implements ICustomerArchiveClient {
|
||||||
|
|
||||||
|
private final ICustomerArchiveService customerArchiveService;
|
||||||
|
|
||||||
|
@TenantIgnore
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@PostMapping(SYNC_PROCESS_NODE)
|
||||||
|
@Override
|
||||||
|
public FR<Boolean> syncProcessNode(@RequestBody CustomerProcessNodeSyncDTO param) {
|
||||||
|
if (param == null) {
|
||||||
|
return FR.data(false);
|
||||||
|
}
|
||||||
|
if (param.getProcessInfo() != null) {
|
||||||
|
return FR.data(customerArchiveService.syncProcessNodeFromProcessInfo(param.getId(), param.getProcessInfo()));
|
||||||
|
}
|
||||||
|
return FR.data(customerArchiveService.syncProcessNode(
|
||||||
|
param.getId(), param.getCurrentNode(), param.getCurrentProcessor(), param.getApprovalStatus()));
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
package org.springblade.transport.feign;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Hidden;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springblade.core.secure.annotation.PreAuth;
|
||||||
|
import org.springblade.core.secure.constant.AuthConstant;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.transport.mk.IMkProcessBizHandler;
|
||||||
|
import org.springblade.transport.mk.MkProcessMessageService;
|
||||||
|
import org.springblade.transport.pojo.dto.MkProcessSyncDTO;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 业务流程同步 Feign 实现
|
||||||
|
*/
|
||||||
|
@Hidden
|
||||||
|
@RestController
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MkProcessClient implements IMkProcessClient {
|
||||||
|
|
||||||
|
private final MkProcessMessageService mkProcessMessageService;
|
||||||
|
|
||||||
|
@TenantIgnore
|
||||||
|
@PreAuth(AuthConstant.PERMIT_ALL)
|
||||||
|
@PostMapping(APPLY)
|
||||||
|
@Override
|
||||||
|
public FR<Boolean> apply(@RequestBody MkProcessSyncDTO param) {
|
||||||
|
if (param == null || param.getId() == null) {
|
||||||
|
return FR.data(false);
|
||||||
|
}
|
||||||
|
IMkProcessBizHandler handler = mkProcessMessageService.handler(param.getBizType());
|
||||||
|
String action = param.getAction() == null ? "sync" : param.getAction();
|
||||||
|
return switch (action) {
|
||||||
|
case "approve" -> FR.data(handler.approveFromProcess(param.getId(), param.getProcessorName()));
|
||||||
|
case "reject" -> FR.data(handler.rejectFromProcess(param.getId(), param.getProcessorName()));
|
||||||
|
default -> FR.data(handler.syncFromProcessInfo(param.getId(), param.getProcessInfo()));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package org.springblade.transport.mk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 业务流程处理器
|
||||||
|
*/
|
||||||
|
public interface IMkProcessBizHandler {
|
||||||
|
|
||||||
|
String bizType();
|
||||||
|
|
||||||
|
Object publicDetail(Long id);
|
||||||
|
|
||||||
|
boolean syncFromProcessInfo(Long id, Object processInfo);
|
||||||
|
|
||||||
|
boolean approveFromProcess(Long id, String processorName);
|
||||||
|
|
||||||
|
boolean rejectFromProcess(Long id, String processorName);
|
||||||
|
}
|
||||||
+439
@@ -0,0 +1,439 @@
|
|||||||
|
package org.springblade.transport.mk;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.utils.Func;
|
||||||
|
import org.springblade.transport.pojo.entity.ContractManage;
|
||||||
|
import org.springblade.transport.pojo.entity.FormalSettlement;
|
||||||
|
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||||
|
import org.springblade.transport.pojo.entity.PreSettlement;
|
||||||
|
import org.springblade.transport.pojo.entity.ProjectApply;
|
||||||
|
import org.springblade.transport.pojo.entity.Waybill;
|
||||||
|
import org.springblade.transport.service.IContractManageService;
|
||||||
|
import org.springblade.transport.service.ICustomerArchiveService;
|
||||||
|
import org.springblade.transport.service.IFormalSettlementService;
|
||||||
|
import org.springblade.transport.service.IPaymentApplicationService;
|
||||||
|
import org.springblade.transport.service.IPreSettlementService;
|
||||||
|
import org.springblade.transport.service.IProjectApplyService;
|
||||||
|
import org.springblade.transport.service.IWaybillService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 各业务 MK 流程处理器
|
||||||
|
*/
|
||||||
|
public final class MkProcessBizHandlers {
|
||||||
|
|
||||||
|
private MkProcessBizHandlers() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class CustomerHandler implements IMkProcessBizHandler {
|
||||||
|
private final ICustomerArchiveService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "customer-archive";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.publicDetail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
return service.syncProcessNodeFromProcessInfo(id, processInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
return service.approveFromProcess(id, processorName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
return service.rejectFromProcess(id, processorName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class ProjectHandler implements IMkProcessBizHandler {
|
||||||
|
private final IProjectApplyService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "project-apply";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
ProjectApply entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
if (!"change_reviewing".equals(entity.getApprovalStatus())) {
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
}
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
ProjectApply entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())
|
||||||
|
|| "change_approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
boolean change = "change_reviewing".equals(entity.getApprovalStatus());
|
||||||
|
entity.setApprovalStatus(change ? "change_approved" : "approved");
|
||||||
|
entity.setEffectiveType("formal");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
entity.setApprovedTime(LocalDateTime.now());
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
ProjectApply entity = service.getById(id);
|
||||||
|
if (entity == null || "rejected".equals(entity.getApprovalStatus())
|
||||||
|
|| "change_rejected".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
boolean change = "change_reviewing".equals(entity.getApprovalStatus());
|
||||||
|
entity.setApprovalStatus(change ? "change_rejected" : "rejected");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class ContractHandler implements IMkProcessBizHandler {
|
||||||
|
private final IContractManageService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "contract-manage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
ContractManage entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
if (!"change_reviewing".equals(entity.getApprovalStatus())) {
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
}
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
ContractManage entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())
|
||||||
|
|| "change_approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
boolean change = "change_reviewing".equals(entity.getApprovalStatus());
|
||||||
|
entity.setApprovalStatus(change ? "change_approved" : "approved");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
ContractManage entity = service.getById(id);
|
||||||
|
if (entity == null || "rejected".equals(entity.getApprovalStatus())
|
||||||
|
|| "change_rejected".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
boolean change = "change_reviewing".equals(entity.getApprovalStatus());
|
||||||
|
entity.setApprovalStatus(change ? "change_rejected" : "rejected");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class WaybillHandler implements IMkProcessBizHandler {
|
||||||
|
private final IWaybillService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "waybill-manage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
Waybill entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
if (Func.isEmpty(node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entity.setCurrentProcessNode(node);
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
Waybill entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entity.setCurrentProcessNode("审核通过");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
Waybill entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entity.setCurrentProcessNode("审核不通过");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class PreSettlementHandler implements IMkProcessBizHandler {
|
||||||
|
private final IPreSettlementService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "pre-settlement";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
PreSettlement entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
PreSettlement entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("approved");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
entity.setApprovedTime(LocalDateTime.now());
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
PreSettlement entity = service.getById(id);
|
||||||
|
if (entity == null || "returned".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("returned");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class FormalSettlementHandler implements IMkProcessBizHandler {
|
||||||
|
private final IFormalSettlementService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "formal-settlement";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
FormalSettlement entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
FormalSettlement entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("approved");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
entity.setApprovedTime(LocalDateTime.now());
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
FormalSettlement entity = service.getById(id);
|
||||||
|
if (entity == null || "returned".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("returned");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public static class PaymentHandler implements IMkProcessBizHandler {
|
||||||
|
private final IPaymentApplicationService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String bizType() {
|
||||||
|
return "payment-application";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object publicDetail(Long id) {
|
||||||
|
return service.detail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean syncFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
PaymentApplication entity = service.getById(id);
|
||||||
|
if (entity == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String node = MkProcessNodeHelper.currentNode(processInfo);
|
||||||
|
String processor = MkProcessNodeHelper.currentProcessor(processInfo);
|
||||||
|
if (Func.isEmpty(node) && Func.isEmpty(processor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(node)) {
|
||||||
|
entity.setCurrentNode(node);
|
||||||
|
}
|
||||||
|
if (Func.isNotEmpty(processor)) {
|
||||||
|
entity.setCurrentProcessor(processor);
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("reviewing");
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
PaymentApplication entity = service.getById(id);
|
||||||
|
if (entity == null || "approved".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("approved");
|
||||||
|
entity.setCurrentNode("审核通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
PaymentApplication entity = service.getById(id);
|
||||||
|
if (entity == null || "returned".equals(entity.getApprovalStatus())) {
|
||||||
|
return entity != null;
|
||||||
|
}
|
||||||
|
entity.setApprovalStatus("returned");
|
||||||
|
entity.setCurrentNode("审核不通过");
|
||||||
|
entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统"));
|
||||||
|
return service.updateById(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+191
@@ -0,0 +1,191 @@
|
|||||||
|
package org.springblade.transport.mk;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.core.tool.utils.StringUtil;
|
||||||
|
import org.springblade.process.feign.IBusinessProcessClient;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公开页流程消息:当前节点立即查询,流程实例详情延迟 5 秒查询后同步业务状态。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MkProcessMessageService {
|
||||||
|
|
||||||
|
private static final long PROCESS_INFO_DELAY_SECONDS = 5L;
|
||||||
|
|
||||||
|
private final IBusinessProcessClient businessProcessClient;
|
||||||
|
private final List<IMkProcessBizHandler> handlers;
|
||||||
|
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2, runnable -> {
|
||||||
|
Thread thread = new Thread(runnable, "mk-process-info-" + THREAD_INDEX.incrementAndGet());
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
});
|
||||||
|
|
||||||
|
private static final AtomicInteger THREAD_INDEX = new AtomicInteger();
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void shutdown() {
|
||||||
|
scheduler.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMkProcessBizHandler handler(String bizType) {
|
||||||
|
Map<String, IMkProcessBizHandler> mapping = handlers.stream()
|
||||||
|
.collect(Collectors.toMap(IMkProcessBizHandler::bizType, Function.identity(), (a, b) -> a));
|
||||||
|
IMkProcessBizHandler handler = mapping.get(bizType);
|
||||||
|
if (handler == null) {
|
||||||
|
throw new IllegalArgumentException("不支持的MK业务类型:" + bizType);
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleProcessMessage(String bizType, Map<String, Object> body) {
|
||||||
|
IMkProcessBizHandler handler = handler(bizType);
|
||||||
|
Map<String, Object> formValues = asMap(body == null ? null : body.get("formValues"));
|
||||||
|
String processId = firstText(formValues, "processId");
|
||||||
|
if (StringUtil.isBlank(processId) && body != null) {
|
||||||
|
processId = firstText(body, "processId");
|
||||||
|
}
|
||||||
|
String loginName = firstText(formValues, "mkLoginName", "loginName");
|
||||||
|
if (StringUtil.isBlank(processId)) {
|
||||||
|
log.warn("公开页流程消息未找到 processId,跳过查询当前节点 bizType={}", bizType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String bizIdText = firstText(asMap(body == null ? null : body.get("formData")), "id", "formInstanceId");
|
||||||
|
queryCurrentNodes(bizType, processId, loginName);
|
||||||
|
scheduleProcessInfo(handler, bizType, processId, loginName, bizIdText, formValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryCurrentNodes(String bizType, String processId, String loginName) {
|
||||||
|
try {
|
||||||
|
FR<Object> result = businessProcessClient.getCurrentNodes(processId, loginName);
|
||||||
|
Object nodeData = result == null ? null : result.getData();
|
||||||
|
log.info("公开页流程消息当前节点详情 bizType={} processId={} loginName={} result={}",
|
||||||
|
bizType, processId, loginName, JSON.toJSONString(nodeData));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("公开页查询当前节点失败 bizType={} processId={} loginName={}", bizType, processId, loginName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleProcessInfo(IMkProcessBizHandler handler, String bizType, String processId,
|
||||||
|
String loginName, String bizIdText, Map<String, Object> formValues) {
|
||||||
|
Map<String, Object> formValuesCopy = new HashMap<>(formValues == null ? Map.of() : formValues);
|
||||||
|
log.info("公开页将在{}秒后查询流程实例详情 bizType={} processId={}", PROCESS_INFO_DELAY_SECONDS, bizType, processId);
|
||||||
|
scheduler.schedule(
|
||||||
|
() -> queryProcessInfo(handler, bizType, processId, loginName, bizIdText, formValuesCopy),
|
||||||
|
PROCESS_INFO_DELAY_SECONDS,
|
||||||
|
TimeUnit.SECONDS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryProcessInfo(IMkProcessBizHandler handler, String bizType, String processId,
|
||||||
|
String loginName, String bizIdText, Map<String, Object> formValues) {
|
||||||
|
try {
|
||||||
|
FR<Object> processInfoResult = businessProcessClient.getProcessInfo(processId, loginName);
|
||||||
|
Object processInfo = processInfoResult == null ? null : processInfoResult.getData();
|
||||||
|
log.info("公开页流程消息流程实例详情 bizType={} processId={} loginName={} result={}",
|
||||||
|
bizType, processId, loginName, JSON.toJSONString(processInfo));
|
||||||
|
if (isProcessFinished(processInfo)) {
|
||||||
|
applyProcessResult(handler, bizType, bizIdText, processId, formValues, true);
|
||||||
|
} else if (isProcessRejected(processInfo)) {
|
||||||
|
applyProcessResult(handler, bizType, bizIdText, processId, formValues, false);
|
||||||
|
} else if (StringUtil.isNotBlank(bizIdText)) {
|
||||||
|
try {
|
||||||
|
handler.syncFromProcessInfo(Long.valueOf(bizIdText), processInfo);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("公开页流程消息业务id格式不正确 bizType={} id={}", bizType, bizIdText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("公开页查询流程实例详情失败 bizType={} processId={} loginName={}", bizType, processId, loginName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isProcessFinished(Object processInfo) {
|
||||||
|
return "30".equals(firstText(asMap(processInfo), "fdProcessStatus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isProcessRejected(Object processInfo) {
|
||||||
|
Map<String, Object> info = asMap(processInfo);
|
||||||
|
if (!"20".equals(firstText(info, "fdProcessStatus"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (hasItems(info.get("currentHandlers"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !hasItems(asMap(info.get("fdTaskInfo")).get("handlerInfos"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasItems(Object value) {
|
||||||
|
return value instanceof Collection<?> collection && !collection.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyProcessResult(IMkProcessBizHandler handler, String bizType, String bizIdText,
|
||||||
|
String processId, Map<String, Object> formValues, boolean approved) {
|
||||||
|
String action = approved ? "审核通过" : "审核驳回";
|
||||||
|
if (StringUtil.isBlank(bizIdText)) {
|
||||||
|
log.warn("流程{}但未找到业务id,跳过同步 bizType={} processId={}", action, bizType, processId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String processorName = firstText(formValues, "mkUserName", "mkLoginName");
|
||||||
|
Long bizId = Long.valueOf(bizIdText);
|
||||||
|
if (approved) {
|
||||||
|
handler.approveFromProcess(bizId, processorName);
|
||||||
|
} else {
|
||||||
|
handler.rejectFromProcess(bizId, processorName);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("流程{}但业务id格式不正确 bizType={} id={}", action, bizType, bizIdText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> asMap(Object value) {
|
||||||
|
if (!(value instanceof Map<?, ?> map)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
map.forEach((key, nested) -> {
|
||||||
|
if (key != null) {
|
||||||
|
result.put(String.valueOf(key), nested);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String firstText(Map<String, Object> source, String... keys) {
|
||||||
|
if (source == null || keys == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (String key : keys) {
|
||||||
|
Object value = source.get(key);
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String text = String.valueOf(value).trim();
|
||||||
|
if (StringUtil.isNotBlank(text) && !"null".equalsIgnoreCase(text)) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
package org.springblade.transport.mk;
|
||||||
|
|
||||||
|
import org.springblade.core.tool.jackson.JsonUtil;
|
||||||
|
import org.springblade.core.tool.utils.Func;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 MK 流程实例详情中的当前节点、当前处理人
|
||||||
|
*/
|
||||||
|
public final class MkProcessNodeHelper {
|
||||||
|
|
||||||
|
private MkProcessNodeHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String currentProcessor(Object processInfo) {
|
||||||
|
return joinDistinct(extractTexts(asMap(processInfo).get("currentHandlers"), "fdName", "name"), "、");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String currentNode(Object processInfo) {
|
||||||
|
Map<String, Object> taskInfo = asMap(asMap(processInfo).get("fdTaskInfo"));
|
||||||
|
return joinDistinct(extractTexts(taskInfo.get("handlerInfos"), "nodeName"), "、");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String text(String value, String fallback) {
|
||||||
|
return Func.isEmpty(value) ? fallback : value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> asMap(Object value) {
|
||||||
|
if (value instanceof Map<?, ?> map) {
|
||||||
|
Map<String, Object> result = new LinkedHashMap<>();
|
||||||
|
map.forEach((key, nested) -> {
|
||||||
|
if (key != null) {
|
||||||
|
result.put(String.valueOf(key), nested);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map<String, Object> parsed = JsonUtil.toMap(JsonUtil.toJson(value));
|
||||||
|
return parsed == null ? Map.of() : parsed;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> extractTexts(Object listObj, String... keys) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (!(listObj instanceof Collection<?> collection) || keys == null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (Object item : collection) {
|
||||||
|
Map<String, Object> map = asMap(item);
|
||||||
|
for (String key : keys) {
|
||||||
|
String text = Func.toStr(map.get(key), "").trim();
|
||||||
|
if (Func.isNotEmpty(text)) {
|
||||||
|
result.add(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String joinDistinct(List<String> values, String delimiter) {
|
||||||
|
return values.stream().filter(Func::isNotEmpty).distinct().collect(Collectors.joining(delimiter));
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
@@ -100,6 +100,53 @@ public interface ICustomerArchiveService extends BaseService<CustomerArchive> {
|
|||||||
*/
|
*/
|
||||||
boolean submitApproval(Long id);
|
boolean submitApproval(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 MK 当前节点同步客商当前节点、当前处理人和审批状态
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param currentNode 当前节点
|
||||||
|
* @param currentProcessor 当前处理人
|
||||||
|
* @param approvalStatus 审批状态,可为空,为空时保持为审核中
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean syncProcessNode(Long id, String currentNode, String currentProcessor, String approvalStatus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 MK getCurrentNodes 返回结果同步客商当前节点
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param currentNodes MK 当前节点详情
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean syncProcessNodeFromMk(Long id, Object currentNodes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 MK 流程实例详情回写当前节点、当前处理人
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param processInfo MK getProcessInfo 返回数据
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean syncProcessNodeFromProcessInfo(Long id, Object processInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 流程结束(fdProcessStatus=30)时将客商置为审核通过
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param processorName 当前处理人,可为空
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean approveFromProcess(Long id, String processorName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MK 流程状态为 20 时将客商置为审核驳回
|
||||||
|
*
|
||||||
|
* @param id 客商ID
|
||||||
|
* @param processorName 当前处理人,可为空
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean rejectFromProcess(Long id, String processorName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 撤回审批并恢复草稿状态
|
* 撤回审批并恢复草稿状态
|
||||||
*
|
*
|
||||||
|
|||||||
-1
@@ -94,7 +94,6 @@ public class AccidentRecordServiceImpl extends BaseServiceImpl<AccidentRecordMap
|
|||||||
AccidentRecordExcel excel = data.get(index);
|
AccidentRecordExcel excel = data.get(index);
|
||||||
try {
|
try {
|
||||||
AccidentRecord accidentRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, AccidentRecord.class));
|
AccidentRecord accidentRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, AccidentRecord.class));
|
||||||
accidentRecord.setAccidentDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getAccidentDate(), "事故发生日期"));
|
|
||||||
prepare(accidentRecord);
|
prepare(accidentRecord);
|
||||||
List<String> validationErrors = validateImportAccidentRecord(accidentRecord);
|
List<String> validationErrors = validateImportAccidentRecord(accidentRecord);
|
||||||
if (Func.isNotEmpty(validationErrors)) {
|
if (Func.isNotEmpty(validationErrors)) {
|
||||||
|
|||||||
-2
@@ -113,8 +113,6 @@ public class AnnualInspectionRecordServiceImpl extends BaseServiceImpl<AnnualIns
|
|||||||
AnnualInspectionRecordExcel excel = data.get(index);
|
AnnualInspectionRecordExcel excel = data.get(index);
|
||||||
try {
|
try {
|
||||||
AnnualInspectionRecord annualInspectionRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, AnnualInspectionRecord.class));
|
AnnualInspectionRecord annualInspectionRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, AnnualInspectionRecord.class));
|
||||||
annualInspectionRecord.setInspectionAssessmentDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getInspectionAssessmentDate(), "检测评定日期"));
|
|
||||||
annualInspectionRecord.setValidUntilDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getValidUntilDate(), "有效期截止日"));
|
|
||||||
prepare(annualInspectionRecord);
|
prepare(annualInspectionRecord);
|
||||||
List<String> validationErrors = validateImportAnnualInspectionRecord(annualInspectionRecord);
|
List<String> validationErrors = validateImportAnnualInspectionRecord(annualInspectionRecord);
|
||||||
if (Func.isNotEmpty(validationErrors)) {
|
if (Func.isNotEmpty(validationErrors)) {
|
||||||
|
|||||||
+182
@@ -0,0 +1,182 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
*/
|
||||||
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||||
|
import org.springblade.core.tool.api.FR;
|
||||||
|
import org.springblade.core.tool.utils.StringUtil;
|
||||||
|
import org.springblade.process.feign.IBusinessProcessClient;
|
||||||
|
import org.springblade.transport.service.ICustomerArchiveService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客商公开页流程消息处理:当前节点立即查询,流程实例详情延迟查询。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@TenantIgnore
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CustomerArchivePublicProcessService {
|
||||||
|
|
||||||
|
private static final long PROCESS_INFO_DELAY_SECONDS = 5L;
|
||||||
|
|
||||||
|
private final ICustomerArchiveService customerArchiveService;
|
||||||
|
private final IBusinessProcessClient businessProcessClient;
|
||||||
|
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2, runnable -> {
|
||||||
|
Thread thread = new Thread(runnable, "customer-archive-process-info-" + THREAD_INDEX.incrementAndGet());
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
});
|
||||||
|
|
||||||
|
private static final AtomicInteger THREAD_INDEX = new AtomicInteger();
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void shutdown() {
|
||||||
|
scheduler.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleProcessMessage(Map<String, Object> body) {
|
||||||
|
Map<String, Object> formValues = asMap(body == null ? null : body.get("formValues"));
|
||||||
|
String processId = firstText(formValues, "processId");
|
||||||
|
if (StringUtil.isBlank(processId) && body != null) {
|
||||||
|
processId = firstText(body, "processId");
|
||||||
|
}
|
||||||
|
String loginName = firstText(formValues, "mkLoginName", "loginName");
|
||||||
|
if (StringUtil.isBlank(processId)) {
|
||||||
|
log.warn("客商公开页流程消息未找到 processId,跳过查询当前节点");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String customerIdText = firstText(asMap(body == null ? null : body.get("formData")), "id");
|
||||||
|
queryCurrentNodes(processId, loginName);
|
||||||
|
scheduleProcessInfo(processId, loginName, customerIdText, formValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryCurrentNodes(String processId, String loginName) {
|
||||||
|
try {
|
||||||
|
FR<Object> result = businessProcessClient.getCurrentNodes(processId, loginName);
|
||||||
|
Object nodeData = result == null ? null : result.getData();
|
||||||
|
log.info("客商公开页流程消息当前节点详情 processId={} loginName={} result={}",
|
||||||
|
processId, loginName, JSON.toJSONString(nodeData));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("客商公开页查询当前节点失败 processId={} loginName={}", processId, loginName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleProcessInfo(String processId, String loginName, String customerIdText,
|
||||||
|
Map<String, Object> formValues) {
|
||||||
|
Map<String, Object> formValuesCopy = new HashMap<>(formValues == null ? Map.of() : formValues);
|
||||||
|
log.info("客商公开页将在{}秒后查询流程实例详情 processId={}", PROCESS_INFO_DELAY_SECONDS, processId);
|
||||||
|
scheduler.schedule(
|
||||||
|
() -> queryProcessInfo(processId, loginName, customerIdText, formValuesCopy),
|
||||||
|
PROCESS_INFO_DELAY_SECONDS,
|
||||||
|
TimeUnit.SECONDS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryProcessInfo(String processId, String loginName, String customerIdText,
|
||||||
|
Map<String, Object> formValues) {
|
||||||
|
try {
|
||||||
|
FR<Object> processInfoResult = businessProcessClient.getProcessInfo(processId, loginName);
|
||||||
|
Object processInfo = processInfoResult == null ? null : processInfoResult.getData();
|
||||||
|
log.info("客商公开页流程消息流程实例详情 processId={} loginName={} result={}",
|
||||||
|
processId, loginName, JSON.toJSONString(processInfo));
|
||||||
|
if (isProcessFinished(processInfo)) {
|
||||||
|
applyProcessResult(customerIdText, processId, formValues, true);
|
||||||
|
} else if (isProcessRejected(processInfo)) {
|
||||||
|
applyProcessResult(customerIdText, processId, formValues, false);
|
||||||
|
} else if (StringUtil.isNotBlank(customerIdText)) {
|
||||||
|
try {
|
||||||
|
customerArchiveService.syncProcessNodeFromProcessInfo(Long.valueOf(customerIdText), processInfo);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("客商公开页流程消息客商id格式不正确:{}", customerIdText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("客商公开页查询流程实例详情失败 processId={} loginName={}", processId, loginName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isProcessFinished(Object processInfo) {
|
||||||
|
return "30".equals(firstText(asMap(processInfo), "fdProcessStatus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isProcessRejected(Object processInfo) {
|
||||||
|
Map<String, Object> info = asMap(processInfo);
|
||||||
|
if (!"20".equals(firstText(info, "fdProcessStatus"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (hasItems(info.get("currentHandlers"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !hasItems(asMap(info.get("fdTaskInfo")).get("handlerInfos"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasItems(Object value) {
|
||||||
|
return value instanceof Collection<?> collection && !collection.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyProcessResult(String customerIdText, String processId, Map<String, Object> formValues,
|
||||||
|
boolean approved) {
|
||||||
|
String action = approved ? "审核通过" : "审核驳回";
|
||||||
|
if (StringUtil.isBlank(customerIdText)) {
|
||||||
|
log.warn("流程{}但未找到客商id,跳过同步 processId={}", action, processId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String processorName = firstText(formValues, "mkUserName", "mkLoginName");
|
||||||
|
Long customerId = Long.valueOf(customerIdText);
|
||||||
|
if (approved) {
|
||||||
|
customerArchiveService.approveFromProcess(customerId, processorName);
|
||||||
|
} else {
|
||||||
|
customerArchiveService.rejectFromProcess(customerId, processorName);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("流程{}但客商id格式不正确:{}", action, customerIdText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> asMap(Object value) {
|
||||||
|
if (!(value instanceof Map<?, ?> map)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
map.forEach((key, nested) -> {
|
||||||
|
if (key != null) {
|
||||||
|
result.put(String.valueOf(key), nested);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String firstText(Map<String, Object> source, String... keys) {
|
||||||
|
if (source == null || keys == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (String key : keys) {
|
||||||
|
Object value = source.get(key);
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String text = String.valueOf(value).trim();
|
||||||
|
if (StringUtil.isNotBlank(text) && !"null".equalsIgnoreCase(text)) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+211
-2
@@ -29,6 +29,7 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
|||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
@@ -85,6 +86,7 @@ import java.math.RoundingMode;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -101,6 +103,7 @@ import java.util.stream.Collectors;
|
|||||||
*
|
*
|
||||||
* @author Chill
|
* @author Chill
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveMapper, CustomerArchive> implements ICustomerArchiveService {
|
public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveMapper, CustomerArchive> implements ICustomerArchiveService {
|
||||||
@@ -214,12 +217,151 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
CustomerArchive before = Objects.requireNonNull(BeanUtil.copyProperties(detail, CustomerArchive.class));
|
CustomerArchive before = Objects.requireNonNull(BeanUtil.copyProperties(detail, CustomerArchive.class));
|
||||||
CustomerArchive after = copyCustomer(before);
|
CustomerArchive after = copyCustomer(before);
|
||||||
after.setApprovalStatus(APPROVAL_REVIEWING);
|
after.setApprovalStatus(APPROVAL_REVIEWING);
|
||||||
after.setCurrentNode("客商准入审批");
|
if (Func.isEmpty(after.getCurrentNode()) || Objects.equals(after.getCurrentNode(), "草稿")) {
|
||||||
after.setCurrentProcessor("待处理");
|
after.setCurrentNode("客商准入审批");
|
||||||
|
after.setCurrentProcessor("待处理");
|
||||||
|
}
|
||||||
addChangeRecord(id, "提交客商准入审批", before, after);
|
addChangeRecord(id, "提交客商准入审批", before, after);
|
||||||
return updateById(after);
|
return updateById(after);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean syncProcessNode(Long id, String currentNode, String currentProcessor, String approvalStatus) {
|
||||||
|
if (Func.isEmpty(id)) {
|
||||||
|
log.warn("同步客商当前节点失败,客商ID为空");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CustomerArchive customer = getById(id);
|
||||||
|
if (customer == null || Objects.equals(customer.getIsDeleted(), 1)) {
|
||||||
|
log.warn("同步客商当前节点失败,客商不存在 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String nextStatus = Func.isEmpty(approvalStatus) ? APPROVAL_REVIEWING : approvalStatus;
|
||||||
|
boolean updated = this.lambdaUpdate()
|
||||||
|
.eq(CustomerArchive::getId, id)
|
||||||
|
.set(Func.isNotEmpty(currentNode), CustomerArchive::getCurrentNode, currentNode)
|
||||||
|
.set(Func.isNotEmpty(currentProcessor), CustomerArchive::getCurrentProcessor, currentProcessor)
|
||||||
|
.set(Func.isNotEmpty(nextStatus), CustomerArchive::getApprovalStatus, nextStatus)
|
||||||
|
.update();
|
||||||
|
log.info("同步客商当前节点 id={} currentNode={} currentProcessor={} approvalStatus={} result={}",
|
||||||
|
id, currentNode, currentProcessor, nextStatus, updated);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean syncProcessNodeFromMk(Long id, Object currentNodes) {
|
||||||
|
if (Func.isEmpty(id) || currentNodes == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<Map<String, Object>> nodes = normalizeMkNodeList(currentNodes);
|
||||||
|
if (nodes.isEmpty()) {
|
||||||
|
log.warn("同步客商当前节点跳过,节点详情为空 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<String> nodeNames = new ArrayList<>();
|
||||||
|
List<String> handlerNames = new ArrayList<>();
|
||||||
|
for (Map<String, Object> node : nodes) {
|
||||||
|
String nodeName = Func.toStr(node.get("nodeName"), "").trim();
|
||||||
|
if (Func.isNotEmpty(nodeName)) {
|
||||||
|
nodeNames.add(nodeName);
|
||||||
|
}
|
||||||
|
Object handlers = node.get("nodeHandlers");
|
||||||
|
if (!(handlers instanceof Collection<?> handlerList)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Object handler : handlerList) {
|
||||||
|
Map<String, Object> handlerMap = asStringObjectMap(handler);
|
||||||
|
String handlerName = Func.toStr(handlerMap.get("handlerName"), "").trim();
|
||||||
|
if (Func.isNotEmpty(handlerName)) {
|
||||||
|
handlerNames.add(handlerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return syncProcessNode(id, joinDistinct(nodeNames), joinDistinct(handlerNames), APPROVAL_REVIEWING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean syncProcessNodeFromProcessInfo(Long id, Object processInfo) {
|
||||||
|
if (Func.isEmpty(id) || processInfo == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Map<String, Object> info = asStringObjectMap(processInfo);
|
||||||
|
if (info.isEmpty()) {
|
||||||
|
log.warn("同步客商当前节点跳过,流程实例详情为空 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String currentProcessor = joinDistinct(extractTexts(info.get("currentHandlers"), "fdName", "name"), "、");
|
||||||
|
Map<String, Object> taskInfo = asStringObjectMap(info.get("fdTaskInfo"));
|
||||||
|
String currentNode = joinDistinct(extractTexts(taskInfo.get("handlerInfos"), "nodeName"), "、");
|
||||||
|
if (Func.isEmpty(currentNode) && Func.isEmpty(currentProcessor)) {
|
||||||
|
log.warn("同步客商当前节点跳过,未解析到节点名称或处理人 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return syncProcessNode(id, currentNode, currentProcessor, APPROVAL_REVIEWING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean approveFromProcess(Long id, String processorName) {
|
||||||
|
if (Func.isEmpty(id)) {
|
||||||
|
log.warn("流程结束审核通过失败,客商ID为空");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CustomerArchive before = getById(id);
|
||||||
|
if (before == null || Objects.equals(before.getIsDeleted(), 1)) {
|
||||||
|
log.warn("流程结束审核通过失败,客商不存在 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Objects.equals(before.getApprovalStatus(), APPROVAL_APPROVED)) {
|
||||||
|
log.info("流程结束审核通过跳过,客商已是审核通过 id={}", id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
CustomerArchive after = copyCustomer(before);
|
||||||
|
after.setAccessType(ACCESS_FORMAL);
|
||||||
|
after.setApprovalStatus(APPROVAL_APPROVED);
|
||||||
|
after.setCurrentNode("审核通过");
|
||||||
|
after.setCurrentProcessor(Func.isEmpty(processorName) ? "系统" : processorName.trim());
|
||||||
|
after.setApprovedTime(LocalDateTime.now());
|
||||||
|
addChangeRecord(id, "客商准入审核通过", before, after);
|
||||||
|
boolean updated = updateById(after);
|
||||||
|
log.info("流程结束审核通过 id={} processor={} result={}", id, after.getCurrentProcessor(), updated);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@TenantIgnore
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean rejectFromProcess(Long id, String processorName) {
|
||||||
|
if (Func.isEmpty(id)) {
|
||||||
|
log.warn("流程审核驳回失败,客商ID为空");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CustomerArchive before = getById(id);
|
||||||
|
if (before == null || Objects.equals(before.getIsDeleted(), 1)) {
|
||||||
|
log.warn("流程审核驳回失败,客商不存在 id={}", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Objects.equals(before.getApprovalStatus(), APPROVAL_REJECTED)) {
|
||||||
|
log.info("流程审核驳回跳过,客商已是审核不通过 id={}", id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
CustomerArchive after = copyCustomer(before);
|
||||||
|
after.setApprovalStatus(APPROVAL_REJECTED);
|
||||||
|
after.setCurrentNode("审核不通过");
|
||||||
|
after.setCurrentProcessor(Func.isEmpty(processorName) ? "系统" : processorName.trim());
|
||||||
|
addChangeRecord(id, "客商准入审核不通过", before, after);
|
||||||
|
boolean updated = updateById(after);
|
||||||
|
log.info("流程审核驳回 id={} processor={} result={}", id, after.getCurrentProcessor(), updated);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public boolean withdrawApproval(Long id) {
|
public boolean withdrawApproval(Long id) {
|
||||||
@@ -1032,6 +1174,73 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
|
|||||||
return Objects.requireNonNull(BeanUtil.copyProperties(customer, CustomerArchive.class));
|
return Objects.requireNonNull(BeanUtil.copyProperties(customer, CustomerArchive.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private List<Map<String, Object>> normalizeMkNodeList(Object currentNodes) {
|
||||||
|
Object source = currentNodes;
|
||||||
|
if (source instanceof String text && Func.isNotEmpty(text.trim())) {
|
||||||
|
source = JsonUtil.parse(text, List.class);
|
||||||
|
}
|
||||||
|
if (source instanceof Collection<?> collection) {
|
||||||
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
|
for (Object item : collection) {
|
||||||
|
Map<String, Object> map = asStringObjectMap(item);
|
||||||
|
if (!map.isEmpty()) {
|
||||||
|
result.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Map<String, Object> single = asStringObjectMap(source);
|
||||||
|
return single.isEmpty() ? List.of() : List.of(single);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> asStringObjectMap(Object value) {
|
||||||
|
if (value instanceof Map<?, ?> map) {
|
||||||
|
Map<String, Object> result = new LinkedHashMap<>();
|
||||||
|
map.forEach((key, nested) -> {
|
||||||
|
if (key != null) {
|
||||||
|
result.put(String.valueOf(key), nested);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map<String, Object> parsed = JsonUtil.toMap(JsonUtil.toJson(value));
|
||||||
|
return parsed == null ? Map.of() : parsed;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String joinDistinct(List<String> values) {
|
||||||
|
return joinDistinct(values, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String joinDistinct(List<String> values, String delimiter) {
|
||||||
|
return values.stream().filter(Func::isNotEmpty).distinct().collect(Collectors.joining(delimiter));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> extractTexts(Object listObj, String... keys) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (!(listObj instanceof Collection<?> collection) || keys == null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (Object item : collection) {
|
||||||
|
Map<String, Object> map = asStringObjectMap(item);
|
||||||
|
for (String key : keys) {
|
||||||
|
String text = Func.toStr(map.get(key), "").trim();
|
||||||
|
if (Func.isNotEmpty(text)) {
|
||||||
|
result.add(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private void addChangeRecord(Long customerId, String content, CustomerArchive before, CustomerArchive after) {
|
private void addChangeRecord(Long customerId, String content, CustomerArchive before, CustomerArchive after) {
|
||||||
Map<String, Object> beforeSnapshot = customerSnapshot(before);
|
Map<String, Object> beforeSnapshot = customerSnapshot(before);
|
||||||
Map<String, Object> afterSnapshot = customerSnapshot(after);
|
Map<String, Object> afterSnapshot = customerSnapshot(after);
|
||||||
|
|||||||
-1
@@ -91,7 +91,6 @@ public class EquipmentLedgerServiceImpl extends BaseServiceImpl<EquipmentLedgerM
|
|||||||
EquipmentLedgerExcel excel = data.get(index);
|
EquipmentLedgerExcel excel = data.get(index);
|
||||||
try {
|
try {
|
||||||
EquipmentLedger equipmentLedger = Objects.requireNonNull(BeanUtil.copyProperties(excel, EquipmentLedger.class));
|
EquipmentLedger equipmentLedger = Objects.requireNonNull(BeanUtil.copyProperties(excel, EquipmentLedger.class));
|
||||||
equipmentLedger.setFactoryDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getFactoryDate(), "出厂日期"));
|
|
||||||
prepare(equipmentLedger);
|
prepare(equipmentLedger);
|
||||||
if (equipmentLedger.getId() == null && Func.isEmpty(equipmentLedger.getEquipmentCode())) {
|
if (equipmentLedger.getId() == null && Func.isEmpty(equipmentLedger.getEquipmentCode())) {
|
||||||
equipmentLedger.setEquipmentCode(nextEquipmentCode(importEquipmentCodes));
|
equipmentLedger.setEquipmentCode(nextEquipmentCode(importEquipmentCodes));
|
||||||
|
|||||||
-3
@@ -119,9 +119,6 @@ public class InsuranceRecordServiceImpl extends BaseServiceImpl<InsuranceRecordM
|
|||||||
InsuranceRecordExcel excel = data.get(index);
|
InsuranceRecordExcel excel = data.get(index);
|
||||||
try {
|
try {
|
||||||
InsuranceRecord insuranceRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, InsuranceRecord.class));
|
InsuranceRecord insuranceRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, InsuranceRecord.class));
|
||||||
insuranceRecord.setStartDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getStartDate(), "开始日期"));
|
|
||||||
insuranceRecord.setEndDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getEndDate(), "结束日期"));
|
|
||||||
insuranceRecord.setInvoiceDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getInvoiceDate(), "开票日期"));
|
|
||||||
prepare(insuranceRecord);
|
prepare(insuranceRecord);
|
||||||
List<String> validationErrors = validateImportInsuranceRecord(insuranceRecord);
|
List<String> validationErrors = validateImportInsuranceRecord(insuranceRecord);
|
||||||
if (Func.isNotEmpty(insuranceRecord.getVehicleType()) && Func.isNotEmpty(insuranceRecord.getInsuranceType()) && Func.isNotEmpty(insuranceRecord.getPolicyNo())) {
|
if (Func.isNotEmpty(insuranceRecord.getVehicleType()) && Func.isNotEmpty(insuranceRecord.getInsuranceType()) && Func.isNotEmpty(insuranceRecord.getPolicyNo())) {
|
||||||
|
|||||||
+1
-36
@@ -174,7 +174,6 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
throw new ServiceException("配载标识号已存在:" + normalizedLoadingNo);
|
throw new ServiceException("配载标识号已存在:" + normalizedLoadingNo);
|
||||||
}
|
}
|
||||||
Waybill first = waybills.get(0);
|
Waybill first = waybills.get(0);
|
||||||
Waybill last = waybills.get(waybills.size() - 1);
|
|
||||||
LoadingManage loadingManage = new LoadingManage();
|
LoadingManage loadingManage = new LoadingManage();
|
||||||
loadingManage.setLoadingNo(normalizedLoadingNo);
|
loadingManage.setLoadingNo(normalizedLoadingNo);
|
||||||
loadingManage.setLoadingSubNos(waybills.stream()
|
loadingManage.setLoadingSubNos(waybills.stream()
|
||||||
@@ -198,8 +197,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
loadingManage.setCarrierName(first.getCarrierName());
|
loadingManage.setCarrierName(first.getCarrierName());
|
||||||
loadingManage.setCarrierContractId(first.getCarrierContractId());
|
loadingManage.setCarrierContractId(first.getCarrierContractId());
|
||||||
loadingManage.setDepartureAddress(first.getDepartureAddress());
|
loadingManage.setDepartureAddress(first.getDepartureAddress());
|
||||||
loadingManage.setTransitAddress(buildImportedRouteTransitAddress(waybills));
|
loadingManage.setArrivalAddress(first.getArrivalAddress());
|
||||||
loadingManage.setArrivalAddress(last.getArrivalAddress());
|
|
||||||
loadingManage.setOriginalNo(first.getOriginalNo());
|
loadingManage.setOriginalNo(first.getOriginalNo());
|
||||||
loadingManage.setDataSource("批量导入");
|
loadingManage.setDataSource("批量导入");
|
||||||
loadingManage.setStartDate(first.getStartDate());
|
loadingManage.setStartDate(first.getStartDate());
|
||||||
@@ -224,39 +222,6 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
.set(Waybill::getLoadingNo, normalizedLoadingNo));
|
.set(Waybill::getLoadingNo, normalizedLoadingNo));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据导入运单构建配载单的途经地:
|
|
||||||
* 组内运单按导入顺序串联路线,上一票的到货地址与下一票的发货地址相同(中途卸货点)时只保留一个点,
|
|
||||||
* 最终形成“首票发货地 → 途经点 → 末票到货地”。
|
|
||||||
*/
|
|
||||||
private String buildImportedRouteTransitAddress(List<Waybill> waybills) {
|
|
||||||
// 按顺序收集全部节点:首票发货地、每票到货地;节点与相邻前一点相同则重合跳过
|
|
||||||
List<String> nodes = new ArrayList<>();
|
|
||||||
for (Waybill waybill : waybills) {
|
|
||||||
String departure = TransportBusinessSupport.trimToNull(waybill.getDepartureAddress());
|
|
||||||
String arrival = TransportBusinessSupport.trimToNull(waybill.getArrivalAddress());
|
|
||||||
appendRouteNode(nodes, departure);
|
|
||||||
appendRouteNode(nodes, arrival);
|
|
||||||
}
|
|
||||||
// 途经点 = 去掉首尾(首票发货地、末票到货地)后的中间节点
|
|
||||||
List<String> transitNodes = nodes.size() > 2 ? nodes.subList(1, nodes.size() - 1) : List.of();
|
|
||||||
if (Func.isEmpty(transitNodes)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return String.join(" - ", transitNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void appendRouteNode(List<String> nodes, String address) {
|
|
||||||
if (Func.isEmpty(address)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!nodes.isEmpty() && nodes.get(nodes.size() - 1).equals(address)) {
|
|
||||||
// 与上一节点相同视为同一地点,重合不重复
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nodes.add(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public BusinessRemoveResultVO removeLoadingManage(String ids) {
|
public BusinessRemoveResultVO removeLoadingManage(String ids) {
|
||||||
|
|||||||
-1
@@ -75,7 +75,6 @@ public class OtherExpenseRecordServiceImpl extends BaseServiceImpl<OtherExpenseR
|
|||||||
OtherExpenseRecordExcel excel = data.get(index);
|
OtherExpenseRecordExcel excel = data.get(index);
|
||||||
try {
|
try {
|
||||||
OtherExpenseRecord otherExpenseRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, OtherExpenseRecord.class));
|
OtherExpenseRecord otherExpenseRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, OtherExpenseRecord.class));
|
||||||
otherExpenseRecord.setExpenseDate(org.springblade.common.excel.LenientDateParser.parseDate(excel.getExpenseDate(), "费用日期"));
|
|
||||||
otherExpenseRecord.setDataSource("批量导入");
|
otherExpenseRecord.setDataSource("批量导入");
|
||||||
prepare(otherExpenseRecord);
|
prepare(otherExpenseRecord);
|
||||||
List<String> validationErrors = validateImportOtherExpenseRecord(otherExpenseRecord);
|
List<String> validationErrors = validateImportOtherExpenseRecord(otherExpenseRecord);
|
||||||
|
|||||||
+6
-3
@@ -43,6 +43,8 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -62,6 +64,7 @@ public class TireReplacementRecordServiceImpl extends BaseServiceImpl<TireReplac
|
|||||||
private static final int REMARK_MAX_LENGTH = 500;
|
private static final int REMARK_MAX_LENGTH = 500;
|
||||||
private static final int ATTACHMENTS_MAX_LENGTH = 1000;
|
private static final int ATTACHMENTS_MAX_LENGTH = 1000;
|
||||||
private static final int MONEY_SCALE = 2;
|
private static final int MONEY_SCALE = 2;
|
||||||
|
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IPage<TireReplacementRecordVO> selectTireReplacementRecordPage(IPage<TireReplacementRecordVO> page, TireReplacementRecordVO tireReplacementRecord) {
|
public IPage<TireReplacementRecordVO> selectTireReplacementRecordPage(IPage<TireReplacementRecordVO> page, TireReplacementRecordVO tireReplacementRecord) {
|
||||||
@@ -141,9 +144,9 @@ public class TireReplacementRecordServiceImpl extends BaseServiceImpl<TireReplac
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return org.springblade.common.excel.LenientDateParser.parseDate(normalizedValue, "换胎时间");
|
return LocalDate.parse(normalizedValue, DATE_FORMATTER);
|
||||||
} catch (Exception exception) {
|
} catch (DateTimeParseException exception) {
|
||||||
validationErrors.add(exception.getMessage());
|
validationErrors.add("换胎时间格式不正确,请使用yyyy-MM-dd格式并填写有效日期");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-7
@@ -416,9 +416,9 @@ public class TransportPlanServiceImpl extends BaseServiceImpl<TransportPlanMappe
|
|||||||
// 2. 校验运输类型枚举值
|
// 2. 校验运输类型枚举值
|
||||||
String transportType = trimToEmpty(excel.getTransportType());
|
String transportType = trimToEmpty(excel.getTransportType());
|
||||||
if (Func.isNotEmpty(transportType)) {
|
if (Func.isNotEmpty(transportType)) {
|
||||||
List<String> validTransportTypes = List.of("公路运输", "铁路运输", "水路运输", "航空运输");
|
List<String> validTransportTypes = List.of("公路整车", "公路配载/零担", "铁路运输", "水路运输", "跨境海运", "航空运输");
|
||||||
if (!validTransportTypes.contains(transportType)) {
|
if (!validTransportTypes.contains(transportType)) {
|
||||||
errors.add("运输类型需系统枚举值(公路运输、铁路运输、水路运输、航空运输)");
|
errors.add("运输类型需系统枚举值(公路整车、公路配载/零担、铁路运输、水路运输、跨境海运、航空运输)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,12 +510,11 @@ public class TransportPlanServiceImpl extends BaseServiceImpl<TransportPlanMappe
|
|||||||
if (Func.isEmpty(value)) {
|
if (Func.isEmpty(value)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// 宽容解析:接受 2026-8-2、2026/8/2 等写法(口径见根工作区 docs/import-spec.md)。
|
try {
|
||||||
LocalDate date = org.springblade.common.excel.LenientDateParser.parseDateLenientlyOrNull(value);
|
return LocalDate.parse(value.trim(), DateTimeFormatter.ISO_LOCAL_DATE);
|
||||||
if (date == null) {
|
} catch (Exception exception) {
|
||||||
throw new ServiceException(fieldName + " 日期格式无法识别:" + value.trim());
|
throw new ServiceException(fieldName + "格式必须为 YYYY-MM-DD");
|
||||||
}
|
}
|
||||||
return date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateImportLength(String value, int maxLength, String fieldName) {
|
private void validateImportLength(String value, int maxLength, String fieldName) {
|
||||||
|
|||||||
+8
-5
@@ -60,6 +60,7 @@ import java.math.BigDecimal;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -1345,12 +1346,14 @@ public class TransportReconciliationServiceImpl
|
|||||||
|
|
||||||
private LocalDateTime parseTimeNullable(String value, String field) {
|
private LocalDateTime parseTimeNullable(String value, String field) {
|
||||||
if (Func.isEmpty(value)) return null;
|
if (Func.isEmpty(value)) return null;
|
||||||
// 宽容解析:统一委托公共解析器,接受 2026-8-2 12:3 等写法(口径见根工作区 docs/import-spec.md)。
|
for (String pattern : List.of("yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-M-d HH:mm:ss", "yyyy-M-d HH:mm",
|
||||||
LocalDateTime result = org.springblade.common.excel.LenientDateParser.parseDateTimeOrNull(value);
|
"yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/M/d HH:mm:ss", "yyyy/M/d HH:mm")) {
|
||||||
if (result == null) {
|
try { return LocalDateTime.parse(value.trim(), DateTimeFormatter.ofPattern(pattern)); } catch (DateTimeParseException ignored) { }
|
||||||
throw new ServiceException(field + " 日期格式无法识别:" + value.trim());
|
|
||||||
}
|
}
|
||||||
return result;
|
for (String pattern : List.of("yyyy-MM-dd", "yyyy-M-d", "yyyy/MM/dd", "yyyy/M/d")) {
|
||||||
|
try { return LocalDate.parse(value.trim(), DateTimeFormatter.ofPattern(pattern)).atStartOfDay(); } catch (DateTimeParseException ignored) { }
|
||||||
|
}
|
||||||
|
throw new ServiceException(field + "格式应为yyyy-MM-dd HH:mm:ss或yyyy-MM-dd");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String matchKey(TransportReconciliationInternal row) {
|
private String matchKey(TransportReconciliationInternal row) {
|
||||||
|
|||||||
+310
-326
@@ -1,326 +1,310 @@
|
|||||||
/**
|
/**
|
||||||
* BladeX Commercial License Agreement
|
* BladeX Commercial License Agreement
|
||||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
* <p>
|
* <p>
|
||||||
* Use of this software is governed by the Commercial License Agreement
|
* Use of this software is governed by the Commercial License Agreement
|
||||||
* obtained after purchasing a license from BladeX.
|
* obtained after purchasing a license from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 1. This software is for development use only under a valid license
|
* 1. This software is for development use only under a valid license
|
||||||
* from BladeX.
|
* from BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* 2. Redistribution of this software's source code to any third party
|
* 2. Redistribution of this software's source code to any third party
|
||||||
* without a commercial license is strictly prohibited.
|
* without a commercial license is strictly prohibited.
|
||||||
* <p>
|
* <p>
|
||||||
* 3. Licensees may copyright their own code but cannot use segments
|
* 3. Licensees may copyright their own code but cannot use segments
|
||||||
* from this software for such purposes. Copyright of this software
|
* from this software for such purposes. Copyright of this software
|
||||||
* remains with BladeX.
|
* remains with BladeX.
|
||||||
* <p>
|
* <p>
|
||||||
* Using this software signifies agreement to this License, and the software
|
* Using this software signifies agreement to this License, and the software
|
||||||
* must not be used for illegal purposes.
|
* must not be used for illegal purposes.
|
||||||
* <p>
|
* <p>
|
||||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||||
* not liable for any claims arising from secondary or illegal development.
|
* not liable for any claims arising from secondary or illegal development.
|
||||||
* <p>
|
* <p>
|
||||||
* Author: Chill Zhuang (bladejava@qq.com)
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
*/
|
*/
|
||||||
package org.springblade.transport.service.impl;
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||||
import org.springblade.core.tool.utils.BeanUtil;
|
import org.springblade.core.tool.utils.BeanUtil;
|
||||||
import org.springblade.core.tool.utils.Func;
|
import org.springblade.core.tool.utils.Func;
|
||||||
import org.springblade.system.cache.UserCache;
|
import org.springblade.system.cache.UserCache;
|
||||||
import org.springblade.transport.excel.ViolationRecordExcel;
|
import org.springblade.transport.excel.ViolationRecordExcel;
|
||||||
import org.springblade.transport.excel.ViolationRecordImportExcel;
|
import org.springblade.transport.excel.ViolationRecordImportExcel;
|
||||||
import org.springblade.transport.mapper.ViolationRecordMapper;
|
import org.springblade.transport.mapper.ViolationRecordMapper;
|
||||||
import org.springblade.transport.pojo.entity.ViolationRecord;
|
import org.springblade.transport.pojo.entity.ViolationRecord;
|
||||||
import org.springblade.transport.pojo.vo.ViolationRecordVO;
|
import org.springblade.transport.pojo.vo.ViolationRecordVO;
|
||||||
import org.springblade.transport.service.IViolationRecordService;
|
import org.springblade.transport.service.IViolationRecordService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 违章记录 服务实现类
|
* 违章记录 服务实现类
|
||||||
*
|
*
|
||||||
* @author Chill
|
* @author Chill
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class ViolationRecordServiceImpl extends BaseServiceImpl<ViolationRecordMapper, ViolationRecord> implements IViolationRecordService {
|
public class ViolationRecordServiceImpl extends BaseServiceImpl<ViolationRecordMapper, ViolationRecord> implements IViolationRecordService {
|
||||||
|
|
||||||
private static final int VEHICLE_NO_MAX_LENGTH = 30;
|
private static final int VEHICLE_NO_MAX_LENGTH = 30;
|
||||||
private static final int DRIVER_NAME_MAX_LENGTH = 20;
|
private static final int DRIVER_NAME_MAX_LENGTH = 20;
|
||||||
private static final int TYPE_MAX_LENGTH = 50;
|
private static final int TYPE_MAX_LENGTH = 50;
|
||||||
private static final int ITEM_MAX_LENGTH = 100;
|
private static final int ITEM_MAX_LENGTH = 100;
|
||||||
private static final int LOCATION_MAX_LENGTH = 100;
|
private static final int LOCATION_MAX_LENGTH = 100;
|
||||||
private static final int PENALTY_UNIT_MAX_LENGTH = 50;
|
private static final int PENALTY_UNIT_MAX_LENGTH = 50;
|
||||||
private static final int DESCRIPTION_MAX_LENGTH = 500;
|
private static final int DESCRIPTION_MAX_LENGTH = 500;
|
||||||
private static final int RESULT_MAX_LENGTH = 500;
|
private static final int RESULT_MAX_LENGTH = 500;
|
||||||
private static final int ATTACHMENTS_MAX_LENGTH = 16000;
|
private static final int ATTACHMENTS_MAX_LENGTH = 16000;
|
||||||
private static final int MAX_DEDUCT_POINTS = 15;
|
private static final int MAX_DEDUCT_POINTS = 15;
|
||||||
private static final String PROCESSED = "已处理";
|
private static final String PROCESSED = "已处理";
|
||||||
private static final String UNPROCESSED = "未处理";
|
private static final String UNPROCESSED = "未处理";
|
||||||
private static final String CAR = "车辆";
|
|
||||||
private static final String SHIP = "船舶";
|
@Override
|
||||||
|
public IPage<ViolationRecordVO> selectViolationRecordPage(IPage<ViolationRecordVO> page, ViolationRecordVO violationRecord) {
|
||||||
@Override
|
List<ViolationRecordVO> records = baseMapper.selectViolationRecordPage(page, violationRecord);
|
||||||
public IPage<ViolationRecordVO> selectViolationRecordPage(IPage<ViolationRecordVO> page, ViolationRecordVO violationRecord) {
|
records.forEach(record -> record.setUpdateUserName(UserCache.getUserRealName(record.getUpdateUser())));
|
||||||
List<ViolationRecordVO> records = baseMapper.selectViolationRecordPage(page, violationRecord);
|
return page.setRecords(records);
|
||||||
records.forEach(record -> record.setUpdateUserName(UserCache.getUserRealName(record.getUpdateUser())));
|
}
|
||||||
return page.setRecords(records);
|
|
||||||
}
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
public boolean submit(ViolationRecord violationRecord) {
|
||||||
@Transactional(rollbackFor = Exception.class)
|
prepare(violationRecord);
|
||||||
public boolean submit(ViolationRecord violationRecord) {
|
validate(violationRecord);
|
||||||
prepare(violationRecord);
|
validateVehicleTypeImmutable(violationRecord);
|
||||||
validate(violationRecord);
|
return saveOrUpdate(violationRecord);
|
||||||
validateVehicleTypeImmutable(violationRecord);
|
}
|
||||||
clearIrrelevantField(violationRecord);
|
|
||||||
return saveOrUpdate(violationRecord);
|
@Override
|
||||||
}
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public List<ViolationRecordImportExcel> importViolationRecord(List<ViolationRecordImportExcel> data) {
|
||||||
@Override
|
if (Func.isEmpty(data)) {
|
||||||
@Transactional(rollbackFor = Exception.class)
|
throw new ServiceException("导入数据不能为空");
|
||||||
public List<ViolationRecordImportExcel> importViolationRecord(List<ViolationRecordImportExcel> data) {
|
}
|
||||||
if (Func.isEmpty(data)) {
|
List<ViolationRecordImportExcel> errorList = new ArrayList<>();
|
||||||
throw new ServiceException("导入数据不能为空");
|
List<ViolationRecord> violationRecordList = new ArrayList<>();
|
||||||
}
|
for (int index = 0; index < data.size(); index++) {
|
||||||
List<ViolationRecordImportExcel> errorList = new ArrayList<>();
|
ViolationRecordImportExcel excel = data.get(index);
|
||||||
List<ViolationRecord> violationRecordList = new ArrayList<>();
|
try {
|
||||||
for (int index = 0; index < data.size(); index++) {
|
ViolationRecord violationRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, ViolationRecord.class));
|
||||||
ViolationRecordImportExcel excel = data.get(index);
|
if ("船舶".equals(trimToEmpty(excel.getVehicleType()))) {
|
||||||
try {
|
violationRecord.setViolationItem(excel.getViolationTypeOrItem());
|
||||||
ViolationRecord violationRecord = Objects.requireNonNull(BeanUtil.copyProperties(excel, ViolationRecord.class));
|
} else {
|
||||||
prepare(violationRecord);
|
violationRecord.setViolationType(excel.getViolationTypeOrItem());
|
||||||
List<String> validationErrors = validateImportViolationRecord(violationRecord);
|
}
|
||||||
if (Func.isNotEmpty(validationErrors)) {
|
prepare(violationRecord);
|
||||||
excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(validationErrors));
|
List<String> validationErrors = validateImportViolationRecord(violationRecord);
|
||||||
errorList.add(excel);
|
if (Func.isNotEmpty(validationErrors)) {
|
||||||
continue;
|
excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(validationErrors));
|
||||||
}
|
errorList.add(excel);
|
||||||
validateVehicleTypeImmutable(violationRecord);
|
continue;
|
||||||
clearIrrelevantField(violationRecord);
|
}
|
||||||
violationRecordList.add(violationRecord);
|
validateVehicleTypeImmutable(violationRecord);
|
||||||
} catch (Exception exception) {
|
violationRecordList.add(violationRecord);
|
||||||
String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败";
|
} catch (Exception exception) {
|
||||||
excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(List.of(message)));
|
String message = exception instanceof ServiceException ? exception.getMessage() : "导入失败";
|
||||||
errorList.add(excel);
|
excel.setErrorMessage(org.springblade.common.excel.ImportFailureExcelUtil.formatErrorMessage(List.of(message)));
|
||||||
}
|
errorList.add(excel);
|
||||||
}
|
}
|
||||||
if (Func.isNotEmpty(errorList)) {
|
}
|
||||||
org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
if (Func.isNotEmpty(errorList)) {
|
||||||
return errorList;
|
org.springframework.transaction.interceptor.TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
||||||
}
|
return errorList;
|
||||||
for (ViolationRecord violationRecord : violationRecordList) {
|
}
|
||||||
if (!save(violationRecord)) {
|
for (ViolationRecord violationRecord : violationRecordList) {
|
||||||
throw new ServiceException("违章记录保存失败");
|
if (!save(violationRecord)) {
|
||||||
}
|
throw new ServiceException("违章记录保存失败");
|
||||||
}
|
}
|
||||||
return errorList;
|
}
|
||||||
}
|
return errorList;
|
||||||
|
}
|
||||||
private List<String> validateImportViolationRecord(ViolationRecord violationRecord) {
|
|
||||||
List<String> validationErrors = new ArrayList<>();
|
private List<String> validateImportViolationRecord(ViolationRecord violationRecord) {
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getVehicleType()), "车船类型不能为空");
|
List<String> validationErrors = new ArrayList<>();
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getVehicleType()) && !"车辆".equals(violationRecord.getVehicleType()) && !"船舶".equals(violationRecord.getVehicleType()), "车船类型不正确");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getVehicleType()), "车船类型不能为空");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getVehicleNo()), "车牌号/船号不能为空");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getVehicleType()) && !"车辆".equals(violationRecord.getVehicleType()) && !"船舶".equals(violationRecord.getVehicleType()), "车船类型不正确");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getDriverName()), "驾驶人/船长不能为空");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getVehicleNo()), "车牌号/船号不能为空");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, "车辆".equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationType()), "类型不能为空");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getDriverName()), "驾驶人/船长不能为空");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, "船舶".equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationItem()), "事项不能为空");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, "车辆".equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationType()), "类型不能为空");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, SHIP.equals(violationRecord.getVehicleType()) && Func.isNotEmpty(violationRecord.getViolationType()), "船舶不适用于类型,该列应留空");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, "船舶".equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationItem()), "事项不能为空");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, CAR.equals(violationRecord.getVehicleType()) && Func.isNotEmpty(violationRecord.getViolationItem()), "车辆不适用于事项,该列应留空");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getViolationTime()), "时间不能为空");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getViolationTime()), "时间不能为空");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getViolationTime()) && violationRecord.getViolationTime().isAfter(LocalDateTime.now()), "时间不能超过当前时间");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getViolationTime()) && violationRecord.getViolationTime().isAfter(LocalDateTime.now()), "时间不能超过当前时间");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getLocation()), "地址不能为空");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getLocation()), "地址不能为空");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getProcessStatus()), "状态不能为空");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getProcessStatus()), "状态不能为空");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getProcessStatus()) && !PROCESSED.equals(violationRecord.getProcessStatus()) && !UNPROCESSED.equals(violationRecord.getProcessStatus()), "状态值不正确");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getProcessStatus()) && !PROCESSED.equals(violationRecord.getProcessStatus()) && !UNPROCESSED.equals(violationRecord.getProcessStatus()), "状态值不正确");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getProcessDescription()), "过程描述不能为空");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(violationRecord.getProcessDescription()), "过程描述不能为空");
|
addImportNonNegativeError(validationErrors, violationRecord.getFineAmount(), "被罚金额");
|
||||||
addImportNonNegativeError(validationErrors, violationRecord.getFineAmount(), "被罚金额");
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getDeductPoints()) && (violationRecord.getDeductPoints() < 0 || violationRecord.getDeductPoints() > MAX_DEDUCT_POINTS), "被扣分数范围为0-15分");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(violationRecord.getDeductPoints()) && (violationRecord.getDeductPoints() < 0 || violationRecord.getDeductPoints() > MAX_DEDUCT_POINTS), "被扣分数范围为0-15分");
|
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字");
|
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getDriverName(), DRIVER_NAME_MAX_LENGTH, "驾驶人/船长不能超过20字");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getDriverName(), DRIVER_NAME_MAX_LENGTH, "驾驶人/船长不能超过20字");
|
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getViolationType(), TYPE_MAX_LENGTH, "类型不能超过50字");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getViolationType(), TYPE_MAX_LENGTH, "类型不能超过50字");
|
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getViolationItem(), ITEM_MAX_LENGTH, "事项不能超过100字");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getViolationItem(), ITEM_MAX_LENGTH, "事项不能超过100字");
|
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getLocation(), LOCATION_MAX_LENGTH, "地址不能超过100字");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getLocation(), LOCATION_MAX_LENGTH, "地址不能超过100字");
|
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getPenaltyUnit(), PENALTY_UNIT_MAX_LENGTH, "被罚单位不能超过50字");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getPenaltyUnit(), PENALTY_UNIT_MAX_LENGTH, "被罚单位不能超过50字");
|
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getProcessDescription(), DESCRIPTION_MAX_LENGTH, "过程描述不能超过500字");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getProcessDescription(), DESCRIPTION_MAX_LENGTH, "过程描述不能超过500字");
|
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getProcessResult(), RESULT_MAX_LENGTH, "处理结果不能超过500字");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getProcessResult(), RESULT_MAX_LENGTH, "处理结果不能超过500字");
|
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件数据不能超过16000字");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, violationRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件数据不能超过16000字");
|
return validationErrors;
|
||||||
return validationErrors;
|
}
|
||||||
}
|
|
||||||
|
private void addImportNonNegativeError(List<String> validationErrors, BigDecimal value, String fieldName) {
|
||||||
private void addImportNonNegativeError(List<String> validationErrors, BigDecimal value, String fieldName) {
|
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, fieldName + "不能小于0");
|
||||||
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0, fieldName + "不能小于0");
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
@Override
|
public List<ViolationRecordExcel> exportViolationRecord(Wrapper<ViolationRecord> queryWrapper) {
|
||||||
public List<ViolationRecordExcel> exportViolationRecord(Wrapper<ViolationRecord> queryWrapper) {
|
return list(queryWrapper).stream().map(violationRecord -> {
|
||||||
return list(queryWrapper).stream().map(violationRecord -> {
|
ViolationRecordExcel excel = Objects.requireNonNull(BeanUtil.copyProperties(violationRecord, ViolationRecordExcel.class));
|
||||||
ViolationRecordExcel excel = Objects.requireNonNull(BeanUtil.copyProperties(violationRecord, ViolationRecordExcel.class));
|
excel.setFineAmount(nonNegative(violationRecord.getFineAmount()));
|
||||||
excel.setFineAmount(nonNegative(violationRecord.getFineAmount()));
|
excel.setDeductPoints(validDeductPoints(violationRecord.getDeductPoints()));
|
||||||
excel.setDeductPoints(validDeductPoints(violationRecord.getDeductPoints()));
|
excel.setUpdateUserName(UserCache.getUserRealName(violationRecord.getUpdateUser()));
|
||||||
excel.setUpdateUserName(UserCache.getUserRealName(violationRecord.getUpdateUser()));
|
return excel;
|
||||||
return excel;
|
}).toList();
|
||||||
}).toList();
|
}
|
||||||
}
|
|
||||||
|
private void prepare(ViolationRecord violationRecord) {
|
||||||
private void prepare(ViolationRecord violationRecord) {
|
violationRecord.setVehicleType(normalizeVehicleType(violationRecord.getVehicleType()));
|
||||||
violationRecord.setVehicleType(normalizeVehicleType(violationRecord.getVehicleType()));
|
violationRecord.setVehicleNo(trimToEmpty(violationRecord.getVehicleNo()).toUpperCase());
|
||||||
violationRecord.setVehicleNo(trimToEmpty(violationRecord.getVehicleNo()).toUpperCase());
|
violationRecord.setDriverName(trimToEmpty(violationRecord.getDriverName()));
|
||||||
violationRecord.setDriverName(trimToEmpty(violationRecord.getDriverName()));
|
violationRecord.setViolationType(trimToNull(violationRecord.getViolationType()));
|
||||||
violationRecord.setViolationType(trimToNull(violationRecord.getViolationType()));
|
violationRecord.setViolationItem(trimToNull(violationRecord.getViolationItem()));
|
||||||
violationRecord.setViolationItem(trimToNull(violationRecord.getViolationItem()));
|
violationRecord.setLocation(trimToEmpty(violationRecord.getLocation()));
|
||||||
violationRecord.setLocation(trimToEmpty(violationRecord.getLocation()));
|
violationRecord.setPenaltyUnit(trimToNull(violationRecord.getPenaltyUnit()));
|
||||||
violationRecord.setPenaltyUnit(trimToNull(violationRecord.getPenaltyUnit()));
|
violationRecord.setProcessStatus(normalizeProcessStatus(violationRecord.getProcessStatus()));
|
||||||
violationRecord.setProcessStatus(normalizeProcessStatus(violationRecord.getProcessStatus()));
|
violationRecord.setProcessDescription(trimToEmpty(violationRecord.getProcessDescription()));
|
||||||
violationRecord.setProcessDescription(trimToEmpty(violationRecord.getProcessDescription()));
|
violationRecord.setProcessResult(trimToNull(violationRecord.getProcessResult()));
|
||||||
violationRecord.setProcessResult(trimToNull(violationRecord.getProcessResult()));
|
violationRecord.setAttachments(trimToNull(violationRecord.getAttachments()));
|
||||||
violationRecord.setAttachments(trimToNull(violationRecord.getAttachments()));
|
if ("车辆".equals(violationRecord.getVehicleType())) {
|
||||||
if (UNPROCESSED.equals(violationRecord.getProcessStatus())) {
|
violationRecord.setViolationItem(null);
|
||||||
violationRecord.setProcessResult(null);
|
} else {
|
||||||
}
|
violationRecord.setViolationType(null);
|
||||||
}
|
}
|
||||||
|
if (UNPROCESSED.equals(violationRecord.getProcessStatus())) {
|
||||||
/**
|
violationRecord.setProcessResult(null);
|
||||||
* 清空与车船类型不匹配的对侧字段
|
}
|
||||||
* <p>
|
}
|
||||||
* 必须在 validate 之后执行:校验需要看到用户填了什么,
|
|
||||||
* 若提前清空,误填的内容会被静默丢弃,用户无从察觉。
|
private void validate(ViolationRecord violationRecord) {
|
||||||
*/
|
if (Func.isEmpty(violationRecord.getVehicleType())) {
|
||||||
private void clearIrrelevantField(ViolationRecord violationRecord) {
|
throw new ServiceException("车船类型不能为空");
|
||||||
if (CAR.equals(violationRecord.getVehicleType())) {
|
}
|
||||||
violationRecord.setViolationItem(null);
|
if (!"车辆".equals(violationRecord.getVehicleType()) && !"船舶".equals(violationRecord.getVehicleType())) {
|
||||||
} else {
|
throw new ServiceException("车船类型不正确");
|
||||||
violationRecord.setViolationType(null);
|
}
|
||||||
}
|
if (Func.isEmpty(violationRecord.getVehicleNo())) {
|
||||||
}
|
throw new ServiceException("车牌号/船号不能为空");
|
||||||
|
}
|
||||||
private void validate(ViolationRecord violationRecord) {
|
if (Func.isEmpty(violationRecord.getDriverName())) {
|
||||||
if (Func.isEmpty(violationRecord.getVehicleType())) {
|
throw new ServiceException("驾驶人/船长不能为空");
|
||||||
throw new ServiceException("车船类型不能为空");
|
}
|
||||||
}
|
if ("车辆".equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationType())) {
|
||||||
if (!CAR.equals(violationRecord.getVehicleType()) && !SHIP.equals(violationRecord.getVehicleType())) {
|
throw new ServiceException("类型不能为空");
|
||||||
throw new ServiceException("车船类型不正确");
|
}
|
||||||
}
|
if ("船舶".equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationItem())) {
|
||||||
if (Func.isEmpty(violationRecord.getVehicleNo())) {
|
throw new ServiceException("事项不能为空");
|
||||||
throw new ServiceException("车牌号/船号不能为空");
|
}
|
||||||
}
|
if (Func.isEmpty(violationRecord.getViolationTime())) {
|
||||||
if (Func.isEmpty(violationRecord.getDriverName())) {
|
throw new ServiceException("时间不能为空");
|
||||||
throw new ServiceException("驾驶人/船长不能为空");
|
}
|
||||||
}
|
if (violationRecord.getViolationTime().isAfter(LocalDateTime.now())) {
|
||||||
if (CAR.equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationType())) {
|
throw new ServiceException("时间不能超过当前时间");
|
||||||
throw new ServiceException("类型不能为空");
|
}
|
||||||
}
|
if (Func.isEmpty(violationRecord.getLocation())) {
|
||||||
if (SHIP.equals(violationRecord.getVehicleType()) && Func.isEmpty(violationRecord.getViolationItem())) {
|
throw new ServiceException("地址不能为空");
|
||||||
throw new ServiceException("事项不能为空");
|
}
|
||||||
}
|
if (Func.isEmpty(violationRecord.getProcessStatus())) {
|
||||||
if (SHIP.equals(violationRecord.getVehicleType()) && Func.isNotEmpty(violationRecord.getViolationType())) {
|
throw new ServiceException("状态不能为空");
|
||||||
throw new ServiceException("船舶不适用于类型,该列应留空");
|
}
|
||||||
}
|
if (!PROCESSED.equals(violationRecord.getProcessStatus()) && !UNPROCESSED.equals(violationRecord.getProcessStatus())) {
|
||||||
if (CAR.equals(violationRecord.getVehicleType()) && Func.isNotEmpty(violationRecord.getViolationItem())) {
|
throw new ServiceException("状态值不正确");
|
||||||
throw new ServiceException("车辆不适用于事项,该列应留空");
|
}
|
||||||
}
|
if (Func.isEmpty(violationRecord.getProcessDescription())) {
|
||||||
if (Func.isEmpty(violationRecord.getViolationTime())) {
|
throw new ServiceException("过程描述不能为空");
|
||||||
throw new ServiceException("时间不能为空");
|
}
|
||||||
}
|
validateNonNegative(violationRecord.getFineAmount(), "被罚金额不能小于0");
|
||||||
if (violationRecord.getViolationTime().isAfter(LocalDateTime.now())) {
|
validateDeductPoints(violationRecord.getDeductPoints());
|
||||||
throw new ServiceException("时间不能超过当前时间");
|
validateLength(violationRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字");
|
||||||
}
|
validateLength(violationRecord.getDriverName(), DRIVER_NAME_MAX_LENGTH, "驾驶人/船长不能超过20字");
|
||||||
if (Func.isEmpty(violationRecord.getLocation())) {
|
validateLength(violationRecord.getViolationType(), TYPE_MAX_LENGTH, "类型不能超过50字");
|
||||||
throw new ServiceException("地址不能为空");
|
validateLength(violationRecord.getViolationItem(), ITEM_MAX_LENGTH, "事项不能超过100字");
|
||||||
}
|
validateLength(violationRecord.getLocation(), LOCATION_MAX_LENGTH, "地址不能超过100字");
|
||||||
if (Func.isEmpty(violationRecord.getProcessStatus())) {
|
validateLength(violationRecord.getPenaltyUnit(), PENALTY_UNIT_MAX_LENGTH, "被罚单位不能超过50字");
|
||||||
throw new ServiceException("状态不能为空");
|
validateLength(violationRecord.getProcessDescription(), DESCRIPTION_MAX_LENGTH, "过程描述不能超过500字");
|
||||||
}
|
validateLength(violationRecord.getProcessResult(), RESULT_MAX_LENGTH, "处理结果不能超过500字");
|
||||||
if (!PROCESSED.equals(violationRecord.getProcessStatus()) && !UNPROCESSED.equals(violationRecord.getProcessStatus())) {
|
validateLength(violationRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件数据不能超过16000字");
|
||||||
throw new ServiceException("状态值不正确");
|
}
|
||||||
}
|
|
||||||
if (Func.isEmpty(violationRecord.getProcessDescription())) {
|
private void validateVehicleTypeImmutable(ViolationRecord violationRecord) {
|
||||||
throw new ServiceException("过程描述不能为空");
|
if (Func.isEmpty(violationRecord.getId())) {
|
||||||
}
|
return;
|
||||||
validateNonNegative(violationRecord.getFineAmount(), "被罚金额不能小于0");
|
}
|
||||||
validateDeductPoints(violationRecord.getDeductPoints());
|
ViolationRecord oldRecord = getById(violationRecord.getId());
|
||||||
validateLength(violationRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字");
|
if (oldRecord != null && Func.isNotEmpty(oldRecord.getVehicleType()) && !oldRecord.getVehicleType().equals(violationRecord.getVehicleType())) {
|
||||||
validateLength(violationRecord.getDriverName(), DRIVER_NAME_MAX_LENGTH, "驾驶人/船长不能超过20字");
|
throw new ServiceException("车船类型保存后不可修改");
|
||||||
validateLength(violationRecord.getViolationType(), TYPE_MAX_LENGTH, "类型不能超过50字");
|
}
|
||||||
validateLength(violationRecord.getViolationItem(), ITEM_MAX_LENGTH, "事项不能超过100字");
|
}
|
||||||
validateLength(violationRecord.getLocation(), LOCATION_MAX_LENGTH, "地址不能超过100字");
|
|
||||||
validateLength(violationRecord.getPenaltyUnit(), PENALTY_UNIT_MAX_LENGTH, "被罚单位不能超过50字");
|
private void validateLength(String value, int maxLength, String message) {
|
||||||
validateLength(violationRecord.getProcessDescription(), DESCRIPTION_MAX_LENGTH, "过程描述不能超过500字");
|
if (Func.isNotEmpty(value) && value.length() > maxLength) {
|
||||||
validateLength(violationRecord.getProcessResult(), RESULT_MAX_LENGTH, "处理结果不能超过500字");
|
throw new ServiceException(message);
|
||||||
validateLength(violationRecord.getAttachments(), ATTACHMENTS_MAX_LENGTH, "附件数据不能超过16000字");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateVehicleTypeImmutable(ViolationRecord violationRecord) {
|
private void validateNonNegative(BigDecimal value, String message) {
|
||||||
if (Func.isEmpty(violationRecord.getId())) {
|
if (Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0) {
|
||||||
return;
|
throw new ServiceException(message);
|
||||||
}
|
}
|
||||||
ViolationRecord oldRecord = getById(violationRecord.getId());
|
}
|
||||||
if (oldRecord != null && Func.isNotEmpty(oldRecord.getVehicleType()) && !oldRecord.getVehicleType().equals(violationRecord.getVehicleType())) {
|
|
||||||
throw new ServiceException("车船类型保存后不可修改");
|
private void validateDeductPoints(Integer value) {
|
||||||
}
|
if (Func.isNotEmpty(value) && (value < 0 || value > MAX_DEDUCT_POINTS)) {
|
||||||
}
|
throw new ServiceException("被扣分数范围为0-15分");
|
||||||
|
}
|
||||||
private void validateLength(String value, int maxLength, String message) {
|
}
|
||||||
if (Func.isNotEmpty(value) && value.length() > maxLength) {
|
|
||||||
throw new ServiceException(message);
|
private BigDecimal nonNegative(BigDecimal value) {
|
||||||
}
|
if (Func.isEmpty(value) || value.compareTo(BigDecimal.ZERO) >= 0) {
|
||||||
}
|
return value;
|
||||||
|
}
|
||||||
private void validateNonNegative(BigDecimal value, String message) {
|
return BigDecimal.ZERO;
|
||||||
if (Func.isNotEmpty(value) && value.compareTo(BigDecimal.ZERO) < 0) {
|
}
|
||||||
throw new ServiceException(message);
|
|
||||||
}
|
private Integer validDeductPoints(Integer value) {
|
||||||
}
|
if (Func.isEmpty(value)) {
|
||||||
|
return value;
|
||||||
private void validateDeductPoints(Integer value) {
|
}
|
||||||
if (Func.isNotEmpty(value) && (value < 0 || value > MAX_DEDUCT_POINTS)) {
|
if (value < 0) {
|
||||||
throw new ServiceException("被扣分数范围为0-15分");
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
return Math.min(value, MAX_DEDUCT_POINTS);
|
||||||
|
}
|
||||||
private BigDecimal nonNegative(BigDecimal value) {
|
|
||||||
if (Func.isEmpty(value) || value.compareTo(BigDecimal.ZERO) >= 0) {
|
private String normalizeVehicleType(String vehicleType) {
|
||||||
return value;
|
String value = trimToEmpty(vehicleType);
|
||||||
}
|
return value.isEmpty() ? "车辆" : value;
|
||||||
return BigDecimal.ZERO;
|
}
|
||||||
}
|
|
||||||
|
private String normalizeProcessStatus(String processStatus) {
|
||||||
private Integer validDeductPoints(Integer value) {
|
String value = trimToEmpty(processStatus);
|
||||||
if (Func.isEmpty(value)) {
|
return value.isEmpty() ? UNPROCESSED : value;
|
||||||
return value;
|
}
|
||||||
}
|
|
||||||
if (value < 0) {
|
private String trimToEmpty(String value) {
|
||||||
return 0;
|
return value == null ? "" : value.trim();
|
||||||
}
|
}
|
||||||
return Math.min(value, MAX_DEDUCT_POINTS);
|
|
||||||
}
|
private String trimToNull(String value) {
|
||||||
|
String trimValue = trimToEmpty(value);
|
||||||
private String normalizeVehicleType(String vehicleType) {
|
return trimValue.isEmpty() ? null : trimValue;
|
||||||
String value = trimToEmpty(vehicleType);
|
}
|
||||||
return value.isEmpty() ? CAR : value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String normalizeProcessStatus(String processStatus) {
|
|
||||||
String value = trimToEmpty(processStatus);
|
|
||||||
return value.isEmpty() ? UNPROCESSED : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String trimToEmpty(String value) {
|
|
||||||
return value == null ? "" : value.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String trimToNull(String value) {
|
|
||||||
String trimValue = trimToEmpty(value);
|
|
||||||
return trimValue.isEmpty() ? null : trimValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
+10
-25
@@ -42,7 +42,6 @@ import io.minio.PutObjectArgs;
|
|||||||
import io.minio.RemoveObjectArgs;
|
import io.minio.RemoveObjectArgs;
|
||||||
import io.minio.http.Method;
|
import io.minio.http.Method;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
@@ -80,14 +79,14 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
private final VoucherImageMapper voucherImageMapper;
|
private final VoucherImageMapper voucherImageMapper;
|
||||||
private final VoucherFileMapper voucherFileMapper;
|
private final VoucherFileMapper voucherFileMapper;
|
||||||
private final ApplicationEventPublisher eventPublisher;
|
private final ApplicationEventPublisher eventPublisher;
|
||||||
private final ObjectProvider<MinioClient> minioClientProvider;
|
private final MinioClient minioClient;
|
||||||
private final String minioBucketName;
|
private final String minioBucketName;
|
||||||
private final String minioRootDirectory;
|
private final String minioRootDirectory;
|
||||||
|
|
||||||
public VoucherManageServiceImpl(VoucherWaybillBatchMapper voucherWaybillBatchMapper, IProjectApplyService projectApplyService,
|
public VoucherManageServiceImpl(VoucherWaybillBatchMapper voucherWaybillBatchMapper, IProjectApplyService projectApplyService,
|
||||||
IWaybillService waybillService,
|
IWaybillService waybillService,
|
||||||
VoucherImageMapper voucherImageMapper, VoucherFileMapper voucherFileMapper,
|
VoucherImageMapper voucherImageMapper, VoucherFileMapper voucherFileMapper,
|
||||||
ApplicationEventPublisher eventPublisher, ObjectProvider<MinioClient> minioClientProvider,
|
ApplicationEventPublisher eventPublisher, MinioClient minioClient,
|
||||||
@Value("${file.storage.minio.bucket-name:${minio.bucket-name:}}") String minioBucketName,
|
@Value("${file.storage.minio.bucket-name:${minio.bucket-name:}}") String minioBucketName,
|
||||||
@Value("${file.storage.minio.root-directory:${minio.root-directory:}}") String minioRootDirectory) {
|
@Value("${file.storage.minio.root-directory:${minio.root-directory:}}") String minioRootDirectory) {
|
||||||
this.voucherWaybillBatchMapper = voucherWaybillBatchMapper;
|
this.voucherWaybillBatchMapper = voucherWaybillBatchMapper;
|
||||||
@@ -96,7 +95,7 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
this.voucherImageMapper = voucherImageMapper;
|
this.voucherImageMapper = voucherImageMapper;
|
||||||
this.voucherFileMapper = voucherFileMapper;
|
this.voucherFileMapper = voucherFileMapper;
|
||||||
this.eventPublisher = eventPublisher;
|
this.eventPublisher = eventPublisher;
|
||||||
this.minioClientProvider = minioClientProvider;
|
this.minioClient = minioClient;
|
||||||
this.minioBucketName = minioBucketName;
|
this.minioBucketName = minioBucketName;
|
||||||
this.minioRootDirectory = minioRootDirectory;
|
this.minioRootDirectory = minioRootDirectory;
|
||||||
}
|
}
|
||||||
@@ -252,7 +251,7 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
List<String> candidateObjectKeys = resolvedObjectKey.equals(objectKey)
|
List<String> candidateObjectKeys = resolvedObjectKey.equals(objectKey)
|
||||||
? List.of(objectKey) : List.of(resolvedObjectKey, objectKey);
|
? List.of(objectKey) : List.of(resolvedObjectKey, objectKey);
|
||||||
for (String candidateObjectKey : candidateObjectKeys) {
|
for (String candidateObjectKey : candidateObjectKeys) {
|
||||||
try (InputStream source = minioClient().getObject(GetObjectArgs.builder().bucket(minioBucketName).object(candidateObjectKey).build());
|
try (InputStream source = minioClient.getObject(GetObjectArgs.builder().bucket(minioBucketName).object(candidateObjectKey).build());
|
||||||
OutputStream target = Files.newOutputStream(archivePath)) {
|
OutputStream target = Files.newOutputStream(archivePath)) {
|
||||||
source.transferTo(target);
|
source.transferTo(target);
|
||||||
return archivePath;
|
return archivePath;
|
||||||
@@ -428,7 +427,7 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
String waybillNo = matchedWaybill == null ? "unmatched" : safePathPart(matchedWaybill.getWaybillNo());
|
String waybillNo = matchedWaybill == null ? "unmatched" : safePathPart(matchedWaybill.getWaybillNo());
|
||||||
String objectKey = buildObjectKey(voucher.getId(), waybillNo, plateNo, entryName);
|
String objectKey = buildObjectKey(voucher.getId(), waybillNo, plateNo, entryName);
|
||||||
String contentType = contentType(fileName);
|
String contentType = contentType(fileName);
|
||||||
minioClient().putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey)
|
minioClient.putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey)
|
||||||
.stream(zipInputStream, entry.getSize(), 10 * 1024 * 1024)
|
.stream(zipInputStream, entry.getSize(), 10 * 1024 * 1024)
|
||||||
.contentType(contentType).build());
|
.contentType(contentType).build());
|
||||||
VoucherFile file = new VoucherFile();
|
VoucherFile file = new VoucherFile();
|
||||||
@@ -491,7 +490,7 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
String waybillNo = matchedWaybill == null ? "unmatched" : safePathPart(matchedWaybill.getWaybillNo());
|
String waybillNo = matchedWaybill == null ? "unmatched" : safePathPart(matchedWaybill.getWaybillNo());
|
||||||
String objectKey = buildObjectKey(voucher.getId(), waybillNo, plateNo, entryName);
|
String objectKey = buildObjectKey(voucher.getId(), waybillNo, plateNo, entryName);
|
||||||
String contentType = contentType(fileName);
|
String contentType = contentType(fileName);
|
||||||
minioClient().putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey)
|
minioClient.putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey)
|
||||||
.stream(zipInputStream, entry.getSize(), 10 * 1024 * 1024)
|
.stream(zipInputStream, entry.getSize(), 10 * 1024 * 1024)
|
||||||
.contentType(contentType).build());
|
.contentType(contentType).build());
|
||||||
VoucherFile file = new VoucherFile();
|
VoucherFile file = new VoucherFile();
|
||||||
@@ -538,7 +537,7 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
String entryName = plateNo + "/" + System.currentTimeMillis() + "_" + fileName;
|
String entryName = plateNo + "/" + System.currentTimeMillis() + "_" + fileName;
|
||||||
String objectKey = buildObjectKey(voucher.getId(), matchedWaybill == null ? "unmatched" : safePathPart(matchedWaybill.getWaybillNo()), plateNo, entryName);
|
String objectKey = buildObjectKey(voucher.getId(), matchedWaybill == null ? "unmatched" : safePathPart(matchedWaybill.getWaybillNo()), plateNo, entryName);
|
||||||
try (InputStream inputStream = imageFile.getInputStream()) {
|
try (InputStream inputStream = imageFile.getInputStream()) {
|
||||||
minioClient().putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey)
|
minioClient.putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey)
|
||||||
.stream(inputStream, imageFile.getSize(), 10 * 1024 * 1024)
|
.stream(inputStream, imageFile.getSize(), 10 * 1024 * 1024)
|
||||||
.contentType(Func.isEmpty(imageFile.getContentType()) ? contentType(fileName) : imageFile.getContentType()).build());
|
.contentType(Func.isEmpty(imageFile.getContentType()) ? contentType(fileName) : imageFile.getContentType()).build());
|
||||||
}
|
}
|
||||||
@@ -607,7 +606,7 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
return Func.isEmpty(normalizedPlateNo) ? "未识别车牌" : normalizedPlateNo;
|
return Func.isEmpty(normalizedPlateNo) ? "未识别车牌" : normalizedPlateNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteObjectQuietly(String objectKey) { try { minioClient().removeObject(RemoveObjectArgs.builder().bucket(minioBucketName).object(objectKey).build()); } catch (Exception exception) { log.warn("删除凭证对象失败 objectKey={}", objectKey, exception); } }
|
private void deleteObjectQuietly(String objectKey) { try { minioClient.removeObject(RemoveObjectArgs.builder().bucket(minioBucketName).object(objectKey).build()); } catch (Exception exception) { log.warn("删除凭证对象失败 objectKey={}", objectKey, exception); } }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@@ -839,7 +838,7 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
String objectKey = buildObjectKey(voucher.getId(), waybillNo,
|
String objectKey = buildObjectKey(voucher.getId(), waybillNo,
|
||||||
Func.isEmpty(plateNo) ? "root" : plateNo, entryName);
|
Func.isEmpty(plateNo) ? "root" : plateNo, entryName);
|
||||||
String contentType = contentType(fileName);
|
String contentType = contentType(fileName);
|
||||||
minioClient().putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey)
|
minioClient.putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey)
|
||||||
.stream(zipInputStream, entry.getSize(), 10 * 1024 * 1024)
|
.stream(zipInputStream, entry.getSize(), 10 * 1024 * 1024)
|
||||||
.contentType(contentType).build());
|
.contentType(contentType).build());
|
||||||
VoucherFile file = new VoucherFile();
|
VoucherFile file = new VoucherFile();
|
||||||
@@ -1053,20 +1052,6 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 MinIO 客户端。
|
|
||||||
* <p>
|
|
||||||
* 未配置 file.storage.minio.endpoint 时该客户端不会被注册,
|
|
||||||
* 此处给出与 {@link #validateMinioConfig()} 一致的明确提示。
|
|
||||||
*/
|
|
||||||
private MinioClient minioClient() {
|
|
||||||
MinioClient minioClient = minioClientProvider.getIfAvailable();
|
|
||||||
if (minioClient == null) {
|
|
||||||
throw new ServiceException("Nacos 未配置 file.storage.minio.endpoint,凭证文件功能不可用");
|
|
||||||
}
|
|
||||||
return minioClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String buildObjectKey(Long voucherId, String waybillNo, String plateNo, String entryName) {
|
private String buildObjectKey(Long voucherId, String waybillNo, String plateNo, String entryName) {
|
||||||
String objectKey = voucherId + "/" + waybillNo + "/" + safePathPart(plateNo) + "/" + safeArchivePath(entryName);
|
String objectKey = voucherId + "/" + waybillNo + "/" + safePathPart(plateNo) + "/" + safeArchivePath(entryName);
|
||||||
if (Func.isEmpty(minioRootDirectory)) {
|
if (Func.isEmpty(minioRootDirectory)) {
|
||||||
@@ -1142,7 +1127,7 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
|
|||||||
|
|
||||||
private String buildVoucherFileUrl(Long fileId, String objectKey) {
|
private String buildVoucherFileUrl(Long fileId, String objectKey) {
|
||||||
try {
|
try {
|
||||||
return minioClient().getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
|
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
|
||||||
.method(Method.GET).bucket(minioBucketName).object(objectKey).expiry(1, java.util.concurrent.TimeUnit.HOURS).build());
|
.method(Method.GET).bucket(minioBucketName).object(objectKey).expiry(1, java.util.concurrent.TimeUnit.HOURS).build());
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
log.warn("生成凭证文件预览地址失败 voucherFileId={}, objectKey={}", fileId, objectKey, exception);
|
log.warn("生成凭证文件预览地址失败 voucherFileId={}, objectKey={}", fileId, objectKey, exception);
|
||||||
|
|||||||
+33
-152
@@ -19,7 +19,6 @@ import org.springblade.core.tool.utils.BeanUtil;
|
|||||||
import org.springblade.core.tool.utils.DateUtil;
|
import org.springblade.core.tool.utils.DateUtil;
|
||||||
import org.springblade.core.tool.utils.Func;
|
import org.springblade.core.tool.utils.Func;
|
||||||
import org.springblade.core.tool.utils.WebUtil;
|
import org.springblade.core.tool.utils.WebUtil;
|
||||||
import org.springblade.core.tool.jackson.JsonUtil;
|
|
||||||
import org.springblade.system.cache.DictCache;
|
import org.springblade.system.cache.DictCache;
|
||||||
import org.springblade.system.cache.DictBizCache;
|
import org.springblade.system.cache.DictBizCache;
|
||||||
import org.springblade.system.cache.UserCache;
|
import org.springblade.system.cache.UserCache;
|
||||||
@@ -52,10 +51,10 @@ import java.io.IOException;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -69,6 +68,7 @@ import java.util.stream.Collectors;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImportBatchMapper, WaybillImportBatch> implements IWaybillImportBatchService {
|
public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImportBatchMapper, WaybillImportBatch> 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_DRAFT = "draft";
|
||||||
private static final String STATUS_COMPLETED = "completed";
|
private static final String STATUS_COMPLETED = "completed";
|
||||||
@@ -184,36 +184,20 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
|||||||
|
|
||||||
List<Map<String, Object>> rows = Func.isEmpty(request.getRows()) ? List.of() : request.getRows();
|
List<Map<String, Object>> rows = Func.isEmpty(request.getRows()) ? List.of() : request.getRows();
|
||||||
|
|
||||||
// 逐行构建运单(未落库),构建失败时报出对应行号
|
|
||||||
List<Waybill> rowWaybills = new ArrayList<>();
|
|
||||||
for (int index = 0; index < rows.size(); index++) {
|
|
||||||
try {
|
|
||||||
rowWaybills.add(buildWaybill(rows.get(index), batch, request.getCarrierContractId(), draft));
|
|
||||||
} catch (Exception exception) {
|
|
||||||
throw new ServiceException("第" + (index + 1) + "行" + (draft ? "保存" : "导入") + "失败:" + exception.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 同一运单标识号的多货物行合并为一条运单,各行转为货物明细
|
|
||||||
Map<Integer, Waybill> waybillByRow = new HashMap<>();
|
|
||||||
Set<Integer> skipRows = new HashSet<>();
|
|
||||||
mergeMultiCargoRows(rows, rowWaybills, waybillByRow, skipRows);
|
|
||||||
|
|
||||||
List<Waybill> waybills = new ArrayList<>();
|
List<Waybill> waybills = new ArrayList<>();
|
||||||
Map<String, List<Waybill>> loadingWaybills = new TreeMap<>();
|
Map<String, List<Waybill>> loadingWaybills = new TreeMap<>();
|
||||||
for (int index = 0; index < rows.size(); index++) {
|
for (int index = 0; index < rows.size(); index++) {
|
||||||
if (skipRows.contains(index)) continue;
|
|
||||||
Waybill waybill = waybillByRow.getOrDefault(index, rowWaybills.get(index));
|
|
||||||
// 配载标识号必须取自行数据:运单落库(prepareForSave)会把新建运单的 loadingNo 置空
|
|
||||||
String loadingIdentifier = stringValue(rows.get(index), "loadingIdentifier", "配载标识号");
|
|
||||||
try {
|
try {
|
||||||
|
String loadingIdentifier = stringValue(rows.get(index), "loadingIdentifier", "配载标识号");
|
||||||
|
Waybill waybill = buildWaybill(rows.get(index), batch, request.getCarrierContractId(), draft);
|
||||||
if (draft) waybillService.saveDraft(waybill); else waybillService.submit(waybill);
|
if (draft) waybillService.saveDraft(waybill); else waybillService.submit(waybill);
|
||||||
|
waybills.add(waybill);
|
||||||
|
if (!draft && IMPORT_TYPE_WAYBILL.equals(batch.getImportType()) && Func.isNotEmpty(loadingIdentifier)) {
|
||||||
|
loadingWaybills.computeIfAbsent(loadingIdentifier, key -> new ArrayList<>()).add(waybill);
|
||||||
|
}
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
throw new ServiceException("第" + (index + 1) + "行" + (draft ? "保存" : "导入") + "失败:" + exception.getMessage());
|
throw new ServiceException("第" + (index + 1) + "行" + (draft ? "保存" : "导入") + "失败:" + exception.getMessage());
|
||||||
}
|
}
|
||||||
waybills.add(waybill);
|
|
||||||
if (!draft && IMPORT_TYPE_WAYBILL.equals(batch.getImportType()) && Func.isNotEmpty(loadingIdentifier)) {
|
|
||||||
loadingWaybills.computeIfAbsent(loadingIdentifier, key -> new ArrayList<>()).add(waybill);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
loadingWaybills.forEach(loadingManageService::createFromImportedWaybills);
|
loadingWaybills.forEach(loadingManageService::createFromImportedWaybills);
|
||||||
batch.setWaybillCount(waybills.size());
|
batch.setWaybillCount(waybills.size());
|
||||||
@@ -234,69 +218,6 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将同一运单标识号的多货物行合并为一条运单:
|
|
||||||
* 首行作为主行(数值字段累加各行),后续行转为货物明细追加到主行货物信息中;
|
|
||||||
* 被 merge 的行记入 skipRows,落库时跳过。
|
|
||||||
*/
|
|
||||||
private void mergeMultiCargoRows(List<Map<String, Object>> rows, List<Waybill> rowWaybills,
|
|
||||||
Map<Integer, Waybill> waybillByRow, Set<Integer> skipRows) {
|
|
||||||
Map<String, List<Integer>> groups = new LinkedHashMap<>();
|
|
||||||
for (int index = 0; index < rowWaybills.size(); index++) {
|
|
||||||
String relationNo = rowWaybills.get(index).getRelationNo();
|
|
||||||
if (Func.isEmpty(relationNo)) continue;
|
|
||||||
groups.computeIfAbsent(relationNo, key -> new ArrayList<>()).add(index);
|
|
||||||
}
|
|
||||||
for (List<Integer> groupRows : groups.values()) {
|
|
||||||
if (groupRows.size() <= 1) continue;
|
|
||||||
Waybill primary = rowWaybills.get(groupRows.get(0));
|
|
||||||
List<Map<String, Object>> goodsList = new ArrayList<>();
|
|
||||||
for (Integer rowIndex : groupRows) {
|
|
||||||
Waybill current = rowWaybills.get(rowIndex);
|
|
||||||
if (!rowIndex.equals(groupRows.get(0))) {
|
|
||||||
// 主行字段保留首行值,数量等数值字段累加同组其余各行
|
|
||||||
mergeNumericFields(primary, current);
|
|
||||||
skipRows.add(rowIndex);
|
|
||||||
waybillByRow.remove(rowIndex);
|
|
||||||
}
|
|
||||||
goodsList.add(buildGoodsItem(rows.get(rowIndex), current));
|
|
||||||
}
|
|
||||||
primary.setGoodsJson(JsonUtil.toJson(goodsList));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 合并多货物行时累加数量、其他费用等可加数值字段;为空的字段跳过。 */
|
|
||||||
private void mergeNumericFields(Waybill primary, Waybill current) {
|
|
||||||
primary.setQuantity(sumNullable(primary.getQuantity(), current.getQuantity()));
|
|
||||||
primary.setOtherFeeTotal(sumNullable(primary.getOtherFeeTotal(), current.getOtherFeeTotal()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private BigDecimal sumNullable(BigDecimal first, BigDecimal second) {
|
|
||||||
if (first == null) return second;
|
|
||||||
if (second == null) return first;
|
|
||||||
return first.add(second);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 由导入行构建一条货物明细,字段与运单详情货物编辑结构保持一致。 */
|
|
||||||
private Map<String, Object> buildGoodsItem(Map<String, Object> row, Waybill waybill) {
|
|
||||||
Map<String, Object> goods = new LinkedHashMap<>();
|
|
||||||
putIfNotEmpty(goods, "cargoName", waybill.getCargoName());
|
|
||||||
putIfNotEmpty(goods, "cargoType", waybill.getCargoType());
|
|
||||||
putIfNotEmpty(goods, "specification", waybill.getSpecification());
|
|
||||||
putIfNotEmpty(goods, "model", waybill.getModel());
|
|
||||||
putIfNotEmpty(goods, "packageType", stringValue(row, "packageType", "包装"));
|
|
||||||
if (waybill.getQuantity() != null) {
|
|
||||||
goods.put("quantity", waybill.getQuantity().toPlainString());
|
|
||||||
}
|
|
||||||
putIfNotEmpty(goods, "quantityUnit", waybill.getQuantityUnit());
|
|
||||||
putIfNotEmpty(goods, "remark", waybill.getRemark());
|
|
||||||
return goods;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putIfNotEmpty(Map<String, Object> goods, String key, String value) {
|
|
||||||
if (Func.isNotEmpty(value)) goods.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IPage<WaybillImportBatchVO> page(IPage<WaybillImportBatch> page, WaybillImportBatchRequest request) {
|
public IPage<WaybillImportBatchVO> page(IPage<WaybillImportBatch> page, WaybillImportBatchRequest request) {
|
||||||
LambdaQueryWrapper<WaybillImportBatch> queryWrapper = Wrappers.<WaybillImportBatch>lambdaQuery()
|
LambdaQueryWrapper<WaybillImportBatch> queryWrapper = Wrappers.<WaybillImportBatch>lambdaQuery()
|
||||||
@@ -465,12 +386,11 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
|||||||
throw new ServiceException(fieldName + "不能为空");
|
throw new ServiceException(fieldName + "不能为空");
|
||||||
}
|
}
|
||||||
String text = String.valueOf(value).trim();
|
String text = String.valueOf(value).trim();
|
||||||
// 宽容解析:接受 2026-8-2、2026-9-1 8:0:0 等写法(口径见根工作区 docs/import-spec.md)。
|
try {
|
||||||
LocalDate date = org.springblade.common.excel.LenientDateParser.parseDateLenientlyOrNull(text);
|
return text.length() == 10 ? LocalDate.parse(text) : LocalDate.parse(text, DATE_TIME_FORMATTER);
|
||||||
if (date == null) {
|
} catch (DateTimeParseException exception) {
|
||||||
throw new ServiceException(fieldName + " 日期格式无法识别:" + text);
|
throw new ServiceException(fieldName + "格式必须为 YYYY-MM-DD HH:mm:ss");
|
||||||
}
|
}
|
||||||
return date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal defaultQuantity(BigDecimal quantity) {
|
private BigDecimal defaultQuantity(BigDecimal quantity) {
|
||||||
@@ -603,9 +523,6 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
|||||||
// 16. 同一运单标识号校验
|
// 16. 同一运单标识号校验
|
||||||
validateWaybillIdentifier(row, i, waybillIdentifierMap, rows, errors);
|
validateWaybillIdentifier(row, i, waybillIdentifierMap, rows, errors);
|
||||||
|
|
||||||
// 17. 同一运单标识号组内一致性校验(地址/配载标识号/数量单位,多货物合并的前提)
|
|
||||||
validateWaybillIdentifierConsistency(row, i, waybillIdentifierMap, rows, errors);
|
|
||||||
|
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
errorMap.put(i, String.join("; ", errors));
|
errorMap.put(i, String.join("; ", errors));
|
||||||
}
|
}
|
||||||
@@ -654,13 +571,21 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
|||||||
if (!isRoadTransport(transportType)) {
|
if (!isRoadTransport(transportType)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 必填、长度与格式统一为一条简短原因,避免多条规则叠加导致失败原因过长;
|
if (Func.isEmpty(vehicleNo)) {
|
||||||
// 文案保留“车牌号”字样,导入失败明细仍能据此定位到车牌号列并标红。
|
errors.add("公路运输时车牌号/航班号/船号/班列号不能为空");
|
||||||
// VEHICLE_NO_PATTERN 已约束总长度为 7 或 8 位,故不再单独判断长度。
|
return;
|
||||||
if (Func.isEmpty(vehicleNo)
|
}
|
||||||
|| !VEHICLE_PROVINCE_PATTERN.matcher(vehicleNo).lookingAt()
|
if (vehicleNo.length() < 7) {
|
||||||
|| !VEHICLE_NO_PATTERN.matcher(vehicleNo).matches()) {
|
errors.add("车牌号长度不能少于7位");
|
||||||
errors.add("车牌号校验不通过");
|
}
|
||||||
|
if (vehicleNo.length() > 8) {
|
||||||
|
errors.add("车牌号长度不能超过8位");
|
||||||
|
}
|
||||||
|
if (!VEHICLE_PROVINCE_PATTERN.matcher(vehicleNo).lookingAt()) {
|
||||||
|
errors.add("车牌号首位必须是省份简称,第二位必须是英文字母");
|
||||||
|
}
|
||||||
|
if (!VEHICLE_NO_PATTERN.matcher(vehicleNo).matches()) {
|
||||||
|
errors.add("车牌号格式不正确,应为首位省份简称、次位英文字母、总长度7或8位");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -901,62 +826,18 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 同一运单标识号组内的发货地址、到货地址、数量单位、配载标识号必须一致:
|
|
||||||
* 多货物行会合并为一条运单,上述字段不一致时无法合并(数量累加也要求单位相同)。
|
|
||||||
*/
|
|
||||||
private void validateWaybillIdentifierConsistency(Map<String, Object> row, int rowIndex,
|
|
||||||
Map<String, List<Integer>> waybillIdentifierMap, List<Map<String, Object>> allRows, List<String> errors) {
|
|
||||||
String waybillIdentifier = stringValue(row, "waybillIdentifier", "同一运单标识号");
|
|
||||||
if (Func.isEmpty(waybillIdentifier)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<Integer> sameIdentifierRows = waybillIdentifierMap.get(waybillIdentifier);
|
|
||||||
if (sameIdentifierRows == null || sameIdentifierRows.size() <= 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
compareGroupValue(rowIndex, sameIdentifierRows, allRows, "departureAddress", "发货地址", errors);
|
|
||||||
compareGroupValue(rowIndex, sameIdentifierRows, allRows, "arrivalAddress", "到货地址", errors);
|
|
||||||
compareGroupValue(rowIndex, sameIdentifierRows, allRows, "quantityUnit", "数量单位", errors);
|
|
||||||
compareGroupValue(rowIndex, sameIdentifierRows, allRows, "loadingIdentifier", "配载标识号", errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 比较同一运单标识号组内其余行的字段值,不一致时记录错误;空值不参与比较。 */
|
|
||||||
private void compareGroupValue(int rowIndex, List<Integer> sameIdentifierRows, List<Map<String, Object>> allRows,
|
|
||||||
String field, String fieldName, List<String> errors) {
|
|
||||||
String currentValue = normalizeCompareValue(stringValue(allRows.get(rowIndex), field, fieldName));
|
|
||||||
if (Func.isEmpty(currentValue)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (Integer otherRowIndex : sameIdentifierRows) {
|
|
||||||
if (otherRowIndex <= rowIndex) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String otherValue = normalizeCompareValue(stringValue(allRows.get(otherRowIndex), field, fieldName));
|
|
||||||
if (Func.isNotEmpty(otherValue) && !currentValue.equals(otherValue)) {
|
|
||||||
errors.add("同一运单标识号下," + fieldName + "必须一致");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String normalizeCompareValue(String value) {
|
|
||||||
return Func.isEmpty(value) ? null : value.replaceAll("\\s+", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private LocalDate parseDateForValidation(Object value, String fieldName, List<String> errors) {
|
private LocalDate parseDateForValidation(Object value, String fieldName, List<String> errors) {
|
||||||
if (value == null || String.valueOf(value).isBlank()) {
|
if (value == null || String.valueOf(value).isBlank()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String text = String.valueOf(value).trim();
|
String text = String.valueOf(value).trim();
|
||||||
// 宽容解析:接受 2026-8-2、2026-9-1 8:0:0 等写法(口径见根工作区 docs/import-spec.md)。
|
try {
|
||||||
LocalDate date = org.springblade.common.excel.LenientDateParser.parseDateLenientlyOrNull(text);
|
return text.length() == 10 ? LocalDate.parse(text) : LocalDate.parse(text, DATE_TIME_FORMATTER);
|
||||||
if (date == null) {
|
} catch (DateTimeParseException exception) {
|
||||||
errors.add(fieldName + " 日期格式无法识别:" + text);
|
errors.add(fieldName + "格式必须为日期格式(YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss)");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> loadTransportTypeOptions() {
|
private Map<String, String> loadTransportTypeOptions() {
|
||||||
@@ -980,8 +861,8 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
|||||||
// 字典读取失败时使用默认值。
|
// 字典读取失败时使用默认值。
|
||||||
}
|
}
|
||||||
if (options.isEmpty()) {
|
if (options.isEmpty()) {
|
||||||
// 运输方式仅支持公路、铁路、水路、航空四种
|
List<String> defaults = List.of("公路运输", "铁路运输", "水路运输", "航空运输",
|
||||||
List<String> defaults = List.of("公路运输", "铁路运输", "水路运输", "航空运输");
|
"公路整车", "公路配载/零担", "铁路整车", "铁路零担", "水路", "航空", "多式联运", "管道运输", "其他");
|
||||||
defaults.forEach(value -> options.put(value, value));
|
defaults.forEach(value -> options.put(value, value));
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
|
|||||||
-6
@@ -885,13 +885,7 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
|||||||
WaybillExcel excel = data.get(index);
|
WaybillExcel excel = data.get(index);
|
||||||
try {
|
try {
|
||||||
Waybill waybill = Objects.requireNonNull(BeanUtil.copyProperties(excel, Waybill.class));
|
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.setDataSource("批量导入");
|
||||||
waybill.setCreateTime(null);
|
|
||||||
waybill.setUpdateTime(null);
|
|
||||||
waybill.setCarrierJson(buildImportCarrierJson(waybill));
|
waybill.setCarrierJson(buildImportCarrierJson(waybill));
|
||||||
submit(waybill);
|
submit(waybill);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
|
|||||||
Vendored
+9
@@ -65,6 +65,15 @@ public interface IMKClient {
|
|||||||
@PostMapping("${thirdParty.mk.getCurrentNodesUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}")
|
@PostMapping("${thirdParty.mk.getCurrentNodesUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}")
|
||||||
MKResultVO<List<MKNodeVO>> getCurrentNodes(@RequestBody MKCurrentNodesDTO param, @RequestParam("access_token") String accessToken);
|
MKResultVO<List<MKNodeVO>> getCurrentNodes(@RequestBody MKCurrentNodesDTO param, @RequestParam("access_token") String accessToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程实例详情
|
||||||
|
* @param param
|
||||||
|
* @param accessToken
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("${thirdParty.mk.getProcessInfoUrl:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getProcessInfo}")
|
||||||
|
MKResultVO<Object> getProcessInfo(@RequestBody MKCurrentNodesDTO param, @RequestParam("access_token") String accessToken);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取节点处理人信息
|
* 获取节点处理人信息
|
||||||
* @param param
|
* @param param
|
||||||
|
|||||||
+6
@@ -1,6 +1,7 @@
|
|||||||
package org.springblade.thirdparty.mk.pojo.dto;
|
package org.springblade.thirdparty.mk.pojo.dto;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
@@ -44,4 +45,9 @@ public class MKProcessCreateDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
private Object tempVarData;
|
private Object tempVarData;
|
||||||
|
/**
|
||||||
|
* 业务类型,仅 ERP 内部使用,不传给 MK
|
||||||
|
*/
|
||||||
|
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
|
||||||
|
private String bizType;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -66,6 +66,14 @@ public interface IMKService {
|
|||||||
*/
|
*/
|
||||||
List<MKNodeVO> getCurrentNodes(String processInstanceId, String loginName);
|
List<MKNodeVO> getCurrentNodes(String processInstanceId, String loginName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程实例详情
|
||||||
|
* @param processInstanceId
|
||||||
|
* @param loginName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Object getProcessInfo(String processInstanceId, String loginName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取节点处理人信息
|
* 获取节点处理人信息
|
||||||
* @param processInstanceId
|
* @param processInstanceId
|
||||||
|
|||||||
+15
@@ -246,6 +246,21 @@ public class MKServiceImpl implements IMKService {
|
|||||||
return nodesResult.getData();
|
return nodesResult.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getProcessInfo(String processInstanceId, String loginName) {
|
||||||
|
String accessToken = getToken();
|
||||||
|
MKCurrentNodesDTO param = new MKCurrentNodesDTO();
|
||||||
|
param.setProcessInstanceId(processInstanceId);
|
||||||
|
param.setLoginName(loginName);
|
||||||
|
MKResultVO<Object> processInfoResult = client.getProcessInfo(param, accessToken);
|
||||||
|
log.info("调用mk接口 获取流程实例详情 :{}", JSONUtil.toJsonStr(processInfoResult));
|
||||||
|
if (processInfoResult == null || !processInfoResult.isSuccess()) {
|
||||||
|
log.error("调用mk接口 获取流程实例详情异常:{}", JSONUtil.toJsonStr(processInfoResult));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return processInfoResult.getData();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MKAllHandlerVO getNodeHandlers(String processInstanceId, String loginName, String nodeId) {
|
public MKAllHandlerVO getNodeHandlers(String processInstanceId, String loginName, String nodeId) {
|
||||||
String accessToken = getToken();
|
String accessToken = getToken();
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ thirdParty:
|
|||||||
processExecuteUrl: ${MK_PROCESS_EXECUTE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/execute}
|
processExecuteUrl: ${MK_PROCESS_EXECUTE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/execute}
|
||||||
processDeleteUrl: ${MK_PROCESS_DELETE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/delete}
|
processDeleteUrl: ${MK_PROCESS_DELETE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/delete}
|
||||||
getCurrentNodesUrl: ${MK_CURRENT_NODES_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}
|
getCurrentNodesUrl: ${MK_CURRENT_NODES_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}
|
||||||
|
getProcessInfoUrl: ${MK_PROCESS_INFO_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getProcessInfo}
|
||||||
getNodeHandlersUrl: ${MK_NODE_HANDLERS_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getNodeHandlerInfos}
|
getNodeHandlersUrl: ${MK_NODE_HANDLERS_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getNodeHandlerInfos}
|
||||||
getManualNodeUrl: ${MK_MANUAL_NODE_URL:/openapi/sys-lbpm/sysLbpmTemplate/openSupport/getManualNode}
|
getManualNodeUrl: ${MK_MANUAL_NODE_URL:/openapi/sys-lbpm/sysLbpmTemplate/openSupport/getManualNode}
|
||||||
pushOrgDeptUrl: ${MK_PUSH_ORG_DEPT_URL:/openapi/sys-org/v2/push/orgDept}
|
pushOrgDeptUrl: ${MK_PUSH_ORG_DEPT_URL:/openapi/sys-org/v2/push/orgDept}
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ thirdParty:
|
|||||||
processExecuteUrl: ${MK_PROCESS_EXECUTE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/execute}
|
processExecuteUrl: ${MK_PROCESS_EXECUTE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/execute}
|
||||||
processDeleteUrl: ${MK_PROCESS_DELETE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/delete}
|
processDeleteUrl: ${MK_PROCESS_DELETE_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/delete}
|
||||||
getCurrentNodesUrl: ${MK_CURRENT_NODES_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}
|
getCurrentNodesUrl: ${MK_CURRENT_NODES_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getCurNodesInfo}
|
||||||
|
getProcessInfoUrl: ${MK_PROCESS_INFO_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getProcessInfo}
|
||||||
getNodeHandlersUrl: ${MK_NODE_HANDLERS_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getNodeHandlerInfos}
|
getNodeHandlersUrl: ${MK_NODE_HANDLERS_URL:/openapi/sys-lbpm/sysLbpmProcess/openSupport/getNodeHandlerInfos}
|
||||||
getManualNodeUrl: ${MK_MANUAL_NODE_URL:/openapi/sys-lbpm/sysLbpmTemplate/openSupport/getManualNode}
|
getManualNodeUrl: ${MK_MANUAL_NODE_URL:/openapi/sys-lbpm/sysLbpmTemplate/openSupport/getManualNode}
|
||||||
pushOrgDeptUrl: ${MK_PUSH_ORG_DEPT_URL:/openapi/sys-org/v2/push/orgDept}
|
pushOrgDeptUrl: ${MK_PUSH_ORG_DEPT_URL:/openapi/sys-org/v2/push/orgDept}
|
||||||
|
|||||||
@@ -218,9 +218,14 @@ blade:
|
|||||||
- /blade-auth/oauth/logout/**
|
- /blade-auth/oauth/logout/**
|
||||||
- /blade-transport/customer-archive/public/**
|
- /blade-transport/customer-archive/public/**
|
||||||
- /customer-archive/public/**
|
- /customer-archive/public/**
|
||||||
|
- /blade-transport/mk-process/public/**
|
||||||
|
- /mk-process/public/**
|
||||||
- /blade-openapi/openApi/mk/process/commonCallback
|
- /blade-openapi/openApi/mk/process/commonCallback
|
||||||
- /openApi/mk/process/commonCallback
|
- /openApi/mk/process/commonCallback
|
||||||
- /feign/client/businessProcess/getCurrentNodes
|
- /feign/client/businessProcess/getCurrentNodes
|
||||||
|
- /feign/client/businessProcess/getProcessInfo
|
||||||
|
- /feign/client/customerArchive/syncProcessNode
|
||||||
|
- /feign/client/mkProcess/**
|
||||||
#授权认证配置
|
#授权认证配置
|
||||||
auth:
|
auth:
|
||||||
- method: ALL
|
- method: ALL
|
||||||
|
|||||||
Reference in New Issue
Block a user