fix(holiday): 观测站速度/拥挤度走势图横轴改用系统配置假期天数
| | |
| | | > **每天结束时**:把当天进展、踩过的坑、新需求、未完成事项更新到本文件,然后可以放心开新对话。 |
| | | > **协作约定(2026-08-31)**:说「提交」= 本地 commit + 推送到远端 git(origin main,Gitblit),不再只做本地 commit。 |
| | | |
| | | ## 最新(2026-10-08 上班前关机快照) |
| | | ## 最新(2026-10-08 走势图附录二观测站图天数修正) |
| | | |
| | | ### 10-08:观测站速度/拥挤度走势图改用系统配置假期天数(已修,待验收) |
| | | |
| | | - **需求(用户)**:走势图最后两张图“普通国省道观测站平均机动车速度”“…平均拥挤度”只含今年数据,横轴天数不应是固定 8 天,而应为系统配置的假期天数。 |
| | | - **改动**:`HolidayTrendChartService.lineChart` 新增可传 `dayLabels` 的重载(默认仍为 `DAY_LABELS` 8 天,其余 13 张图零改动);`HolidayTrendService.observationData` 改为按 `configService.findHolidayDays(year, holidayType)`(`day_index>=1`)的天数与日期生成数据点和横轴标签,最后两张图传入该标签。 |
| | | - **配置依据**:`holiday_calendar` 2026 十一 `day_index 1..7`(7 天,`day_index 0` = 09-30 环比基期);2025 = 8 天、2024 = 7 天。 |
| | | - **验证**:`mvn -o test` 16/16 通过(新增自定义横轴标签单元测试);真实云只读生成走势图,与用户已下载版逐图对比:image1~13 的 SHA-256 完全一致,仅 image14(速度)、image15(拥挤度)变化;OCR 确认新图横轴为 10月1日~10月7日、无 10月8日。 |
| | | - **边界**:其余图仍固定 8 天口径,未改;未导入/覆盖/重导任何业务数据。 |
| | | - **重启**:为让按钮下载用上新代码,已用 `start-dev.ps1` 重启后端(前端未动),重启时间 2026-10-08 10:38:53;可直接在系统里重新下载走势图验收。 |
| | | |
| | | ## 历史(2026-10-08 上班前关机快照) |
| | | |
| | | ### 10-08:走势图 `(14)` 与已验收 `(12)` 比对(内容一致) |
| | | |
| | |
| | | |
| | | public byte[] lineChart(String yAxisLabel, List<ChartSeries> series, boolean percentAxis, |
| | | int valueDecimals, int width, int height) { |
| | | return lineChart(yAxisLabel, series, percentAxis, valueDecimals, DAY_LABELS, width, height); |
| | | } |
| | | |
| | | public byte[] lineChart(String yAxisLabel, List<ChartSeries> series, boolean percentAxis, |
| | | int valueDecimals, List<String> dayLabels, int width, int height) { |
| | | List<String> axisLabels = (dayLabels == null || dayLabels.isEmpty()) ? DAY_LABELS : dayLabels; |
| | | XYSeriesCollection dataset = new XYSeriesCollection(); |
| | | for (int seriesIndex = 0; seriesIndex < series.size(); seriesIndex++) { |
| | | ChartSeries item = series.get(seriesIndex); |
| | |
| | | plot.setRangeGridlinesVisible(false); |
| | | plot.setDomainTickBandPaint(null); |
| | | plot.setRangeTickBandPaint(null); |
| | | SymbolAxis domainAxis = new SymbolAxis(null, DAY_LABELS.toArray(new String[0])); |
| | | SymbolAxis domainAxis = new SymbolAxis(null, axisLabels.toArray(new String[0])); |
| | | domainAxis.setGridBandPaint(new Color(0, 0, 0, 0)); |
| | | domainAxis.setGridBandAlternatePaint(new Color(0, 0, 0, 0)); |
| | | domainAxis.setLowerMargin(0.04); |
| | |
| | | import java.io.InputStream; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | |
| | | blocks.add(new HolidayTrendWordService.ChartBlock( |
| | | prefix + "普通国省道观测站平均机动车速度", |
| | | chartService.lineChart("公里/小时", |
| | | Collections.singletonList(series("平均速度", observation.speed)), false, 1100, 590), |
| | | Collections.singletonList(series("平均速度", observation.speed)), false, 2, |
| | | observation.labels, 1100, 590), |
| | | lineImageSize(5268595L, 2821305L))); |
| | | blocks.add(new HolidayTrendWordService.ChartBlock( |
| | | prefix + "普通国省道观测站平均拥挤度", |
| | | chartService.lineChart("拥挤度", |
| | | Collections.singletonList(series("平均拥挤度", observation.congestion)), false, 1100, 590), |
| | | Collections.singletonList(series("平均拥挤度", observation.congestion)), false, 2, |
| | | observation.labels, 1100, 590), |
| | | lineImageSize(5268595L, 2821305L))); |
| | | |
| | | File template = resolveTemplateFile(); |
| | |
| | | private ObservationData observationData(int year, String holidayType) { |
| | | List<HolidayCalendar> days = configService.findHolidayDays(year, holidayType); |
| | | if (days.isEmpty()) { |
| | | return new ObservationData(nulls(), nulls()); |
| | | return new ObservationData(nulls(), nulls(), HolidayTrendChartService.DAY_LABELS); |
| | | } |
| | | LocalDate start = days.get(0).getHolidayDate(); |
| | | LocalDate end = start.plusDays(HolidayTrendChartService.DAY_LABELS.size() - 1L); |
| | | LocalDate end = days.get(days.size() - 1).getHolidayDate(); |
| | | List<ObservationDailyOperation> rows = observationStationFlowMapper.selectDailyOperations(start, end); |
| | | Map<LocalDate, ObservationDailyOperation> byDate = new LinkedHashMap<>(); |
| | | for (ObservationDailyOperation row : rows) { |
| | | byDate.put(row.getObsDate(), row); |
| | | } |
| | | DateTimeFormatter labelFormat = DateTimeFormatter.ofPattern("M月d日"); |
| | | List<BigDecimal> speed = new ArrayList<>(); |
| | | List<BigDecimal> congestion = new ArrayList<>(); |
| | | for (int i = 0; i < HolidayTrendChartService.DAY_LABELS.size(); i++) { |
| | | ObservationDailyOperation row = byDate.get(start.plusDays(i)); |
| | | List<String> labels = new ArrayList<>(); |
| | | for (HolidayCalendar day : days) { |
| | | LocalDate date = day.getHolidayDate(); |
| | | ObservationDailyOperation row = byDate.get(date); |
| | | speed.add(row == null ? null : row.getAverageSpeed()); |
| | | congestion.add(row == null ? null : row.getAverageCongestion()); |
| | | labels.add(date.format(labelFormat)); |
| | | } |
| | | return new ObservationData(speed, congestion); |
| | | return new ObservationData(speed, congestion, labels); |
| | | } |
| | | |
| | | private HolidayTrendChartService.ChartSeries series(String name, List<BigDecimal> values) { |
| | |
| | | private static class ObservationData { |
| | | private final List<BigDecimal> speed; |
| | | private final List<BigDecimal> congestion; |
| | | private final List<String> labels; |
| | | |
| | | private ObservationData(List<BigDecimal> speed, List<BigDecimal> congestion) { |
| | | private ObservationData(List<BigDecimal> speed, List<BigDecimal> congestion, List<String> labels) { |
| | | this.speed = speed; |
| | | this.congestion = congestion; |
| | | this.labels = labels; |
| | | } |
| | | } |
| | | } |
| | |
| | | assertFalse(java.util.Arrays.equals(twoDecimals, threeDecimals)); |
| | | } |
| | | |
| | | @Test |
| | | void rendersLineChartWithConfiguredDayLabels() { |
| | | HolidayTrendChartService service = new HolidayTrendChartService(); |
| | | HolidayTrendChartService.ChartSeries congestion = new HolidayTrendChartService.ChartSeries(); |
| | | congestion.setName("\u5e73\u5747\u62e5\u6324\u5ea6"); |
| | | congestion.setValues(java.util.Arrays.asList( |
| | | new BigDecimal("0.50"), new BigDecimal("0.48"), new BigDecimal("0.47"), |
| | | new BigDecimal("0.49"), new BigDecimal("0.49"), new BigDecimal("0.49"), |
| | | new BigDecimal("0.47"))); |
| | | java.util.List<String> sevenDays = java.util.Arrays.asList( |
| | | "10\u67081\u65e5", "10\u67082\u65e5", "10\u67083\u65e5", "10\u67084\u65e5", |
| | | "10\u67085\u65e5", "10\u67086\u65e5", "10\u67087\u65e5"); |
| | | |
| | | byte[] custom = service.lineChart("\u62e5\u6324\u5ea6", |
| | | java.util.Collections.singletonList(congestion), false, 2, sevenDays, 1100, 590); |
| | | byte[] defaults = service.lineChart("\u62e5\u6324\u5ea6", |
| | | java.util.Collections.singletonList(congestion), false, 2, 1100, 590); |
| | | |
| | | assertPng(custom); |
| | | assertPng(defaults); |
| | | assertFalse(java.util.Arrays.equals(custom, defaults), |
| | | "custom day labels should change the rendered axis"); |
| | | } |
| | | |
| | | private void assertNoLargeLightGrayBackground(byte[] data) throws Exception { |
| | | BufferedImage image = ImageIO.read(new ByteArrayInputStream(data)); |
| | | int matches = 0; |