fix: 过鱼设施AI自动数据管理

This commit is contained in:
tangwei 2026-08-19 12:30:30 +08:00
parent 0164db2eb0
commit 4d214f1d03
5 changed files with 751 additions and 61 deletions

View File

@ -0,0 +1,314 @@
package com.yfd.platform.qgc_base.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_base.domain.SdEngInfoBHOperateRequest;
import com.yfd.platform.qgc_base.domain.SdFishDictoryB;
import com.yfd.platform.qgc_base.domain.SdFpssrlAiR;
import com.yfd.platform.qgc_base.domain.SdFpssrlRAiRequest;
import com.yfd.platform.qgc_base.service.ISdFishDictoryBService;
import com.yfd.platform.qgc_base.service.ISdFpssrlAiRService;
import com.yfd.platform.qgc_data.service.AttachmentUploadService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
* 过鱼设施AI盒子自动数据表 前端控制器
* </p>
*/
@Slf4j
@RestController
@RequestMapping("/base/fpssrlAiR")
@Tag(name = "过鱼设施AI自动数据管理")
public class SdFpssrlAiRController {
@Resource
private ISdFpssrlAiRService sdFpssrlAiRService;
@Resource
private ObjectMapper objectMapper;
@Resource
private AttachmentUploadService attachmentUploadService;
@Resource
private ISdFishDictoryBService sdFishDictoryBService;
// ==================== CRUD 方法 ====================
@PostMapping("/queryPageList")
@Operation(summary = "分页查询过鱼AI自动数据列表支持动态过滤和排序")
public ResponseResult queryPageList(@RequestBody DataSourceRequest request) {
Page<SdFpssrlAiR> page = sdFpssrlAiRService.queryPageList(request);
return ResponseResult.successData(page);
}
@GetMapping("/getById")
@Operation(summary = "根据ID查询过鱼AI自动数据")
public ResponseResult getById(@RequestParam String id) {
return ResponseResult.successData(sdFpssrlAiRService.getById(id));
}
@Log(module = "过鱼设施AI自动数据管理", value = "新增过鱼AI自动数据")
@PostMapping("/add")
@Operation(summary = "新增过鱼AI自动数据")
public ResponseResult add(@RequestParam("data") String dataStr,
@RequestParam(value = "picFiles", required = false) List<MultipartFile> picFiles,
@RequestParam(value = "vdFiles", required = false) List<MultipartFile> vdFiles) {
try {
SdEngInfoBHOperateRequest request = objectMapper.readValue(dataStr, SdEngInfoBHOperateRequest.class);
SdFpssrlAiR entity = request == null || request.getEngInfo() == null ? null
: objectMapper.convertValue(request.getEngInfo(), SdFpssrlAiR.class);
if (entity == null) {
return ResponseResult.error("数据不能为空");
}
// 上传附件并设置到实体图片firstImgUrl视频videoUrl
applyUploadedFiles(entity, picFiles, vdFiles);
boolean result = sdFpssrlAiRService.add(entity, request.getSource());
return result ? ResponseResult.success("新增成功") : ResponseResult.error("新增失败");
} catch (Exception e) {
log.error("新增过鱼AI自动数据失败", e);
return ResponseResult.error("新增失败: " + e.getMessage());
}
}
@Log(module = "过鱼设施AI自动数据管理", value = "修改过鱼AI自动数据")
@PostMapping("/update")
@Operation(summary = "修改过鱼AI自动数据")
public ResponseResult update(@RequestParam("data") String dataStr,
@RequestParam(value = "picFiles", required = false) List<MultipartFile> picFiles,
@RequestParam(value = "vdFiles", required = false) List<MultipartFile> vdFiles) {
try {
SdEngInfoBHOperateRequest request = objectMapper.readValue(dataStr, SdEngInfoBHOperateRequest.class);
Map<String, Object> engInfo = request == null ? null : request.getEngInfo();
if (engInfo == null || engInfo.get("id") == null) {
return ResponseResult.error("数据或ID不能为空");
}
// 获取修改前的实体用于后续清理被替换的旧附件
SdFpssrlAiR before = sdFpssrlAiRService.getById((String) engInfo.get("id"));
List<String> oldAttachmentIds = before != null ? collectAttachmentIds(before) : Collections.emptyList();
// 上传新附件并合并回 patch map仅当本次有文件上传时才覆盖对应字段
SdFpssrlAiR tempEntity = objectMapper.convertValue(engInfo, SdFpssrlAiR.class);
applyUploadedFiles(tempEntity, picFiles, vdFiles);
if (picFiles != null && !picFiles.isEmpty()) {
engInfo.put("firstimgurl", tempEntity.getFirstImgUrl());
}
if (vdFiles != null && !vdFiles.isEmpty()) {
engInfo.put("videourl", tempEntity.getVideoUrl());
}
boolean result = sdFpssrlAiRService.update(engInfo, request.getSource());
if (result) {
// 清理被替换的旧附件
SdFpssrlAiR after = sdFpssrlAiRService.getById((String) engInfo.get("id"));
deleteReplacedFiles(oldAttachmentIds, collectAttachmentIds(after));
}
return result ? ResponseResult.success("修改成功") : ResponseResult.error("修改失败");
} catch (Exception e) {
log.error("修改过鱼AI自动数据失败", e);
return ResponseResult.error("修改失败: " + e.getMessage());
}
}
@Log(module = "过鱼设施AI自动数据管理", value = "删除过鱼AI自动数据")
@PostMapping("/delete")
@Operation(summary = "删除过鱼AI自动数据")
public ResponseResult delete(@RequestBody SdEngInfoBHOperateRequest request) {
List<String> ids = request == null ? null : request.getIds();
if (ids == null || ids.isEmpty()) {
return ResponseResult.error("ID不能为空");
}
// 删除前先收集所有需要清理的附件ID
List<String> allAttachmentIds = new ArrayList<>();
for (String id : ids) {
SdFpssrlAiR entity = sdFpssrlAiRService.getById(id);
if (entity != null) {
allAttachmentIds.addAll(collectAttachmentIds(entity));
}
}
boolean result = sdFpssrlAiRService.delete(ids, request.getSource());
if (result) {
// 删除关联的附件
deleteAttachments(allAttachmentIds);
}
return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败");
}
// ==================== AI 设备识别数据上报接口 ====================
/**
* AI设备图片/视频上传接口
* 步骤1先上传图片获取附件URL再将URL填入数据上报接口
*/
@PostMapping("/ai/uploadImage")
@Operation(summary = "AI设备图片上传")
public ResponseResult aiUploadImage(@RequestParam("file") MultipartFile file) {
if (file == null || file.isEmpty()) {
return ResponseResult.error("文件不能为空");
}
try {
List<MultipartFile> files = new ArrayList<>();
files.add(file);
List<String> attachmentIds = attachmentUploadService.uploadMultipartFiles(files);
if (attachmentIds != null && !attachmentIds.isEmpty()) {
return ResponseResult.successData(attachmentIds);
} else {
return ResponseResult.error("图片上传失败");
}
} catch (Exception e) {
log.error("AI图片上传失败", e);
return ResponseResult.error("图片上传失败: " + e.getMessage());
}
}
/**
* AI设备识别数据上报接口支持单条和批量
* 步骤2上传完图片后将附件ID填入JSON数组调用此接口
*/
@PostMapping("/ai/report")
@Operation(summary = "AI设备识别数据上报支持批量")
public ResponseResult aiReport(@RequestBody List<SdFpssrlRAiRequest> requests) {
if (requests == null || requests.isEmpty()) {
return ResponseResult.error("请求数据不能为空");
}
List<SdFishDictoryB> list = sdFishDictoryBService.list(new LambdaQueryWrapper<SdFishDictoryB>().eq(SdFishDictoryB::getIsDeleted, "0").select(SdFishDictoryB::getId, SdFishDictoryB::getName));
Map<String, String> idNameMap = list.stream()
.filter(item -> item.getId() != null && item.getName() != null)
.collect(Collectors.toMap(
SdFishDictoryB::getName,
SdFishDictoryB::getId,
(oldValue, newValue) -> oldValue // 如果有重复 key 保留旧值实际不会重复
));
// 逐条校验
for (int i = 0; i < requests.size(); i++) {
SdFpssrlRAiRequest req = requests.get(i);
if (req == null) {
return ResponseResult.error("" + (i + 1) + "条数据为空");
}
if (req.getStcd() == null || req.getStcd().isEmpty()) {
return ResponseResult.error("" + (i + 1) + "条过鱼设施编码(stcd)不能为空");
}
if (req.getFwdx() == null || req.getFwdx().isEmpty()) {
return ResponseResult.error("" + (i + 1) + "条服务对象(fwdx)不能为空");
}
if (req.getTm() == null) {
return ResponseResult.error("" + (i + 1) + "条识别时间(tm)不能为空");
}
if (req.getFtp() == null || req.getFtp().isEmpty()) {
return ResponseResult.error("" + (i + 1) + "条鱼种类(ftp)不能为空");
}
if (StrUtil.isNotBlank(req.getFtp())) {
req.setFtp(idNameMap.getOrDefault(req.getFtp(), req.getFtp()));
}
}
try {
List<SdFpssrlAiR> result = sdFpssrlAiRService.processAiReportBatch(requests);
log.info("AI批量上报成功共{}条", result.size());
return ResponseResult.success();
} catch (Exception e) {
log.error("AI识别数据批量上报失败", e);
return ResponseResult.error("上报失败: " + e.getMessage());
}
}
// ==================== 附件处理辅助方法 ====================
/**
* 上传图片/视频附件并追加附件ID到 firstImgUrl/videoUrl 字段与已有ID以逗号拼接
*/
private void applyUploadedFiles(SdFpssrlAiR entity, List<MultipartFile> picFiles, List<MultipartFile> vdFiles) {
if (picFiles != null && !picFiles.isEmpty()) {
List<String> ids = attachmentUploadService.uploadMultipartFiles(picFiles);
if (!ids.isEmpty()) {
entity.setFirstImgUrl(mergeIds(entity.getFirstImgUrl(), ids));
}
}
if (vdFiles != null && !vdFiles.isEmpty()) {
List<String> ids = attachmentUploadService.uploadMultipartFiles(vdFiles);
if (!ids.isEmpty()) {
entity.setVideoUrl(mergeIds(entity.getVideoUrl(), ids));
}
}
}
/**
* 将新上传的附件ID列表追加到已有ID字符串后面逗号分隔
*/
private String mergeIds(String existing, List<String> ids) {
String newIds = ids.stream()
.filter(StrUtil::isNotBlank)
.collect(Collectors.joining(","));
if (StrUtil.isBlank(newIds)) {
return existing;
}
return StrUtil.isBlank(existing) ? newIds : existing + "," + newIds;
}
/**
* 收集实体中 firstImgUrl/videoUrl 字段的附件ID
*/
private List<String> collectAttachmentIds(SdFpssrlAiR entity) {
List<String> ids = new ArrayList<>();
if (entity == null) {
return ids;
}
if (StrUtil.isNotBlank(entity.getFirstImgUrl())) {
Arrays.stream(entity.getFirstImgUrl().split(","))
.map(String::trim)
.filter(StrUtil::isNotBlank)
.forEach(ids::add);
}
if (StrUtil.isNotBlank(entity.getVideoUrl())) {
Arrays.stream(entity.getVideoUrl().split(","))
.map(String::trim)
.filter(StrUtil::isNotBlank)
.forEach(ids::add);
}
return ids;
}
/**
* 删除被替换的旧附件old中有但new中没有的
*/
private void deleteReplacedFiles(List<String> oldIds, List<String> newIds) {
for (String oldId : oldIds) {
if (StrUtil.isBlank(oldId)) {
continue;
}
if (!newIds.contains(oldId)) {
attachmentUploadService.deleteFile(oldId);
}
}
}
/**
* 批量删除附件
*/
private void deleteAttachments(List<String> attachmentIds) {
for (String id : attachmentIds) {
if (StrUtil.isNotBlank(id)) {
attachmentUploadService.deleteFile(id);
}
}
}
}

