diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFpssrlRController.java b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFpssrlRController.java new file mode 100644 index 00000000..4883f43f --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdFpssrlRController.java @@ -0,0 +1,124 @@ +package com.yfd.platform.qgc_base.controller; + +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.SdFpssrlR; +import com.yfd.platform.qgc_base.domain.SdFpssrlRAiRequest; +import com.yfd.platform.qgc_base.service.ISdFpssrlRService; +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 java.util.List; + +/** + *

+ * 过鱼设施自动数据表(AI识别) 前端控制器 + *

+ */ +@Slf4j +@RestController +@RequestMapping("/base/fpssrlR") +@Tag(name = "过鱼设施自动数据管理") +public class SdFpssrlRController { + + @Resource + private ISdFpssrlRService sdFpssrlRService; + + @Resource + private ObjectMapper objectMapper; + + // ==================== CRUD 方法 ==================== + + @PostMapping("/queryPageList") + @Operation(summary = "分页查询过鱼自动数据列表(支持动态过滤和排序)") + public ResponseResult queryPageList(@RequestBody DataSourceRequest request) { + Page page = sdFpssrlRService.queryPageList(request); + return ResponseResult.successData(page); + } + + @GetMapping("/getById") + @Operation(summary = "根据ID查询过鱼自动数据") + public ResponseResult getById(@RequestParam String id) { + return ResponseResult.successData(sdFpssrlRService.getById(id)); + } + + @Log(module = "过鱼设施自动数据管理", value = "新增过鱼自动数据") + @PostMapping("/add") + @Operation(summary = "新增过鱼自动数据") + public ResponseResult add(@RequestBody SdEngInfoBHOperateRequest request) { + SdFpssrlR entity = request == null || request.getEngInfo() == null ? null + : objectMapper.convertValue(request.getEngInfo(), SdFpssrlR.class); + if (entity == null) { + return ResponseResult.error("数据不能为空"); + } + boolean result = sdFpssrlRService.add(entity, request.getSource()); + return result ? ResponseResult.success("新增成功") : ResponseResult.error("新增失败"); + } + + @Log(module = "过鱼设施自动数据管理", value = "修改过鱼自动数据") + @PostMapping("/update") + @Operation(summary = "修改过鱼自动数据") + public ResponseResult update(@RequestBody SdEngInfoBHOperateRequest request) { + SdFpssrlR entity = request == null || request.getEngInfo() == null ? null + : objectMapper.convertValue(request.getEngInfo(), SdFpssrlR.class); + if (entity == null || entity.getId() == null) { + return ResponseResult.error("数据或ID不能为空"); + } + boolean result = sdFpssrlRService.update(entity, request.getSource()); + return result ? ResponseResult.success("修改成功") : ResponseResult.error("修改失败"); + } + + @Log(module = "过鱼设施自动数据管理", value = "删除过鱼自动数据") + @PostMapping("/delete") + @Operation(summary = "删除过鱼自动数据") + public ResponseResult delete(@RequestBody SdEngInfoBHOperateRequest request) { + List ids = request == null ? null : request.getIds(); + if (ids == null || ids.isEmpty()) { + return ResponseResult.error("ID不能为空"); + } + boolean result = sdFpssrlRService.delete(ids, request.getSource()); + return result ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败"); + } + + // ==================== AI 设备识别数据上报接口 ==================== + + /** + * AI设备识别数据上报接口 + * 接收AI设备自动识别的过鱼数据并入库 + */ + @PostMapping("/ai/report") + @Operation(summary = "AI设备识别数据上报") + public ResponseResult aiReport(@RequestBody SdFpssrlRAiRequest request) { + if (request == null) { + return ResponseResult.error("请求数据不能为空"); + } + if (request.getStcd() == null || request.getStcd().isEmpty()) { + return ResponseResult.error("过鱼设施编码(stcd)不能为空"); + } + if (request.getTm() == null) { + return ResponseResult.error("识别时间(tm)不能为空"); + } + if (request.getFtp() == null || request.getFtp().isEmpty()) { + return ResponseResult.error("鱼种类(ftp)不能为空"); + } + + try { + SdFpssrlR entity = sdFpssrlRService.processAiReport(request); + if (entity != null) { + return ResponseResult.successData(entity.getId()); + } else { + return ResponseResult.error("数据保存失败"); + } + } catch (Exception e) { + log.error("AI识别数据上报失败", e); + return ResponseResult.error("上报失败: " + e.getMessage()); + } + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFpssrlR.java b/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFpssrlR.java new file mode 100644 index 00000000..a768db6f --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFpssrlR.java @@ -0,0 +1,180 @@ +package com.yfd.platform.qgc_base.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +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; + +/** + *

+ * 过鱼设施自动数据表(AI识别) + *

+ */ +@Data +@TableName("SD_FPSSRL_R") +public class SdFpssrlR implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(type = IdType.ASSIGN_UUID) + private String id; + + /** + * 过鱼设施编码 + */ + private String stcd; + + /** + * 时间 + */ + private Date tm; + + /** + * 鱼种类 + */ + private String ftp; + + /** + * 过鱼数量 + */ + private Integer fcnt; + + /** + * 鱼尺寸:大/中/小 + */ + private String fsz; + + /** + * 鱼长度 + */ + private BigDecimal length; + + /** + * 鱼宽度 + */ + private BigDecimal width; + + /** + * 鱼速度 + */ + private String fishspeed; + + /** + * 游向:0=上行 1=下行 + */ + private Integer direction; + + /** + * 鱼位置 + */ + private Long fishposition; + + /** + * 鱼截图主图片url + */ + private String firstImgUrl; + + /** + * 鱼截图副图片url + */ + private String secondImgUrl; + + /** + * 视频url + */ + private String videoUrl; + + /** + * 水温:单位:℃ + */ + private BigDecimal temperature; + + /** + * 水位:单位:m + */ + private BigDecimal waterlevel; + + /** + * 流速:单位:m/s + */ + private BigDecimal speed; + + /** + * 流量:单位:m3/s + */ + private BigDecimal q; + + /** + * 溶氧:单位:mg/L + */ + private BigDecimal dox; + + /** + * 浊度:单位:NTU + */ + private Integer tu; + + /** + * 过鱼通道 + */ + private String channelno; + + /** + * 创建人:关联SYS_USER.ID + */ + private String recordUser; + + /** + * 创建时间 + */ + private Date recordTime; + + /** + * 更新人:关联SYS_USER.ID + */ + private String modifyUser; + + /** + * 更新时间 + */ + private Date modifyTime; + + /** + * 是否已删除:0=未删除 1=已删除 + */ + private Integer isDeleted; + + /** + * 删除人:关联SYS_USER.ID + */ + private String deleteUser; + + /** + * 删除时间 + */ + private Date deleteTime; + + /** + * 附件ID + */ + private String fid; + + /** + * 备注 + */ + private String remark; + + /** + * 过鱼设施名称(非表字段,用于列表展示) + */ + @TableField(exist = false) + private String stnm; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFpssrlRAiRequest.java b/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFpssrlRAiRequest.java new file mode 100644 index 00000000..37b9c3e4 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_base/domain/SdFpssrlRAiRequest.java @@ -0,0 +1,120 @@ +package com.yfd.platform.qgc_base.domain; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + *

+ * AI设备识别数据上报请求 + *

+ */ +@Data +public class SdFpssrlRAiRequest { + + /** + * 过鱼设施编码(必填) + */ + private String stcd; + + /** + * 识别时间(必填),格式:yyyy-MM-dd HH:mm:ss + */ + private Date tm; + + /** + * 鱼种类(必填) + */ + private String ftp; + + /** + * 过鱼数量,默认1 + */ + private Integer fcnt; + + /** + * 鱼尺寸:大/中/小 + */ + private String fsz; + + /** + * 鱼长度,单位:cm + */ + private BigDecimal length; + + /** + * 鱼宽度,单位:cm + */ + private BigDecimal width; + + /** + * 鱼速度 + */ + private String fishspeed; + + /** + * 游向:0=上行 1=下行 + */ + private Integer direction; + + /** + * 鱼位置 + */ + private Long fishposition; + + /** + * 主图片URL + */ + private String firstImgUrl; + + /** + * 副图片URL + */ + private String secondImgUrl; + + /** + * 视频URL + */ + private String videoUrl; + + /** + * 水温:单位:℃ + */ + private BigDecimal temperature; + + /** + * 水位:单位:m + */ + private BigDecimal waterlevel; + + /** + * 流速:单位:m/s + */ + private BigDecimal speed; + + /** + * 流量:单位:m³/s + */ + private BigDecimal q; + + /** + * 溶氧:单位:mg/L + */ + private BigDecimal dox; + + /** + * 浊度:单位:NTU + */ + private Integer tu; + + /** + * 过鱼通道,默认"主通道" + */ + private String channelno; + + /** + * 备注 + */ + private String remark; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/mapper/SdFpssrlRMapper.java b/backend/src/main/java/com/yfd/platform/qgc_base/mapper/SdFpssrlRMapper.java new file mode 100644 index 00000000..6998c983 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_base/mapper/SdFpssrlRMapper.java @@ -0,0 +1,14 @@ +package com.yfd.platform.qgc_base.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yfd.platform.qgc_base.domain.SdFpssrlR; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 过鱼设施自动数据表 Mapper 接口 + *

+ */ +@Mapper +public interface SdFpssrlRMapper extends BaseMapper { +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdFpssrlRService.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdFpssrlRService.java new file mode 100644 index 00000000..4c129542 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdFpssrlRService.java @@ -0,0 +1,47 @@ +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.SdFpssrlR; +import com.yfd.platform.qgc_base.domain.SdFpssrlRAiRequest; + +import java.util.List; + +/** + *

+ * 过鱼设施自动数据表 服务接口 + *

+ */ +public interface ISdFpssrlRService extends IService { + + /** + * 分页查询(Kendo Grid) + */ + Page queryPageList(DataSourceRequest request); + + /** + * 新增 + */ + boolean add(SdFpssrlR entity, String source); + + /** + * 修改 + */ + boolean update(SdFpssrlR entity, String source); + + /** + * 删除(逻辑删除) + */ + boolean delete(List ids, String source); + + /** + * 根据ID查询(排除已删除的) + */ + SdFpssrlR getById(String id); + + /** + * 处理AI设备上报的识别数据 + */ + SdFpssrlR processAiReport(SdFpssrlRAiRequest request); +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFpssrlRServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFpssrlRServiceImpl.java new file mode 100644 index 00000000..04eb0406 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFpssrlRServiceImpl.java @@ -0,0 +1,129 @@ +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.SdFpssrlR; +import com.yfd.platform.qgc_base.domain.SdFpssrlRAiRequest; +import com.yfd.platform.qgc_base.mapper.SdFpssrlRMapper; +import com.yfd.platform.qgc_base.service.IMsOperationLogService; +import com.yfd.platform.qgc_base.service.ISdFpssrlRService; +import com.yfd.platform.utils.DataSourceRequestUtil; +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.Date; +import java.util.List; + +/** + *

+ * 过鱼设施自动数据表 服务实现类 + *

+ */ +@Slf4j +@Service +public class SdFpssrlRServiceImpl extends ServiceImpl implements ISdFpssrlRService { + + private static final String TABLE_NAME = "SD_FPSSRL_R"; + + @Resource + private IMsOperationLogService msOperationLogService; + + @Override + public Page queryPageList(DataSourceRequest request) { + return DataSourceRequestUtil.executeQuery(request, SdFpssrlR.class, this); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean add(SdFpssrlR entity, String source) { + boolean result = this.save(entity); +// if (result) { +// msOperationLogService.recordAddDetailLog(entity.getId(),TABLE_NAME, entity, source); +// } + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean update(SdFpssrlR entity, String source) { +// SdFpssrlR before = this.getById(entity.getId()); + boolean result = this.updateById(entity); +// if (result && before != null) { +// msOperationLogService.recordModifyDetailLog(entity.getId(),TABLE_NAME, before, entity, source); +// } + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean delete(List ids, String source) { + if (ids == null || ids.isEmpty()) return false; + int count = 0; + for (String id : ids) { +// SdFpssrlR entity = getById(id); + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + wrapper.eq(SdFpssrlR::getId, id); + wrapper.set(SdFpssrlR::getIsDeleted, 1); + wrapper.set(SdFpssrlR::getDeleteUser, SecurityUtils.getCurrentUsername()); + wrapper.set(SdFpssrlR::getDeleteTime, new Date()); + if (this.update(wrapper)) { +// msOperationLogService.recordDeleteDetailLog(id,TABLE_NAME, entity, source); + count++; + } + } + return count > 0; + } + + @Override + public SdFpssrlR getById(String id) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SdFpssrlR::getId, id) + .eq(SdFpssrlR::getIsDeleted, 0); + return getOne(wrapper); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public SdFpssrlR processAiReport(SdFpssrlRAiRequest request) { + SdFpssrlR entity = new SdFpssrlR(); + entity.setStcd(request.getStcd()); + entity.setTm(request.getTm()); + entity.setFtp(request.getFtp()); + entity.setFcnt(request.getFcnt() != null ? request.getFcnt() : 1); + entity.setFsz(request.getFsz()); + entity.setLength(request.getLength()); + entity.setWidth(request.getWidth()); + entity.setFishspeed(request.getFishspeed()); + entity.setDirection(request.getDirection()); + entity.setFishposition(request.getFishposition()); + entity.setFirstImgUrl(request.getFirstImgUrl()); + entity.setSecondImgUrl(request.getSecondImgUrl()); + entity.setVideoUrl(request.getVideoUrl()); + entity.setTemperature(request.getTemperature()); + entity.setWaterlevel(request.getWaterlevel()); + entity.setSpeed(request.getSpeed()); + entity.setQ(request.getQ()); + entity.setDox(request.getDox()); + entity.setTu(request.getTu()); + entity.setChannelno(StrUtil.isNotBlank(request.getChannelno()) ? request.getChannelno() : "主通道"); + entity.setRecordUser("AI_SYSTEM"); + entity.setRecordTime(new Date()); + entity.setIsDeleted(0); + entity.setRemark(request.getRemark()); + + boolean result = this.save(entity); + if (result) { + log.info("AI识别数据保存成功, id={}, stcd={}, ftp={}", entity.getId(), entity.getStcd(), entity.getFtp()); + } else { + log.error("AI识别数据保存失败, stcd={}, ftp={}", request.getStcd(), request.getFtp()); + } + return result ? entity : null; + } +}