feat: 增殖站增殖情况(app)

This commit is contained in:
tangwei 2026-06-15 19:17:36 +08:00
parent afa40d0372
commit 21202f4160
4 changed files with 436 additions and 0 deletions

View File

@ -0,0 +1,29 @@
package com.yfd.platform.qgc_env.fb.controller;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_env.fb.service.FbStationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/fb/msfbrdm")
@Tag(name = "鱼类增殖站增殖情况")
@Validated
public class FbMsfbrdmController {
@Resource
private FbStationService fbStationService;
@PostMapping("/fbFlData/GetKendoListCust")
@Operation(summary = "增殖站增殖情况(app)")
public ResponseResult getFbFlData(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getFbFlDataKendoListCust(dataSourceRequest));
}
}

View File

@ -0,0 +1,39 @@
package com.yfd.platform.qgc_env.fb.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "增殖站增殖情况")
public class FbFlDataVo {
@Schema(description = "增殖站编码")
private String stcd;
@Schema(description = "增殖站名称")
private String stnm;
@Schema(description = "电站编码")
private String rstcd;
@Schema(description = "电站名称")
private String ennm;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "年份")
private String yr;
@Schema(description = "鱼类名称")
private String ftpName;
@Schema(description = "目标放鱼数量")
private Long targetFcnt;
@Schema(description = "实际放鱼数量")
private Long realFcnt;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_env.fb.service;
import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFlDataVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsDataVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsDataVo;
import com.yfd.platform.qgc_env.fb.entity.vo.YearRpStatisticsVo; import com.yfd.platform.qgc_env.fb.entity.vo.YearRpStatisticsVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbStationOverviewSecondVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationOverviewSecondVo;
@ -14,6 +15,8 @@ public interface FbStationService {
DataSourceResult<FbStationOverviewSecondVo> getOverviewKendoListCust(DataSourceRequest dataSourceRequest); DataSourceResult<FbStationOverviewSecondVo> getOverviewKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbFlDataVo> getFbFlDataKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbStationStaticsDataVo> getQgcFbStaticsData(DataSourceRequest dataSourceRequest); DataSourceResult<FbStationStaticsDataVo> getQgcFbStaticsData(DataSourceRequest dataSourceRequest);
DataSourceResult<FbStationOverviewSecondVo> getOverviewSecond(DataSourceRequest dataSourceRequest); DataSourceResult<FbStationOverviewSecondVo> getOverviewSecond(DataSourceRequest dataSourceRequest);

View File

@ -3,11 +3,15 @@ package com.yfd.platform.qgc_env.fb.service.impl;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceLoadOptionsBase; import com.yfd.platform.common.DataSourceLoadOptionsBase;
import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.common.GroupHelper;
import com.yfd.platform.common.GroupingInfo;
import com.yfd.platform.common.MicroservicDynamicSQLMapper; import com.yfd.platform.common.MicroservicDynamicSQLMapper;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFtpStatisticsVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbFtpStatisticsVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbFlDataVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbStationOverviewSecondVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationOverviewSecondVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsDataVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsDataVo;
import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsRawVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsRawVo;
@ -58,6 +62,16 @@ public class FbStationServiceImpl implements FbStationService {
return result; return result;
} }
@Override
public DataSourceResult<FbFlDataVo> getFbFlDataKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
GroupingInfo[] groups = loadOptions == null ? null : loadOptions.getGroup();
if (groups != null && groups.length > 0) {
return queryFbFlDataGroupList(dataSourceRequest, groups);
}
return queryFbFlDataDetailList(dataSourceRequest, loadOptions);
}
@Override @Override
public DataSourceResult<FbStationStaticsDataVo> getQgcFbStaticsData(DataSourceRequest dataSourceRequest) { public DataSourceResult<FbStationStaticsDataVo> getQgcFbStaticsData(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
@ -467,6 +481,357 @@ public class FbStationServiceImpl implements FbStationService {
return sql.toString(); return sql.toString();
} }
private DataSourceResult<FbFlDataVo> queryFbFlDataDetailList(DataSourceRequest dataSourceRequest,
DataSourceLoadOptionsBase loadOptions) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ")
.append(buildFbFlDataDetailSelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect()))
.append(" FROM (")
.append(buildFbFlDataCoreSql())
.append(") t WHERE 1 = 1 ");
Map<String, Object> paramMap = new HashMap<>();
String filterSql = buildFbFlDataFilterCondition(
dataSourceRequest == null ? null : dataSourceRequest.getFilter(),
paramMap,
new int[]{0}
);
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
sql.append(buildFbFlDataOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort()));
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<FbFlDataVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, FbFlDataVo.class);
DataSourceResult<FbFlDataVo> result = new DataSourceResult<>();
result.setData(list);
result.setTotal(page != null ? page.getTotal() : list.size());
result.setAggregates(new HashMap<>());
return result;
}
@SuppressWarnings({"rawtypes", "unchecked"})
private DataSourceResult<FbFlDataVo> queryFbFlDataGroupList(DataSourceRequest dataSourceRequest,
GroupingInfo[] groupInfos) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM (")
.append(buildFbFlDataCoreSql())
.append(") t WHERE 1 = 1 ");
Map<String, Object> paramMap = new HashMap<>();
String filterSql = buildFbFlDataFilterCondition(
dataSourceRequest == null ? null : dataSourceRequest.getFilter(),
paramMap,
new int[]{0}
);
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
String groupSql = buildFbFlDataGroupSql(sql.toString(), dataSourceRequest == null ? null : dataSourceRequest.getGroup());
List<Map<String, Object>> rows = microservicDynamicSQLMapper.pageAllList(null, groupSql, paramMap);
DataSourceResult<FbFlDataVo> result = new DataSourceResult<>();
if (Boolean.TRUE.equals(dataSourceRequest.getGroupResultFlat())) {
result.setData((List<FbFlDataVo>) (List<?>) new GroupHelper().faltGroup(rows, Arrays.asList(groupInfos)));
} else {
result.setData((List<FbFlDataVo>) (List<?>) new GroupHelper().group(rows, Arrays.asList(groupInfos)));
}
result.setTotal(0L);
result.setAggregates(new HashMap<>());
return result;
}
private String buildFbFlDataCoreSql() {
String planFishNameExpr = buildFishNameExpr("planDet.FTP");
String actualFishNameExpr = buildFishNameExpr("actualDet.FTP");
StringBuilder sql = new StringBuilder();
sql.append("SELECT fb.STCD AS stcd, ")
.append("fb.STNM AS stnm, ")
.append("fb.RSTCD AS rstcd, ")
.append("eng.ENNM AS ennm, ")
.append("fb.BASE_ID AS baseId, ")
.append("hb.BASENAME AS baseName, ")
.append("stat.YR AS yr, ")
.append("stat.FTPNAME AS ftpName, ")
.append("stat.TARGETFCNT AS targetFcnt, ")
.append("stat.REALFCNT AS realFcnt ")
.append("FROM SD_FBRD_B_H fb ")
.append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fb.RSTCD ")
.append(" AND NVL(eng.IS_DELETED, 0) = 0 ")
.append("LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = fb.BASE_ID ")
.append(" AND NVL(hb.IS_DELETED, 0) = 0 ")
.append(" AND NVL(hb.ENABLED, 1) = 1 ")
.append("LEFT JOIN (")
.append(" SELECT COALESCE(planAgg.STCD, actualAgg.STCD) AS STCD, ")
.append(" COALESCE(planAgg.YR, actualAgg.YR) AS YR, ")
.append(" COALESCE(planAgg.FTPNAME, actualAgg.FTPNAME) AS FTPNAME, ")
.append(" planAgg.TARGETFCNT AS TARGETFCNT, ")
.append(" actualAgg.REALFCNT AS REALFCNT ")
.append(" FROM (")
.append(" SELECT plan.RSTCD AS STCD, ")
.append(" TO_CHAR(plan.PLANSD, 'YYYY') AS YR, ")
.append(" ").append(planFishNameExpr).append(" AS FTPNAME, ")
.append(" SUM(planDet.FCNT) AS TARGETFCNT ")
.append(" FROM SD_ENGFRPLAN_B plan ")
.append(" INNER JOIN SD_ENGFRPLANDET_B planDet ON plan.ID = planDet.RPJH_ID ")
.append(" AND NVL(planDet.IS_DELETED, 0) = 0 ")
.append(" AND planDet.FTP IS NOT NULL ")
.append(" INNER JOIN SD_FBRD_B_H fbPlan ON fbPlan.STCD = plan.RSTCD ")
.append(buildFishJoinSql("planDet.FTP", "fbPlan.HBRVCD"))
.append(" WHERE NVL(plan.IS_DELETED, 0) = 0 ")
.append(" GROUP BY plan.RSTCD, TO_CHAR(plan.PLANSD, 'YYYY'), ").append(planFishNameExpr)
.append(" ) planAgg ")
.append(" FULL OUTER JOIN (")
.append(" SELECT run.RSTCD AS STCD, ")
.append(" TO_CHAR(run.TM, 'YYYY') AS YR, ")
.append(" ").append(actualFishNameExpr).append(" AS FTPNAME, ")
.append(" SUM(actualDet.FCNT) AS REALFCNT ")
.append(" FROM SD_ENGFR_R run ")
.append(" INNER JOIN SD_RPIMNFISH_R actualDet ON run.ID = actualDet.RPIMN_ID ")
.append(" AND NVL(actualDet.IS_DELETED, 0) = 0 ")
.append(" AND actualDet.FTP IS NOT NULL ")
.append(" INNER JOIN SD_FBRD_B_H fbRun ON fbRun.STCD = run.RSTCD ")
.append(buildFishJoinSql("actualDet.FTP", "fbRun.HBRVCD"))
.append(" WHERE NVL(run.IS_DELETED, 0) = 0 ")
.append(" GROUP BY run.RSTCD, TO_CHAR(run.TM, 'YYYY'), ").append(actualFishNameExpr)
.append(" ) actualAgg ")
.append(" ON planAgg.STCD = actualAgg.STCD ")
.append(" AND NVL(planAgg.YR, '~') = NVL(actualAgg.YR, '~') ")
.append(" AND NVL(planAgg.FTPNAME, '~') = NVL(actualAgg.FTPNAME, '~') ")
.append(") stat ON fb.STCD = stat.STCD");
return sql.toString();
}
private String buildFbFlDataDetailSelectSql(List<String> select) {
List<String> fields = CollUtil.isEmpty(select)
? List.of("stcd", "stnm", "rstcd", "ennm", "baseId", "baseName", "yr", "ftpName", "targetFcnt", "realFcnt")
: select;
List<String> selectParts = new ArrayList<>();
for (String field : fields) {
String column = mapFbFlDataColumn(field);
if (StrUtil.isNotBlank(column)) {
selectParts.add(column + " AS " + field);
}
}
if (selectParts.isEmpty()) {
selectParts.add("t.stcd AS stcd");
}
return String.join(", ", selectParts);
}
private String buildFbFlDataFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
if (filter == null) {
return "";
}
if (StrUtil.isNotBlank(filter.getField())) {
return buildFbFlDataLeafCondition(filter, paramMap, indexHolder);
}
if (CollUtil.isEmpty(filter.getFilters())) {
return "";
}
List<String> conditions = new ArrayList<>();
for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) {
String childSql = buildFbFlDataFilterCondition(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 buildFbFlDataLeafCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
String field = filter.getField();
String column = mapFbFlDataColumn(field);
if (StrUtil.isBlank(column)) {
return "";
}
String operator = StrUtil.blankToDefault(filter.getOperator(), "eq").toLowerCase();
Object value = filter.getValue();
if ("isnull".equals(operator)) {
return column + " IS NULL";
}
if ("isnotnull".equals(operator)) {
return column + " IS NOT NULL";
}
if ("in".equals(operator)) {
List<Object> values = normalizeFbFlDataValues(value);
if (values.isEmpty()) {
return "";
}
List<String> placeholders = new ArrayList<>();
for (Object item : values) {
String key = "fbFlDataP" + indexHolder[0]++;
paramMap.put(key, item);
placeholders.add("#{map." + key + "}");
}
return column + " IN (" + String.join(", ", placeholders) + ")";
}
if (value == null) {
return "";
}
String key = "fbFlDataP" + indexHolder[0]++;
return switch (operator) {
case "eq" -> {
paramMap.put(key, value);
yield column + " = #{map." + key + "}";
}
case "neq" -> {
paramMap.put(key, value);
yield column + " <> #{map." + key + "}";
}
case "contains" -> {
paramMap.put(key, "%" + value + "%");
yield column + " LIKE #{map." + key + "}";
}
case "startswith" -> {
paramMap.put(key, value + "%");
yield column + " LIKE #{map." + key + "}";
}
case "endswith" -> {
paramMap.put(key, "%" + value);
yield column + " LIKE #{map." + key + "}";
}
case "gt" -> {
paramMap.put(key, value);
yield column + " > #{map." + key + "}";
}
case "gte" -> {
paramMap.put(key, value);
yield column + " >= #{map." + key + "}";
}
case "lt" -> {
paramMap.put(key, value);
yield column + " < #{map." + key + "}";
}
case "lte" -> {
paramMap.put(key, value);
yield column + " <= #{map." + key + "}";
}
default -> "";
};
}
private String buildFbFlDataOrderBySql(List<DataSourceRequest.SortDescriptor> sortDescriptors) {
if (CollUtil.isEmpty(sortDescriptors)) {
return " ORDER BY t.baseId ASC, t.stcd ASC, t.yr ASC, t.ftpName ASC";
}
List<String> orderByParts = new ArrayList<>();
for (DataSourceRequest.SortDescriptor descriptor : sortDescriptors) {
if (descriptor == null || StrUtil.isBlank(descriptor.getField())) {
continue;
}
String column = mapFbFlDataColumn(descriptor.getField());
if (StrUtil.isBlank(column)) {
continue;
}
String direction = "desc".equalsIgnoreCase(descriptor.getDir()) ? "DESC" : "ASC";
orderByParts.add(column + " " + direction);
}
if (orderByParts.isEmpty()) {
return " ORDER BY t.baseId ASC, t.stcd ASC, t.yr ASC, t.ftpName ASC";
}
return " ORDER BY " + String.join(", ", orderByParts);
}
private String buildFbFlDataGroupSql(String baseSql, List<DataSourceRequest.GroupDescriptor> groups) {
if (CollUtil.isEmpty(groups)) {
return baseSql;
}
List<DataSourceRequest.GroupDescriptor> validGroups = groups.stream()
.filter(Objects::nonNull)
.filter(group -> StrUtil.isNotBlank(group.getField()))
.filter(group -> StrUtil.isNotBlank(mapFbFlDataColumn(group.getField())))
.toList();
if (validGroups.isEmpty()) {
return baseSql;
}
List<String> fields = validGroups.stream().map(DataSourceRequest.GroupDescriptor::getField).toList();
StringBuilder sql = new StringBuilder("SELECT ");
for (int i = 0; i < fields.size(); i++) {
if (i > 0) {
sql.append(", ");
}
sql.append(fields.get(i));
}
for (String field : fields) {
sql.append(", COUNT(*) AS count_").append(field);
}
sql.append(" FROM (").append(baseSql).append(") t GROUP BY ");
for (int i = 0; i < fields.size(); i++) {
if (i > 0) {
sql.append(", ");
}
sql.append(fields.get(i));
}
List<String> orderByParts = new ArrayList<>();
for (DataSourceRequest.GroupDescriptor descriptor : validGroups) {
if (Boolean.FALSE.equals(descriptor.getNeedSortFlag())) {
continue;
}
String direction = "desc".equalsIgnoreCase(descriptor.getDir()) ? "DESC" : "ASC";
orderByParts.add(descriptor.getField() + " " + direction);
}
if (!orderByParts.isEmpty()) {
sql.append(" ORDER BY ").append(String.join(", ", orderByParts));
}
return sql.toString();
}
private String mapFbFlDataColumn(String field) {
return switch (field) {
case "stcd" -> "t.stcd";
case "stnm" -> "t.stnm";
case "rstcd" -> "t.rstcd";
case "ennm" -> "t.ennm";
case "baseId" -> "t.baseId";
case "baseName" -> "t.baseName";
case "yr" -> "t.yr";
case "ftpName" -> "t.ftpName";
case "targetFcnt" -> "t.targetFcnt";
case "realFcnt" -> "t.realFcnt";
default -> "";
};
}
private List<Object> normalizeFbFlDataValues(Object value) {
List<Object> values = new ArrayList<>();
if (value == null) {
return values;
}
if (value instanceof Collection<?> collection) {
values.addAll(collection);
return values;
}
if (value instanceof Object[] array) {
values.addAll(Arrays.asList(array));
return values;
}
String text = String.valueOf(value).trim();
if (text.startsWith("[") && text.endsWith("]")) {
text = text.substring(1, text.length() - 1);
}
if (text.contains(",")) {
for (String item : text.split(",")) {
String trimmed = StrUtil.trim(item);
if (StrUtil.isNotBlank(trimmed)) {
values.add(trimmed);
}
}
return values;
}
values.add(value);
return values;
}
@Override @Override
public DataSourceResult<FbStationOverviewSecondVo> getQgcOverviewSecond(DataSourceRequest dataSourceRequest) { public DataSourceResult<FbStationOverviewSecondVo> getQgcOverviewSecond(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();