fix: 优化excel综合导出水质方法
This commit is contained in:
parent
3d952315a5
commit
616c1fbcba
@ -54,9 +54,9 @@ public class QgcExportController {
|
|||||||
List<String> monthList = parseCsv(months);
|
List<String> monthList = parseCsv(months);
|
||||||
List<String> stationList = parseCsv(stcd);
|
List<String> stationList = parseCsv(stcd);
|
||||||
|
|
||||||
if (dataFields.isEmpty()) {
|
// if (dataFields.isEmpty()) {
|
||||||
dataFields = Arrays.asList("v", "q", "z");
|
// dataFields = Arrays.asList("v", "q", "z");
|
||||||
}
|
// }
|
||||||
if (tmDimension == null || tmDimension.isEmpty()) {
|
if (tmDimension == null || tmDimension.isEmpty()) {
|
||||||
tmDimension = "month";
|
tmDimension = "month";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
package com.yfd.platform.qgc_export.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 水质监测数据表(小时级)
|
||||||
|
* 对应 Oracle 表: QGC_REFA.SD_WQ_R
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("SD_WQ_R")
|
||||||
|
public class SdWqR implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.INPUT)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/** 站码 */
|
||||||
|
private String stcd;
|
||||||
|
|
||||||
|
/** 采样时间 */
|
||||||
|
private Date tm;
|
||||||
|
|
||||||
|
/** 水温 (℃) */
|
||||||
|
private BigDecimal wtmp;
|
||||||
|
|
||||||
|
/** PH */
|
||||||
|
private BigDecimal ph;
|
||||||
|
|
||||||
|
/** 溶解氧 (mg/L) */
|
||||||
|
private BigDecimal dox;
|
||||||
|
|
||||||
|
/** 电导率 (μS/cm) */
|
||||||
|
private BigDecimal cond;
|
||||||
|
|
||||||
|
/** 浊度 (NTU) */
|
||||||
|
private BigDecimal tu;
|
||||||
|
|
||||||
|
/** 是否达标: 0=不达标 1=达标 */
|
||||||
|
private Integer sfdb;
|
||||||
|
|
||||||
|
/** 是否已删除 */
|
||||||
|
private Integer isDeleted;
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package com.yfd.platform.qgc_export.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 水质监测日数据表
|
||||||
|
* 对应 Oracle 表: QGC_REFA.SD_WQDAY_S
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("SD_WQDAY_S")
|
||||||
|
public class SdWqdayS implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.INPUT)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/** 站码 */
|
||||||
|
private String stcd;
|
||||||
|
|
||||||
|
/** 时间 */
|
||||||
|
private Date dt;
|
||||||
|
|
||||||
|
/** 水温 (℃) */
|
||||||
|
private BigDecimal wtmp;
|
||||||
|
|
||||||
|
/** PH */
|
||||||
|
private BigDecimal ph;
|
||||||
|
|
||||||
|
/** 溶解氧 (mg/L) */
|
||||||
|
private BigDecimal dox;
|
||||||
|
|
||||||
|
/** 电导率 (μS/cm) */
|
||||||
|
private BigDecimal cond;
|
||||||
|
|
||||||
|
/** 浊度 (NTU) */
|
||||||
|
private BigDecimal tu;
|
||||||
|
|
||||||
|
/** 是否达标 */
|
||||||
|
private Integer sfdb;
|
||||||
|
|
||||||
|
/** 是否已删除 */
|
||||||
|
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.SdWqR;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SD_WQ_R 水质小时数据 Mapper
|
||||||
|
*/
|
||||||
|
public interface SdWqRMapper extends BaseMapper<SdWqR> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量查询测站在指定时间范围内的原始小时数据(含达标标志)
|
||||||
|
*
|
||||||
|
* @param stcdList 测站编码列表
|
||||||
|
* @param fieldName 查询字段名(WTMP/PH/DOX/COND/TU)
|
||||||
|
* @param startTime 起始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @return [STCD, TM, VALUE, SFDB]
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectRawData(@Param("stcdList") List<String> stcdList,
|
||||||
|
@Param("fieldName") String fieldName,
|
||||||
|
@Param("startTime") String startTime,
|
||||||
|
@Param("endTime") String endTime);
|
||||||
|
}
|
||||||
@ -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.SdWqdayS;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SD_WQDAY_S 水质日数据 Mapper
|
||||||
|
*/
|
||||||
|
public interface SdWqdaySMapper extends BaseMapper<SdWqdayS> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量查询测站在指定时间范围内的原始日数据
|
||||||
|
*
|
||||||
|
* @param stcdList 测站编码列表
|
||||||
|
* @param fieldName 查询字段名(WTMP/PH/DOX/COND/TU)
|
||||||
|
* @param startTime 起始时间
|
||||||
|
* @param endTime 结束时间
|
||||||
|
* @return [STCD, DT, VALUE]
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectRawData(@Param("stcdList") List<String> stcdList,
|
||||||
|
@Param("fieldName") String fieldName,
|
||||||
|
@Param("startTime") String startTime,
|
||||||
|
@Param("endTime") String endTime);
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.yfd.platform.qgc_export.processor;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电导率(COND) 指标处理器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CondProcessor extends WqIndicatorProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFieldName() {
|
||||||
|
return "COND";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSheetName() {
|
||||||
|
return "电导率(μS/cm)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDecimalPlaces() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSttpType() {
|
||||||
|
return "WQ";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.yfd.platform.qgc_export.processor;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 溶解氧(DOX) 指标处理器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class DoxProcessor extends WqIndicatorProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFieldName() {
|
||||||
|
return "DOX";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSheetName() {
|
||||||
|
return "溶解氧(mg/L)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDecimalPlaces() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSttpType() {
|
||||||
|
return "WQ";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,7 +24,8 @@ public interface ExportIndicatorProcessor {
|
|||||||
* 测站类型(STTP),用于区分同一电站下不同用途的测站。
|
* 测站类型(STTP),用于区分同一电站下不同用途的测站。
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>V/Q/Z 河道水情 → "ZQ"</li>
|
* <li>V/Q/Z 河道水情 → "ZQ"</li>
|
||||||
* <li>QEC 生态流量 → 待定(如 "SQ")</li>
|
* <li>WQ 水质 → null(不区分类型,取第一个测站)</li>
|
||||||
|
* <li>QEC 生态流量 → 待定</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* 返回 null 表示不按 STTP 过滤,取该电站的第一个测站。
|
* 返回 null 表示不按 STTP 过滤,取该电站的第一个测站。
|
||||||
*/
|
*/
|
||||||
@ -32,6 +33,20 @@ public interface ExportIndicatorProcessor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数值保留的小数位数,默认 3 位
|
||||||
|
*/
|
||||||
|
default int getDecimalPlaces() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有小时达标率指标(水质指标返回 true,在月均下方追加一行"小时达标率")
|
||||||
|
*/
|
||||||
|
default boolean hasComplianceRate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询原始数据
|
* 查询原始数据
|
||||||
*
|
*
|
||||||
|
|||||||
@ -13,6 +13,8 @@ public class IndicatorDataRow {
|
|||||||
private Date tm;
|
private Date tm;
|
||||||
/** 指标值 */
|
/** 指标值 */
|
||||||
private BigDecimal value;
|
private BigDecimal value;
|
||||||
|
/** 是否达标(仅水质指标使用,0=不达标 1=达标) */
|
||||||
|
private Integer sfdb;
|
||||||
|
|
||||||
public IndicatorDataRow() {}
|
public IndicatorDataRow() {}
|
||||||
|
|
||||||
@ -28,4 +30,6 @@ public class IndicatorDataRow {
|
|||||||
public void setTm(Date tm) { this.tm = tm; }
|
public void setTm(Date tm) { this.tm = tm; }
|
||||||
public BigDecimal getValue() { return value; }
|
public BigDecimal getValue() { return value; }
|
||||||
public void setValue(BigDecimal value) { this.value = value; }
|
public void setValue(BigDecimal value) { this.value = value; }
|
||||||
|
public Integer getSfdb() { return sfdb; }
|
||||||
|
public void setSfdb(Integer sfdb) { this.sfdb = sfdb; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.yfd.platform.qgc_export.processor;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PH 指标处理器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class PhProcessor extends WqIndicatorProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFieldName() {
|
||||||
|
return "PH";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSheetName() {
|
||||||
|
return "PH";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDecimalPlaces() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSttpType() {
|
||||||
|
return "WQ";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.yfd.platform.qgc_export.processor;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 浊度(TU) 指标处理器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TuProcessor extends WqIndicatorProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFieldName() {
|
||||||
|
return "TU";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSheetName() {
|
||||||
|
return "浊度(NTU)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDecimalPlaces() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSttpType() {
|
||||||
|
return "WQ";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
package com.yfd.platform.qgc_export.processor;
|
||||||
|
|
||||||
|
import com.yfd.platform.qgc_export.mapper.SdWqRMapper;
|
||||||
|
import com.yfd.platform.qgc_export.mapper.SdWqdaySMapper;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 水质指标处理器基类 — 5个水质指标(WTMP/PH/DOX/COND/TU)共用查询逻辑
|
||||||
|
* <p>
|
||||||
|
* 小时表查询额外提取 SFDB(是否达标)字段,用于计算小时达标率。
|
||||||
|
* 子类需标注 @Component 并提供 getFieldName/getSheetName/getDecimalPlaces。
|
||||||
|
*/
|
||||||
|
public abstract class WqIndicatorProcessor implements ExportIndicatorProcessor {
|
||||||
|
|
||||||
|
protected SdWqRMapper sdWqRMapper;
|
||||||
|
protected SdWqdaySMapper sdWqdaySMapper;
|
||||||
|
|
||||||
|
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
public void setMappers(SdWqRMapper rMapper, SdWqdaySMapper sMapper) {
|
||||||
|
this.sdWqRMapper = rMapper;
|
||||||
|
this.sdWqdaySMapper = sMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSttpType() {
|
||||||
|
return null; // 水质不按STTP过滤,取第一个测站
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasComplianceRate() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IndicatorDataRow> queryRawData(List<String> stcds, Date startTime, Date endTime, boolean isDaily) {
|
||||||
|
String startStr = SDF.format(startTime);
|
||||||
|
String endStr = SDF.format(endTime);
|
||||||
|
|
||||||
|
List<Map<String, Object>> rawList;
|
||||||
|
if (isDaily) {
|
||||||
|
rawList = sdWqdaySMapper.selectRawData(stcds, getFieldName(), startStr, endStr);
|
||||||
|
} else {
|
||||||
|
rawList = sdWqRMapper.selectRawData(stcds, getFieldName(), startStr, endStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<IndicatorDataRow> rows = new ArrayList<>();
|
||||||
|
if (rawList != null) {
|
||||||
|
for (Map<String, Object> map : rawList) {
|
||||||
|
String stcd = (String) map.get("STCD");
|
||||||
|
Date tm = (Date) map.get(isDaily ? "DT" : "TM");
|
||||||
|
BigDecimal value = toBigDecimal(map.get("VALUE"));
|
||||||
|
if (stcd != null && tm != null && value != null) {
|
||||||
|
IndicatorDataRow row = new IndicatorDataRow(stcd, tm, value);
|
||||||
|
// 小时表额外携带 SFDB(达标标志)
|
||||||
|
if (!isDaily) {
|
||||||
|
Object sfdbObj = map.get("SFDB");
|
||||||
|
if (sfdbObj instanceof Number) {
|
||||||
|
row.setSfdb(((Number) sfdbObj).intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rows.add(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal toBigDecimal(Object val) {
|
||||||
|
if (val instanceof BigDecimal) return (BigDecimal) val;
|
||||||
|
if (val instanceof Number) return BigDecimal.valueOf(((Number) val).doubleValue());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.yfd.platform.qgc_export.processor;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 水温(WTMP) 指标处理器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class WtmpProcessor extends WqIndicatorProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFieldName() {
|
||||||
|
return "WTMP";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSheetName() {
|
||||||
|
return "水温(℃)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDecimalPlaces() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSttpType() {
|
||||||
|
return "WQ";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -3,13 +3,10 @@ package com.yfd.platform.qgc_export.service.impl;
|
|||||||
import com.yfd.platform.qgc_export.domain.StationMapping;
|
import com.yfd.platform.qgc_export.domain.StationMapping;
|
||||||
import com.yfd.platform.qgc_export.mapper.SdRiverRMapper;
|
import com.yfd.platform.qgc_export.mapper.SdRiverRMapper;
|
||||||
import com.yfd.platform.qgc_export.mapper.SdRiverdaySMapper;
|
import com.yfd.platform.qgc_export.mapper.SdRiverdaySMapper;
|
||||||
|
import com.yfd.platform.qgc_export.mapper.SdWqRMapper;
|
||||||
|
import com.yfd.platform.qgc_export.mapper.SdWqdaySMapper;
|
||||||
import com.yfd.platform.qgc_export.mapper.StationMappingMapper;
|
import com.yfd.platform.qgc_export.mapper.StationMappingMapper;
|
||||||
import com.yfd.platform.qgc_export.processor.ExportIndicatorProcessor;
|
import com.yfd.platform.qgc_export.processor.*;
|
||||||
import com.yfd.platform.qgc_export.processor.IndicatorDataRow;
|
|
||||||
import com.yfd.platform.qgc_export.processor.RiverIndicatorProcessor;
|
|
||||||
import com.yfd.platform.qgc_export.processor.VProcessor;
|
|
||||||
import com.yfd.platform.qgc_export.processor.QProcessor;
|
|
||||||
import com.yfd.platform.qgc_export.processor.ZProcessor;
|
|
||||||
import com.yfd.platform.qgc_export.service.IQgcExportService;
|
import com.yfd.platform.qgc_export.service.IQgcExportService;
|
||||||
import com.yfd.platform.utils.ExportZipUtil;
|
import com.yfd.platform.utils.ExportZipUtil;
|
||||||
|
|
||||||
@ -30,27 +27,23 @@ import java.util.stream.Collectors;
|
|||||||
* 综合导出服务实现(月度报表)
|
* 综合导出服务实现(月度报表)
|
||||||
* <p>
|
* <p>
|
||||||
* 格式:每月一个 Excel 文件 → ZIP 下载。
|
* 格式:每月一个 Excel 文件 → ZIP 下载。
|
||||||
* 每个 Excel 含多个 Sheet(每个指标一个 Sheet)。
|
* 每个 Excel 含多个 Sheet,顺序:水温→PH→溶解氧→电导率→浊度→流速→流量→水位。
|
||||||
*
|
*
|
||||||
* <h3>Sheet 结构</h3>
|
* <h3>Sheet 结构</h3>
|
||||||
* <pre>
|
* <pre>
|
||||||
* 日期 | 班多 | 羊曲 ← 表头(Row 0:第一列=日期,后面列=测站名称)
|
* 日期 | 班多 | 羊曲 ← 表头(Row 0)
|
||||||
* 01 | 2757.711 | 2709.839 ← 每日数据(Row 1~31)
|
* 01 | 2757.711 | 2709.839 ← 日数据(Row 1~31)
|
||||||
* 02 | 2757.806 | 2709.794
|
* 02 | 2757.806 | 2709.794
|
||||||
* ...
|
* ...
|
||||||
* 31 | 2757.751 | 2709.714
|
* 日均最低 | 2757.549 | 2709.565 ← 汇总指标(7~8行)
|
||||||
* 日均最低 | 2757.549 | 2709.565 ← 汇总指标(7行)
|
|
||||||
* 日均最高 | 2757.879 | 2709.903
|
* 日均最高 | 2757.879 | 2709.903
|
||||||
* 月内最低 | 2756.979 | 2709.463
|
* 月内最低 | 2756.979 | 2709.463
|
||||||
* 月内最低时间 | 31日 08时 | 27日 08时
|
* 月内最低时间 | 31日 08时 | 27日 08时
|
||||||
* 月内最高 | 2758.003 | 2709.983
|
* 月内最高 | 2758.003 | 2709.983
|
||||||
* 月内最高时间 | 12日 16时 | 24日 16时
|
* 月内最高时间 | 12日 16时 | 24日 16时
|
||||||
* 月均 | 2757.751 | 2757.751
|
* 月均 | 2757.751 | 2757.751
|
||||||
|
* 小时达标率 | 95.2% | 93.8% ← 仅水质指标有此行
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
|
||||||
* <h3>电站→测站映射(STTP 类型区分)</h3>
|
|
||||||
* 同一电站(RSTCD)在 V_MS_STBPRP_T 视图中可能有多个测站(STCD),
|
|
||||||
* 不同类型的指标需要不同类型的测站数据。通过 {@link ExportIndicatorProcessor#getSttpType()} 区分。
|
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class QgcExportServiceImpl implements IQgcExportService {
|
public class QgcExportServiceImpl implements IQgcExportService {
|
||||||
@ -60,11 +53,11 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
@Resource
|
@Resource
|
||||||
private StationMappingMapper stationMappingMapper;
|
private StationMappingMapper stationMappingMapper;
|
||||||
|
|
||||||
|
// V/Q/Z 相关
|
||||||
@Resource
|
@Resource
|
||||||
private SdRiverRMapper sdRiverRMapper;
|
private SdRiverRMapper sdRiverRMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private SdRiverdaySMapper sdRiverdaySMapper;
|
private SdRiverdaySMapper sdRiverdaySMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private VProcessor vProcessor;
|
private VProcessor vProcessor;
|
||||||
@Resource
|
@Resource
|
||||||
@ -72,12 +65,29 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
@Resource
|
@Resource
|
||||||
private ZProcessor zProcessor;
|
private ZProcessor zProcessor;
|
||||||
|
|
||||||
/** 时间格式:dd日 HH时(如 "31日 08时") */
|
// WQ 相关
|
||||||
|
@Resource
|
||||||
|
private SdWqRMapper sdWqRMapper;
|
||||||
|
@Resource
|
||||||
|
private SdWqdaySMapper sdWqdaySMapper;
|
||||||
|
@Resource
|
||||||
|
private WtmpProcessor wtmpProcessor;
|
||||||
|
@Resource
|
||||||
|
private PhProcessor phProcessor;
|
||||||
|
@Resource
|
||||||
|
private DoxProcessor doxProcessor;
|
||||||
|
@Resource
|
||||||
|
private CondProcessor condProcessor;
|
||||||
|
@Resource
|
||||||
|
private TuProcessor tuProcessor;
|
||||||
|
|
||||||
private static final SimpleDateFormat SDF_TIME = new SimpleDateFormat("dd日 HH时");
|
private static final SimpleDateFormat SDF_TIME = new SimpleDateFormat("dd日 HH时");
|
||||||
|
|
||||||
/** 汇总指标行标签(7个) */
|
/** 基础汇总指标(7个) */
|
||||||
private static final List<String> INDICATOR_LABELS = Collections.unmodifiableList(
|
private static final List<String> BASE_LABELS = Collections.unmodifiableList(
|
||||||
Arrays.asList("日均最低", "日均最高", "月内最低", "月内最低时间", "月内最高", "月内最高时间", "月均"));
|
Arrays.asList("日均最低", "日均最高", "月内最低", "月内最低时间", "月内最高", "月内最高时间", "月均"));
|
||||||
|
/** 小时达标率标签 */
|
||||||
|
private static final String LABEL_COMPLIANCE = "小时达标率";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exportData(List<String> dataFields, List<String> months,
|
public void exportData(List<String> dataFields, List<String> months,
|
||||||
@ -96,7 +106,7 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
|
||||||
// 3. 电站 → 测站映射(按 STTP 类型分别获取)
|
// 3. 电站 → 测站映射
|
||||||
StationResolution stationRes = resolveStations(stationCodes, sttpTypes);
|
StationResolution stationRes = resolveStations(stationCodes, sttpTypes);
|
||||||
if (stationRes.displayNames.isEmpty()) {
|
if (stationRes.displayNames.isEmpty()) {
|
||||||
log.warn("未找到任何电站映射数据,导出取消");
|
log.warn("未找到任何电站映射数据,导出取消");
|
||||||
@ -142,18 +152,12 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
|
|
||||||
// ======================== 构建 Sheet 数据 ========================
|
// ======================== 构建 Sheet 数据 ========================
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询一个月的数据并组装为一个 Sheet 的全部行:
|
|
||||||
* <ol>
|
|
||||||
* <li>日数据行(01~31):每天每电站一个值</li>
|
|
||||||
* <li>汇总指标行(7行):日均最低、日均最高、月内最低、月内最低时间、月内最高、月内最高时间、月均</li>
|
|
||||||
* </ol>
|
|
||||||
*/
|
|
||||||
private List<List<Object>> buildSheetRows(
|
private List<List<Object>> buildSheetRows(
|
||||||
ExportIndicatorProcessor processor, MonthRange mr,
|
ExportIndicatorProcessor processor, MonthRange mr,
|
||||||
List<String> stationOrder, StationResolution stationRes) {
|
List<String> stationOrder, StationResolution stationRes) {
|
||||||
|
|
||||||
String sttp = processor.getSttpType();
|
String sttp = processor.getSttpType();
|
||||||
|
int decimals = processor.getDecimalPlaces();
|
||||||
|
|
||||||
// 构建该处理器对应的 RSTCD→STCD 映射
|
// 构建该处理器对应的 RSTCD→STCD 映射
|
||||||
Map<String, String> rstcdToStcd = new LinkedHashMap<>();
|
Map<String, String> rstcdToStcd = new LinkedHashMap<>();
|
||||||
@ -171,16 +175,22 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
|
|
||||||
List<String> uniqueStcds = rstcdToStcd.values().stream().distinct().toList();
|
List<String> uniqueStcds = rstcdToStcd.values().stream().distinct().toList();
|
||||||
|
|
||||||
// 查询日表 + 小时表数据
|
// 查询日表 + 小时表
|
||||||
List<IndicatorDataRow> dailyRows = processor.queryRawData(uniqueStcds, mr.getStart(), mr.getEnd(), true);
|
List<IndicatorDataRow> dailyRows = processor.queryRawData(uniqueStcds, mr.getStart(), mr.getEnd(), true);
|
||||||
List<IndicatorDataRow> hourlyRows = processor.queryRawData(uniqueStcds, mr.getStart(), mr.getEnd(), false);
|
List<IndicatorDataRow> hourlyRows = processor.queryRawData(uniqueStcds, mr.getStart(), mr.getEnd(), false);
|
||||||
|
|
||||||
// 汇总聚合
|
// 汇总聚合(含达标率)
|
||||||
Map<String, Aggregation> aggMap = aggregate(dailyRows, hourlyRows, rstcdToStcd);
|
Map<String, Aggregation> aggMap = aggregate(dailyRows, hourlyRows, rstcdToStcd, processor.hasComplianceRate());
|
||||||
|
|
||||||
// 日数据按 (stcd, day) 索引
|
// 日数据索引
|
||||||
Map<String, Map<Integer, BigDecimal>> dailyByStcd = indexDailyByDay(dailyRows);
|
Map<String, Map<Integer, BigDecimal>> dailyByStcd = indexDailyByDay(dailyRows);
|
||||||
|
|
||||||
|
// 指标标签
|
||||||
|
List<String> labels = new ArrayList<>(BASE_LABELS);
|
||||||
|
if (processor.hasComplianceRate()) {
|
||||||
|
labels.add(LABEL_COMPLIANCE);
|
||||||
|
}
|
||||||
|
|
||||||
List<List<Object>> rows = new ArrayList<>();
|
List<List<Object>> rows = new ArrayList<>();
|
||||||
|
|
||||||
// ---- 日数据行 ----
|
// ---- 日数据行 ----
|
||||||
@ -192,28 +202,29 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
String stcd = rstcdToStcd.get(rstcd);
|
String stcd = rstcdToStcd.get(rstcd);
|
||||||
Map<Integer, BigDecimal> dayMap = stcd != null ? dailyByStcd.get(stcd) : null;
|
Map<Integer, BigDecimal> dayMap = stcd != null ? dailyByStcd.get(stcd) : null;
|
||||||
BigDecimal val = dayMap != null ? dayMap.get(d) : null;
|
BigDecimal val = dayMap != null ? dayMap.get(d) : null;
|
||||||
row.add(formatOrEmpty(val));
|
row.add(formatOrEmpty(val, decimals));
|
||||||
}
|
}
|
||||||
rows.add(row);
|
rows.add(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- 汇总指标行 ----
|
// ---- 汇总指标行 ----
|
||||||
for (int i = 0; i < 7; i++) {
|
for (int i = 0; i < labels.size(); i++) {
|
||||||
List<Object> row = new ArrayList<>();
|
List<Object> row = new ArrayList<>();
|
||||||
row.add(INDICATOR_LABELS.get(i));
|
row.add(labels.get(i));
|
||||||
|
|
||||||
for (String rstcd : stationOrder) {
|
for (String rstcd : stationOrder) {
|
||||||
Aggregation agg = aggMap.get(rstcd);
|
Aggregation agg = aggMap.get(rstcd);
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0: row.add(formatOrEmpty(agg != null ? agg.getDailyMin() : null)); break;
|
case 0: row.add(formatOrEmpty(agg != null ? agg.getDailyMin() : null, decimals)); break;
|
||||||
case 1: row.add(formatOrEmpty(agg != null ? agg.getDailyMax() : null)); break;
|
case 1: row.add(formatOrEmpty(agg != null ? agg.getDailyMax() : null, decimals)); break;
|
||||||
case 2: row.add(formatOrEmpty(agg != null ? agg.getExtremeMin() : null)); break;
|
case 2: row.add(formatOrEmpty(agg != null ? agg.getExtremeMin() : null, decimals)); break;
|
||||||
case 3: row.add(agg != null && agg.getExtremeMinTime() != null
|
case 3: row.add(agg != null && agg.getExtremeMinTime() != null
|
||||||
? SDF_TIME.format(agg.getExtremeMinTime()) : ""); break;
|
? SDF_TIME.format(agg.getExtremeMinTime()) : ""); break;
|
||||||
case 4: row.add(formatOrEmpty(agg != null ? agg.getExtremeMax() : null)); break;
|
case 4: row.add(formatOrEmpty(agg != null ? agg.getExtremeMax() : null, decimals)); break;
|
||||||
case 5: row.add(agg != null && agg.getExtremeMaxTime() != null
|
case 5: row.add(agg != null && agg.getExtremeMaxTime() != null
|
||||||
? SDF_TIME.format(agg.getExtremeMaxTime()) : ""); break;
|
? SDF_TIME.format(agg.getExtremeMaxTime()) : ""); break;
|
||||||
case 6: row.add(formatOrEmpty(agg != null ? agg.getMonthlyAvg() : null)); break;
|
case 6: row.add(formatOrEmpty(agg != null ? agg.getMonthlyAvg() : null, decimals)); break;
|
||||||
|
case 7: row.add(formatComplianceRate(agg != null ? agg.getComplianceRate() : null)); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rows.add(row);
|
rows.add(row);
|
||||||
@ -224,8 +235,19 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
|
|
||||||
// ======================== 指标处理器匹配 ========================
|
// ======================== 指标处理器匹配 ========================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册顺序决定 Sheet 在 Excel 中的顺序:
|
||||||
|
* 水质指标(水温→PH→溶解氧→电导率→浊度)→ 河道水情(流速→流量→水位)
|
||||||
|
*/
|
||||||
private List<ExportIndicatorProcessor> resolveProcessors(List<String> dataFields) {
|
private List<ExportIndicatorProcessor> resolveProcessors(List<String> dataFields) {
|
||||||
Map<String, ExportIndicatorProcessor> processorMap = new LinkedHashMap<>();
|
Map<String, ExportIndicatorProcessor> processorMap = new LinkedHashMap<>();
|
||||||
|
// WQ 在前
|
||||||
|
processorMap.put("wtmp", wtmpProcessor);
|
||||||
|
processorMap.put("ph", phProcessor);
|
||||||
|
processorMap.put("dox", doxProcessor);
|
||||||
|
processorMap.put("cond", condProcessor);
|
||||||
|
processorMap.put("tu", tuProcessor);
|
||||||
|
// V/Q/Z 在后
|
||||||
processorMap.put("v", vProcessor);
|
processorMap.put("v", vProcessor);
|
||||||
processorMap.put("q", qProcessor);
|
processorMap.put("q", qProcessor);
|
||||||
processorMap.put("z", zProcessor);
|
processorMap.put("z", zProcessor);
|
||||||
@ -237,6 +259,8 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
if (p != null) {
|
if (p != null) {
|
||||||
if (p instanceof RiverIndicatorProcessor) {
|
if (p instanceof RiverIndicatorProcessor) {
|
||||||
((RiverIndicatorProcessor) p).setMappers(sdRiverRMapper, sdRiverdaySMapper);
|
((RiverIndicatorProcessor) p).setMappers(sdRiverRMapper, sdRiverdaySMapper);
|
||||||
|
} else if (p instanceof WqIndicatorProcessor) {
|
||||||
|
((WqIndicatorProcessor) p).setMappers(sdWqRMapper, sdWqdaySMapper);
|
||||||
}
|
}
|
||||||
result.add(p);
|
result.add(p);
|
||||||
}
|
}
|
||||||
@ -244,7 +268,7 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================== 电站映射(按 STTP 类型区分 + 测站名称) ========================
|
// ======================== 电站映射 ========================
|
||||||
|
|
||||||
private StationResolution resolveStations(List<String> rstcds, Set<String> sttpTypes) {
|
private StationResolution resolveStations(List<String> rstcds, Set<String> sttpTypes) {
|
||||||
StationResolution result = new StationResolution();
|
StationResolution result = new StationResolution();
|
||||||
@ -267,7 +291,7 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测站名称:优先 ZQ 类型的 STNM → 任意 STNM → ENNM → RSTCD
|
// 测站名称:优先 ZQ 类型 STNM → 任意 STNM → ENNM → RSTCD
|
||||||
String displayName = null;
|
String displayName = null;
|
||||||
for (StationMapping m : rows) {
|
for (StationMapping m : rows) {
|
||||||
if ("ZQ".equals(m.getSttp()) && m.getStnm() != null) {
|
if ("ZQ".equals(m.getSttp()) && m.getStnm() != null) {
|
||||||
@ -288,7 +312,7 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
}
|
}
|
||||||
result.displayNames.put(rstcd, displayName);
|
result.displayNames.put(rstcd, displayName);
|
||||||
|
|
||||||
// STTP → STCD 映射:每种 STTP 取第一个
|
// STTP → STCD 映射
|
||||||
Map<String, String> sttpMap = new LinkedHashMap<>();
|
Map<String, String> sttpMap = new LinkedHashMap<>();
|
||||||
for (StationMapping m : rows) {
|
for (StationMapping m : rows) {
|
||||||
String sttp = m.getSttp();
|
String sttp = m.getSttp();
|
||||||
@ -327,7 +351,6 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 计算月份的天数 */
|
|
||||||
private int getDaysInMonth(MonthRange mr) {
|
private int getDaysInMonth(MonthRange mr) {
|
||||||
Calendar cal = Calendar.getInstance();
|
Calendar cal = Calendar.getInstance();
|
||||||
cal.setTime(mr.getEnd());
|
cal.setTime(mr.getEnd());
|
||||||
@ -339,7 +362,7 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
|
|
||||||
private Map<String, Aggregation> aggregate(
|
private Map<String, Aggregation> aggregate(
|
||||||
List<IndicatorDataRow> dailyRows, List<IndicatorDataRow> hourlyRows,
|
List<IndicatorDataRow> dailyRows, List<IndicatorDataRow> hourlyRows,
|
||||||
Map<String, String> rstcdToStcd) {
|
Map<String, String> rstcdToStcd, boolean calcCompliance) {
|
||||||
|
|
||||||
Map<String, Aggregation> result = new LinkedHashMap<>();
|
Map<String, Aggregation> result = new LinkedHashMap<>();
|
||||||
|
|
||||||
@ -347,7 +370,7 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
String stcd = rstcdToStcd.get(rstcd);
|
String stcd = rstcdToStcd.get(rstcd);
|
||||||
Aggregation agg = new Aggregation();
|
Aggregation agg = new Aggregation();
|
||||||
|
|
||||||
// 日均最低/最高/月均:筛选该测站的所有日数据
|
// 日均最低/最高/月均
|
||||||
List<BigDecimal> dailyValues = dailyRows.stream()
|
List<BigDecimal> dailyValues = dailyRows.stream()
|
||||||
.filter(r -> Objects.equals(r.getStcd(), stcd) && r.getValue() != null)
|
.filter(r -> Objects.equals(r.getStcd(), stcd) && r.getValue() != null)
|
||||||
.map(IndicatorDataRow::getValue)
|
.map(IndicatorDataRow::getValue)
|
||||||
@ -355,12 +378,11 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
if (!dailyValues.isEmpty()) {
|
if (!dailyValues.isEmpty()) {
|
||||||
agg.setDailyMin(Collections.min(dailyValues));
|
agg.setDailyMin(Collections.min(dailyValues));
|
||||||
agg.setDailyMax(Collections.max(dailyValues));
|
agg.setDailyMax(Collections.max(dailyValues));
|
||||||
// 月均 = 日均值的平均值
|
|
||||||
BigDecimal sum = dailyValues.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
BigDecimal sum = dailyValues.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
agg.setMonthlyAvg(sum.divide(BigDecimal.valueOf(dailyValues.size()), 3, RoundingMode.HALF_UP));
|
agg.setMonthlyAvg(sum.divide(BigDecimal.valueOf(dailyValues.size()), 3, RoundingMode.HALF_UP));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 月内最低/最高及时间:筛选该测站的所有小时数据
|
// 月内最低/最高及时间
|
||||||
List<IndicatorDataRow> hourlyStationData = hourlyRows.stream()
|
List<IndicatorDataRow> hourlyStationData = hourlyRows.stream()
|
||||||
.filter(r -> Objects.equals(r.getStcd(), stcd) && r.getValue() != null)
|
.filter(r -> Objects.equals(r.getStcd(), stcd) && r.getValue() != null)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
@ -375,14 +397,22 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
agg.setExtremeMaxTime(maxRow.getTm());
|
agg.setExtremeMaxTime(maxRow.getTm());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 小时达标率(仅水质指标)
|
||||||
|
if (calcCompliance) {
|
||||||
|
List<IndicatorDataRow> sfdbRows = hourlyStationData.stream()
|
||||||
|
.filter(r -> r.getSfdb() != null)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!sfdbRows.isEmpty()) {
|
||||||
|
long compliant = sfdbRows.stream().filter(r -> r.getSfdb() == 1).count();
|
||||||
|
agg.setComplianceRate(BigDecimal.valueOf(compliant * 100.0 / sfdbRows.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result.put(rstcd, agg);
|
result.put(rstcd, agg);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将日表数据按 (stcd → day → value) 索引,供日数据行快速查找
|
|
||||||
*/
|
|
||||||
private Map<String, Map<Integer, BigDecimal>> indexDailyByDay(List<IndicatorDataRow> dailyRows) {
|
private Map<String, Map<Integer, BigDecimal>> indexDailyByDay(List<IndicatorDataRow> dailyRows) {
|
||||||
Map<String, Map<Integer, BigDecimal>> result = new LinkedHashMap<>();
|
Map<String, Map<Integer, BigDecimal>> result = new LinkedHashMap<>();
|
||||||
for (IndicatorDataRow row : dailyRows) {
|
for (IndicatorDataRow row : dailyRows) {
|
||||||
@ -395,9 +425,14 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String formatOrEmpty(BigDecimal value) {
|
private static String formatOrEmpty(BigDecimal value, int decimals) {
|
||||||
if (value == null) return "";
|
if (value == null) return "";
|
||||||
return value.setScale(3, RoundingMode.HALF_UP).toPlainString();
|
return value.setScale(decimals, RoundingMode.HALF_UP).toPlainString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatComplianceRate(BigDecimal value) {
|
||||||
|
if (value == null) return "";
|
||||||
|
return value.setScale(1, RoundingMode.HALF_UP).toPlainString() + "%";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getFileNamePrefix(String tmDimension) {
|
private static String getFileNamePrefix(String tmDimension) {
|
||||||
@ -413,19 +448,22 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
// ======================== 内部数据类 ========================
|
// ======================== 内部数据类 ========================
|
||||||
|
|
||||||
private static class StationResolution {
|
private static class StationResolution {
|
||||||
/** RSTCD → 测站名称(列标题显示用) */
|
|
||||||
final Map<String, String> displayNames = new LinkedHashMap<>();
|
final Map<String, String> displayNames = new LinkedHashMap<>();
|
||||||
/** RSTCD → (STTP → STCD) */
|
|
||||||
final Map<String, Map<String, String>> sttpStcdMap = new LinkedHashMap<>();
|
final Map<String, Map<String, String>> sttpStcdMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
String getDisplayName(String rstcd) {
|
String getDisplayName(String rstcd) {
|
||||||
return displayNames.getOrDefault(rstcd, rstcd);
|
return displayNames.getOrDefault(rstcd, rstcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定 STTP 的测站编码。sttp 为 null 时返回第一个可用的 STCD。
|
||||||
|
*/
|
||||||
String getStcd(String rstcd, String sttp) {
|
String getStcd(String rstcd, String sttp) {
|
||||||
Map<String, String> inner = sttpStcdMap.get(rstcd);
|
Map<String, String> inner = sttpStcdMap.get(rstcd);
|
||||||
if (inner == null || sttp == null) return null;
|
if (inner == null || inner.isEmpty()) return null;
|
||||||
return inner.get(sttp);
|
if (sttp != null) return inner.get(sttp);
|
||||||
|
// sttp 为 null:返回第一个可用的 STCD
|
||||||
|
return inner.values().iterator().next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,12 +479,11 @@ public class QgcExportServiceImpl implements IQgcExportService {
|
|||||||
private BigDecimal dailyMin;
|
private BigDecimal dailyMin;
|
||||||
private BigDecimal dailyMax;
|
private BigDecimal dailyMax;
|
||||||
private BigDecimal extremeMin;
|
private BigDecimal extremeMin;
|
||||||
/** 月内最低发生时间 */
|
|
||||||
private Date extremeMinTime;
|
private Date extremeMinTime;
|
||||||
private BigDecimal extremeMax;
|
private BigDecimal extremeMax;
|
||||||
/** 月内最高发生时间 */
|
|
||||||
private Date extremeMaxTime;
|
private Date extremeMaxTime;
|
||||||
/** 月均(所有日值的平均值) */
|
|
||||||
private BigDecimal monthlyAvg;
|
private BigDecimal monthlyAvg;
|
||||||
|
/** 小时达标率(百分比,仅水质指标使用) */
|
||||||
|
private BigDecimal complianceRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,10 +12,7 @@ import com.yfd.platform.qgc_base.domain.SdEngInfoBH;
|
|||||||
import com.yfd.platform.qgc_base.service.ISdEngInfoBHService;
|
import com.yfd.platform.qgc_base.service.ISdEngInfoBHService;
|
||||||
import com.yfd.platform.qgc_base.service.ISdHbrvDicService;
|
import com.yfd.platform.qgc_base.service.ISdHbrvDicService;
|
||||||
import com.yfd.platform.system.domain.*;
|
import com.yfd.platform.system.domain.*;
|
||||||
import com.yfd.platform.system.mapper.SysMenuMapper;
|
import com.yfd.platform.system.mapper.*;
|
||||||
import com.yfd.platform.system.mapper.SysOrganizationMapper;
|
|
||||||
import com.yfd.platform.system.mapper.SysRoleMapper;
|
|
||||||
import com.yfd.platform.system.mapper.SysUserTenantMapper;
|
|
||||||
import com.yfd.platform.system.service.ISmsVerifyCodeService;
|
import com.yfd.platform.system.service.ISmsVerifyCodeService;
|
||||||
import com.yfd.platform.system.service.ISysLogService;
|
import com.yfd.platform.system.service.ISysLogService;
|
||||||
import com.yfd.platform.system.service.IUserService;
|
import com.yfd.platform.system.service.IUserService;
|
||||||
@ -85,6 +82,10 @@ public class SmsVerifyCodeController {
|
|||||||
@Resource
|
@Resource
|
||||||
private ISdHbrvDicService hbrvDicService;
|
private ISdHbrvDicService hbrvDicService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SysUserMapper sysUserMapper;
|
||||||
|
|
||||||
|
|
||||||
@Value("${rsa.private_key}")
|
@Value("${rsa.private_key}")
|
||||||
private String privateKey;
|
private String privateKey;
|
||||||
private static final String URGE_CONTENT = "根据生态环境部要求,请贵电站尽快完成过鱼数据的报送工作,感谢支持。";
|
private static final String URGE_CONTENT = "根据生态环境部要求,请贵电站尽快完成过鱼数据的报送工作,感谢支持。";
|
||||||
@ -478,7 +479,7 @@ public class SmsVerifyCodeController {
|
|||||||
return ResponseResult.error("验证码错误或已过期");
|
return ResponseResult.error("验证码错误或已过期");
|
||||||
}
|
}
|
||||||
|
|
||||||
SysUser user = userService.getUserByPhone(phone, tenantId);
|
SysUser user = userService.getUserByPhone(phone, null);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ResponseResult.error("该手机号未注册");
|
return ResponseResult.error("该手机号未注册");
|
||||||
}
|
}
|
||||||
@ -500,19 +501,43 @@ public class SmsVerifyCodeController {
|
|||||||
Authentication authenticate = new UsernamePasswordAuthenticationToken(user, null, authenticationToken.getAuthorities());
|
Authentication authenticate = new UsernamePasswordAuthenticationToken(user, null, authenticationToken.getAuthorities());
|
||||||
SecurityContextHolder.getContext().setAuthentication(authenticate);
|
SecurityContextHolder.getContext().setAuthentication(authenticate);
|
||||||
|
|
||||||
LoginUser loginUser = new LoginUser();
|
// 判断是否为超级管理员(LEVEL=1)
|
||||||
loginUser.setUser(user);
|
boolean isSuperAdmin = (isSuperAdmin(user.getId())||user.getUsertype()==0);
|
||||||
loginUser.setUsername(user.getUsername());
|
|
||||||
//Todo 根据用户查询权限信息 添加到LoginUser中
|
// 查询用户可访问的门户列表
|
||||||
|
List<String> accessibleTenantIds = sysUserTenantMapper.getTenantIdsByUserId(user.getId());
|
||||||
|
|
||||||
|
// 非超级管理员必须指定门户,且必须在可访问列表中
|
||||||
|
if (!isSuperAdmin) {
|
||||||
|
if (StrUtil.isBlank(tenantId)) {
|
||||||
|
throw new RuntimeException("用户无权限访问该平台");
|
||||||
|
}
|
||||||
|
if (accessibleTenantIds == null || !accessibleTenantIds.contains(tenantId)) {
|
||||||
|
throw new RuntimeException("用户无权限访问该平台");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 加载权限:超级管理员加载全部权限,普通用户按门户过滤
|
// 加载权限:超级管理员加载全部权限,普通用户按门户过滤
|
||||||
boolean isSuperAdmin = userService.isSuperAdmin(user.getId());
|
|
||||||
List<String> permissions;
|
List<String> permissions;
|
||||||
if (isSuperAdmin) {
|
if (isSuperAdmin) {
|
||||||
permissions = sysMenuMapper.selectPermsByUserId(user.getId(), null);
|
permissions = sysMenuMapper.selectPermsByUserId(user.getId(), null);
|
||||||
} else {
|
} else {
|
||||||
permissions = sysMenuMapper.selectPermsByUserId(user.getId(), tenantId);
|
permissions = sysMenuMapper.selectPermsByUserId(user.getId(), tenantId);
|
||||||
}
|
}
|
||||||
loginUser.setPermissions(permissions);
|
|
||||||
|
LoginUser loginUser = new LoginUser(user, permissions, tenantId, accessibleTenantIds, isSuperAdmin);
|
||||||
|
|
||||||
|
// LoginUser loginUser = new LoginUser();
|
||||||
|
// loginUser.setUser(user);
|
||||||
|
// loginUser.setUsername(user.getUsername());
|
||||||
|
// boolean isSuperAdmin = userService.isSuperAdmin(user.getId());
|
||||||
|
// List<String> permissions;
|
||||||
|
// if (isSuperAdmin) {
|
||||||
|
// permissions = sysMenuMapper.selectPermsByUserId(user.getId(), null);
|
||||||
|
// } else {
|
||||||
|
// permissions = sysMenuMapper.selectPermsByUserId(user.getId(), tenantId);
|
||||||
|
// }
|
||||||
|
// loginUser.setPermissions(permissions);
|
||||||
HttpServletRequest request = RequestHolder.getHttpServletRequest();
|
HttpServletRequest request = RequestHolder.getHttpServletRequest();
|
||||||
SysLog sysLog = new SysLog();
|
SysLog sysLog = new SysLog();
|
||||||
sysLog.setUsercode(user.getUsername());
|
sysLog.setUsercode(user.getUsername());
|
||||||
@ -549,4 +574,12 @@ public class SmsVerifyCodeController {
|
|||||||
|
|
||||||
return ResponseResult.successData(map);
|
return ResponseResult.successData(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断用户是否为超级管理员(拥有LEVEL=1的角色)
|
||||||
|
*/
|
||||||
|
private boolean isSuperAdmin(String userId) {
|
||||||
|
String maxLevel = sysUserMapper.getMaxLevel(userId);
|
||||||
|
return "1".equals(maxLevel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
27
backend/src/main/resources/mapper/qgc_export/SdWqRMapper.xml
Normal file
27
backend/src/main/resources/mapper/qgc_export/SdWqRMapper.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?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.SdWqRMapper">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
水质小时数据动态字段查询
|
||||||
|
利用 STCD + TM + IS_DELETED 复合索引
|
||||||
|
-->
|
||||||
|
<select id="selectRawData" resultType="java.util.HashMap">
|
||||||
|
SELECT
|
||||||
|
STCD,
|
||||||
|
TM,
|
||||||
|
${fieldName} AS VALUE,
|
||||||
|
SFDB
|
||||||
|
FROM SD_WQ_R
|
||||||
|
WHERE IS_DELETED = 0
|
||||||
|
AND STCD IN
|
||||||
|
<foreach collection="stcdList" item="stcd" open="(" separator="," close=")">
|
||||||
|
#{stcd}
|
||||||
|
</foreach>
|
||||||
|
AND TM >= TO_DATE(#{startTime}, 'YYYY-MM-DD HH24:MI:SS')
|
||||||
|
AND TM < TO_DATE(#{endTime}, 'YYYY-MM-DD HH24:MI:SS')
|
||||||
|
AND ${fieldName} IS NOT NULL
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
<?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.SdWqdaySMapper">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
水质日数据动态字段查询
|
||||||
|
利用 STCD + DT + IS_DELETED 复合索引
|
||||||
|
-->
|
||||||
|
<select id="selectRawData" resultType="java.util.HashMap">
|
||||||
|
SELECT
|
||||||
|
STCD,
|
||||||
|
DT,
|
||||||
|
${fieldName} AS VALUE
|
||||||
|
FROM SD_WQDAY_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 ${fieldName} IS NOT NULL
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Loading…
Reference in New Issue
Block a user