| | |
| | | package com.trafficaudit.holiday.service; |
| | | |
| | | import com.trafficaudit.holiday.HolidayNumberUtils; |
| | | import com.trafficaudit.holiday.entity.HolidayCalendar; |
| | | import com.trafficaudit.holiday.service.HolidayStatService.DailyMetrics; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | |
| | | import org.w3c.dom.Node; |
| | | import org.w3c.dom.NodeList; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.xml.parsers.DocumentBuilderFactory; |
| | | import javax.xml.transform.OutputKeys; |
| | | import javax.xml.transform.Transformer; |
| | |
| | | import java.io.FileInputStream; |
| | | import java.io.InputStream; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.nio.file.Files; |
| | | import java.time.LocalDate; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.function.Function; |
| | | import java.util.zip.ZipEntry; |
| | | import java.util.zip.ZipInputStream; |
| | | import java.util.zip.ZipOutputStream; |
| | |
| | | |
| | | private static final String WORD_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; |
| | | private static final BigDecimal EPSILON = new BigDecimal("0.0000001"); |
| | | private static final int EXCEL_ONE_DECIMAL_PERCENT = 1; |
| | | private static final int EXCEL_TWO_DECIMAL_PERCENT = 2; |
| | | private static final int EXCEL_SEVEN_DECIMAL_YI = 7; |
| | | private static final BigDecimal TEN_THOUSAND = new BigDecimal("10000"); |
| | | |
| | | @Value("${holiday.bulletin-template:docs/专项统计/重要节假日/湖北省国庆假期综合运输客流快报模板.docx}") |
| | | private String bulletinTemplatePath; |
| | | |
| | | private final HolidayStatService statService; |
| | | @Resource |
| | | private HolidayConfigService configService; |
| | | private static final ThreadLocal<Document> CURRENT_DOCUMENT = new ThreadLocal<>(); |
| | | |
| | | public HolidayBulletinService(HolidayStatService statService) { |
| | |
| | | throw new IllegalArgumentException("所选日期不在已配置的节假日范围内"); |
| | | } |
| | | DailyMetrics previousDay = current.getDayIndex() > 1 |
| | | ? statService.dailyMetrics(current.getYear(), current.getHolidayType(), current.getDayIndex() - 1) : null; |
| | | ? statService.ringRatioBaseMetrics(current.getYear(), current.getHolidayType(), current.getDayIndex()) : null; |
| | | HolidayCalendar previousDayConfig = configService.findPreviousDay(current.getYear(), current.getHolidayType()); |
| | | LocalDate previousDayDate = previousDayConfig == null || previousDayConfig.getHolidayDate() == null |
| | | ? current.getDate().minusDays(1) : previousDayConfig.getHolidayDate(); |
| | | DailyMetrics previousCalendarDay = previousDay != null |
| | | ? previousDay : statService.dailyMetricsByDate(previousDayDate); |
| | | DailyMetrics previousYear = statService.dailyMetrics(current.getYear() - 1, current.getHolidayType(), current.getDayIndex()); |
| | | DailyMetrics twoYearsAgo = statService.dailyMetrics(current.getYear() - 2, current.getHolidayType(), current.getDayIndex()); |
| | | DailyMetrics currentCumulative = statService.cumulativeMetrics(current.getYear(), current.getHolidayType(), current.getDayIndex()); |
| | | DailyMetrics previousYearCumulative = statService.cumulativeMetrics(current.getYear() - 1, current.getHolidayType(), current.getDayIndex()); |
| | | DailyMetrics twoYearsAgoCumulative = statService.cumulativeMetrics(current.getYear() - 2, current.getHolidayType(), current.getDayIndex()); |
| | | |
| | | if (current.getTotalPersonFlow() == null) { |
| | | throw new IllegalArgumentException("所选日期的全社会跨区域人员流动量没有足够数据,无法生成快报"); |
| | | } |
| | | |
| | | String currentTotal = formatNumber(current.getTotalPersonFlow()); |
| | | String cumulativeTotalYi = formatNumber(currentCumulative.getTotalPersonFlow() == null |
| | | ? null : HolidayNumberUtils.divide(currentCumulative.getTotalPersonFlow(), BigDecimal.valueOf(10000))); |
| | | String ringRatioClause = previousDay == null ? "" : ",环比" + ratioPhrase( |
| | | current.getTotalPersonFlow(), previousDay.getTotalPersonFlow()); |
| | | String paragraph1 = String.format("%d月%d日(假期第%d天),全省全社会跨区域人员流动量%s万人次%s,比2025年同期%s。", |
| | | current.getTotalPersonFlow(), previousDay.getTotalPersonFlow(), EXCEL_TWO_DECIMAL_PERCENT); |
| | | String paragraph1 = String.format("%d月%d日(假期第%d天),全省全社会跨区域人员流动量%s万人次%s,比2025年同期%s,比2024年同期%s。", |
| | | date.getMonthValue(), date.getDayOfMonth(), current.getDayIndex(), currentTotal, |
| | | ringRatioClause, |
| | | ratioPhrase(current.getTotalPersonFlow(), previousYear == null ? null : previousYear.getTotalPersonFlow())); |
| | | String paragraph2 = String.format("假期以来,全省全社会跨区域人员流动量累计%s亿人次,比2025年同期%s。", |
| | | cumulativeTotalYi, |
| | | ratioPhrase(currentCumulative.getTotalPersonFlow(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getTotalPersonFlow())); |
| | | ratioPhrase(current.getTotalPersonFlow(), previousYear == null ? null : previousYear.getTotalPersonFlow(), EXCEL_ONE_DECIMAL_PERCENT), |
| | | ratioPhrase(current.getTotalPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getTotalPersonFlow(), EXCEL_ONE_DECIMAL_PERCENT)); |
| | | String paragraph2 = cumulativeParagraph(currentCumulative, previousYearCumulative, twoYearsAgoCumulative); |
| | | |
| | | File template = resolveTemplateFile(); |
| | | if (!template.exists() || !template.isFile()) { |
| | |
| | | try { |
| | | replaceParagraph(document, text -> text.startsWith("10月") && text.contains("假期第"), paragraph1); |
| | | replaceParagraph(document, text -> text.startsWith("假期以来"), paragraph2); |
| | | fillTable(document, current, previousDay, previousYear, currentCumulative, previousYearCumulative); |
| | | fillTable(document, current, previousDay, previousCalendarDay, previousYear, twoYearsAgo, |
| | | currentCumulative, previousYearCumulative, twoYearsAgoCumulative); |
| | | byte[] replacedXml = serializeDocument(document); |
| | | return replaceZipEntry(templateBytes, "word/document.xml", replacedXml); |
| | | } finally { |
| | |
| | | } |
| | | |
| | | private void fillTable(Document document, DailyMetrics current, DailyMetrics previousDay, |
| | | DailyMetrics previousYear, DailyMetrics currentCumulative, |
| | | DailyMetrics previousYearCumulative) { |
| | | DailyMetrics previousCalendarDay, DailyMetrics previousYear, DailyMetrics twoYearsAgo, |
| | | DailyMetrics currentCumulative, DailyMetrics previousYearCumulative, |
| | | DailyMetrics twoYearsAgoCumulative) { |
| | | DailyMetrics firstDayRailBase = previousDay == null ? previousCalendarDay : previousDay; |
| | | DailyMetrics firstDayCivilAviationBase = previousDay == null ? previousCalendarDay : previousDay; |
| | | Element table = firstElement(document, "tbl"); |
| | | if (table == null) { |
| | | throw new IllegalArgumentException("快报模板中找不到数据表"); |
| | | } |
| | | DailyMetrics previousYearCivilCumulative = comparableCumulative( |
| | | current, previousYear, DailyMetrics::getCivilAviation); |
| | | DailyMetrics twoYearsAgoCivilCumulative = comparableCumulative( |
| | | current, twoYearsAgo, DailyMetrics::getCivilAviation); |
| | | writeTableRow(table, 2, new String[]{ |
| | | number(current.getNonBusinessPersonFlow()), |
| | | ratio(current.getNonBusinessPersonFlow(), previousDay == null ? null : previousDay.getNonBusinessPersonFlow()), |
| | | ratio(current.getNonBusinessPersonFlow(), previousYear == null ? null : previousYear.getNonBusinessPersonFlow()), |
| | | "—", |
| | | number(currentCumulative.getNonBusinessPersonFlow()), |
| | | ratio(current.getNonBusinessPersonFlow(), previousDay == null ? null : previousDay.getNonBusinessPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT), |
| | | ratio(current.getNonBusinessPersonFlow(), previousYear == null ? null : previousYear.getNonBusinessPersonFlow(), |
| | | EXCEL_ONE_DECIMAL_PERCENT), |
| | | ratio(current.getNonBusinessPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getNonBusinessPersonFlow(), |
| | | EXCEL_ONE_DECIMAL_PERCENT), |
| | | numberCumulative(currentCumulative.getNonBusinessPersonFlow()), |
| | | ratio(currentCumulative.getNonBusinessPersonFlow(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getNonBusinessPersonFlow()), |
| | | "—" |
| | | previousYearCumulative == null ? null : previousYearCumulative.getNonBusinessPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT), |
| | | ratio(currentCumulative.getNonBusinessPersonFlow(), |
| | | twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getNonBusinessPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT) |
| | | }); |
| | | writeTableRow(table, 3, new String[]{ |
| | | number(current.getRoad()), |
| | | ratio(current.getRoad(), previousDay == null ? null : previousDay.getRoad()), |
| | | ratio(current.getRoad(), previousYear == null ? null : previousYear.getRoad()), |
| | | "—", |
| | | ratio(current.getRoad(), previousDay == null ? null : previousDay.getRoad(), EXCEL_ONE_DECIMAL_PERCENT), |
| | | ratio(current.getRoad(), previousYear == null ? null : previousYear.getRoad(), EXCEL_ONE_DECIMAL_PERCENT), |
| | | ratio(current.getRoad(), twoYearsAgo == null ? null : twoYearsAgo.getRoad(), EXCEL_TWO_DECIMAL_PERCENT), |
| | | number(currentCumulative.getRoad()), |
| | | ratio(currentCumulative.getRoad(), previousYearCumulative == null ? null : previousYearCumulative.getRoad()), |
| | | "—" |
| | | ratio(currentCumulative.getRoad(), previousYearCumulative == null ? null : previousYearCumulative.getRoad(), |
| | | EXCEL_ONE_DECIMAL_PERCENT), |
| | | ratio(currentCumulative.getRoad(), twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getRoad(), |
| | | EXCEL_ONE_DECIMAL_PERCENT) |
| | | }); |
| | | writeTableRow(table, 4, new String[]{ |
| | | number(current.getRoadPersonFlow()), |
| | | ratio(current.getRoadPersonFlow(), previousDay == null ? null : previousDay.getRoadPersonFlow()), |
| | | ratio(current.getRoadPersonFlow(), previousYear == null ? null : previousYear.getRoadPersonFlow()), |
| | | "—", |
| | | number(currentCumulative.getRoadPersonFlow()), |
| | | ratio(currentCumulative.getRoadPersonFlow(), previousYearCumulative == null ? null : previousYearCumulative.getRoadPersonFlow()), |
| | | "—" |
| | | ratio(current.getRoadPersonFlow(), previousDay == null ? null : previousDay.getRoadPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT), |
| | | ratio(current.getRoadPersonFlow(), previousYear == null ? null : previousYear.getRoadPersonFlow(), |
| | | EXCEL_ONE_DECIMAL_PERCENT), |
| | | ratio(current.getRoadPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getRoadPersonFlow(), |
| | | EXCEL_ONE_DECIMAL_PERCENT), |
| | | numberCumulative(currentCumulative.getRoadPersonFlow()), |
| | | ratio(currentCumulative.getRoadPersonFlow(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getRoadPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT), |
| | | ratio(currentCumulative.getRoadPersonFlow(), |
| | | twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getRoadPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT) |
| | | }); |
| | | writeTableRow(table, 5, transportRow(current.getRail(), previousDay == null ? null : previousDay.getRail(), |
| | | previousYear == null ? null : previousYear.getRail(), currentCumulative.getRail(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getRail())); |
| | | writeTableRow(table, 6, transportRow(current.getCivilAviation(), previousDay == null ? null : previousDay.getCivilAviation(), |
| | | previousYear == null ? null : previousYear.getCivilAviation(), currentCumulative.getCivilAviation(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getCivilAviation())); |
| | | writeTableRow(table, 7, transportRow(current.getWater(), previousDay == null ? null : previousDay.getWater(), |
| | | previousYear == null ? null : previousYear.getWater(), currentCumulative.getWater(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getWater())); |
| | | writeTableRow(table, 8, transportRow(current.getTotalPersonFlow(), previousDay == null ? null : previousDay.getTotalPersonFlow(), |
| | | previousYear == null ? null : previousYear.getTotalPersonFlow(), currentCumulative.getTotalPersonFlow(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getTotalPersonFlow())); |
| | | writeTableRow(table, 5, transportRow(current.getRail(), |
| | | firstDayRailBase == null ? null : firstDayRailBase.getRail(), |
| | | previousYear == null ? null : previousYear.getRail(), |
| | | twoYearsAgo == null ? null : twoYearsAgo.getRail(), |
| | | currentCumulative.getRail(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getRail(), |
| | | twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getRail(), |
| | | EXCEL_ONE_DECIMAL_PERCENT)); |
| | | writeTableRow(table, 6, transportRow(current.getCivilAviation(), |
| | | firstDayCivilAviationBase == null ? null : firstDayCivilAviationBase.getCivilAviation(), |
| | | previousYear == null ? null : previousYear.getCivilAviation(), |
| | | twoYearsAgo == null ? null : twoYearsAgo.getCivilAviation(), |
| | | currentCumulative.getCivilAviation(), |
| | | previousYearCivilCumulative == null ? null : previousYearCivilCumulative.getCivilAviation(), |
| | | twoYearsAgoCivilCumulative == null ? null : twoYearsAgoCivilCumulative.getCivilAviation(), |
| | | EXCEL_ONE_DECIMAL_PERCENT)); |
| | | writeTableRow(table, 7, transportRow(current.getWater(), |
| | | previousDay == null ? null : previousDay.getWater(), |
| | | previousYear == null ? null : previousYear.getWater(), |
| | | twoYearsAgo == null ? null : twoYearsAgo.getWater(), |
| | | currentCumulative.getWater(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getWater(), |
| | | twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getWater(), |
| | | EXCEL_TWO_DECIMAL_PERCENT)); |
| | | writeTableRow(table, 8, new String[]{ |
| | | number(current.getTotalPersonFlow()), |
| | | ratio(current.getTotalPersonFlow(), previousDay == null ? null : previousDay.getTotalPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT), |
| | | ratio(current.getTotalPersonFlow(), previousYear == null ? null : previousYear.getTotalPersonFlow(), |
| | | EXCEL_ONE_DECIMAL_PERCENT), |
| | | ratio(current.getTotalPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getTotalPersonFlow(), |
| | | EXCEL_ONE_DECIMAL_PERCENT), |
| | | numberCumulative(currentCumulative.getTotalPersonFlow()), |
| | | ratio(currentCumulative.getTotalPersonFlow(), |
| | | previousYearCumulative == null ? null : previousYearCumulative.getTotalPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT), |
| | | ratio(currentCumulative.getTotalPersonFlow(), |
| | | twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getTotalPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT) |
| | | }); |
| | | } |
| | | |
| | | private String[] transportRow(BigDecimal current, BigDecimal previousDay, BigDecimal previousYear, |
| | | BigDecimal currentCumulative, BigDecimal previousYearCumulative) { |
| | | BigDecimal twoYearsAgo, BigDecimal currentCumulative, |
| | | BigDecimal previousYearCumulative, BigDecimal twoYearsAgoCumulative, |
| | | int ringRatioExcelScale) { |
| | | return new String[]{ |
| | | number(current), |
| | | ratio(current, previousDay), |
| | | ratio(current, previousYear), |
| | | "—", |
| | | ratio(current, previousDay, ringRatioExcelScale), |
| | | ratio(current, previousYear, EXCEL_ONE_DECIMAL_PERCENT), |
| | | ratio(current, twoYearsAgo, EXCEL_ONE_DECIMAL_PERCENT), |
| | | number(currentCumulative), |
| | | ratio(currentCumulative, previousYearCumulative), |
| | | "—" |
| | | ratio(currentCumulative, previousYearCumulative, EXCEL_ONE_DECIMAL_PERCENT), |
| | | ratio(currentCumulative, twoYearsAgoCumulative, EXCEL_ONE_DECIMAL_PERCENT) |
| | | }; |
| | | } |
| | | |
| | |
| | | int logicalColumn = 0; |
| | | for (Element cell : cells) { |
| | | int span = gridSpan(cell); |
| | | if (logicalColumn >= 2 && logicalColumn < 9) { |
| | | if (logicalColumn >= 2) { |
| | | int valueIndex = logicalColumn - 2; |
| | | if (valueIndex < values.length) { |
| | | setCellText(cell, values[valueIndex]); |
| | |
| | | Element pPr = firstChildElement(templateParagraph, "pPr"); |
| | | if (pPr != null) paragraph.appendChild(pPr.cloneNode(true)); |
| | | } |
| | | Element templateRun = templateParagraph == null ? null : firstChildElement(templateParagraph, "r"); |
| | | Element rPr = templateRun == null ? null : firstChildElement(templateRun, "rPr"); |
| | | Element run = createElement("r"); |
| | | if (rPr != null) run.appendChild(rPr.cloneNode(true)); |
| | | Element t = createElement("t"); |
| | | t.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve"); |
| | | t.setTextContent(text == null ? "" : text); |
| | |
| | | return builder.toString(); |
| | | } |
| | | |
| | | private String ratioPhrase(BigDecimal current, BigDecimal base) { |
| | | if (current == null || base == null || base.abs().compareTo(EPSILON) < 0) return "无可比数据"; |
| | | BigDecimal ratio = HolidayNumberUtils.divide(current, base); |
| | | BigDecimal percent = HolidayNumberUtils.multiply(ratio.subtract(BigDecimal.ONE), BigDecimal.valueOf(100)); |
| | | if (percent == null || percent.abs().compareTo(EPSILON) < 0) return "持平"; |
| | | private String ratioPhrase(BigDecimal current, BigDecimal base, int excelPercentScale) { |
| | | BigDecimal percent = bulletinPercent(current, base, excelPercentScale); |
| | | if (percent == null) return "无可比数据"; |
| | | if (percent.signum() == 0) return "持平"; |
| | | return (percent.signum() > 0 ? "增长" : "下降") + HolidayNumberUtils.format1(percent.abs()) + "%"; |
| | | } |
| | | |
| | | private String ratio(BigDecimal current, BigDecimal base) { |
| | | if (current == null || base == null || base.abs().compareTo(EPSILON) < 0) return "—"; |
| | | return ratioPhrase(current, base); |
| | | private DailyMetrics comparableCumulative(DailyMetrics current, DailyMetrics comparisonYear, |
| | | Function<DailyMetrics, BigDecimal> selector) { |
| | | if (current == null || comparisonYear == null) return null; |
| | | int coveredDay = 0; |
| | | for (int day = current.getDayIndex(); day >= 1; day--) { |
| | | DailyMetrics metrics = statService.dailyMetrics(current.getYear(), current.getHolidayType(), day); |
| | | if (metrics != null && selector.apply(metrics) != null) { |
| | | coveredDay = day; |
| | | break; |
| | | } |
| | | } |
| | | if (coveredDay == 0) return null; |
| | | return statService.cumulativeMetrics(comparisonYear.getYear(), current.getHolidayType(), coveredDay); |
| | | } |
| | | |
| | | private String cumulativeParagraph(DailyMetrics currentCumulative, |
| | | DailyMetrics previousYearCumulative, |
| | | DailyMetrics twoYearsAgoCumulative) { |
| | | BigDecimal total = currentCumulative == null ? null : currentCumulative.getTotalPersonFlow(); |
| | | return String.format("假期以来,全省全社会跨区域人员流动量累计%s万人次,比2025年同期%s,比2024年同期%s。", |
| | | formatNumber(displayedCumulativeWan(total)), |
| | | ratioPhrase(total, previousYearCumulative == null ? null : previousYearCumulative.getTotalPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT), |
| | | ratioPhrase(total, twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getTotalPersonFlow(), |
| | | EXCEL_TWO_DECIMAL_PERCENT)); |
| | | } |
| | | |
| | | private String ratio(BigDecimal current, BigDecimal base, int excelPercentScale) { |
| | | BigDecimal percent = bulletinPercent(current, base, excelPercentScale); |
| | | if (percent == null) return "—"; |
| | | return percent.signum() == 0 ? "0%" : percent.toPlainString() + "%"; |
| | | } |
| | | |
| | | /** |
| | | * Mirrors the source Excel percentage cell format, then applies the bulletin's one-decimal rule. |
| | | * Excel stores full precision but displays 0.0% or 0.00%; reviewers compare against that display. |
| | | */ |
| | | private BigDecimal bulletinPercent(BigDecimal current, BigDecimal base, int excelPercentScale) { |
| | | if (current == null || base == null || base.abs().compareTo(EPSILON) < 0) return null; |
| | | BigDecimal ratio = HolidayNumberUtils.divide(current, base); |
| | | if (ratio == null) return null; |
| | | BigDecimal percent = HolidayNumberUtils.multiply(ratio.subtract(BigDecimal.ONE), BigDecimal.valueOf(100)); |
| | | if (percent == null) return null; |
| | | BigDecimal displayed = percent.setScale(excelPercentScale, RoundingMode.HALF_UP); |
| | | return displayed.setScale(1, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private String number(BigDecimal value) { |
| | | return value == null ? "—" : formatNumber(value); |
| | | } |
| | | |
| | | private String numberCumulative(BigDecimal value) { |
| | | return value == null ? "—" : formatNumber(displayedCumulativeWan(value)); |
| | | } |
| | | |
| | | /** |
| | | * Source cumulative cells U5/X5/AA5 are stored in 100-million units and displayed with seven decimals. |
| | | * Mirror that displayed precision before the bulletin converts the value to 10-thousand units. |
| | | */ |
| | | private BigDecimal displayedCumulativeWan(BigDecimal cumulativeWan) { |
| | | if (cumulativeWan == null) return null; |
| | | BigDecimal yi = cumulativeWan.divide(TEN_THOUSAND, EXCEL_SEVEN_DECIMAL_YI, RoundingMode.HALF_UP); |
| | | return HolidayNumberUtils.normalize(yi.multiply(TEN_THOUSAND)); |
| | | } |
| | | |
| | | private String formatNumber(BigDecimal value) { |
| | | if (value == null) return ""; |
| | | return HolidayNumberUtils.format2(value); |