xyc
1 天以前 bc822c6ca3e1ce3e16a38ba877449fc697be9511
fix(holiday): 折线图按标签精度绘制
3个文件已修改
56 ■■■■■ 已修改文件
HANDOFF.md 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayTrendChartService.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayTrendChartServiceTest.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HANDOFF.md
@@ -6,6 +6,13 @@
## 最新(2026-10-06)
### 10-06:折线图统一按显示标签精度绘制
- **口径(用户 2026-10-06 确认)**:同一张折线图中,同一个显示标签必须对应同一个点位高度;分析文字不得引用比该图显示精度更细的差异。
- **实现**:`HolidayTrendChartService.lineChart` 在所有原始统计计算完成后,于最终入图边界调用 `displayValue`;普通图按该图 `valueDecimals` 做 `HALF_UP` 舍入,百分比点标签按 1 位百分比精度(即原始小数 3 位)舍入。折线坐标和点标签共用同一舍入值,纵轴格式沿用该图精度。
- **边界**:只在最终图表显示层舍入,不改数据库、不改累计、快报、同比、环比或调整口径;该规则用于静态分析报告图,不能让文字引用图上无法分辨的微小差异。
- **验证**:`HolidayTrendChartServiceTest` 聚焦测试通过;后端全量 `mvn -q test -f traffic-audit-server\pom.xml` 通过。新增测试覆盖“两个不同原值按 2 位标签舍入后生成相同几何”和百分比精度换算。测试报告:`docs/功能测试报告/功能测试报告_折线图按标签精度绘制_2026-10-06.md`(本地留存,不入库)。
### 10-06:观测站平均拥挤度走势图改为 3 位小数
- **问题**:用户导入 10-05 观测站数据后反馈,最后一张拥挤度图中 10-04、10-05 标签都显示 `0.49`,但点位高度不同。
traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayTrendChartService.java
@@ -49,6 +49,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
@@ -76,6 +77,7 @@
    private static final double RIGHT_LABEL_BAND = 74.0;
    private static final double ITEM_LABEL_GAP = 10.0;
    private static final float HALO_OUTLINE_WIDTH = 4.0f;
    private static final int PERCENT_ITEM_LABEL_DECIMALS = 1;
    private static final Color ITEM_LABEL_COLOR = new Color(55, 55, 55);
    private static final Color[] SERIES_COLORS = {
            new Color(192, 80, 77),
@@ -107,7 +109,7 @@
            for (int i = 0; i < item.getValues().size(); i++) {
                BigDecimal value = item.getValues().get(i);
                if (value != null) {
                    xySeries.add(i, value.doubleValue());
                    xySeries.add(i, displayValue(value, percentAxis, valueDecimals).doubleValue());
                }
            }
            dataset.addSeries(xySeries);
@@ -1113,10 +1115,16 @@
        return total;
    }
    static BigDecimal displayValue(BigDecimal value, boolean percentItemLabels, int valueDecimals) {
        if (value == null) return null;
        int scale = percentItemLabels ? PERCENT_ITEM_LABEL_DECIMALS + 2 : valueDecimals;
        return value.setScale(scale, RoundingMode.HALF_UP);
    }
    private String formatLineLabel(Number value, boolean percentItemLabels, int valueDecimals) {
        if (percentItemLabels) {
            NumberFormat formatter = NumberFormat.getPercentInstance();
            formatter.setMaximumFractionDigits(1);
            formatter.setMaximumFractionDigits(PERCENT_ITEM_LABEL_DECIMALS);
            return formatter.format(value.doubleValue());
        }
        DecimalFormat formatter = new DecimalFormat("#,##0");
traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayTrendChartServiceTest.java
@@ -5,7 +5,10 @@
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -42,6 +45,40 @@
    }
    @Test
    void roundsLineDataToTheSamePrecisionAsLabels() {
        assertEquals(new BigDecimal("0.49"),
                HolidayTrendChartService.displayValue(new BigDecimal("0.4904"), false, 2));
        assertEquals(new BigDecimal("0.49"),
                HolidayTrendChartService.displayValue(new BigDecimal("0.4911"), false, 2));
        assertEquals(new BigDecimal("0.491"),
                HolidayTrendChartService.displayValue(new BigDecimal("0.4911"), false, 3));
        assertEquals(new BigDecimal("0.123"),
                HolidayTrendChartService.displayValue(new BigDecimal("0.1234"), true, 2));
    }
    @Test
    void rendersSameGeometryWhenValuesRoundToSameLabel() {
        HolidayTrendChartService service = new HolidayTrendChartService();
        HolidayTrendChartService.ChartSeries first = new HolidayTrendChartService.ChartSeries();
        first.setName("平均拥挤度");
        first.setValues(java.util.Arrays.asList(
                new BigDecimal("0.4904"), new BigDecimal("0.4923"), new BigDecimal("0.5100")));
        HolidayTrendChartService.ChartSeries second = new HolidayTrendChartService.ChartSeries();
        second.setName("平均拥挤度");
        second.setValues(java.util.Arrays.asList(
                new BigDecimal("0.4911"), new BigDecimal("0.4934"), new BigDecimal("0.5100")));
        byte[] firstChart = service.lineChart("拥挤度",
                java.util.Collections.singletonList(first), false, 2, 1100, 590);
        byte[] secondChart = service.lineChart("拥挤度",
                java.util.Collections.singletonList(second), false, 2, 1100, 590);
        assertPng(firstChart);
        assertPng(secondChart);
        assertArrayEquals(firstChart, secondChart);
    }
    @Test
    void rendersHigherPrecisionLineLabelsWhenRequested() {
        HolidayTrendChartService service = new HolidayTrendChartService();
        HolidayTrendChartService.ChartSeries congestion = new HolidayTrendChartService.ChartSeries();