feat: 全过程鱼类放鱼数据

This commit is contained in:
tangwei 2026-06-24 10:38:39 +08:00
parent 201c36e3b6
commit 8567930f94
4 changed files with 454 additions and 0 deletions

View File

@ -91,6 +91,12 @@ public class FbStationController {
return ResponseResult.successData(fbStationService.getFishCountKendoListCust(dataSourceRequest));
}
@PostMapping("/fishrun/qgc/GetKendoListCust")
@Operation(summary = "全过程鱼类放鱼数据")
public ResponseResult getFishRunQgcKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getFishRunQgcKendoListCust(dataSourceRequest));
}
@PostMapping("/fishType/GetKendoListCust")
@Operation(summary = "增殖站鱼种完成情况统计")
public ResponseResult getFishTypeKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {

View File

@ -0,0 +1,37 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import lombok.Data;
@Data
public class FbFishRunQgcVo {
private String stcd;
private String stnm;
private String ftp;
private String ftpName;
private String baseId;
private String baseName;
private String flyr;
private Long fcnt;
private Long totalFcnt;
private String fid;
private String release;
private Integer baseStepSort;
private Integer siteStepSort;
private Integer rvcdStepSort;
private Integer rstcdStepSort;
}

View File

@ -6,6 +6,7 @@ import com.yfd.platform.qgc_env.fb.entity.vo.FbBsmfRQgcVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbBsmfRFishTableVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFlDataVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFishCountFinishVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFishRunQgcVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFishTypeStcdVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFishTypeFinishVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbRelatedYrVo;
@ -31,6 +32,8 @@ public interface FbStationService {
DataSourceResult<FbFishCountFinishVo> getFishCountKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbFishRunQgcVo> getFishRunQgcKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbFishTypeFinishVo> getFishTypeKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbFishTypeStcdVo> getFishTypeStcdList(DataSourceRequest dataSourceRequest);

View File

@ -16,6 +16,7 @@ import com.yfd.platform.qgc_env.fb.entity.vo.FbBsmfRFishHeadColumnVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbBsmfRFishSummaryVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbBsmfRFishTableVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFishCountFinishVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFishRunQgcVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFishTypeStcdVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFishTypeFinishVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFtpStatisticsVo;
@ -118,6 +119,66 @@ public class FbStationServiceImpl implements FbStationService {
return result;
}
@Override
public DataSourceResult<FbFishRunQgcVo> getFishRunQgcKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
String flyrFilter = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "flyr");
String rstcdFilter = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "rstcd");
Date[] flyrRange = parseFishRunFlyrRange(flyrFilter);
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder();
sql.append("SELECT r.stcd AS stcd, ")
.append("r.stnm AS stnm, ")
.append("r.baseId AS baseId, ")
.append("r.baseName AS baseName, ")
.append("r.baseStepSort AS baseStepSort, ")
.append("r.siteStepSort AS siteStepSort, ")
.append("r.rvcdStepSort AS rvcdStepSort, ")
// .append("r.rstcdStepSort AS rstcdStepSort, ")
.append("r.flyr AS flyr, ")
.append("r.ftp AS ftp, ")
.append("r.ftpName AS ftpName, ")
.append("r.fcnt AS fcnt, ")
.append("r.totalFcnt AS totalFcnt, ")
.append("r.fid AS fid, ")
.append("r.release AS release ")
.append("FROM (")
.append(buildFishRunQgcBaseSql(
parseFishTypeFilterValues(rstcdFilter),
flyrRange[0],
flyrRange[1],
paramMap
))
.append(") r WHERE 1 = 1 ");
String filterSql = buildFishRunQgcFilterCondition(
dataSourceRequest == null ? null : dataSourceRequest.getFilter(),
paramMap,
new int[]{0}
);
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
sql.append(buildFishRunQgcOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort()));
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<FbFishRunQgcVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(
page,
sql.toString(),
paramMap,
FbFishRunQgcVo.class
);
normalizeFishRunQgcRows(list);
appendFishRunMissingYears(list, flyrRange[0], flyrRange[1], page);
DataSourceResult<FbFishRunQgcVo> result = new DataSourceResult<>();
result.setData(list);
result.setTotal(page != null ? page.getTotal() : list.size());
result.setAggregates(new HashMap<>());
return result;
}
@Override
public DataSourceResult<FbFishTypeFinishVo> getFishTypeKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
@ -953,6 +1014,353 @@ public class FbStationServiceImpl implements FbStationService {
return " ORDER BY " + String.join(", ", orderByParts);
}
private String buildFishRunQgcBaseSql(List<String> stcdList,
Date startTime,
Date endTime,
Map<String, Object> paramMap) {
String ftpNameExpr = buildFishNameExpr("agg.FTP");
StringBuilder sql = new StringBuilder();
sql.append("SELECT agg.STCD AS stcd, ")
.append("eng.ENNM AS stnm, ")
.append("eng.BASE_ID AS baseId, ")
.append("NVL(hb.BASENAME, eng.BASE_NAME) AS baseName, ")
.append("hb.ORDER_INDEX AS baseStepSort, ")
.append("siteAlong.SORT AS siteStepSort, ")
.append("along.ORDER_INDEX AS rvcdStepSort, ")
// .append("rstAlong.SORT AS rstcdStepSort, ")
.append("TO_CHAR(agg.FLYR) AS flyr, ")
.append("COALESCE(TO_CHAR(NVL(relRv.ZY_FISH_ID, relRv.FISH_ID)), ")
.append("TO_CHAR(NVL(relZy.ZY_FISH_ID, relZy.FISH_ID)), TO_CHAR(agg.FTP)) AS ftp, ")
.append(ftpNameExpr).append(" AS ftpName, ")
.append("agg.FCNT AS fcnt, ")
.append("totalAgg.TOTALFCNT AS totalFcnt, ")
.append("agg.FID AS fid, ")
.append("agg.RELEASE AS release ")
.append("FROM (")
.append(" SELECT run.STCD AS STCD, ")
.append(" TO_NUMBER(TO_CHAR(run.TM, 'YYYY')) AS FLYR, ")
.append(" det.FTP AS FTP, ")
.append(" SUM(det.FCNT) AS FCNT, ")
.append(" MAX(run.FPRFID) || ',' || MAX(run.FLRFID) || ',' || MAX(run.BRRFID) || ',' || MAX(run.BRFFID) AS FID, ")
.append(" REGEXP_REPLACE(LISTAGG(fb.STNM, ',') WITHIN GROUP (ORDER BY fb.STCD), '([^,]+)(,\\1)+', '\\1') AS RELEASE ")
.append(" FROM SD_RPIMNFISH_R det ")
.append(" INNER JOIN SD_ENGFR_R run ON det.RPIMN_ID = run.ID ")
.append(" AND NVL(run.IS_DELETED, 0) = 0 ")
.append(" LEFT JOIN SD_FBRD_B_H fb ON fb.STCD = run.RSTCD ")
// .append(" AND NVL(fb.IS_DELETED, 0) = 0 ")
.append(" WHERE NVL(det.IS_DELETED, 0) = 0 ")
.append(" AND det.FTP IS NOT NULL ");
appendFishRunQgcTimeFilter(sql, paramMap, "run", startTime, endTime, "fishRunDetail");
appendInCondition(sql, paramMap, "run.STCD", stcdList, "fishRunDetailStcd");
sql.append(" GROUP BY run.STCD, det.FTP, TO_NUMBER(TO_CHAR(run.TM, 'YYYY')) ")
.append(") agg ")
.append("LEFT JOIN (")
.append(" SELECT run.STCD AS STCD, ")
.append(" TO_NUMBER(TO_CHAR(run.TM, 'YYYY')) AS FLYR, ")
.append(" SUM(det.FCNT) AS TOTALFCNT ")
.append(" FROM SD_RPIMNFISH_R det ")
.append(" INNER JOIN SD_ENGFR_R run ON det.RPIMN_ID = run.ID ")
.append(" AND NVL(run.IS_DELETED, 0) = 0 ")
.append(" WHERE NVL(det.IS_DELETED, 0) = 0 ")
.append(" AND det.FTP IS NOT NULL ");
appendFishRunQgcTimeFilter(sql, paramMap, "run", startTime, endTime, "fishRunTotal");
appendInCondition(sql, paramMap, "run.STCD", stcdList, "fishRunTotalStcd");
sql.append(" GROUP BY run.STCD, TO_NUMBER(TO_CHAR(run.TM, 'YYYY')) ")
.append(") totalAgg ON totalAgg.STCD = agg.STCD AND totalAgg.FLYR = agg.FLYR ")
.append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = agg.STCD ")
.append(" AND NVL(eng.IS_DELETED, 0) = 0 ")
.append("LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID ")
.append(" AND NVL(hb.IS_DELETED, 0) = 0 ")
.append("LEFT JOIN MS_ALONG_B along ON along.RVCD = eng.HBRVCD ")
.append(" AND along.CODE = 'common' ")
.append(" AND NVL(along.IS_DELETED, 0) = 0 ")
// .append("LEFT JOIN MS_ALONGDET_B rstAlong ON rstAlong.ALONG_ID = along.ID ")
// .append(" AND rstAlong.STCD = eng.RSTCD ")
// .append(" AND NVL(rstAlong.IS_DELETED, 0) = 0 ")
.append("LEFT JOIN MS_ALONGDET_B siteAlong ON siteAlong.ALONG_ID = along.ID ")
.append(" AND siteAlong.STCD = eng.STCD ")
.append(" AND NVL(siteAlong.IS_DELETED, 0) = 0 ")
.append(buildFishJoinSql("agg.FTP", "eng.HBRVCD"))
.append("WHERE NVL(eng.IS_DELETED, 0) = 0 ");
return sql.toString();
}
private void appendFishRunQgcTimeFilter(StringBuilder sql,
Map<String, Object> paramMap,
String alias,
Date startTime,
Date endTime,
String keyPrefix) {
if (startTime != null) {
String startKey = keyPrefix + "Start";
paramMap.put(startKey, startTime);
sql.append(" AND ").append(alias).append(".TM >= #{map.").append(startKey).append("} ");
}
if (endTime != null) {
String endKey = keyPrefix + "End";
paramMap.put(endKey, endTime);
sql.append(" AND ").append(alias).append(".TM <= #{map.").append(endKey).append("} ");
}
}
private String buildFishRunQgcFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
if (filter == null) {
return "";
}
if (StrUtil.isNotBlank(filter.getField())) {
return buildFishRunQgcLeafCondition(filter, paramMap, indexHolder);
}
if (CollUtil.isEmpty(filter.getFilters())) {
return "";
}
List<String> conditions = new ArrayList<>();
for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) {
String childSql = buildFishRunQgcFilterCondition(child, paramMap, indexHolder);
if (StrUtil.isNotBlank(childSql)) {
conditions.add("(" + childSql + ")");
}
}
if (conditions.isEmpty()) {
return "";
}
String logic = "or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND ";
return String.join(logic, conditions);
}
private String buildFishRunQgcLeafCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
if ("flyr".equalsIgnoreCase(filter.getField()) || "rstcd".equalsIgnoreCase(filter.getField())) {
return "";
}
String column = mapFishRunQgcColumn(filter.getField());
if (StrUtil.isBlank(column)) {
return "";
}
String operator = StrUtil.blankToDefault(filter.getOperator(), "eq").toLowerCase();
if ("isnull".equals(operator)) {
return column + " IS NULL";
}
if ("isnotnull".equals(operator)) {
return column + " IS NOT NULL";
}
if ("isempty".equals(operator)) {
return "(" + column + " IS NULL OR " + column + " = '')";
}
if ("isnotempty".equals(operator)) {
return "(" + column + " IS NOT NULL AND " + column + " <> '')";
}
if ("in".equals(operator)) {
List<Object> values = normalizeQgcBsmfRValues(filter.getValue());
if (values.isEmpty()) {
return "";
}
List<String> placeholders = new ArrayList<>();
for (Object value : values) {
String key = "fishRunQgcP" + indexHolder[0]++;
paramMap.put(key, normalizeFishRunQgcValue(filter.getField(), value));
placeholders.add("#{map." + key + "}");
}
return column + " IN (" + String.join(", ", placeholders) + ")";
}
Object value = filter.getValue();
if (value == null) {
return "";
}
String key = "fishRunQgcP" + indexHolder[0]++;
Object normalizedValue = normalizeFishRunQgcValue(filter.getField(), value);
return switch (operator) {
case "eq" -> {
paramMap.put(key, normalizedValue);
yield column + " = #{map." + key + "}";
}
case "neq" -> {
paramMap.put(key, normalizedValue);
yield column + " <> #{map." + key + "}";
}
case "gt" -> {
paramMap.put(key, normalizedValue);
yield column + " > #{map." + key + "}";
}
case "gte" -> {
paramMap.put(key, normalizedValue);
yield column + " >= #{map." + key + "}";
}
case "lt" -> {
paramMap.put(key, normalizedValue);
yield column + " < #{map." + key + "}";
}
case "lte" -> {
paramMap.put(key, normalizedValue);
yield column + " <= #{map." + key + "}";
}
case "contains" -> {
paramMap.put(key, "%" + String.valueOf(normalizedValue).trim() + "%");
yield column + " LIKE #{map." + key + "}";
}
case "doesnotcontain" -> {
paramMap.put(key, "%" + String.valueOf(normalizedValue).trim() + "%");
yield column + " NOT LIKE #{map." + key + "}";
}
case "startswith" -> {
paramMap.put(key, String.valueOf(normalizedValue).trim() + "%");
yield column + " LIKE #{map." + key + "}";
}
case "endswith" -> {
paramMap.put(key, "%" + String.valueOf(normalizedValue).trim());
yield column + " LIKE #{map." + key + "}";
}
default -> "";
};
}
private String mapFishRunQgcColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
return switch (field) {
case "stcd" -> "r.stcd";
case "stnm" -> "r.stnm";
case "baseId" -> "r.baseId";
case "baseName" -> "r.baseName";
case "flyr" -> "r.flyr";
case "ftp" -> "r.ftp";
case "ftpName" -> "r.ftpName";
case "fcnt" -> "r.fcnt";
case "totalFcnt" -> "r.totalFcnt";
case "release" -> "r.release";
case "baseStepSort" -> "r.baseStepSort";
case "siteStepSort" -> "r.siteStepSort";
case "rvcdStepSort" -> "r.rvcdStepSort";
case "rstcdStepSort" -> "r.rstcdStepSort";
default -> null;
};
}
private Object normalizeFishRunQgcValue(String field, Object value) {
if (value == null) {
return null;
}
if ("fcnt".equals(field) || "totalFcnt".equals(field) || "baseStepSort".equals(field)
|| "siteStepSort".equals(field) || "rvcdStepSort".equals(field)
|| "rstcdStepSort".equals(field)) {
try {
return Long.parseLong(String.valueOf(value).trim());
} catch (Exception ex) {
return null;
}
}
return value;
}
private String buildFishRunQgcOrderBySql(List<DataSourceRequest.SortDescriptor> sorts) {
if (CollUtil.isEmpty(sorts)) {
return " ORDER BY r.baseStepSort ASC NULLS LAST, r.rvcdStepSort ASC NULLS LAST, " +
"r.rstcdStepSort ASC NULLS LAST, r.siteStepSort ASC NULLS LAST, r.flyr ASC, r.ftpName ASC";
}
List<String> orderByParts = new ArrayList<>();
for (DataSourceRequest.SortDescriptor sort : sorts) {
if (sort == null || StrUtil.isBlank(sort.getField())) {
continue;
}
String column = mapFishRunQgcColumn(sort.getField());
if (StrUtil.isBlank(column)) {
continue;
}
String direction = "desc".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC";
orderByParts.add(column + " " + direction);
}
if (orderByParts.isEmpty()) {
return " ORDER BY r.baseStepSort ASC NULLS LAST, r.rvcdStepSort ASC NULLS LAST, " +
"r.rstcdStepSort ASC NULLS LAST, r.siteStepSort ASC NULLS LAST, r.flyr ASC, r.ftpName ASC";
}
return " ORDER BY " + String.join(", ", orderByParts);
}
private Date[] parseFishRunFlyrRange(String flyrFilter) {
if (StrUtil.isBlank(flyrFilter)) {
return new Date[]{null, null};
}
String value = flyrFilter.trim();
if (value.matches("\\d{4}")) {
Date start = parseDateTimeSafely(value + "-01-01 00:00:00");
Date end = parseDateTimeSafely(value + "-12-31 23:59:59");
return new Date[]{start, end};
}
if (!value.contains(",")) {
Date point = parseDateTimeSafely(value);
return new Date[]{point, point};
}
String[] parts = value.split(",");
if (parts.length < 2) {
return new Date[]{null, null};
}
Date first = parseDateTimeSafely(parts[0].trim());
Date second = parseDateTimeSafely(parts[1].trim());
if (first == null || second == null) {
return new Date[]{null, null};
}
return first.after(second) ? new Date[]{second, first} : new Date[]{first, second};
}
private void normalizeFishRunQgcRows(List<FbFishRunQgcVo> list) {
if (CollUtil.isEmpty(list)) {
return;
}
for (FbFishRunQgcVo item : list) {
if (item == null) {
continue;
}
if (item.getFid() != null) {
LinkedHashSet<String> fidSet = Arrays.stream(item.getFid().split(","))
.map(StrUtil::trim)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toCollection(LinkedHashSet::new));
item.setFid(fidSet.isEmpty() ? null : String.join(",", fidSet));
}
if (item.getRelease() != null) {
LinkedHashSet<String> releaseSet = Arrays.stream(item.getRelease().split(","))
.map(StrUtil::trim)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toCollection(LinkedHashSet::new));
item.setRelease(releaseSet.isEmpty() ? null : String.join(",", releaseSet));
}
if (item.getFcnt() == null) {
item.setFcnt(0L);
}
if (item.getTotalFcnt() == null) {
item.setTotalFcnt(0L);
}
}
}
private void appendFishRunMissingYears(List<FbFishRunQgcVo> list, Date startTime, Date endTime, Page<?> page) {
if (page != null || startTime == null || endTime == null) {
return;
}
int startYear = Integer.parseInt(DateUtil.format(startTime, "yyyy"));
int endYear = Integer.parseInt(DateUtil.format(endTime, "yyyy"));
Set<String> existingYears = list.stream()
.filter(Objects::nonNull)
.map(FbFishRunQgcVo::getFlyr)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toCollection(LinkedHashSet::new));
for (int year = startYear; year <= endYear; year++) {
String yearText = String.valueOf(year);
if (existingYears.contains(yearText)) {
continue;
}
FbFishRunQgcVo vo = new FbFishRunQgcVo();
vo.setFlyr(yearText);
vo.setFcnt(0L);
vo.setTotalFcnt(0L);
list.add(vo);
}
list.sort(Comparator.comparing(FbFishRunQgcVo::getFlyr, Comparator.nullsLast(String::compareTo)));
}
private String buildFishTypeStcdListSql(String baseId, String sttpCode, Map<String, Object> paramMap) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT fb.STCD AS stcd, fb.STNM AS stnm, fb.LGTD AS lgtd, fb.LTTD AS lttd, fb.BASE_ID AS baseId ")