diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java index 71aeb46f..35fab7a8 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java @@ -1,9 +1,11 @@ package com.yfd.platform.qgc_env.fb.controller; +import com.yfd.platform.annotation.Log; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.qgc_env.fb.entity.vo.BreedStageVO; +import com.yfd.platform.qgc_env.fb.entity.vo.FbFishRunQgcDeleteParam; import com.yfd.platform.qgc_env.fb.service.FbStationService; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Operation; @@ -212,6 +214,14 @@ public class FbStationController { return ResponseResult.successData(fbStationService.getFishRunQgcKendoListCust(dataSourceRequest)); } + @Log(module = "鱼类增殖站模块", value = "删除全过程鱼类放鱼数据") + @PostMapping("/fishrun/qgc/removeFishRunQgcData") + @Operation(summary = "删除全过程鱼类放鱼数据(按站点+年份+鱼种)") + public ResponseResult removeFishRunQgcData(@RequestBody List params) { + fbStationService.removeFishRunQgcData(params); + return ResponseResult.success(); + } + @PostMapping("/fishType/GetKendoListCust") @Operation(summary = "增殖站鱼种完成情况统计") public ResponseResult getFishTypeKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FbFishRunQgcDeleteParam.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FbFishRunQgcDeleteParam.java new file mode 100644 index 00000000..9c8a6058 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FbFishRunQgcDeleteParam.java @@ -0,0 +1,25 @@ +package com.yfd.platform.qgc_env.fb.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 全过程鱼类放鱼数据删除参数(按 站点+年份+鱼种 维度删除) + */ +@Data +@Schema(description = "全过程鱼类放鱼数据删除参数") +public class FbFishRunQgcDeleteParam implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "电站站码") + private String stcd; + + @Schema(description = "放流年份 yyyy") + private String flyr; + + @Schema(description = "鱼种类:关联SD_FISHDICTORY_B.ID") + private String ftp; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java index da2ef0e6..a4b5bc41 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java @@ -21,6 +21,13 @@ public interface FbStationService { DataSourceResult getFishRunQgcKendoListCust(DataSourceRequest dataSourceRequest); + /** + * 批量删除全过程鱼类放鱼数据(按 站点+年份+鱼种 维度逻辑删除 SD_RPIMNFISH_R 明细) + * + * @param params 删除参数列表(stcd + flyr + ftp) + */ + boolean removeFishRunQgcData(List params); + DataSourceResult getFishTypeKendoListCust(DataSourceRequest dataSourceRequest); DataSourceResult getFishTypeStcdList(DataSourceRequest dataSourceRequest); diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java index 80f8b9b0..e49e5681 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java @@ -11,51 +11,19 @@ import com.yfd.platform.common.Group; import com.yfd.platform.common.GroupHelper; import com.yfd.platform.common.GroupingInfo; import com.yfd.platform.common.MicroservicDynamicSQLMapper; -import com.yfd.platform.qgc_env.fb.entity.vo.BreedStageVO; -import com.yfd.platform.qgc_env.fb.entity.vo.FbBsmfRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbBsdeathRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbBsctmoBVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbFbbwtRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbFbcwqRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbBsrfiRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbOutfishRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbFishartinlRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbFishhatchrecRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbFishhatchproRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbScwemRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbFishbreedRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbFishdpacRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbBsmfRQgcVo; -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; -import com.yfd.platform.qgc_env.fb.entity.vo.FbEngFishVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbFlDataVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbMsfbrdmQgcVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbRelatedYrVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbReleaseDirectionVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbResearchVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbStBaseInfoVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbStInfoResultVo; -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.FbStationStaticsRawVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FbTracingPointVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FishbreedRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.FishhatchrecRVo; -import com.yfd.platform.qgc_env.fb.entity.vo.HeadColunmsVo; -import com.yfd.platform.qgc_env.fb.entity.vo.TableVo; -import com.yfd.platform.qgc_env.fb.entity.vo.YearRpStatisticsVo; +import com.yfd.platform.qgc_env.fb.entity.vo.*; import com.yfd.platform.qgc_env.fb.service.FbStationService; import com.yfd.platform.qgc_env.wt.utils.SiteAvoidanceUtils; +import com.yfd.platform.qgc_base.domain.MsOperationLog; +import com.yfd.platform.qgc_base.domain.MsOperationLogDetail; +import com.yfd.platform.qgc_base.mapper.MsOperationLogDetailMapper; +import com.yfd.platform.qgc_base.mapper.MsOperationLogMapper; import com.yfd.platform.utils.QgcQueryWrapperUtil; +import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.*; import java.math.BigDecimal; @@ -68,6 +36,33 @@ public class FbStationServiceImpl implements FbStationService { @Resource private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; + @Resource + private JdbcTemplate jdbcTemplate; + + @Resource + private MsOperationLogMapper msOperationLogMapper; + + @Resource + private MsOperationLogDetailMapper msOperationLogDetailMapper; + + private static final String FISH_RUN_DETAIL_TABLE_NAME = "SD_RPIMNFISH_R"; + + private static final Map FISH_RUN_FIELD_MEANING_MAP = new HashMap<>(); + + static { + FISH_RUN_FIELD_MEANING_MAP.put("FTP", "鱼种类"); + FISH_RUN_FIELD_MEANING_MAP.put("FSZ", "平均长度"); + FISH_RUN_FIELD_MEANING_MAP.put("FWET", "平均体重"); + FISH_RUN_FIELD_MEANING_MAP.put("FCNT", "计划放殖鱼数量"); + FISH_RUN_FIELD_MEANING_MAP.put("TAGTE", "标记类型"); + FISH_RUN_FIELD_MEANING_MAP.put("TAGCNT", "标记数量"); + FISH_RUN_FIELD_MEANING_MAP.put("FAGE", "鱼龄"); + FISH_RUN_FIELD_MEANING_MAP.put("FID", "鱼类档案ID"); + FISH_RUN_FIELD_MEANING_MAP.put("PROTECTLVL", "保护等级"); + FISH_RUN_FIELD_MEANING_MAP.put("FA", "亲本来源"); + FISH_RUN_FIELD_MEANING_MAP.put("REMARK", "备注"); + } + @Override public List getYearRpStatistics(String year) { Map paramMap = new HashMap<>(); @@ -200,6 +195,123 @@ public class FbStationServiceImpl implements FbStationService { return result; } + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeFishRunQgcData(List params) { + if (CollUtil.isEmpty(params)) { + return true; + } + Set processed = new HashSet<>(); + for (FbFishRunQgcDeleteParam param : params) { + if (param == null || StrUtil.isBlank(param.getStcd()) + || StrUtil.isBlank(param.getFlyr()) || StrUtil.isBlank(param.getFtp())) { + continue; + } + String key = param.getStcd() + "|" + param.getFlyr() + "|" + param.getFtp(); + if (!processed.add(key)) { + continue; + } + List> beforeRows = queryFishRunDetailRows(param); + int deleteCount = jdbcTemplate.update( + "UPDATE SD_RPIMNFISH_R det " + + "SET det.IS_DELETED = 1, det.DELETE_USER = ?, det.DELETE_TIME = SYSDATE " + + "WHERE NVL(det.IS_DELETED, 0) = 0 " + + " AND det.FTP = ? " + + " AND det.RPIMN_ID IN ( " + + " SELECT run.ID FROM SD_ENGFR_R run " + + " WHERE NVL(run.IS_DELETED, 0) = 0 " + + " AND run.STCD = ? " + + " AND TO_CHAR(run.TM, 'YYYY') = ? )", + resolveLogOperator(), param.getFtp(), param.getStcd(), param.getFlyr() + ); + recordFishRunDeleteLog(beforeRows, param, deleteCount); + } + return true; + } + + private List> queryFishRunDetailRows(FbFishRunQgcDeleteParam param) { + String sql = "SELECT det.ID, det.RPIMN_ID, det.FTP, det.FSZ, det.FWET, det.FCNT, " + + "det.TAGTE, det.TAGCNT, det.FAGE, det.FID, det.PROTECTLVL, det.FA, det.REMARK " + + "FROM SD_RPIMNFISH_R det " + + "INNER JOIN SD_ENGFR_R run ON det.RPIMN_ID = run.ID AND NVL(run.IS_DELETED, 0) = 0 " + + "WHERE NVL(det.IS_DELETED, 0) = 0 " + + " AND det.FTP = ? AND run.STCD = ? AND TO_CHAR(run.TM, 'YYYY') = ?"; + List> rows = jdbcTemplate.queryForList(sql, param.getFtp(), param.getStcd(), param.getFlyr()); + List> normalized = new ArrayList<>(); + for (Map row : rows) { + normalized.add(normalizeFishRunLogRow(row)); + } + return normalized; + } + + private Map normalizeFishRunLogRow(Map row) { + Map normalized = new LinkedHashMap<>(); + if (row == null || row.isEmpty()) { + return normalized; + } + for (Map.Entry entry : row.entrySet()) { + normalized.put(entry.getKey() == null ? null : entry.getKey().toUpperCase(), entry.getValue()); + } + return normalized; + } + + private void recordFishRunDeleteLog(List> rows, FbFishRunQgcDeleteParam param, int deleteCount) { + if (CollUtil.isEmpty(rows)) { + return; + } + List details = new ArrayList<>(); + for (Map row : rows) { + MsOperationLog mainLog = new MsOperationLog(); + mainLog.setOperator(resolveLogOperator()); + mainLog.setRecordId(String.valueOf(row.get("ID"))); + mainLog.setOperateTime(new Date()); + mainLog.setTableName(FISH_RUN_DETAIL_TABLE_NAME); + mainLog.setRemark("删除全过程鱼类放鱼数据(站点:" + param.getStcd() + + ",年份:" + param.getFlyr() + ",删除条数:" + deleteCount + ")"); + msOperationLogMapper.insert(mainLog); + for (Map.Entry entry : row.entrySet()) { + if (StrUtil.isBlank(entry.getKey()) || entry.getValue() == null) { + continue; + } + MsOperationLogDetail detail = new MsOperationLogDetail(); + detail.setMainId(mainLog.getId()); + detail.setTableName(FISH_RUN_DETAIL_TABLE_NAME); + detail.setStationCode(param.getStcd()); + detail.setFieldCode(entry.getKey()); + detail.setFieldMeaning(FISH_RUN_FIELD_MEANING_MAP.getOrDefault(entry.getKey(), entry.getKey())); + detail.setOldValueCode(formatFishRunLogValue(entry.getValue())); + detail.setOldValueName(formatFishRunLogValue(entry.getValue())); + detail.setRemark("删除字段值"); + details.add(detail); + } + } + for (MsOperationLogDetail detail : details) { + msOperationLogDetailMapper.insert(detail); + } + } + + private String resolveLogOperator() { + try { + return SecurityUtils.getCurrentUsername(); + } catch (Exception ignored) { + try { + return SecurityUtils.getUserId(); + } catch (Exception ex) { + return null; + } + } + } + + private String formatFishRunLogValue(Object value) { + if (value == null) { + return null; + } + if (value instanceof Date date) { + return DateUtil.formatDateTime(date); + } + return String.valueOf(value); + } + @Override public DataSourceResult getFishTypeKendoListCust(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();