|
|
|
@ -6,13 +6,19 @@ import com.gaotao.modules.base.service.LabelDataProcessorService; |
|
|
|
import com.gaotao.modules.base.utils.CoordinateTransformer; |
|
|
|
import com.gaotao.modules.base.utils.ZplGenerator; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.commons.lang3.time.DateUtils; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.stereotype.Service; |
|
|
|
|
|
|
|
import java.math.BigDecimal; |
|
|
|
import java.math.RoundingMode; |
|
|
|
import java.text.DecimalFormat; |
|
|
|
import java.time.LocalDate; |
|
|
|
import java.time.ZoneId; |
|
|
|
import java.time.format.DateTimeFormatter; |
|
|
|
import java.time.temporal.ChronoUnit; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.Date; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.regex.Matcher; |
|
|
|
@ -123,16 +129,36 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 处理文本元素,支持数字格式化 |
|
|
|
* 处理文本元素,支持数字、日期、字符串格式化 |
|
|
|
*/ |
|
|
|
private String processTextElement(String originalData, Map<String, Object> dataMap, ReportLabelList element) { |
|
|
|
// 首先替换数据源字段 |
|
|
|
String replacedData = replaceDataSourceFields(originalData, dataMap); |
|
|
|
|
|
|
|
// 如果元素有数字格式化设置,尝试格式化数字 |
|
|
|
// 根据数据类型进行不同的处理 |
|
|
|
String dataType = element.getDataType(); |
|
|
|
if (dataType == null) { |
|
|
|
dataType = "text"; // 默认为文本类型 |
|
|
|
} |
|
|
|
|
|
|
|
switch (dataType) { |
|
|
|
case "number": |
|
|
|
if (hasNumberFormatSettings(element)) { |
|
|
|
return formatTextAsNumber(replacedData, element); |
|
|
|
} |
|
|
|
break; |
|
|
|
case "date": |
|
|
|
return processDateElement(replacedData, element); |
|
|
|
case "string": |
|
|
|
return processStringElement(replacedData, element); |
|
|
|
case "text": |
|
|
|
default: |
|
|
|
// 文本类型也可能需要数字格式化(向后兼容) |
|
|
|
if (hasNumberFormatSettings(element)) { |
|
|
|
return formatTextAsNumber(replacedData, element); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
return replacedData; |
|
|
|
} |
|
|
|
@ -253,6 +279,259 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
return result.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 处理日期元素 |
|
|
|
*/ |
|
|
|
private String processDateElement(String dateValue, ReportLabelList element) { |
|
|
|
if (dateValue == null || dateValue.trim().isEmpty()) { |
|
|
|
return dateValue; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
String extractType = element.getDateExtractType(); |
|
|
|
if (extractType == null) { |
|
|
|
extractType = "full"; |
|
|
|
} |
|
|
|
|
|
|
|
// 尝试解析日期 |
|
|
|
java.time.LocalDate date = parseDate(dateValue); |
|
|
|
if (date == null) { |
|
|
|
log.warn("无法解析日期: {}", dateValue); |
|
|
|
return dateValue; |
|
|
|
} |
|
|
|
|
|
|
|
switch (extractType) { |
|
|
|
case "year": |
|
|
|
return String.valueOf(date.getYear()); |
|
|
|
case "month": |
|
|
|
return String.valueOf(date.getMonthValue()); |
|
|
|
case "day": |
|
|
|
return String.valueOf(date.getDayOfMonth()); |
|
|
|
case "week": |
|
|
|
return calculateWeekNumber(date, element.getFirstWeekDate()); |
|
|
|
case "weekday": |
|
|
|
return calculateWeekday(date, element.getFirstDayOfWeek()); |
|
|
|
case "full": |
|
|
|
default: |
|
|
|
return formatFullDate(date, element); |
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
log.error("日期处理失败: dateValue={}, error={}", dateValue, e.getMessage()); |
|
|
|
return dateValue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 解析日期字符串 |
|
|
|
*/ |
|
|
|
private LocalDate parseDate(String dateValue) { |
|
|
|
String[] patterns = { |
|
|
|
// 年月日 |
|
|
|
"yyyy-MM-dd", "yyyy/MM/dd", "yyyy.MM.dd", |
|
|
|
"dd-MM-yyyy", "dd/MM/yyyy", "dd.MM.yyyy", |
|
|
|
"MM-dd-yyyy", "MM/dd/yyyy", "MM.dd.yyyy", |
|
|
|
"yyyyMMdd", |
|
|
|
|
|
|
|
// 年月日 + 时分秒 |
|
|
|
"yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy.MM.dd HH:mm:ss", |
|
|
|
"dd-MM-yyyy HH:mm:ss", "dd/MM/yyyy HH:mm:ss", "dd.MM.yyyy HH:mm:ss", |
|
|
|
"MM-dd-yyyy HH:mm:ss", "MM/dd/yyyy HH:mm:ss", "MM.dd.yyyy HH:mm:ss", |
|
|
|
"yyyyMMdd HHmmss", |
|
|
|
|
|
|
|
// 年月日 + 时分 |
|
|
|
"yyyy-MM-dd HH:mm", "yyyy/MM/dd HH:mm", "yyyy.MM.dd HH:mm", |
|
|
|
"dd-MM-yyyy HH:mm", "dd/MM/yyyy HH:mm", "dd.MM.yyyy HH:mm", |
|
|
|
"MM-dd-yyyy HH:mm", "MM/dd/yyyy HH:mm", "MM.dd.yyyy HH:mm", |
|
|
|
"yyyyMMdd HHmm", |
|
|
|
|
|
|
|
// 带毫秒 |
|
|
|
"yyyy-MM-dd HH:mm:ss.SSS", "yyyy/MM/dd HH:mm:ss.SSS", "yyyy.MM.dd HH:mm:ss.SSS" |
|
|
|
}; |
|
|
|
|
|
|
|
try { |
|
|
|
Date date = DateUtils.parseDate(dateValue.trim(), patterns); |
|
|
|
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); |
|
|
|
} catch (Exception e) { |
|
|
|
log.debug("日期解析失败: {}", dateValue); |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 计算周数 |
|
|
|
*/ |
|
|
|
private String calculateWeekNumber(java.time.LocalDate date, String firstWeekDateStr) { |
|
|
|
try { |
|
|
|
java.time.LocalDate firstWeekDate; |
|
|
|
if (firstWeekDateStr != null && !firstWeekDateStr.trim().isEmpty()) { |
|
|
|
firstWeekDate = parseDate(firstWeekDateStr); |
|
|
|
if (firstWeekDate == null) { |
|
|
|
// 如果解析失败,使用年初作为第一周 |
|
|
|
firstWeekDate = java.time.LocalDate.of(date.getYear(), 1, 1); |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 默认使用年初作为第一周 |
|
|
|
firstWeekDate = java.time.LocalDate.of(date.getYear(), 1, 1); |
|
|
|
} |
|
|
|
|
|
|
|
long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(firstWeekDate, date); |
|
|
|
int weekNumber = (int) (daysBetween / 7) + 1; |
|
|
|
return String.valueOf(Math.max(1, weekNumber)); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
log.error("周数计算失败: date={}, firstWeekDate={}", date, firstWeekDateStr); |
|
|
|
return "1"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 计算星期几 |
|
|
|
*/ |
|
|
|
private String calculateWeekday(java.time.LocalDate date, String firstDayOfWeekStr) { |
|
|
|
try { |
|
|
|
int firstDayOfWeek = 1; // 默认周一为第一天 |
|
|
|
if (firstDayOfWeekStr != null && !firstDayOfWeekStr.trim().isEmpty()) { |
|
|
|
firstDayOfWeek = Integer.parseInt(firstDayOfWeekStr); |
|
|
|
} |
|
|
|
|
|
|
|
int dayOfWeek = date.getDayOfWeek().getValue(); // 1=周一, 7=周日 |
|
|
|
|
|
|
|
// 调整为指定的第一天 |
|
|
|
int adjustedDay = ((dayOfWeek - firstDayOfWeek + 7) % 7) + 1; |
|
|
|
return String.valueOf(adjustedDay); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
log.error("星期几计算失败: date={}, firstDayOfWeek={}", date, firstDayOfWeekStr); |
|
|
|
return "1"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 格式化完整日期 |
|
|
|
*/ |
|
|
|
private String formatFullDate(java.time.LocalDate date, ReportLabelList element) { |
|
|
|
try { |
|
|
|
String dateFormat = element.getDateFormat() != null ? element.getDateFormat() : "ymd"; |
|
|
|
String separator = element.getDateSeparator() != null ? element.getDateSeparator() : "-"; |
|
|
|
String yearDigits = element.getYearDigits() != null ? element.getYearDigits() : "4"; |
|
|
|
String monthDayDigits = element.getMonthDayDigits() != null ? element.getMonthDayDigits() : "2"; |
|
|
|
|
|
|
|
// 格式化年份 |
|
|
|
String year = "4".equals(yearDigits) ? |
|
|
|
String.format("%04d", date.getYear()) : |
|
|
|
String.format("%02d", date.getYear() % 100); |
|
|
|
|
|
|
|
// 格式化月份和日期 |
|
|
|
String month = "2".equals(monthDayDigits) ? |
|
|
|
String.format("%02d", date.getMonthValue()) : |
|
|
|
String.valueOf(date.getMonthValue()); |
|
|
|
|
|
|
|
String day = "2".equals(monthDayDigits) ? |
|
|
|
String.format("%02d", date.getDayOfMonth()) : |
|
|
|
String.valueOf(date.getDayOfMonth()); |
|
|
|
|
|
|
|
// 根据格式组合 |
|
|
|
switch (dateFormat) { |
|
|
|
case "dmy": |
|
|
|
return day + separator + month + separator + year; |
|
|
|
case "mdy": |
|
|
|
return month + separator + day + separator + year; |
|
|
|
case "ymd": |
|
|
|
default: |
|
|
|
return year + separator + month + separator + day; |
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
log.error("日期格式化失败: date={}", date); |
|
|
|
return date.toString(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 处理字符串元素 |
|
|
|
*/ |
|
|
|
private String processStringElement(String stringValue, ReportLabelList element) { |
|
|
|
if (stringValue == null || stringValue.isEmpty()) { |
|
|
|
return stringValue; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
String processType = element.getStringProcessType(); |
|
|
|
if (processType == null || "none".equals(processType)) { |
|
|
|
return stringValue; |
|
|
|
} |
|
|
|
|
|
|
|
switch (processType) { |
|
|
|
case "substring_start": |
|
|
|
return processSubstringStart(stringValue, element.getSubstringStartLength()); |
|
|
|
case "substring_end": |
|
|
|
return processSubstringEnd(stringValue, element.getSubstringEndLength()); |
|
|
|
case "split": |
|
|
|
return processSplit(stringValue, element.getSplitCharacter(), element.getSplitIndex()-1); |
|
|
|
case "replace": |
|
|
|
return processReplace(stringValue, element.getReplaceFrom(), element.getReplaceTo()); |
|
|
|
default: |
|
|
|
return stringValue; |
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
log.error("字符串处理失败: stringValue={}, processType={}, error={}", |
|
|
|
stringValue, element.getStringProcessType(), e.getMessage()); |
|
|
|
return stringValue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 截取前面字符 |
|
|
|
*/ |
|
|
|
private String processSubstringStart(String value, Integer length) { |
|
|
|
if (length == null || length <= 0) { |
|
|
|
return value; |
|
|
|
} |
|
|
|
return value.length() <= length ? value : value.substring(0, length); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 截取后面字符 |
|
|
|
*/ |
|
|
|
private String processSubstringEnd(String value, Integer length) { |
|
|
|
if (length == null || length <= 0) { |
|
|
|
return value; |
|
|
|
} |
|
|
|
return value.length() <= length ? value : value.substring(value.length() - length); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 按字符分割 |
|
|
|
*/ |
|
|
|
private String processSplit(String value, String splitChar, Integer index) { |
|
|
|
if (splitChar == null || splitChar.isEmpty() || index == null || index < 0) { |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
String[] parts = value.split(Pattern.quote(splitChar)); |
|
|
|
return index < parts.length ? parts[index] : ""; |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("字符串分割失败: value={}, splitChar={}, index={}", value, splitChar, index); |
|
|
|
return value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 替换字符 |
|
|
|
*/ |
|
|
|
private String processReplace(String value, String from, String to) { |
|
|
|
if (from == null || from.isEmpty()) { |
|
|
|
return value; |
|
|
|
} |
|
|
|
if (to == null) { |
|
|
|
to = ""; |
|
|
|
} |
|
|
|
return value.replace(from, to); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 复制元素对象 |
|
|
|
*/ |
|
|
|
@ -282,6 +561,24 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService |
|
|
|
copy.setThousandsSeparator(original.getThousandsSeparator()); |
|
|
|
copy.setDigits(original.getDigits()); |
|
|
|
copy.setStep(original.getStep()); |
|
|
|
|
|
|
|
// 复制新增的数据类型相关字段 |
|
|
|
copy.setDataType(original.getDataType()); |
|
|
|
copy.setDateExtractType(original.getDateExtractType()); |
|
|
|
copy.setFirstWeekDate(original.getFirstWeekDate()); |
|
|
|
copy.setFirstDayOfWeek(original.getFirstDayOfWeek()); |
|
|
|
copy.setDateFormat(original.getDateFormat()); |
|
|
|
copy.setDateSeparator(original.getDateSeparator()); |
|
|
|
copy.setYearDigits(original.getYearDigits()); |
|
|
|
copy.setMonthDayDigits(original.getMonthDayDigits()); |
|
|
|
copy.setStringProcessType(original.getStringProcessType()); |
|
|
|
copy.setSubstringStartLength(original.getSubstringStartLength()); |
|
|
|
copy.setSubstringEndLength(original.getSubstringEndLength()); |
|
|
|
copy.setSplitCharacter(original.getSplitCharacter()); |
|
|
|
copy.setSplitIndex(original.getSplitIndex()); |
|
|
|
copy.setReplaceFrom(original.getReplaceFrom()); |
|
|
|
copy.setReplaceTo(original.getReplaceTo()); |
|
|
|
|
|
|
|
return copy; |
|
|
|
} |
|
|
|
@Override |
|
|
|
|