fix: 增加小时和日表导出

This commit is contained in:
tangwei 2026-08-06 18:32:23 +08:00
parent f2564ceca9
commit 29105cf1f5

View File

@ -169,6 +169,12 @@ public class QgcExportServiceImpl implements IQgcExportService {
public void exportData(List<String> dataFields, List<String> months,
List<String> stationCodes, boolean isDailyDimension,
String tmDimension, HttpServletResponse response) {
// hour/day 模式仅导出原始数据不做聚合处理
if ("hour".equals(tmDimension) || "day".equals(tmDimension)) {
exportRawData(dataFields, months, stationCodes, tmDimension, response);
return;
}
// 1. 指标处理器匹配
List<ExportIndicatorProcessor> processors = resolveProcessors(dataFields);
if (processors.isEmpty()) {
@ -1331,4 +1337,195 @@ public class QgcExportServiceImpl implements IQgcExportService {
/** 小时达标率(百分比,仅水质指标使用) */
private BigDecimal complianceRate;
}
// ======================== hour/day 原始数据导出 ========================
/**
* hour/day 模式仅导出原始数据不做汇总/达标率等聚合处理
*/
private void exportRawData(List<String> dataFields, List<String> months,
List<String> stationCodes, String tmDimension,
HttpServletResponse response) {
if (months.isEmpty()) {
log.warn("hour/day 模式需要传入时间范围参数");
return;
}
boolean isDaily = "day".equals(tmDimension);
// 解析月份字段 "2026-05" 当月起止时间
String monthStr = months.get(0);
String startTime, endTime;
if (monthStr.matches("\\d{4}-\\d{2}")) {
// 月份格式YYYY-MM 当月1日 ~ 下月1日
startTime = monthStr + "-01 00:00:00";
// 计算下月
int year = Integer.parseInt(monthStr.substring(0, 4));
int month = Integer.parseInt(monthStr.substring(5, 7));
if (month == 12) {
endTime = (year + 1) + "-01-01 00:00:00";
} else {
endTime = year + "-" + String.format("%02d", month + 1) + "-01 00:00:00";
}
} else {
startTime = monthStr;
endTime = months.size() >= 2 ? months.get(1) : monthStr;
if (!startTime.contains(":")) startTime += " 00:00:00";
if (!endTime.contains(":")) endTime += " 23:59:59";
}
// 1. 指标处理器去掉日变幅 processor
List<ExportIndicatorProcessor> processors = resolveProcessors(dataFields).stream()
.filter(p -> !p.isVariation())
.toList();
if (processors.isEmpty()) {
log.warn("未找到匹配的指标处理器");
return;
}
// 2. 电站映射
Set<String> sttpTypes = processors.stream()
.map(ExportIndicatorProcessor::getSttpType)
.collect(Collectors.toCollection(LinkedHashSet::new));
StationResolution stationRes = resolveStations(stationCodes, sttpTypes);
if (stationRes.displayNames.isEmpty()) return;
List<String> stationOrder = new ArrayList<>(stationRes.displayNames.keySet());
// 3. 文件名
String timestamp = String.valueOf(System.currentTimeMillis());
String excelFileName = monthStr + (isDaily ? "日数据_" : "小时数据_") + timestamp;
String zipFileName = getFileNamePrefix(tmDimension) + ".zip";
// 4. 构建 Sheet
List<ExportZipUtil.SheetData> sheets = new ArrayList<>();
for (ExportIndicatorProcessor processor : processors) {
String sttp = processor.getSttpType();
List<String> stcds = new ArrayList<>();
Map<String, String> stcdDisplayMap = new LinkedHashMap<>();
for (String rstcd : stationOrder) {
String stcd = stationRes.getStcd(rstcd, sttp);
if (stcd != null) {
stcds.add(stcd);
String name = stationRes.getDisplayName(rstcd, sttp);
stcdDisplayMap.put(stcd, StrUtil.isNotBlank(name) ? name : stcd);
}
}
if (stcds.isEmpty()) continue;
List<List<Object>> rows;
List<String> headers;
if (processor instanceof RwtProcessor) {
rows = buildRwtRawSheetRows(stcds, stcdDisplayMap, startTime, endTime);
headers = Arrays.asList("测站", "时间", "水深(m)", "水温(℃)");
} else {
rows = buildRawSheetRows(processor, stcds, stcdDisplayMap, startTime, endTime, isDaily);
if (rows == null) continue;
// 表头时间 | 测站1 | 测站2 | ...
headers = new ArrayList<>();
headers.add("时间");
for (String stcd : stcds) {
headers.add(stcdDisplayMap.getOrDefault(stcd, stcd));
}
}
ExportZipUtil.SheetData sd = new ExportZipUtil.SheetData(processor.getSheetName(), headers, rows);
sheets.add(sd);
}
if (sheets.isEmpty()) {
log.warn("hour/day 模式:没有可用数据");
return;
}
// 5. ZIP 导出
try {
ExportZipUtil.exportToResponse(response, zipFileName,
Collections.singletonList(new ExportZipUtil.ExcelData(excelFileName, sheets)));
} catch (Exception e) {
log.error("hour/day 导出失败", e);
}
}
/**
* 构建标准格式原始数据行 RWT
* 每行 = 一个时间点 = 各测站的原始值
*/
private List<List<Object>> buildRawSheetRows(ExportIndicatorProcessor processor,
List<String> stcds,
Map<String, String> stcdDisplayMap,
String startTime, String endTime,
boolean isDaily) {
try {
Date start = SDF.parse(startTime);
Date end = SDF.parse(endTime);
List<IndicatorDataRow> rawData = processor.queryRawData(stcds, start, end, isDaily);
if (rawData == null || rawData.isEmpty()) return null;
// 按时间分组timeKey (stcd value)
Map<String, Map<String, BigDecimal>> timeMap = new LinkedHashMap<>();
SimpleDateFormat timeFmt = new SimpleDateFormat(isDaily ? "yyyy-MM-dd" : "yyyy-MM-dd HH:mm:ss");
for (IndicatorDataRow row : rawData) {
String timeKey = timeFmt.format(row.getTm());
timeMap.computeIfAbsent(timeKey, k -> new LinkedHashMap<>())
.put(row.getStcd(), row.getValue());
}
// 构建行数据按时间排序避免 LinkedHashMap 插入顺序导致乱序
List<List<Object>> rows = new ArrayList<>();
List<String> sortedTimes = new ArrayList<>(timeMap.keySet());
Collections.sort(sortedTimes);
for (String timeKey : sortedTimes) {
List<Object> row = new ArrayList<>();
row.add(timeKey);
Map<String, BigDecimal> stcdValMap = timeMap.get(timeKey);
for (String stcd : stcds) {
BigDecimal val = stcdValMap.get(stcd);
row.add(val != null ? formatTemp(val) : "");
}
rows.add(row);
}
return rows;
} catch (Exception e) {
log.error("构建原始数据 Sheet 失败: {}", processor.getFieldName(), e);
return null;
}
}
/**
* 构建 RWT 垂向水温原始数据行
* 格式测站 | 时间 | 水深(m) | 水温()
*/
private List<List<Object>> buildRwtRawSheetRows(List<String> stcds,
Map<String, String> stcdDisplayMap,
String startTime, String endTime) {
try {
List<Map<String, Object>> rawList = sdWtvtdaySMapper.selectDailyData(stcds, startTime, endTime);
if (rawList == null || rawList.isEmpty()) return null;
SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd");
List<List<Object>> rows = new ArrayList<>();
for (Map<String, Object> map : rawList) {
String stcd = (String) map.get("STCD");
Object wthgObj = map.get("WTHG");
Object vwtObj = map.get("VWT");
Object dayNumObj = map.get("DAY_NUM");
if (stcd == null || vwtObj == null) continue;
String displayName = stcdDisplayMap.getOrDefault(stcd, stcd);
String depth = wthgObj != null ? formatNumberCell(formatNumber(wthgObj)) : "";
BigDecimal vwt = toBigDecimal(vwtObj);
List<Object> row = new ArrayList<>();
row.add(displayName);
row.add(dayNumObj != null ? "" + dayNumObj + "" : "");
row.add(depth);
row.add(formatTemp(vwt));
rows.add(row);
}
return rows;
} catch (Exception e) {
log.error("构建 RWT 原始数据失败", e);
return null;
}
}
}