fix: 增加垂向水温导出sheet功能
This commit is contained in:
parent
97982109ff
commit
f2564ceca9
@ -7,6 +7,7 @@ import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 垂向水温年份数据Mapper
|
||||
@ -28,4 +29,20 @@ public interface SdWtvtRMapper extends BaseMapper<SdWtvtYearVo> {
|
||||
"ORDER BY STCD, TO_CHAR(TM, 'yyyy') DESC" +
|
||||
"</script>")
|
||||
List<SdWtvtYearVo> getWtrvDefaultYear(@Param("stcd") String stcd);
|
||||
|
||||
/**
|
||||
* 查询各测站水深对应的高程(HGT),按 STCD、WTHG 分组取最大值
|
||||
*/
|
||||
@Select("<script>" +
|
||||
"SELECT STCD, WTHG, MAX(HGT) AS HGT " +
|
||||
"FROM SD_WTVT_R " +
|
||||
"WHERE IS_DELETED = 0 " +
|
||||
"AND HGT IS NOT NULL " +
|
||||
"AND STCD IN " +
|
||||
"<foreach collection='stcdList' item='stcd' open='(' separator=',' close=')'>" +
|
||||
"#{stcd}" +
|
||||
"</foreach>" +
|
||||
"GROUP BY STCD, WTHG" +
|
||||
"</script>")
|
||||
List<Map<String, Object>> selectDepthElevation(@Param("stcdList") List<String> stcdList);
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package com.yfd.platform.qgc_export.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* SD_WTVTDAY_S 垂向水温日统计表
|
||||
*/
|
||||
@Data
|
||||
@TableName("SD_WTVTDAY_S")
|
||||
public class SdWtvtdayS implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
private String stcd;
|
||||
private Date dt;
|
||||
private BigDecimal wthg; // 水深
|
||||
private BigDecimal vwt; // 水温
|
||||
private String recordUser;
|
||||
private Date recordTime;
|
||||
private Date modifyTime;
|
||||
private Integer isDeleted;
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.yfd.platform.qgc_export.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.yfd.platform.qgc_export.domain.SdWtvtdayS;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SD_WTVTDAY_S 垂向水温日数据 Mapper
|
||||
*/
|
||||
public interface SdWtvtdaySMapper extends BaseMapper<SdWtvtdayS> {
|
||||
|
||||
/**
|
||||
* 查询月内每日垂向水温数据(含 EXTRACT(DAY FROM DT)),用于按指定日期筛选
|
||||
*/
|
||||
List<Map<String, Object>> selectDailyData(@Param("stcdList") List<String> stcdList,
|
||||
@Param("startTime") String startTime,
|
||||
@Param("endTime") String endTime);
|
||||
|
||||
/**
|
||||
* 查询月均垂向水温,按 STCD、WTHG 分组
|
||||
*/
|
||||
List<Map<String, Object>> selectMonthlyAvg(@Param("stcdList") List<String> stcdList,
|
||||
@Param("startTime") String startTime,
|
||||
@Param("endTime") String endTime);
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.yfd.platform.qgc_export.processor;
|
||||
|
||||
import com.yfd.platform.qgc_env.wt.mapper.SdWtvtRMapper;
|
||||
import com.yfd.platform.qgc_export.mapper.SdWtvtdaySMapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 垂向水温(RWT) 处理器 — 双表头格式,按水深分层展示
|
||||
* <p>
|
||||
* STTP: WTVT, 使用 SD_WTVT_R / SD_WTVTDAY_S 表
|
||||
*/
|
||||
@Component
|
||||
public class RwtProcessor implements ExportIndicatorProcessor {
|
||||
|
||||
private SdWtvtRMapper sdWtvtRMapper;
|
||||
private SdWtvtdaySMapper sdWtvtdaySMapper;
|
||||
|
||||
public void setMappers(SdWtvtRMapper rMapper, SdWtvtdaySMapper sMapper) {
|
||||
this.sdWtvtRMapper = rMapper;
|
||||
this.sdWtvtdaySMapper = sMapper;
|
||||
}
|
||||
|
||||
public SdWtvtRMapper getSdWtvtRMapper() { return sdWtvtRMapper; }
|
||||
public SdWtvtdaySMapper getSdWtvtdaySMapper() { return sdWtvtdaySMapper; }
|
||||
|
||||
@Override
|
||||
public String getFieldName() {
|
||||
return "rwt";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSheetName() {
|
||||
return "垂向水温";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSttpType() {
|
||||
return "WTVT";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDecimalPlaces() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 11;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IndicatorDataRow> queryRawData(List<String> stcds, Date startTime, Date endTime, boolean isDaily) {
|
||||
// RWT 使用自定义 Sheet 构建,不走标准数据查询流程
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,9 @@ import com.yfd.platform.qgc_export.mapper.SdHydropwdaySMapper;
|
||||
import com.yfd.platform.qgc_export.mapper.SdQecRMapper;
|
||||
import com.yfd.platform.qgc_export.mapper.SdQecdaySMapper;
|
||||
import com.yfd.platform.qgc_export.mapper.StationMappingMapper;
|
||||
import com.yfd.platform.qgc_export.mapper.MsAlongdetBMapper;
|
||||
import com.yfd.platform.qgc_env.wt.mapper.SdWtvtRMapper;
|
||||
import com.yfd.platform.qgc_export.mapper.SdWtvtdaySMapper;
|
||||
import com.yfd.platform.qgc_export.processor.*;
|
||||
import com.yfd.platform.qgc_export.service.IQgcExportService;
|
||||
import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqRuleVo;
|
||||
@ -142,6 +145,17 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
||||
@Resource
|
||||
private EngEqDataService engEqDataService;
|
||||
|
||||
@Resource
|
||||
private MsAlongdetBMapper msAlongdetBMapper;
|
||||
|
||||
@Resource
|
||||
private SdWtvtRMapper sdWtvtRMapper;
|
||||
@Resource
|
||||
private SdWtvtdaySMapper sdWtvtdaySMapper;
|
||||
|
||||
@Resource
|
||||
private RwtProcessor rwtProcessor;
|
||||
|
||||
private static final SimpleDateFormat SDF_TIME = new SimpleDateFormat("dd日 HH时");
|
||||
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@ -192,6 +206,8 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
||||
// QEC 自定义三栏达标率格式
|
||||
if (processor instanceof QecProcessor) {
|
||||
rows = buildQecSheetRows(mr, stationOrder, stationRes);
|
||||
} else if (processor instanceof RwtProcessor) {
|
||||
rows = buildRwtSheetRows(mr, stationOrder, stationRes);
|
||||
} else {
|
||||
rows = buildSheetRows(processor, mr, stationOrder, stationRes);
|
||||
}
|
||||
@ -206,6 +222,15 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
||||
headers.add(title);
|
||||
for (int i = 1; i < 6; i++) headers.add("");
|
||||
}
|
||||
} else if (processor instanceof RwtProcessor) {
|
||||
// 垂向水温双表头:测站名称 | 水深 | 5日 | | 15日 | | 25日 | | 月均 |
|
||||
headers = new ArrayList<>();
|
||||
headers.add("测站名称");
|
||||
headers.add("水深(m)");
|
||||
headers.add("5日"); headers.add("");
|
||||
headers.add("15日"); headers.add("");
|
||||
headers.add("25日"); headers.add("");
|
||||
headers.add("月均"); headers.add("");
|
||||
} else {
|
||||
// 仅包含当前处理器 STTP 类型有对应测站的电站
|
||||
headers = new ArrayList<>();
|
||||
@ -228,6 +253,31 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
||||
new int[]{0, 0, 6, 11}, // 水利部
|
||||
new int[]{0, 0, 12, 17} // 多年平均
|
||||
));
|
||||
} else if (processor instanceof RwtProcessor) {
|
||||
// 垂向水温双表头合并单元格
|
||||
sd.setHeaderRowCount(1);
|
||||
List<int[]> regions = new ArrayList<>(Arrays.asList(
|
||||
new int[]{0, 1, 0, 0}, // 测站名称 header
|
||||
new int[]{0, 1, 1, 1}, // 水深(m) header
|
||||
new int[]{0, 0, 2, 3}, // 5日
|
||||
new int[]{0, 0, 4, 5}, // 15日
|
||||
new int[]{0, 0, 6, 7}, // 25日
|
||||
new int[]{0, 0, 8, 9} // 月均
|
||||
));
|
||||
// 数据行测站名称相同合并(rows[0] 是子标题行,数据从 rows[1] 开始,sheet 行号 = 2 + i)
|
||||
int dataStartRow = 2; // headers(1) + subheader(1)
|
||||
for (int i = 1; i < rows.size(); ) {
|
||||
String name = rows.get(i).get(0).toString();
|
||||
int j = i + 1;
|
||||
while (j < rows.size() && name.equals(rows.get(j).get(0).toString())) {
|
||||
j++;
|
||||
}
|
||||
if (j - i > 1) {
|
||||
regions.add(new int[]{dataStartRow + i - 1, dataStartRow + j - 2, 0, 0});
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
sd.setMergedRegions(regions);
|
||||
}
|
||||
sheets.add(sd);
|
||||
if ("WQ".equals(sttp)) {
|
||||
@ -494,6 +544,179 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
||||
* <p>
|
||||
* 返回的 rows[0] 是子标题行(|达标数|总数|达标率(%)|达标数|总数|达标率(%)|),后续为电站数据行。
|
||||
*/
|
||||
|
||||
// ======================== RWT 垂向水温 ========================
|
||||
|
||||
/**
|
||||
* 构建垂向水温(RWT) Sheet 数据 — 双表头格式,按测站和水深分层
|
||||
*/
|
||||
private List<List<Object>> buildRwtSheetRows(MonthRange mr, List<String> stationOrder,
|
||||
StationResolution stationRes) {
|
||||
List<String> stcdList = new ArrayList<>();
|
||||
// WTVT 测站→显示名 映射
|
||||
Map<String, String> stcdDisplayMap = new LinkedHashMap<>();
|
||||
for (String rstcd : stationOrder) {
|
||||
String stcd = stationRes.getStcd(rstcd, "WTVT");
|
||||
if (stcd != null) {
|
||||
stcdList.add(stcd);
|
||||
String displayName = stationRes.getDisplayName(rstcd, "WTVT");
|
||||
stcdDisplayMap.put(stcd, StrUtil.isNotBlank(displayName) ? displayName : stcd);
|
||||
}
|
||||
}
|
||||
if (stcdList.isEmpty()) return null;
|
||||
|
||||
String startStr = SDF.format(mr.getStart());
|
||||
String endStr = SDF.format(mr.getEnd());
|
||||
|
||||
// 1. 查询日数据(含 EXTRACT(DAY FROM DT))
|
||||
List<Map<String, Object>> dailyData = sdWtvtdaySMapper.selectDailyData(stcdList, startStr, endStr);
|
||||
// 2. 查询月均
|
||||
List<Map<String, Object>> monthlyData = sdWtvtdaySMapper.selectMonthlyAvg(stcdList, startStr, endStr);
|
||||
// 3. 查询高程
|
||||
List<Map<String, Object>> elevationData = sdWtvtRMapper.selectDepthElevation(stcdList);
|
||||
|
||||
// 按 (STCD, WTHG) 构建日水温索引
|
||||
Map<String, Map<String, BigDecimal>> dayVwtMap = new LinkedHashMap<>();
|
||||
Map<String, BigDecimal> wthgOrderKey = new LinkedHashMap<>();
|
||||
for (Map<String, Object> row : dailyData) {
|
||||
String stcd = (String) row.get("STCD");
|
||||
Object wthgObj = row.get("WTHG");
|
||||
Object vwtObj = row.get("VWT");
|
||||
Object dayNumObj = row.get("DAY_NUM");
|
||||
if (stcd == null || wthgObj == null || vwtObj == null || dayNumObj == null) continue;
|
||||
|
||||
String wthg = formatNumber(wthgObj);
|
||||
int dayNum = ((Number) dayNumObj).intValue();
|
||||
BigDecimal vwt = toBigDecimal(vwtObj);
|
||||
|
||||
String key = stcd + "|" + wthg;
|
||||
dayVwtMap.computeIfAbsent(key, k -> new LinkedHashMap<>())
|
||||
.putIfAbsent(String.valueOf(dayNum), vwt);
|
||||
wthgOrderKey.putIfAbsent(wthg, toBigDecimal(wthgObj));
|
||||
}
|
||||
|
||||
// 月均索引
|
||||
Map<String, BigDecimal> monthlyAvgMap = new LinkedHashMap<>();
|
||||
for (Map<String, Object> row : monthlyData) {
|
||||
String stcd = (String) row.get("STCD");
|
||||
Object wthgObj = row.get("WTHG");
|
||||
Object vwtObj = row.get("VWT");
|
||||
if (stcd == null || wthgObj == null || vwtObj == null) continue;
|
||||
|
||||
String wthg = formatNumber(wthgObj);
|
||||
String key = stcd + "|" + wthg;
|
||||
monthlyAvgMap.put(key, toBigDecimal(vwtObj));
|
||||
wthgOrderKey.putIfAbsent(wthg, toBigDecimal(wthgObj));
|
||||
}
|
||||
|
||||
// 高程索引
|
||||
Map<String, BigDecimal> elevationMap = new LinkedHashMap<>();
|
||||
for (Map<String, Object> row : elevationData) {
|
||||
String stcd = (String) row.get("STCD");
|
||||
Object wthgObj = row.get("WTHG");
|
||||
Object hgtObj = row.get("HGT");
|
||||
if (stcd == null || wthgObj == null || hgtObj == null) continue;
|
||||
|
||||
String wthg = formatNumber(wthgObj);
|
||||
elevationMap.put(stcd + "|" + wthg, toBigDecimal(hgtObj));
|
||||
}
|
||||
|
||||
// 收集所有 (STCD, WTHG) 组合,按测站顺序和 WTHG 升序排列
|
||||
Set<String> allKeys = new LinkedHashSet<>();
|
||||
allKeys.addAll(dayVwtMap.keySet());
|
||||
allKeys.addAll(monthlyAvgMap.keySet());
|
||||
|
||||
List<String> sortedKeys = new ArrayList<>();
|
||||
for (String stcd : stcdList) {
|
||||
String prefix = stcd + "|";
|
||||
List<String> stcdKeys = new ArrayList<>();
|
||||
for (String key : allKeys) {
|
||||
if (key.startsWith(prefix)) {
|
||||
stcdKeys.add(key.substring(prefix.length()));
|
||||
}
|
||||
}
|
||||
stcdKeys.sort(Comparator.comparing(k -> wthgOrderKey.getOrDefault(k, BigDecimal.ZERO)));
|
||||
for (String wthg : stcdKeys) {
|
||||
sortedKeys.add(prefix + wthg);
|
||||
}
|
||||
}
|
||||
|
||||
// 构建数据行
|
||||
List<List<Object>> rows = new ArrayList<>();
|
||||
// 子标题行(Row 0)
|
||||
List<Object> subHeaderRow = new ArrayList<>();
|
||||
subHeaderRow.add(""); subHeaderRow.add("");
|
||||
subHeaderRow.add("水温(℃)"); subHeaderRow.add("相应高程(m)");
|
||||
subHeaderRow.add("水温(℃)"); subHeaderRow.add("相应高程(m)");
|
||||
subHeaderRow.add("水温(℃)"); subHeaderRow.add("相应高程(m)");
|
||||
subHeaderRow.add("水温(℃)"); subHeaderRow.add("相应高程(m)");
|
||||
rows.add(subHeaderRow);
|
||||
|
||||
for (String key : sortedKeys) {
|
||||
int sep = key.indexOf('|');
|
||||
String stcd = key.substring(0, sep);
|
||||
String wthg = key.substring(sep + 1);
|
||||
|
||||
Map<String, BigDecimal> dayMap = dayVwtMap.getOrDefault(key, Collections.emptyMap());
|
||||
BigDecimal elev = elevationMap.get(key);
|
||||
BigDecimal monthlyAvg = monthlyAvgMap.get(key);
|
||||
|
||||
List<Object> row = new ArrayList<>();
|
||||
row.add(stcdDisplayMap.getOrDefault(stcd, stcd));
|
||||
row.add(formatNumberCell(wthg));
|
||||
row.add(formatTemp(dayMap.get("5")));
|
||||
row.add(formatElev(elev));
|
||||
row.add(formatTemp(dayMap.get("15")));
|
||||
row.add(formatElev(elev));
|
||||
row.add(formatTemp(dayMap.get("25")));
|
||||
row.add(formatElev(elev));
|
||||
row.add(formatTemp(monthlyAvg));
|
||||
row.add(formatElev(elev));
|
||||
rows.add(row);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
private String formatNumberCell(String numStr) {
|
||||
BigDecimal val = toBigDecimal(numStr);
|
||||
return val != null ? stripTrailingZeros(val) : numStr;
|
||||
}
|
||||
|
||||
private String formatTemp(BigDecimal val) {
|
||||
if (val == null) return "";
|
||||
return val.setScale(2, java.math.RoundingMode.HALF_UP).toPlainString();
|
||||
}
|
||||
|
||||
private String formatElev(BigDecimal val) {
|
||||
if (val == null) return "";
|
||||
return stripTrailingZeros(val);
|
||||
}
|
||||
|
||||
private String formatNumber(Object obj) {
|
||||
if (obj instanceof BigDecimal) return stripTrailingZeros((BigDecimal) obj);
|
||||
if (obj instanceof Number) return String.valueOf(obj);
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
private BigDecimal toBigDecimal(Object val) {
|
||||
if (val instanceof BigDecimal) return (BigDecimal) val;
|
||||
if (val instanceof Number) return BigDecimal.valueOf(((Number) val).doubleValue());
|
||||
if (val instanceof String) {
|
||||
try {
|
||||
return new BigDecimal((String) val);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String stripTrailingZeros(BigDecimal val) {
|
||||
if (val == null) return "";
|
||||
return val.stripTrailingZeros().toPlainString();
|
||||
}
|
||||
|
||||
private List<List<Object>> buildWqComplianceSheet(
|
||||
MonthRange mr, List<String> stationOrder, StationResolution stationRes) {
|
||||
|
||||
@ -659,6 +882,8 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
||||
processorMap.put("qo", qoProcessor);
|
||||
// 生态流量(STTP=ENG,仅标准格式无日变幅)
|
||||
processorMap.put("qec", qecProcessor);
|
||||
// 垂向水温(STTP=WTVT, 双表头分层格式)
|
||||
processorMap.put("rwt", rwtProcessor);
|
||||
|
||||
// WQ 别名:展开为全部水质指标
|
||||
List<String> expanded = new ArrayList<>();
|
||||
@ -721,6 +946,8 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
||||
((HydropwIndicatorProcessor) p).setMappers(sdHydropwRMapper, sdHydropwdaySMapper);
|
||||
} else if (p instanceof QecProcessor) {
|
||||
((QecProcessor) p).setMappers(sdQecRMapper, sdQecdaySMapper);
|
||||
} else if (p instanceof RwtProcessor) {
|
||||
((RwtProcessor) p).setMappers(sdWtvtRMapper, sdWtvtdaySMapper);
|
||||
}
|
||||
result.add(p);
|
||||
}
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.yfd.platform.qgc_export.mapper.SdWtvtdaySMapper">
|
||||
|
||||
<!-- 查询月内每日垂向水温数据 -->
|
||||
<select id="selectDailyData" resultType="java.util.HashMap">
|
||||
SELECT
|
||||
STCD,
|
||||
WTHG,
|
||||
VWT,
|
||||
EXTRACT(DAY FROM DT) AS DAY_NUM
|
||||
FROM SD_WTVTDAY_S
|
||||
WHERE IS_DELETED = 0
|
||||
AND STCD IN
|
||||
<foreach collection="stcdList" item="stcd" open="(" separator="," close=")">
|
||||
#{stcd}
|
||||
</foreach>
|
||||
AND DT >= TO_DATE(#{startTime}, 'YYYY-MM-DD HH24:MI:SS')
|
||||
AND DT < TO_DATE(#{endTime}, 'YYYY-MM-DD HH24:MI:SS')
|
||||
AND VWT IS NOT NULL
|
||||
</select>
|
||||
|
||||
<!-- 查询月均垂向水温 -->
|
||||
<select id="selectMonthlyAvg" resultType="java.util.HashMap">
|
||||
SELECT
|
||||
STCD,
|
||||
WTHG,
|
||||
AVG(VWT) AS VWT
|
||||
FROM SD_WTVTDAY_S
|
||||
WHERE IS_DELETED = 0
|
||||
AND STCD IN
|
||||
<foreach collection="stcdList" item="stcd" open="(" separator="," close=")">
|
||||
#{stcd}
|
||||
</foreach>
|
||||
AND DT >= TO_DATE(#{startTime}, 'YYYY-MM-DD HH24:MI:SS')
|
||||
AND DT < TO_DATE(#{endTime}, 'YYYY-MM-DD HH24:MI:SS')
|
||||
AND VWT IS NOT NULL
|
||||
GROUP BY STCD, WTHG
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Loading…
Reference in New Issue
Block a user