View File

@ -115,6 +115,10 @@ public class SdFpssrlAiR implements Serializable {
/** 备注 */
private String remark;
/** 鱼种类名称(非表字段,用于列表展示) */
@TableField(exist = false)
private String ftpName;
/** 过鱼设施名称(非表字段,用于列表展示) */
@TableField(exist = false)
private String stnm;

View File

@ -0,0 +1,48 @@
package com.yfd.platform.qgc_base.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.qgc_base.domain.SdFpssrlAiR;
import com.yfd.platform.qgc_base.domain.SdFpssrlRAiRequest;
import java.util.List;
import java.util.Map;
/**
* <p>
* 过鱼设施AI盒子自动数据表 服务接口
* </p>
*/
public interface ISdFpssrlAiRService extends IService<SdFpssrlAiR> {
/**
* 分页查询Kendo Grid
*/
Page<SdFpssrlAiR> queryPageList(DataSourceRequest request);
/**
* 新增
*/
boolean add(SdFpssrlAiR entity, String source);
/**
* 修改按前端 patch 显式更新字段 null 置空
*/
boolean update(Map<String, Object> engInfoPatch, String source) throws Exception;
/**
* 删除逻辑删除
*/
boolean delete(List<String> ids, String source);
/**
* 根据ID查询排除已删除的
*/
SdFpssrlAiR getById(String id);
/**
* 批量处理AI设备上报的识别数据
*/
List<SdFpssrlAiR> processAiReportBatch(List<SdFpssrlRAiRequest> requests);
}

View File

@ -0,0 +1,153 @@
package com.yfd.platform.qgc_base.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.qgc_base.domain.SdFpssrlAiR;
import com.yfd.platform.qgc_base.domain.SdFpssrlRAiRequest;
import com.yfd.platform.qgc_base.mapper.SdFpssrlAiRMapper;
import com.yfd.platform.qgc_base.service.IMsOperationLogService;
import com.yfd.platform.qgc_base.service.ISdFpssrlAiRService;
import com.yfd.platform.utils.CodeToNameMetadataBo;
import com.yfd.platform.utils.DataSourceRequestUtil;
import com.yfd.platform.utils.DictCodeToNameConverter;
import com.yfd.platform.utils.SecurityUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* <p>
* 过鱼设施AI盒子自动数据表 服务实现类
* </p>
*/
@Slf4j
@Service
public class SdFpssrlAiRServiceImpl extends ServiceImpl<SdFpssrlAiRMapper, SdFpssrlAiR> implements ISdFpssrlAiRService {
private static final String TABLE_NAME = "SD_FPSSRL_AI_R";
@Resource
private IMsOperationLogService msOperationLogService;
@Resource
private DictCodeToNameConverter dictCodeToNameConverter;
@Resource
private PatchUpdateHelper patchUpdateHelper;
private static final Set<String> TRANSIENT_FIELDS = Set.of("stnm", "ftpName", "serialVersionUID");
/**
* 代码转名称元数据配置列表
*/
private static final List<CodeToNameMetadataBo> CODE_TO_NAME_META_LIST = new ArrayList<>();
static {
CODE_TO_NAME_META_LIST.add(CodeToNameMetadataBo.builder().codeProperty("ftp").modifyProperty("ftpName")
.dictType("DYNAMIC").dictSource("SD_FISHDICTORY_B").codeColumn("ID").nameColumn("NAME")
.filter("NVL(IS_DELETED, 0) = 0 AND NVL(ENABLE, 1) = 1").build());
}
@Override
public Page<SdFpssrlAiR> queryPageList(DataSourceRequest request) {
return DataSourceRequestUtil.executeQuery(request, SdFpssrlAiR.class, this);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean add(SdFpssrlAiR entity, String source) {
boolean result = this.save(entity);
if (result) {
dictCodeToNameConverter.convertCodeToName(entity, CODE_TO_NAME_META_LIST);
msOperationLogService.recordAddDetailLog(entity.getId(), TABLE_NAME, entity, source, CODE_TO_NAME_META_LIST);
}
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean update(Map<String, Object> engInfoPatch, String source) throws Exception {
return patchUpdateHelper.execute(this, engInfoPatch, source, TABLE_NAME, SdFpssrlAiR.class,
TRANSIENT_FIELDS, CODE_TO_NAME_META_LIST, "id");
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean delete(List<String> ids, String source) {
if (ids == null || ids.isEmpty()) return false;
int count = 0;
for (String id : ids) {
SdFpssrlAiR entity = getById(id);
LambdaUpdateWrapper<SdFpssrlAiR> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(SdFpssrlAiR::getId, id);
wrapper.set(SdFpssrlAiR::getIsDeleted, 1);
wrapper.set(SdFpssrlAiR::getDeleteUser, SecurityUtils.getCurrentUsername());
wrapper.set(SdFpssrlAiR::getDeleteTime, new Date());
if (this.update(wrapper)) {
msOperationLogService.recordDeleteDetailLog(id, TABLE_NAME, entity, source);
count++;
}
}
return count > 0;
}
@Override
public SdFpssrlAiR getById(String id) {
LambdaQueryWrapper<SdFpssrlAiR> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFpssrlAiR::getId, id)
.eq(SdFpssrlAiR::getIsDeleted, 0);
return getOne(wrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public List<SdFpssrlAiR> processAiReportBatch(List<SdFpssrlRAiRequest> requests) {
List<SdFpssrlAiR> entities = new ArrayList<>();
Date now = new Date();
for (SdFpssrlRAiRequest req : requests) {
SdFpssrlAiR entity = new SdFpssrlAiR();
entity.setStcd(req.getFwdx());
entity.setAiBoxCode(req.getStcd());
entity.setTm(req.getTm());
entity.setFtp(req.getFtp());
entity.setFcnt(req.getFcnt() != null ? req.getFcnt() : 1);
entity.setFsz(req.getFsz());
entity.setLength(req.getLength());
entity.setWidth(req.getWidth());
entity.setFishspeed(req.getFishspeed());
entity.setDirection(req.getDirection());
entity.setFishposition(req.getFishposition());
entity.setFirstImgUrl(req.getFirstImgUrl());
entity.setSecondImgUrl(req.getSecondImgUrl());
entity.setVideoUrl(req.getVideoUrl());
entity.setTemperature(req.getTemperature());
entity.setWaterlevel(req.getWaterlevel());
entity.setSpeed(req.getSpeed());
entity.setQ(req.getQ());
entity.setDox(req.getDox());
entity.setTu(req.getTu());
entity.setChannelno(StrUtil.isNotBlank(req.getChannelno()) ? req.getChannelno() : "主通道");
entity.setFid(req.getFid());
entity.setRemark(req.getRemark());
entity.setRecordUser("AI_SYSTEM");
entity.setRecordTime(now);
entity.setModifyUser("AI_SYSTEM");
entity.setModifyTime(now);
entity.setIsDeleted(0);
entities.add(entity);
}
this.baseMapper.mergeFishRecords(entities);
return entities;
}
}

View File

@ -1232,7 +1232,7 @@ public class FpRunServiceImpl implements FpRunService {
DataSourceLoadOptionsBase loadOptions) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ")
.append(buildQgcFpssrlDetailSelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect()))
.append(buildQgcFpssrlDetailAISelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect()))
.append(" FROM (")
.append(buildQgcFpssrlAiRCoreSql())
.append(") t WHERE 1 = 1 ");
@ -1704,12 +1704,12 @@ public class FpRunServiceImpl implements FpRunService {
") src";
}
private String buildQgcFpssrlAiRCoreSql() {
return "SELECT " +
"src.ID AS id, " +
"src.STCD AS stcd, " +
"src.STNM AS stnm, " +
"src.ISFS AS isfs, " +
"src.BASEID AS baseId, " +
"src.BASENAME AS baseName, " +
"src.RSTCD AS rstcd, " +
@ -1729,6 +1729,12 @@ public class FpRunServiceImpl implements FpRunService {
"src.FISHSPEED AS fishspeed, " +
"src.DIRECTION AS direction, " +
"src.TEMPERATURE AS temperature, " +
"src.WATERLEVEL AS waterlevel, " +
"src.FISHPOSITION AS fishposition, " +
"src.REMARK AS remark, " +
"src.DOX AS dox, " +
"src.Q AS q, " +
"src.TU AS tu, " +
"src.SPEED AS speed, " +
"src.CHANNELNO AS channelno, " +
"src.FCNT AS fcnt, " +
@ -1757,11 +1763,18 @@ public class FpRunServiceImpl implements FpRunService {
" COALESCE(fishRv.NAME, relRv.FISH_NAME, fishZy.NAME, relZy.FISH_NAME, fishDirect.NAME, t.FTP) AS FTP, " +
" t.FTP AS FISHID, " +
" t.FSZ AS FSZ, " +
" null AS ISFS, " +
" TO_CHAR(t.LENGTH) AS LENGTH, " +
" TO_CHAR(t.WIDTH) AS WIDTH, " +
" TO_CHAR(t.FISHSPEED) AS FISHSPEED, " +
" TO_CHAR(t.DIRECTION) AS DIRECTION, " +
" TO_CHAR(t.TEMPERATURE) AS TEMPERATURE, " +
" TO_CHAR(t.WATERLEVEL) AS WATERLEVEL, " +
" TO_CHAR(t.FISHPOSITION) AS FISHPOSITION, " +
" TO_CHAR(t.REMARK) AS REMARK, " +
" TO_CHAR(t.DOX) AS DOX, " +
" TO_CHAR(t.Q) AS Q, " +
" TO_CHAR(t.TU) AS TU, " +
" TO_CHAR(t.SPEED) AS SPEED, " +
" t.CHANNELNO AS CHANNELNO, " +
" TO_CHAR(t.FCNT) AS FCNT, " +
@ -1773,64 +1786,6 @@ public class FpRunServiceImpl implements FpRunService {
" fp.STTP AS STCODE, " +
" sttp.STTP_NAME AS STNAME " +
" FROM SD_FPSSRL_AI_R t " +
" INNER JOIN V_MS_STBPRP_T fp ON fp.STCD = t.STCD " +
" LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = fp.STTP AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " +
" LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
" LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " +
" LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = eng.HBRVCD " +
" AND hbrv.BASEID = eng.BASE_ID " +
" AND NVL(hbrv.IS_DELETED, 0) = 0 " +
" AND NVL(hbrv.ENABLED, 1) = 1 " +
" LEFT JOIN SD_FISHDICTORY_RLTN_B relRv ON relRv.FISH_ID = t.FTP " +
" AND relRv.RVCD = eng.HBRVCD " +
" AND NVL(relRv.IS_DELETED, 0) = 0 " +
" LEFT JOIN SD_FISHDICTORY_B fishRv ON fishRv.ID = relRv.ZY_FISH_ID " +
" AND NVL(fishRv.IS_DELETED, 0) = 0 " +
" AND NVL(fishRv.ENABLE, 1) = 1 " +
" LEFT JOIN SD_FISHDICTORY_RLTN_B relZy ON relZy.FISH_ID = t.FTP " +
" AND relZy.RVCD = 'ZY' " +
" AND NVL(relZy.IS_DELETED, 0) = 0 " +
" LEFT JOIN SD_FISHDICTORY_B fishZy ON fishZy.ID = relZy.ZY_FISH_ID " +
" AND NVL(fishZy.IS_DELETED, 0) = 0 " +
" AND NVL(fishZy.ENABLE, 1) = 1 " +
" LEFT JOIN SD_FISHDICTORY_B fishDirect ON fishDirect.ID = t.FTP " +
" AND NVL(fishDirect.IS_DELETED, 0) = 0 " +
" AND NVL(fishDirect.ENABLE, 1) = 1 " +
" WHERE NVL(t.IS_DELETED, 0) = 0 " +
" UNION ALL " +
" SELECT t.ID AS ID, " +
" t.STCD AS STCD, " +
" fp.STNM AS STNM, " +
" eng.BASE_ID AS BASEID, " +
" hb.BASENAME AS BASENAME, " +
" fp.RSTCD AS RSTCD, " +
" eng.ENNM AS ENNM, " +
" eng.HBRVCD AS HBRVCD, " +
" NVL(hb.ORDER_INDEX, 999999) AS BASESTEPSORT, " +
" NVL(hbrv.ORDER_INDEX, 999999) AS RVCDSTEPSORT, " +
" NVL(fp.ORDER_INDEX, 999999) AS SITESTEPSORT, " +
" NVL(eng.ORDER_INDEX, 999999) AS RSTCDSTEPSORT, " +
" t.STRDT AS TM, " +
" TO_CHAR(t.STRDT, 'YYYY') AS YR, " +
" COALESCE(fishRv.NAME, relRv.FISH_NAME, fishZy.NAME, relZy.FISH_NAME, fishDirect.NAME, t.FTP) AS FTP, " +
" t.FTP AS FISHID, " +
" t.FSZ AS FSZ, " +
" CAST(NULL AS VARCHAR2(50)) AS LENGTH, " +
" CAST(NULL AS VARCHAR2(50)) AS WIDTH, " +
" CAST(NULL AS VARCHAR2(50)) AS FISHSPEED, " +
" TO_CHAR(t.DIRECTION) AS DIRECTION, " +
" CAST(NULL AS VARCHAR2(50)) AS TEMPERATURE, " +
" CAST(NULL AS VARCHAR2(50)) AS SPEED, " +
" CAST(NULL AS VARCHAR2(100)) AS CHANNELNO, " +
" TO_CHAR(t.FCNT) AS FCNT, " +
" t.PICPTH AS FIRSTIMGURL, " +
" t.VDPTH AS VIDEOURL, " +
" 1 AS MWAY, " +
" t.STRDT AS STRDT, " +
" t.ENDDT AS ENDDT, " +
" fp.STTP AS STCODE, " +
" sttp.STTP_NAME AS STNAME " +
" FROM SD_FPSS_R t " +
" INNER JOIN SD_FPSS_B_H fp ON fp.STCD = t.STCD " +
" LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = fp.STTP AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " +
" LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
@ -1855,10 +1810,164 @@ public class FpRunServiceImpl implements FpRunService {
" AND NVL(fishDirect.IS_DELETED, 0) = 0 " +
" AND NVL(fishDirect.ENABLE, 1) = 1 " +
" WHERE NVL(t.IS_DELETED, 0) = 0 " +
// " AND (t.TASK_STATUS = 'Approved' OR t.TASK_STATUS IS NULL) " +
") src";
}
// private String buildQgcFpssrlAiRCoreSql() {
// return "SELECT " +
// "src.ID AS id, " +
// "src.STCD AS stcd, " +
// "src.STNM AS stnm, " +
// "src.BASEID AS baseId, " +
// "src.BASENAME AS baseName, " +
// "src.RSTCD AS rstcd, " +
// "src.ENNM AS ennm, " +
// "src.HBRVCD AS hbrvcd, " +
// "src.BASESTEPSORT AS baseStepSort, " +
// "src.RVCDSTEPSORT AS rvcdStepSort, " +
// "src.SITESTEPSORT AS siteStepSort, " +
// "src.RSTCDSTEPSORT AS rstcdStepSort, " +
// "src.TM AS tm, " +
// "src.YR AS yr, " +
// "src.FTP AS ftp, " +
// "src.FISHID AS fishId, " +
// "src.FSZ AS fsz, " +
// "src.LENGTH AS length, " +
// "src.WIDTH AS width, " +
// "src.FISHSPEED AS fishspeed, " +
// "src.DIRECTION AS direction, " +
// "src.TEMPERATURE AS temperature, " +
// "src.SPEED AS speed, " +
// "src.CHANNELNO AS channelno, " +
// "src.FCNT AS fcnt, " +
// "src.FIRSTIMGURL AS firstimgurl, " +
// "src.VIDEOURL AS videourl, " +
// "src.MWAY AS mway, " +
// "src.STRDT AS strdt, " +
// "src.ENDDT AS enddt, " +
// "src.STCODE AS stCode, " +
// "src.STNAME AS stName " +
// "FROM ( " +
// " SELECT t.ID AS ID, " +
// " t.STCD AS STCD, " +
// " fp.STNM AS STNM, " +
// " eng.BASE_ID AS BASEID, " +
// " hb.BASENAME AS BASENAME, " +
// " fp.RSTCD AS RSTCD, " +
// " eng.ENNM AS ENNM, " +
// " eng.HBRVCD AS HBRVCD, " +
// " NVL(hb.ORDER_INDEX, 999999) AS BASESTEPSORT, " +
// " NVL(hbrv.ORDER_INDEX, 999999) AS RVCDSTEPSORT, " +
// " NVL(fp.ORDER_INDEX, 999999) AS SITESTEPSORT, " +
// " NVL(eng.ORDER_INDEX, 999999) AS RSTCDSTEPSORT, " +
// " t.TM AS TM, " +
// " TO_CHAR(t.TM, 'YYYY') AS YR, " +
// " COALESCE(fishRv.NAME, relRv.FISH_NAME, fishZy.NAME, relZy.FISH_NAME, fishDirect.NAME, t.FTP) AS FTP, " +
// " t.FTP AS FISHID, " +
// " t.FSZ AS FSZ, " +
// " TO_CHAR(t.LENGTH) AS LENGTH, " +
// " TO_CHAR(t.WIDTH) AS WIDTH, " +
// " TO_CHAR(t.FISHSPEED) AS FISHSPEED, " +
// " TO_CHAR(t.DIRECTION) AS DIRECTION, " +
// " TO_CHAR(t.TEMPERATURE) AS TEMPERATURE, " +
// " TO_CHAR(t.SPEED) AS SPEED, " +
// " t.CHANNELNO AS CHANNELNO, " +
// " TO_CHAR(t.FCNT) AS FCNT, " +
// " t.FIRSTIMGURL AS FIRSTIMGURL, " +
// " t.VIDEOURL AS VIDEOURL, " +
// " 2 AS MWAY, " +
// " CAST(NULL AS DATE) AS STRDT, " +
// " CAST(NULL AS DATE) AS ENDDT, " +
// " fp.STTP AS STCODE, " +
// " sttp.STTP_NAME AS STNAME " +
// " FROM SD_FPSSRL_AI_R t " +
// " INNER JOIN V_MS_STBPRP_T fp ON fp.STCD = t.STCD " +
// " LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = fp.STTP AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " +
// " LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
// " LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " +
// " LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = eng.HBRVCD " +
// " AND hbrv.BASEID = eng.BASE_ID " +
// " AND NVL(hbrv.IS_DELETED, 0) = 0 " +
// " AND NVL(hbrv.ENABLED, 1) = 1 " +
// " LEFT JOIN SD_FISHDICTORY_RLTN_B relRv ON relRv.FISH_ID = t.FTP " +
// " AND relRv.RVCD = eng.HBRVCD " +
// " AND NVL(relRv.IS_DELETED, 0) = 0 " +
// " LEFT JOIN SD_FISHDICTORY_B fishRv ON fishRv.ID = relRv.ZY_FISH_ID " +
// " AND NVL(fishRv.IS_DELETED, 0) = 0 " +
// " AND NVL(fishRv.ENABLE, 1) = 1 " +
// " LEFT JOIN SD_FISHDICTORY_RLTN_B relZy ON relZy.FISH_ID = t.FTP " +
// " AND relZy.RVCD = 'ZY' " +
// " AND NVL(relZy.IS_DELETED, 0) = 0 " +
// " LEFT JOIN SD_FISHDICTORY_B fishZy ON fishZy.ID = relZy.ZY_FISH_ID " +
// " AND NVL(fishZy.IS_DELETED, 0) = 0 " +
// " AND NVL(fishZy.ENABLE, 1) = 1 " +
// " LEFT JOIN SD_FISHDICTORY_B fishDirect ON fishDirect.ID = t.FTP " +
// " AND NVL(fishDirect.IS_DELETED, 0) = 0 " +
// " AND NVL(fishDirect.ENABLE, 1) = 1 " +
// " WHERE NVL(t.IS_DELETED, 0) = 0 " +
//// " UNION ALL " +
//// " SELECT t.ID AS ID, " +
//// " t.STCD AS STCD, " +
//// " fp.STNM AS STNM, " +
//// " eng.BASE_ID AS BASEID, " +
//// " hb.BASENAME AS BASENAME, " +
//// " fp.RSTCD AS RSTCD, " +
//// " eng.ENNM AS ENNM, " +
//// " eng.HBRVCD AS HBRVCD, " +
//// " NVL(hb.ORDER_INDEX, 999999) AS BASESTEPSORT, " +
//// " NVL(hbrv.ORDER_INDEX, 999999) AS RVCDSTEPSORT, " +
//// " NVL(fp.ORDER_INDEX, 999999) AS SITESTEPSORT, " +
//// " NVL(eng.ORDER_INDEX, 999999) AS RSTCDSTEPSORT, " +
//// " t.STRDT AS TM, " +
//// " TO_CHAR(t.STRDT, 'YYYY') AS YR, " +
//// " COALESCE(fishRv.NAME, relRv.FISH_NAME, fishZy.NAME, relZy.FISH_NAME, fishDirect.NAME, t.FTP) AS FTP, " +
//// " t.FTP AS FISHID, " +
//// " t.FSZ AS FSZ, " +
//// " CAST(NULL AS VARCHAR2(50)) AS LENGTH, " +
//// " CAST(NULL AS VARCHAR2(50)) AS WIDTH, " +
//// " CAST(NULL AS VARCHAR2(50)) AS FISHSPEED, " +
//// " TO_CHAR(t.DIRECTION) AS DIRECTION, " +
//// " CAST(NULL AS VARCHAR2(50)) AS TEMPERATURE, " +
//// " CAST(NULL AS VARCHAR2(50)) AS SPEED, " +
//// " CAST(NULL AS VARCHAR2(100)) AS CHANNELNO, " +
//// " TO_CHAR(t.FCNT) AS FCNT, " +
//// " t.PICPTH AS FIRSTIMGURL, " +
//// " t.VDPTH AS VIDEOURL, " +
//// " 1 AS MWAY, " +
//// " t.STRDT AS STRDT, " +
//// " t.ENDDT AS ENDDT, " +
//// " fp.STTP AS STCODE, " +
//// " sttp.STTP_NAME AS STNAME " +
//// " FROM SD_FPSS_R t " +
//// " INNER JOIN SD_FPSS_B_H fp ON fp.STCD = t.STCD " +
//// " LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = fp.STTP AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " +
//// " LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
//// " LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " +
//// " LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = eng.HBRVCD " +
//// " AND hbrv.BASEID = eng.BASE_ID " +
//// " AND NVL(hbrv.IS_DELETED, 0) = 0 " +
//// " AND NVL(hbrv.ENABLED, 1) = 1 " +
//// " LEFT JOIN SD_FISHDICTORY_RLTN_B relRv ON relRv.FISH_ID = t.FTP " +
//// " AND relRv.RVCD = eng.HBRVCD " +
//// " AND NVL(relRv.IS_DELETED, 0) = 0 " +
//// " LEFT JOIN SD_FISHDICTORY_B fishRv ON fishRv.ID = relRv.ZY_FISH_ID " +
//// " AND NVL(fishRv.IS_DELETED, 0) = 0 " +
//// " AND NVL(fishRv.ENABLE, 1) = 1 " +
//// " LEFT JOIN SD_FISHDICTORY_RLTN_B relZy ON relZy.FISH_ID = t.FTP " +
//// " AND relZy.RVCD = 'ZY' " +
//// " AND NVL(relZy.IS_DELETED, 0) = 0 " +
//// " LEFT JOIN SD_FISHDICTORY_B fishZy ON fishZy.ID = relZy.ZY_FISH_ID " +
//// " AND NVL(fishZy.IS_DELETED, 0) = 0 " +
//// " AND NVL(fishZy.ENABLE, 1) = 1 " +
//// " LEFT JOIN SD_FISHDICTORY_B fishDirect ON fishDirect.ID = t.FTP " +
//// " AND NVL(fishDirect.IS_DELETED, 0) = 0 " +
//// " AND NVL(fishDirect.ENABLE, 1) = 1 " +
//// " WHERE NVL(t.IS_DELETED, 0) = 0 " +
//// " AND (t.TASK_STATUS = 'Approved' OR t.TASK_STATUS IS NULL) " +
// ") src";
// }
private String buildQgcSdfpssrDetailSelectSql(List<String> selectFields) {
Map<String, String> selectMap = new LinkedHashMap<>();
selectMap.put("stcd", "t.stcd AS stcd");
@ -1966,6 +2075,68 @@ public class FpRunServiceImpl implements FpRunService {
return String.join(", ", actualColumns);
}
private String buildQgcFpssrlDetailAISelectSql(List<String> selectFields) {
Map<String, String> selectMap = new LinkedHashMap<>();
selectMap.put("id", "t.id AS id");
selectMap.put("yr", "t.yr AS yr");
selectMap.put("stcd", "t.stcd AS stcd");
selectMap.put("stnm", "CASE WHEN t.stName IS NULL THEN t.stnm ELSE t.stName || t.stnm END AS stnm");
selectMap.put("baseId", "t.baseId AS baseId");
selectMap.put("baseName", "t.baseName AS baseName");
selectMap.put("rstcd", "t.rstcd AS rstcd");
selectMap.put("ennm", "t.ennm AS ennm");
selectMap.put("isfs", "t.isfs AS isfs");
selectMap.put("hbrvcd", "t.hbrvcd AS hbrvcd");
selectMap.put("baseStepSort", "t.baseStepSort AS baseStepSort");
selectMap.put("rvcdStepSort", "t.rvcdStepSort AS rvcdStepSort");
selectMap.put("siteStepSort", "t.siteStepSort AS siteStepSort");
selectMap.put("rstcdStepSort", "t.rstcdStepSort AS rstcdStepSort");
selectMap.put("tm", "t.tm AS tm");
selectMap.put("ftp", "t.ftp AS ftp");
selectMap.put("fishId", "t.fishId AS fishId");
selectMap.put("fsz", "t.fsz AS fsz");
selectMap.put("length", "t.length AS length");
selectMap.put("width", "t.width AS width");
selectMap.put("fishspeed", "t.fishspeed AS fishspeed");
selectMap.put("waterlevel", "t.waterlevel AS waterlevel");
selectMap.put("fishposition", "t.fishposition AS fishposition");
selectMap.put("dox", "t.dox AS dox");
selectMap.put("q", "t.q AS q");
selectMap.put("tu", "t.tu AS tu");
selectMap.put("remark", "t.remark AS remark");
selectMap.put("direction", "t.direction AS direction");
selectMap.put("directionName", "CASE t.direction WHEN '0' THEN '上行' WHEN '1' THEN '下行' WHEN '2' THEN '上行折返' WHEN '3' THEN '下行折返' END AS directionName");
selectMap.put("temperature", "t.temperature AS temperature");
selectMap.put("speed", "t.speed AS speed");
selectMap.put("channelno", "t.channelno AS channelno");
selectMap.put("fcnt", "t.fcnt AS fcnt");
selectMap.put("firstimgurl", "t.firstimgurl AS firstimgurl");
selectMap.put("videourl", "t.videourl AS videourl");
selectMap.put("mway", "t.mway AS mway");
selectMap.put("strdt", "t.strdt AS strdt");
selectMap.put("enddt", "t.enddt AS enddt");
selectMap.put("stCode", "t.stCode AS stCode");
selectMap.put("stName", "t.stName AS stName");
if (CollUtil.isEmpty(selectFields)) {
return String.join(", ", selectMap.values());
}
List<String> actualColumns = new ArrayList<>();
for (String field : selectFields) {
String column = selectMap.get(field);
if (StrUtil.isNotBlank(column)) {
actualColumns.add(column);
}
}
if (actualColumns.isEmpty()) {
actualColumns.addAll(selectMap.values());
}
return String.join(", ", actualColumns);
}
private String buildQgcSdfpssrFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {