feat: 新需求功能代码提交。

This commit is contained in:
tianyongbao
2025-10-15 14:14:22 +08:00
parent 1e5013a1eb
commit f54859f62d
27 changed files with 2399 additions and 32 deletions

View File

@@ -0,0 +1,105 @@
package org.dromara.fishery.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.fishery.domain.vo.DeviceBindRecordVo;
import org.dromara.fishery.domain.bo.DeviceBindRecordBo;
import org.dromara.fishery.service.IDeviceBindRecordService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 设备绑定记录
*
* @author intc
* @date 2025-10-14
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/fishery/deviceBindRecord")
public class DeviceBindRecordController extends BaseController {
private final IDeviceBindRecordService deviceBindRecordService;
/**
* 查询设备绑定记录列表
*/
@SaCheckPermission("fishery:deviceBindRecord:list")
@GetMapping("/list")
public TableDataInfo<DeviceBindRecordVo> list(DeviceBindRecordBo bo, PageQuery pageQuery) {
return deviceBindRecordService.queryPageList(bo, pageQuery);
}
/**
* 导出设备绑定记录列表
*/
@SaCheckPermission("fishery:deviceBindRecord:export")
@Log(title = "设备绑定记录", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(DeviceBindRecordBo bo, HttpServletResponse response) {
List<DeviceBindRecordVo> list = deviceBindRecordService.queryList(bo);
ExcelUtil.exportExcel(list, "设备绑定记录", DeviceBindRecordVo.class, response);
}
/**
* 获取设备绑定记录详细信息
*
* @param id 主键
*/
@SaCheckPermission("fishery:deviceBindRecord:query")
@GetMapping("/{id}")
public R<DeviceBindRecordVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(deviceBindRecordService.queryById(id));
}
/**
* 新增设备绑定记录
*/
@SaCheckPermission("fishery:deviceBindRecord:add")
@Log(title = "设备绑定记录", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody DeviceBindRecordBo bo) {
return toAjax(deviceBindRecordService.insertByBo(bo));
}
/**
* 修改设备绑定记录
*/
@SaCheckPermission("fishery:deviceBindRecord:edit")
@Log(title = "设备绑定记录", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody DeviceBindRecordBo bo) {
return toAjax(deviceBindRecordService.updateByBo(bo));
}
/**
* 删除设备绑定记录
*
* @param ids 主键串
*/
@SaCheckPermission("fishery:deviceBindRecord:remove")
@Log(title = "设备绑定记录", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(deviceBindRecordService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@@ -0,0 +1,105 @@
package org.dromara.fishery.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.fishery.domain.vo.DeviceVo;
import org.dromara.fishery.domain.bo.DeviceBo;
import org.dromara.fishery.service.IDeviceService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* 设备管理
*
* @author intc
* @date 2025-10-14
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/fishery/device")
public class DeviceController extends BaseController {
private final IDeviceService deviceService;
/**
* 查询设备管理列表
*/
@SaCheckPermission("fishery:device:list")
@GetMapping("/list")
public TableDataInfo<DeviceVo> list(DeviceBo bo, PageQuery pageQuery) {
return deviceService.queryPageList(bo, pageQuery);
}
/**
* 导出设备管理列表
*/
@SaCheckPermission("fishery:device:export")
@Log(title = "设备管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(DeviceBo bo, HttpServletResponse response) {
List<DeviceVo> list = deviceService.queryList(bo);
ExcelUtil.exportExcel(list, "设备管理", DeviceVo.class, response);
}
/**
* 获取设备管理详细信息
*
* @param id 主键
*/
@SaCheckPermission("fishery:device:query")
@GetMapping("/{id}")
public R<DeviceVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(deviceService.queryById(id));
}
/**
* 新增设备管理
*/
@SaCheckPermission("fishery:device:add")
@Log(title = "设备管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody DeviceBo bo) {
return toAjax(deviceService.insertByBo(bo));
}
/**
* 修改设备管理
*/
@SaCheckPermission("fishery:device:edit")
@Log(title = "设备管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody DeviceBo bo) {
return toAjax(deviceService.updateByBo(bo));
}
/**
* 删除设备管理
*
* @param ids 主键串
*/
@SaCheckPermission("fishery:device:remove")
@Log(title = "设备管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(deviceService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@@ -0,0 +1,243 @@
package org.dromara.fishery.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* 设备管理对象 aqu_device
*
* @author intc
* @date 2025-10-14
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("aqu_device")
public class Device extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 用户id
*/
private Long userId;
/**
* 物联网IotId
*/
private String iotId;
/**
* 设备编号
*/
private String serialNum;
/**
* 设备名称
*/
private String deviceName;
/**
* 设备类型
*/
private Integer deviceType;
/**
* 绑定时间
*/
private Date bindTime;
/**
* 服务到期
*/
private Date deadTime;
/**
* 塘口id
*/
private Long pondId;
/**
* 溶解氧参数配置开关
*/
private Integer isOxygenUsed;
/**
* 溶解氧
*/
private Double valueDissolvedOxygen;
/**
* 是否已触发溶解氧报警
*/
private Integer isOxygenWarnExist;
/**
* 水温
*/
private Double valueTemperature;
/**
* 是否已触发温度报警
*/
private Integer isTempWarnExist;
/**
* 饱和度
*/
private Double valueSaturability;
/**
* PH
*/
private Double valuePh;
/**
* 盐度
*/
private Double valueSalinity;
/**
* 溶解氧电话告警开关
*/
private Integer oxyWarnCallOpen;
/**
* 低溶氧告警免打扰
*/
private Integer oxyWarnCallNoDis;
/**
* 上次溶解氧电话告警时间
*/
private Date oxyWarnCallLastTime;
/**
* 溶解氧电话告警下限
*/
private Double oxyWarnLower;
/**
* 温度电话告警开关
*/
private Integer tempWarnCallOpen;
/**
* 温度告警免打扰
*/
private Integer tempWarnCallNoDis;
/**
* 上次温度电话告警时间
*/
private Date tempWarnCallLastTime;
/**
* 温度电话告警上限
*/
private Double tempWarnUpper;
/**
* 温度电话告警下限
*/
private Double tempWarnLower;
/**
* 设置的盐度补偿
*/
private Double salinityCompensation;
/**
* 输入额定电压
*/
private Integer inputVoltage;
/**
* 设备告警状态码
*/
private Integer warnCode;
/**
* 物联网卡号
*/
private String iccId;
/**
* 相位差
*/
private Double phaseDifference;
/**
* 荧光值
*/
private Double tfluorescence;
/**
* 参比值
*/
private Double treference;
/**
* 线性系数补偿
*/
private Double phaseCompensation;
/**
* 相位差补偿
*/
private Double phasedifCompensation;
/**
* 温度补偿
*/
private Double temperatureCompensation;
/**
* 电压告警开关
*/
private Integer voltageWarnOpen;
/**
* 备注
*/
private String remark;
/**
* 设备分类
*/
private String category;
/**
* 电量电话告警开关
*/
private Long batteryWarnCallOpen;
/**
* 电量告警免打扰
*/
private Long batteryWarnCallNoDis;
/**
* 上次电量电话告警时间
*/
private Date batteryWarnCallLastTime;
/**
* 电量电话告警下限
*/
private Long batteryWarnLower;
}

View File

@@ -0,0 +1,56 @@
package org.dromara.fishery.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 设备绑定记录对象 aqu_device_bind_record
*
* @author intc
* @date 2025-10-14
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("aqu_device_bind_record")
public class DeviceBindRecord extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 物联网IotId
*/
private String iotId;
/**
* 设备类型
*/
private Long deviceType;
/**
* 设备编号
*/
private String serialNum;
/**
* 用户id
*/
private Long userId;
/**
* 绑定/解绑
*/
private Integer isBind;
}

View File

@@ -0,0 +1,60 @@
package org.dromara.fishery.domain.bo;
import org.dromara.fishery.domain.DeviceBindRecord;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 设备绑定记录业务对象 aqu_device_bind_record
*
* @author intc
* @date 2025-10-14
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = DeviceBindRecord.class, reverseConvertGenerate = false)
public class DeviceBindRecordBo extends BaseEntity {
/**
* 主键id
*/
// @NotNull(message = "主键id不能为空", groups = { EditGroup.class })
private Long id;
/**
* 物联网IotId
*/
@NotBlank(message = "物联网IotId不能为空", groups = { AddGroup.class, EditGroup.class })
private String iotId;
/**
* 设备类型
*/
@NotNull(message = "设备类型不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deviceType;
/**
* 设备编号
*/
@NotBlank(message = "设备编号不能为空", groups = { AddGroup.class, EditGroup.class })
private String serialNum;
/**
* 用户id
*/
@NotNull(message = "用户id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long userId;
/**
* 绑定/解绑
*/
@NotNull(message = "绑定/解绑不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer isBind;
}

View File

@@ -0,0 +1,275 @@
package org.dromara.fishery.domain.bo;
import org.dromara.fishery.domain.Device;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 设备管理业务对象 aqu_device
*
* @author intc
* @date 2025-10-14
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = Device.class, reverseConvertGenerate = false)
public class DeviceBo extends BaseEntity {
/**
* 主键id
*/
// @NotNull(message = "主键id不能为空", groups = { EditGroup.class })
private Long id;
/**
* 用户id
*/
private Long userId;
/**
* 物联网IotId
*/
@NotBlank(message = "物联网IotId不能为空", groups = { AddGroup.class, EditGroup.class })
private String iotId;
/**
* 设备编号
*/
@NotBlank(message = "设备编号不能为空", groups = { AddGroup.class, EditGroup.class })
private String serialNum;
/**
* 设备名称
*/
@NotBlank(message = "设备名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String deviceName;
/**
* 设备类型
*/
@NotNull(message = "设备类型不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer deviceType;
/**
* 绑定时间
*/
@NotNull(message = "绑定时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date bindTime;
/**
* 服务到期
*/
@NotNull(message = "服务到期不能为空", groups = { AddGroup.class, EditGroup.class })
private Date deadTime;
/**
* 塘口id
*/
private Long pondId;
/**
* 溶解氧参数配置开关
*/
// @NotNull(message = "溶解氧参数配置开关不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer isOxygenUsed;
/**
* 溶解氧
*/
// @NotNull(message = "溶解氧不能为空", groups = { AddGroup.class, EditGroup.class })
private Double valueDissolvedOxygen;
/**
* 是否已触发溶解氧报警
*/
// @NotNull(message = "是否已触发溶解氧报警不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer isOxygenWarnExist;
/**
* 水温
*/
// @NotNull(message = "水温不能为空", groups = { AddGroup.class, EditGroup.class })
private Double valueTemperature;
/**
* 是否已触发温度报警
*/
// @NotNull(message = "是否已触发温度报警不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer isTempWarnExist;
/**
* 饱和度
*/
// @NotNull(message = "饱和度不能为空", groups = { AddGroup.class, EditGroup.class })
private Double valueSaturability;
/**
* PH
*/
// @NotNull(message = "PH不能为空", groups = { AddGroup.class, EditGroup.class })
private Double valuePh;
/**
* 盐度
*/
// @NotNull(message = "盐度不能为空", groups = { AddGroup.class, EditGroup.class })
private Double valueSalinity;
/**
* 溶解氧电话告警开关
*/
// @NotNull(message = "溶解氧电话告警开关不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer oxyWarnCallOpen;
/**
* 低溶氧告警免打扰
*/
// @NotNull(message = "低溶氧告警免打扰不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer oxyWarnCallNoDis;
/**
* 上次溶解氧电话告警时间
*/
// @NotNull(message = "上次溶解氧电话告警时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date oxyWarnCallLastTime;
/**
* 溶解氧电话告警下限
*/
// @NotNull(message = "溶解氧电话告警下限不能为空", groups = { AddGroup.class, EditGroup.class })
private Double oxyWarnLower;
/**
* 温度电话告警开关
*/
// @NotNull(message = "温度电话告警开关不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer tempWarnCallOpen;
/**
* 温度告警免打扰
*/
// @NotNull(message = "温度告警免打扰不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer tempWarnCallNoDis;
/**
* 上次温度电话告警时间
*/
// @NotNull(message = "上次温度电话告警时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date tempWarnCallLastTime;
/**
* 温度电话告警上限
*/
// @NotNull(message = "温度电话告警上限不能为空", groups = { AddGroup.class, EditGroup.class })
private Double tempWarnUpper;
/**
* 温度电话告警下限
*/
// @NotNull(message = "温度电话告警下限不能为空", groups = { AddGroup.class, EditGroup.class })
private Double tempWarnLower;
/**
* 设置的盐度补偿
*/
// @NotNull(message = "设置的盐度补偿不能为空", groups = { AddGroup.class, EditGroup.class })
private Double salinityCompensation;
/**
* 输入额定电压
*/
// @NotNull(message = "输入额定电压不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer inputVoltage;
/**
* 设备告警状态码
*/
// @NotNull(message = "设备告警状态码不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer warnCode;
/**
* 物联网卡号
*/
private String iccId;
/**
* 相位差
*/
// @NotNull(message = "相位差不能为空", groups = { AddGroup.class, EditGroup.class })
private Double phaseDifference;
/**
* 荧光值
*/
// @NotNull(message = "荧光值不能为空", groups = { AddGroup.class, EditGroup.class })
private Double tfluorescence;
/**
* 参比值
*/
// @NotNull(message = "参比值不能为空", groups = { AddGroup.class, EditGroup.class })
private Double treference;
/**
* 线性系数补偿
*/
// @NotNull(message = "线性系数补偿不能为空", groups = { AddGroup.class, EditGroup.class })
private Double phaseCompensation;
/**
* 相位差补偿
*/
// @NotNull(message = "相位差补偿不能为空", groups = { AddGroup.class, EditGroup.class })
private Double phasedifCompensation;
/**
* 温度补偿
*/
// @NotNull(message = "温度补偿不能为空", groups = { AddGroup.class, EditGroup.class })
private Double temperatureCompensation;
/**
* 电压告警开关
*/
// @NotNull(message = "电压告警开关不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer voltageWarnOpen;
/**
* 备注
*/
private String remark;
/**
* 设备分类
*/
private String category;
/**
* 电量电话告警开关
*/
private Long batteryWarnCallOpen;
/**
* 电量告警免打扰
*/
private Long batteryWarnCallNoDis;
/**
* 上次电量电话告警时间
*/
private Date batteryWarnCallLastTime;
/**
* 电量电话告警下限
*/
private Long batteryWarnLower;
}

View File

@@ -74,5 +74,15 @@ public class PondBo extends BaseEntity {
*/
private String remark;
/**
* 提报时间开始
*/
private String startTime;
/**
* 提报时间结束
*/
private String endTime;
}

View File

@@ -130,5 +130,9 @@ public class AquUserVo implements Serializable {
@ExcelProperty(value = "备注")
private String remark;
private Date createTime;
private Date updateTime;
}

View File

@@ -0,0 +1,86 @@
package org.dromara.fishery.domain.vo;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.fishery.domain.DeviceBindRecord;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
/**
* 设备绑定记录视图对象 aqu_device_bind_record
*
* @author intc
* @date 2025-10-14
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = DeviceBindRecord.class)
public class DeviceBindRecordVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 物联网IotId
*/
@ExcelProperty(value = "物联网IotId")
private String iotId;
/**
* 设备类型
*/
@ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "aqu_device_type")
private Long deviceType;
/**
* 设备编号
*/
@ExcelProperty(value = "设备编号")
private String serialNum;
/**
* 用户id
*/
@ExcelProperty(value = "用户id")
private Long userId;
/**
* 绑定/解绑
*/
@ExcelProperty(value = "绑定/解绑", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "is_bind")
private Integer isBind;
/**
* 手机号
*/
@ExcelProperty(value = "手机号")
private String mobilePhone;
/**
* 用户名
*/
@ExcelProperty(value = "用户名")
private String userName;
private Date createTime;
private Date updateTime;
}

View File

@@ -64,5 +64,9 @@ public class DeviceThresholdVo implements Serializable {
@ExcelProperty(value = "备注")
private String remark;
private Date createTime;
private Date updateTime;
}

View File

@@ -0,0 +1,344 @@
package org.dromara.fishery.domain.vo;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.common.json.handler.DoubleSerializer;
import org.dromara.fishery.domain.Device;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
/**
* 设备管理视图对象 aqu_device
*
* @author intc
* @date 2025-10-14
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = Device.class)
public class DeviceVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 用户id
*/
@ExcelProperty(value = "用户id")
private Long userId;
/**
* 物联网IotId
*/
@ExcelProperty(value = "物联网IotId")
private String iotId;
/**
* 设备编号
*/
@ExcelProperty(value = "设备编号")
private String serialNum;
/**
* 设备名称
*/
@ExcelProperty(value = "设备名称")
private String deviceName;
/**
* 设备类型
*/
@ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "aqu_device_type")
private Integer deviceType;
/**
* 绑定时间
*/
@ExcelProperty(value = "绑定时间")
private Date bindTime;
/**
* 服务到期
*/
@ExcelProperty(value = "服务到期")
private Date deadTime;
/**
* 塘口id
*/
@ExcelProperty(value = "塘口id")
private Long pondId;
/**
* 溶解氧参数配置开关
*/
@ExcelProperty(value = "溶解氧参数配置开关")
private Integer isOxygenUsed;
/**
* 溶解氧
*/
@ExcelProperty(value = "溶解氧")
@JsonSerialize(using = DoubleSerializer.class)
private Double valueDissolvedOxygen;
/**
* 是否已触发溶解氧报警
*/
@ExcelProperty(value = "是否已触发溶解氧报警")
private Integer isOxygenWarnExist;
/**
* 水温
*/
@ExcelProperty(value = "水温")
@JsonSerialize(using = DoubleSerializer.class)
private Double valueTemperature;
/**
* 是否已触发温度报警
*/
@ExcelProperty(value = "是否已触发温度报警")
private Integer isTempWarnExist;
/**
* 饱和度
*/
@ExcelProperty(value = "饱和度")
@JsonSerialize(using = DoubleSerializer.class)
private Double valueSaturability;
/**
* PH
*/
@ExcelProperty(value = "PH")
@JsonSerialize(using = DoubleSerializer.class)
private Double valuePh;
/**
* 盐度
*/
@ExcelProperty(value = "盐度")
@JsonSerialize(using = DoubleSerializer.class)
private Double valueSalinity;
/**
* 溶解氧电话告警开关
*/
@ExcelProperty(value = "溶解氧电话告警开关")
private Integer oxyWarnCallOpen;
/**
* 低溶氧告警免打扰
*/
@ExcelProperty(value = "低溶氧告警免打扰")
private Integer oxyWarnCallNoDis;
/**
* 上次溶解氧电话告警时间
*/
@ExcelProperty(value = "上次溶解氧电话告警时间")
private Date oxyWarnCallLastTime;
/**
* 溶解氧电话告警下限
*/
@ExcelProperty(value = "溶解氧电话告警下限")
@JsonSerialize(using = DoubleSerializer.class)
private Double oxyWarnLower;
/**
* 温度电话告警开关
*/
@ExcelProperty(value = "温度电话告警开关")
private Integer tempWarnCallOpen;
/**
* 温度告警免打扰
*/
@ExcelProperty(value = "温度告警免打扰")
private Integer tempWarnCallNoDis;
/**
* 上次温度电话告警时间
*/
@ExcelProperty(value = "上次温度电话告警时间")
private Date tempWarnCallLastTime;
/**
* 温度电话告警上限
*/
@ExcelProperty(value = "温度电话告警上限")
@JsonSerialize(using = DoubleSerializer.class)
private Double tempWarnUpper;
/**
* 温度电话告警下限
*/
@ExcelProperty(value = "温度电话告警下限")
@JsonSerialize(using = DoubleSerializer.class)
private Double tempWarnLower;
/**
* 设置的盐度补偿
*/
@ExcelProperty(value = "设置的盐度补偿")
@JsonSerialize(using = DoubleSerializer.class)
private Double salinityCompensation;
/**
* 输入额定电压
*/
@ExcelProperty(value = "输入额定电压")
private Integer inputVoltage;
/**
* 设备告警状态码
*/
@ExcelProperty(value = "设备告警状态码")
private Integer warnCode;
/**
* 物联网卡号
*/
@ExcelProperty(value = "物联网卡号")
private String iccId;
/**
* 相位差
*/
@ExcelProperty(value = "相位差")
@JsonSerialize(using = DoubleSerializer.class)
private Double phaseDifference;
/**
* 荧光值
*/
@ExcelProperty(value = "荧光值")
@JsonSerialize(using = DoubleSerializer.class)
private Double tfluorescence;
/**
* 参比值
*/
@ExcelProperty(value = "参比值")
@JsonSerialize(using = DoubleSerializer.class)
private Double treference;
/**
* 线性系数补偿
*/
@ExcelProperty(value = "线性系数补偿")
@JsonSerialize(using = DoubleSerializer.class)
private Double phaseCompensation;
/**
* 相位差补偿
*/
@ExcelProperty(value = "相位差补偿")
@JsonSerialize(using = DoubleSerializer.class)
private Double phasedifCompensation;
/**
* 温度补偿
*/
@ExcelProperty(value = "温度补偿")
@JsonSerialize(using = DoubleSerializer.class)
private Double temperatureCompensation;
/**
* 电压告警开关
*/
@ExcelProperty(value = "电压告警开关")
private Integer voltageWarnOpen;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 设备分类
*/
@ExcelProperty(value = "设备分类")
private String category;
/**
* 电量电话告警开关
*/
@ExcelProperty(value = "电量电话告警开关")
private Long batteryWarnCallOpen;
/**
* 电量告警免打扰
*/
@ExcelProperty(value = "电量告警免打扰")
private Long batteryWarnCallNoDis;
/**
* 上次电量电话告警时间
*/
@ExcelProperty(value = "上次电量电话告警时间")
private Date batteryWarnCallLastTime;
/**
* 电量电话告警下限
*/
@ExcelProperty(value = "电量电话告警下限")
private Long batteryWarnLower;
/**
* 手机号
*/
@ExcelProperty(value = "手机号")
private String mobilePhone;
/**
* 用户名
*/
@ExcelProperty(value = "用户名")
private String userName;
/**
* 塘口名称
*/
@ExcelProperty(value = "塘口名称")
private String pondName;
/**
* 是否过期0-未过期1-已过期)
*/
@ExcelProperty(value = "是否过期")
private Integer isExpired;
/**
* 过期天数(正数表示已过期天数,负数表示距离过期还有多少天)
*/
@ExcelProperty(value = "过期天数")
private Long expiredDays;
private Date createTime;
private Date updateTime;
}

View File

@@ -53,5 +53,9 @@ public class FishVo implements Serializable {
@ExcelProperty(value = "备注")
private String remark;
private Date createTime;
private Date updateTime;
}

View File

@@ -1,19 +1,16 @@
package org.dromara.fishery.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.fishery.domain.Pond;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import org.dromara.fishery.domain.Pond;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
/**
@@ -78,5 +75,27 @@ public class PondVo implements Serializable {
@ExcelProperty(value = "夜间防止误关")
private Integer keepNightOpen;
/**
* 鱼品种列表
*/
@ExcelProperty(value = "鱼品种列表")
private String fishKindNames;
/**
* 用户名
*/
@ExcelProperty(value = "用户名")
private String userName;
/**
* 手机号
*/
@ExcelProperty(value = "手机号")
private String mobilePhone;
private Date createTime;
private Date updateTime;
}

View File

@@ -0,0 +1,15 @@
package org.dromara.fishery.mapper;
import org.dromara.fishery.domain.DeviceBindRecord;
import org.dromara.fishery.domain.vo.DeviceBindRecordVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 设备绑定记录Mapper接口
*
* @author intc
* @date 2025-10-14
*/
public interface DeviceBindRecordMapper extends BaseMapperPlus<DeviceBindRecord, DeviceBindRecordVo> {
}

View File

@@ -0,0 +1,16 @@
package org.dromara.fishery.mapper;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.fishery.domain.Device;
import org.dromara.fishery.domain.vo.DeviceVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 设备管理Mapper接口
*
* @author intc
* @date 2025-10-14
*/
public interface DeviceMapper extends BaseMapperPlus<Device, DeviceVo> {
}

View File

@@ -0,0 +1,68 @@
package org.dromara.fishery.service;
import org.dromara.fishery.domain.vo.DeviceBindRecordVo;
import org.dromara.fishery.domain.bo.DeviceBindRecordBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 设备绑定记录Service接口
*
* @author intc
* @date 2025-10-14
*/
public interface IDeviceBindRecordService {
/**
* 查询设备绑定记录
*
* @param id 主键
* @return 设备绑定记录
*/
DeviceBindRecordVo queryById(Long id);
/**
* 分页查询设备绑定记录列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 设备绑定记录分页列表
*/
TableDataInfo<DeviceBindRecordVo> queryPageList(DeviceBindRecordBo bo, PageQuery pageQuery);
/**
* 查询符合条件的设备绑定记录列表
*
* @param bo 查询条件
* @return 设备绑定记录列表
*/
List<DeviceBindRecordVo> queryList(DeviceBindRecordBo bo);
/**
* 新增设备绑定记录
*
* @param bo 设备绑定记录
* @return 是否新增成功
*/
Boolean insertByBo(DeviceBindRecordBo bo);
/**
* 修改设备绑定记录
*
* @param bo 设备绑定记录
* @return 是否修改成功
*/
Boolean updateByBo(DeviceBindRecordBo bo);
/**
* 校验并批量删除设备绑定记录信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,68 @@
package org.dromara.fishery.service;
import org.dromara.fishery.domain.vo.DeviceVo;
import org.dromara.fishery.domain.bo.DeviceBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 设备管理Service接口
*
* @author intc
* @date 2025-10-14
*/
public interface IDeviceService {
/**
* 查询设备管理
*
* @param id 主键
* @return 设备管理
*/
DeviceVo queryById(Long id);
/**
* 分页查询设备管理列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 设备管理分页列表
*/
TableDataInfo<DeviceVo> queryPageList(DeviceBo bo, PageQuery pageQuery);
/**
* 查询符合条件的设备管理列表
*
* @param bo 查询条件
* @return 设备管理列表
*/
List<DeviceVo> queryList(DeviceBo bo);
/**
* 新增设备管理
*
* @param bo 设备管理
* @return 是否新增成功
*/
Boolean insertByBo(DeviceBo bo);
/**
* 修改设备管理
*
* @param bo 设备管理
* @return 是否修改成功
*/
Boolean updateByBo(DeviceBo bo);
/**
* 校验并批量删除设备管理信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -73,7 +73,7 @@ public class AquUserServiceImpl implements IAquUserService {
private LambdaQueryWrapper<AquUser> buildQueryWrapper(AquUserBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<AquUser> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(AquUser::getId);
lqw.orderByDesc(AquUser::getCreateTime);
lqw.like(StringUtils.isNotBlank(bo.getUserName()), AquUser::getUserName, bo.getUserName());
lqw.like(StringUtils.isNotBlank(bo.getMobilePhone()), AquUser::getMobilePhone, bo.getMobilePhone());
lqw.eq(StringUtils.isNotBlank(bo.getProvince()), AquUser::getProvince, bo.getProvince());

View File

@@ -0,0 +1,236 @@
package org.dromara.fishery.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.dromara.fishery.domain.AquUser;
import org.dromara.fishery.domain.bo.DeviceBindRecordBo;
import org.dromara.fishery.domain.vo.DeviceBindRecordVo;
import org.dromara.fishery.domain.DeviceBindRecord;
import org.dromara.fishery.mapper.AquUserMapper;
import org.dromara.fishery.mapper.DeviceBindRecordMapper;
import org.dromara.fishery.service.IDeviceBindRecordService;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.stream.Collectors;
/**
* 设备绑定记录Service业务层处理
*
* @author intc
* @date 2025-10-14
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class DeviceBindRecordServiceImpl implements IDeviceBindRecordService {
private final DeviceBindRecordMapper baseMapper;
private final AquUserMapper aquUserMapper;
/**
* 查询设备绑定记录
*
* @param id 主键
* @return 设备绑定记录
*/
@Override
public DeviceBindRecordVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询设备绑定记录列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 设备绑定记录分页列表
*/
@Override
public TableDataInfo<DeviceBindRecordVo> queryPageList(DeviceBindRecordBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<DeviceBindRecord> lqw = buildQueryWrapper(bo);
Page<DeviceBindRecordVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
// 批量填充用户信息
enrichRecordListWithUserInfo(result.getRecords());
return TableDataInfo.build(result);
}
/**
* 查询符合条件的设备绑定记录列表
*
* @param bo 查询条件
* @return 设备绑定记录列表
*/
@Override
public List<DeviceBindRecordVo> queryList(DeviceBindRecordBo bo) {
LambdaQueryWrapper<DeviceBindRecord> lqw = buildQueryWrapper(bo);
List<DeviceBindRecordVo> recordList = baseMapper.selectVoList(lqw);
// 批量填充用户信息
enrichRecordListWithUserInfo(recordList);
return recordList;
}
private LambdaQueryWrapper<DeviceBindRecord> buildQueryWrapper(DeviceBindRecordBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<DeviceBindRecord> lqw = Wrappers.lambdaQuery();
lqw.orderByDesc(DeviceBindRecord::getCreateTime);
lqw.like(StringUtils.isNotBlank(bo.getIotId()), DeviceBindRecord::getIotId, bo.getIotId());
lqw.eq(bo.getDeviceType() != null, DeviceBindRecord::getDeviceType, bo.getDeviceType());
lqw.eq(StringUtils.isNotBlank(bo.getSerialNum()), DeviceBindRecord::getSerialNum, bo.getSerialNum());
lqw.eq(bo.getUserId() != null, DeviceBindRecord::getUserId, bo.getUserId());
lqw.eq(bo.getIsBind() != null, DeviceBindRecord::getIsBind, bo.getIsBind());
// 处理额外的查询参数
if (params != null && !params.isEmpty()) {
handleExtraParams(lqw, params);
}
return lqw;
}
/**
* 处理额外的查询参数
*
* @param lqw 查询包装器
* @param params 额外参数
*/
private void handleExtraParams(LambdaQueryWrapper<DeviceBindRecord> lqw, Map<String, Object> params) {
// 处理用户搜索关键词(用户名或手机号)
String userKeyword = (String) params.get("userKeyword");
if (StringUtils.isNotBlank(userKeyword)) {
List<Long> matchingUserIds = getMatchingUserIds(userKeyword);
if (matchingUserIds.isEmpty()) {
// 如果没有符合条件的用户,直接返回空结果
lqw.eq(DeviceBindRecord::getId, -1); // 使用不存在的ID来返回空结果
return;
}
lqw.in(DeviceBindRecord::getUserId, matchingUserIds);
}
}
/**
* 新增设备绑定记录
*
* @param bo 设备绑定记录
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(DeviceBindRecordBo bo) {
DeviceBindRecord add = MapstructUtils.convert(bo, DeviceBindRecord.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改设备绑定记录
*
* @param bo 设备绑定记录
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(DeviceBindRecordBo bo) {
DeviceBindRecord update = MapstructUtils.convert(bo, DeviceBindRecord.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(DeviceBindRecord entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除设备绑定记录信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 为记录列表批量填充用户信息
*
* @param recordList 记录列表
*/
private void enrichRecordListWithUserInfo(List<DeviceBindRecordVo> recordList) {
if (recordList == null || recordList.isEmpty()) {
return;
}
// 收集所有的用户ID
List<Long> userIds = recordList.stream()
.map(DeviceBindRecordVo::getUserId)
.filter(userId -> userId != null)
.distinct()
.collect(Collectors.toList());
if (userIds.isEmpty()) {
return;
}
// 批量查询用户信息
List<AquUser> userList = aquUserMapper.selectBatchIds(userIds);
Map<Long, AquUser> userMap = userList.stream()
.collect(Collectors.toMap(AquUser::getId, user -> user, (existing, replacement) -> existing));
// 为每条记录设置用户信息
for (DeviceBindRecordVo record : recordList) {
if (record.getUserId() != null) {
AquUser user = userMap.get(record.getUserId());
if (user != null) {
record.setUserName(user.getUserName());
record.setMobilePhone(user.getMobilePhone());
}
}
}
}
/**
* 根据用户关键词查询符合条件的用户ID列表
*
* @param userKeyword 用户搜索关键词(用户名或手机号)
* @return 符合条件的用户ID列表
*/
private List<Long> getMatchingUserIds(String userKeyword) {
if (StringUtils.isBlank(userKeyword)) {
return Arrays.asList();
}
LambdaQueryWrapper<AquUser> userQuery = Wrappers.lambdaQuery();
userQuery.like(AquUser::getUserName, userKeyword)
.or()
.like(AquUser::getMobilePhone, userKeyword);
List<AquUser> matchingUsers = aquUserMapper.selectList(userQuery);
return matchingUsers.stream()
.map(AquUser::getId)
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,389 @@
package org.dromara.fishery.service.impl;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.fishery.domain.AquUser;
import org.dromara.fishery.domain.Device;
import org.dromara.fishery.domain.Pond;
import org.dromara.fishery.domain.bo.DeviceBo;
import org.dromara.fishery.domain.vo.DeviceVo;
import org.dromara.fishery.mapper.AquUserMapper;
import org.dromara.fishery.mapper.DeviceMapper;
import org.dromara.fishery.mapper.PondMapper;
import org.dromara.fishery.service.IDeviceService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* 设备管理Service业务层处理
*
* @author intc
* @date 2025-10-14
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class DeviceServiceImpl implements IDeviceService {
private final DeviceMapper baseMapper;
private final AquUserMapper aquUserMapper;
private final PondMapper pondMapper;
/**
* 查询设备管理
*
* @param id 主键
* @return 设备管理
*/
@Override
public DeviceVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询设备管理列表 - 批量查询方案避免N+1问题
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 设备管理分页列表
*/
@Override
public TableDataInfo<DeviceVo> queryPageList(DeviceBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<Device> lqw = buildQueryWrapper(bo);
Page<DeviceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
// 批量填充关联数据
enrichDeviceListWithUserInfo(result.getRecords());
enrichDeviceListWithPondInfo(result.getRecords());
// 计算过期信息
calculateExpirationInfo(result.getRecords());
return TableDataInfo.build(result);
}
/**
* 查询符合条件的设备管理列表 - 批量查询方案避免N+1问题
*
* @param bo 查询条件
* @return 设备管理列表
*/
@Override
public List<DeviceVo> queryList(DeviceBo bo) {
LambdaQueryWrapper<Device> lqw = buildQueryWrapper(bo);
List<DeviceVo> deviceList = baseMapper.selectVoList(lqw);
// 批量填充关联数据
enrichDeviceListWithUserInfo(deviceList);
enrichDeviceListWithPondInfo(deviceList);
// 计算过期信息
calculateExpirationInfo(deviceList);
return deviceList;
}
private LambdaQueryWrapper<Device> buildQueryWrapper(DeviceBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<Device> lqw = Wrappers.lambdaQuery();
// 处理排序逼辑如果expiredFlag为1按过期时间倒序否则按创建时间倒序
String expiredFlag = params != null ? (String) params.get("expiredFlag") : null;
if ("1".equals(expiredFlag)) {
// 按deadTime倒序过期时间越早的越靠后即过期越久的越靠前
lqw.orderByAsc(Device::getDeadTime);
} else {
lqw.orderByDesc(Device::getCreateTime);
}
lqw.eq(bo.getUserId() != null, Device::getUserId, bo.getUserId());
lqw.eq(StringUtils.isNotBlank(bo.getSerialNum()), Device::getSerialNum, bo.getSerialNum());
lqw.like(StringUtils.isNotBlank(bo.getDeviceName()), Device::getDeviceName, bo.getDeviceName());
lqw.eq(bo.getDeviceType() != null, Device::getDeviceType, bo.getDeviceType());
lqw.eq(bo.getBindTime() != null, Device::getBindTime, bo.getBindTime());
lqw.eq(bo.getPondId() != null, Device::getPondId, bo.getPondId());
lqw.like(StringUtils.isNotBlank(bo.getIccId()), Device::getIccId, bo.getIccId());
lqw.eq(StringUtils.isNotBlank(bo.getCategory()), Device::getCategory, bo.getCategory());
// 处理额外的查询参数
if (params != null && !params.isEmpty()) {
handleExtraParams(lqw, params);
}
return lqw;
}
/**
* 处理额外的查询参数
*
* @param lqw 查询包装器
* @param params 额外参数
*/
private void handleExtraParams(LambdaQueryWrapper<Device> lqw, Map<String, Object> params) {
// 处理用户搜索关键词(用户名或手机号)
String userKeyword = (String) params.get("userKeyword");
if (StringUtils.isNotBlank(userKeyword)) {
List<Long> matchingUserIds = getMatchingUserIds(userKeyword);
if (matchingUserIds.isEmpty()) {
// 如果没有符合条件的用户,直接返回空结果
lqw.eq(Device::getId, -1); // 使用不存在的ID来返回空结果
return;
}
lqw.in(Device::getUserId, matchingUserIds);
}
// 处理塘口搜索关键词(塘口名称)
String pondKeyword = (String) params.get("pondKeyword");
if (StringUtils.isNotBlank(pondKeyword)) {
List<Long> matchingPondIds = getMatchingPondIds(pondKeyword);
if (matchingPondIds.isEmpty()) {
// 如果没有符合条件的塘口,直接返回空结果
lqw.eq(Device::getId, -1); // 使用不存在的ID来返回空结果
return;
}
lqw.in(Device::getPondId, matchingPondIds);
}
// 处理是否过期查询条件
String isExpiredStr = (String) params.get("isExpired");
if (StringUtils.isNotBlank(isExpiredStr)) {
try {
Integer isExpired = Integer.parseInt(isExpiredStr);
Date currentDate = new Date();
if (isExpired == 1) {
// 查询已过期的设备deadTime < 当前时间)
lqw.lt(Device::getDeadTime, currentDate);
} else if (isExpired == 0) {
// 查询未过期的设备deadTime >= 当前时间 或 deadTime 为空)
lqw.and(wrapper -> wrapper.ge(Device::getDeadTime, currentDate)
.or()
.isNull(Device::getDeadTime));
}
} catch (NumberFormatException e) {
log.warn("isExpired参数格式错误: {}", isExpiredStr);
}
}
}
/**
* 新增设备管理
*
* @param bo 设备管理
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(DeviceBo bo) {
Device add = MapstructUtils.convert(bo, Device.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改设备管理
*
* @param bo 设备管理
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(DeviceBo bo) {
Device update = MapstructUtils.convert(bo, Device.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(Device entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除设备管理信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 为设备列表批量填充用户信息
*
* @param deviceList 设备列表
*/
private void enrichDeviceListWithUserInfo(List<DeviceVo> deviceList) {
if (deviceList == null || deviceList.isEmpty()) {
return;
}
// 收集所有的用户ID
List<Long> userIds = deviceList.stream()
.map(DeviceVo::getUserId)
.filter(userId -> userId != null)
.distinct()
.collect(Collectors.toList());
if (userIds.isEmpty()) {
return;
}
// 批量查询用户信息
List<AquUser> userList = aquUserMapper.selectBatchIds(userIds);
Map<Long, AquUser> userMap = userList.stream()
.collect(Collectors.toMap(AquUser::getId, user -> user, (existing, replacement) -> existing));
// 为每个设备设置用户信息
for (DeviceVo device : deviceList) {
if (device.getUserId() != null) {
AquUser user = userMap.get(device.getUserId());
if (user != null) {
device.setUserName(user.getUserName());
device.setMobilePhone(user.getMobilePhone());
}
}
}
}
/**
* 为设备列表批量填充塘口信息
*
* @param deviceList 设备列表
*/
private void enrichDeviceListWithPondInfo(List<DeviceVo> deviceList) {
if (deviceList == null || deviceList.isEmpty()) {
return;
}
// 收集所有的塘口ID
List<Long> pondIds = deviceList.stream()
.map(DeviceVo::getPondId)
.filter(pondId -> pondId != null)
.distinct()
.collect(Collectors.toList());
if (pondIds.isEmpty()) {
return;
}
// 批量查询塘口信息
List<Pond> pondList = pondMapper.selectBatchIds(pondIds);
Map<Long, Pond> pondMap = pondList.stream()
.collect(Collectors.toMap(Pond::getId, pond -> pond, (existing, replacement) -> existing));
// 为每个设备设置塘口信息
for (DeviceVo device : deviceList) {
if (device.getPondId() != null) {
Pond pond = pondMap.get(device.getPondId());
if (pond != null) {
device.setPondName(pond.getPondName());
}
}
}
}
/**
* 根据用户关键词查询符合条件的用户ID列表
*
* @param userKeyword 用户搜索关键词(用户名或手机号)
* @return 符合条件的用户ID列表
*/
private List<Long> getMatchingUserIds(String userKeyword) {
if (StringUtils.isBlank(userKeyword)) {
return Arrays.asList();
}
LambdaQueryWrapper<AquUser> userQuery = Wrappers.lambdaQuery();
userQuery.like(AquUser::getUserName, userKeyword)
.or()
.like(AquUser::getMobilePhone, userKeyword);
List<AquUser> matchingUsers = aquUserMapper.selectList(userQuery);
return matchingUsers.stream()
.map(AquUser::getId)
.collect(Collectors.toList());
}
/**
* 根据塘口关键词查询符合条件的塘口ID列表
*
* @param pondKeyword 塘口搜索关键词(塘口名称)
* @return 符合条件的塘口ID列表
*/
private List<Long> getMatchingPondIds(String pondKeyword) {
if (StringUtils.isBlank(pondKeyword)) {
return Arrays.asList();
}
LambdaQueryWrapper<Pond> pondQuery = Wrappers.lambdaQuery();
pondQuery.like(Pond::getPondName, pondKeyword);
List<Pond> matchingPonds = pondMapper.selectList(pondQuery);
return matchingPonds.stream()
.map(Pond::getId)
.collect(Collectors.toList());
}
/**
* 计算设备列表的过期信息
*
* @param deviceList 设备列表
*/
private void calculateExpirationInfo(List<DeviceVo> deviceList) {
if (deviceList == null || deviceList.isEmpty()) {
return;
}
Date currentDate = new Date();
long currentTime = currentDate.getTime();
for (DeviceVo device : deviceList) {
Date deadTime = device.getDeadTime();
if (deadTime == null) {
// 如果没有设置到期时间,设置为未过期
device.setIsExpired(0);
device.setExpiredDays(null);
continue;
}
long deadTimestamp = deadTime.getTime();
// 计算时间差(毫秒)
long diffMillis = currentTime - deadTimestamp;
// 转换为天数
long daysDiff = diffMillis / (24 * 60 * 60 * 1000);
if (currentTime > deadTimestamp) {
// 已过期
device.setIsExpired(1);
device.setExpiredDays(daysDiff); // 正数表示已过期天数
} else {
// 未过期
device.setIsExpired(0);
device.setExpiredDays(daysDiff); // 负数表示距离过期还有多少天
}
}
}
}

View File

@@ -73,7 +73,8 @@ public class DeviceThresholdServiceImpl implements IDeviceThresholdService {
private LambdaQueryWrapper<DeviceThreshold> buildQueryWrapper(DeviceThresholdBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<DeviceThreshold> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(DeviceThreshold::getId);
lqw.orderByDesc(DeviceThreshold::getCreateTime);
lqw.orderByAsc(DeviceThreshold::getThresholdType);
lqw.eq(bo.getThresholdType() != null, DeviceThreshold::getThresholdType, bo.getThresholdType());
lqw.like(StringUtils.isNotBlank(bo.getThresholdName()), DeviceThreshold::getThresholdName, bo.getThresholdName());
lqw.eq(bo.getLimitUpper() != null, DeviceThreshold::getLimitUpper, bo.getLimitUpper());

View File

@@ -1,24 +1,32 @@
package org.dromara.fishery.service.impl;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.fishery.domain.AquUser;
import org.dromara.fishery.domain.Fish;
import org.dromara.fishery.domain.Pond;
import org.dromara.fishery.domain.bo.PondBo;
import org.dromara.fishery.domain.vo.PondVo;
import org.dromara.fishery.domain.Pond;
import org.dromara.fishery.mapper.AquUserMapper;
import org.dromara.fishery.mapper.FishMapper;
import org.dromara.fishery.mapper.PondMapper;
import org.dromara.fishery.service.IPondService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* 塘口管理Service业务层处理
@@ -33,6 +41,10 @@ public class PondServiceImpl implements IPondService {
private final PondMapper baseMapper;
private final FishMapper fishMapper;
private final AquUserMapper aquUserMapper;
/**
* 查询塘口管理
*
@@ -55,6 +67,13 @@ public class PondServiceImpl implements IPondService {
public TableDataInfo<PondVo> queryPageList(PondBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<Pond> lqw = buildQueryWrapper(bo);
Page<PondVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
// 填充鱼类名称信息
enrichPondListWithFishNames(result.getRecords());
// 填充用户信息
enrichPondListWithUserInfo(result.getRecords());
return TableDataInfo.build(result);
}
@@ -67,21 +86,92 @@ public class PondServiceImpl implements IPondService {
@Override
public List<PondVo> queryList(PondBo bo) {
LambdaQueryWrapper<Pond> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
List<PondVo> list = baseMapper.selectVoList(lqw);
// 填充鱼类名称信息
enrichPondListWithFishNames(list);
// 填充用户信息
enrichPondListWithUserInfo(list);
return list;
}
private LambdaQueryWrapper<Pond> buildQueryWrapper(PondBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<Pond> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(Pond::getId);
lqw.eq(bo.getUserId() != null, Pond::getUserId, bo.getUserId());
lqw.like(StringUtils.isNotBlank(bo.getPondName()), Pond::getPondName, bo.getPondName());
lqw.like(StringUtils.isNotBlank(bo.getFishKindIds()), Pond::getFishKindIds, bo.getFishKindIds());
lqw.eq(bo.getPlaceTime() != null, Pond::getPlaceTime, bo.getPlaceTime());
lqw.eq(bo.getKeepNightOpen() != null, Pond::getKeepNightOpen, bo.getKeepNightOpen());
// 基础条件查询
lqw.eq(bo.getUserId() != null, Pond::getUserId, bo.getUserId())
.like(StringUtils.isNotBlank(bo.getPondName()), Pond::getPondName, bo.getPondName())
.like(StringUtils.isNotBlank(bo.getFishKindIds()), Pond::getFishKindIds, bo.getFishKindIds())
.eq(bo.getPlaceTime() != null, Pond::getPlaceTime, bo.getPlaceTime())
.eq(bo.getKeepNightOpen() != null, Pond::getKeepNightOpen, bo.getKeepNightOpen());
// 处理额外的查询参数
if (params != null && !params.isEmpty()) {
handleExtraParams(lqw, params);
}
// 默认按创建时间升序排列
lqw.orderByDesc(Pond::getCreateTime);
return lqw;
}
/**
* 处理额外的查询参数
*
* @param lqw 查询包装器
* @param params 额外参数
*/
private void handleExtraParams(LambdaQueryWrapper<Pond> lqw, Map<String, Object> params) {
// 处理用户搜索关键词
String userKeyword = (String) params.get("userKeyword");
if (StringUtils.isNotBlank(userKeyword)) {
List<Long> matchingUserIds = getMatchingUserIds(userKeyword);
if (matchingUserIds.isEmpty()) {
// 如果没有符合条件的用户,直接返回空结果
lqw.eq(Pond::getId, -1); // 使用不存在的ID来返回空结果
return;
}
lqw.in(Pond::getUserId, matchingUserIds);
}
// 处理时间范围查询
Object startTimeObj = params.get("startTime");
Object endTimeObj = params.get("endTime");
String startTime = startTimeObj != null ? startTimeObj.toString() : null;
String endTime = endTimeObj != null ? endTimeObj.toString() : null;
if (StringUtils.isNotBlank(startTime)) {
try {
// 验证日期格式并添加时分秒
String startDateTime = startTime.trim();
if (startDateTime.length() == 10) { // yyyy-MM-dd 格式
startDateTime += " 00:00:00";
}
lqw.ge(Pond::getCreateTime, startDateTime);
} catch (Exception e) {
log.warn("开始时间格式不正确: {}", startTime, e);
}
}
if (StringUtils.isNotBlank(endTime)) {
try {
// 验证日期格式并添加时分秒
String endDateTime = endTime.trim();
if (endDateTime.length() == 10) { // yyyy-MM-dd 格式
endDateTime += " 23:59:59";
}
lqw.le(Pond::getCreateTime, endDateTime);
} catch (Exception e) {
log.warn("结束时间格式不正确: {}", endTime, e);
}
}
}
/**
* 新增塘口管理
*
@@ -133,4 +223,134 @@ public class PondServiceImpl implements IPondService {
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 为塘口列表填充鱼类名称信息
* 这个方法替代了原来在查询中的复杂子查询
*
* @param pondList 塘口列表
*/
private void enrichPondListWithFishNames(List<PondVo> pondList) {
if (pondList == null || pondList.isEmpty()) {
return;
}
// 收集所有的鱼类ID
List<Long> allFishIds = pondList.stream()
.map(PondVo::getFishKindIds)
.filter(StringUtils::isNotBlank)
.flatMap(fishKindIds -> parseFishIds(fishKindIds).stream())
.distinct()
.collect(Collectors.toList());
if (allFishIds.isEmpty()) {
return;
}
// 批量查询鱼类信息
List<Fish> fishList = fishMapper.selectBatchIds(allFishIds);
Map<Long, String> fishNameMap = fishList.stream()
.collect(Collectors.toMap(Fish::getId, Fish::getFishName, (existing, replacement) -> existing));
// 为每个塘口设置鱼类名称如果PondVo有fishNames字段的话
// 注意由于PondVo中没有fishNames字段这里只是示例代码
// 实际使用时可能需要扩展PondVo或者通过其他方式返回鱼类名称
for (PondVo pond : pondList) {
List<Long> fishIds = parseFishIds(pond.getFishKindIds());
List<String> fishNames = fishIds.stream()
.map(id -> fishNameMap.getOrDefault(id, "未知鱼类"))
.collect(Collectors.toList());
pond.setFishKindNames(String.join(",", fishNames)); // 如果PondVo有这个字段的话
}
}
/**
* 解析鱼类ID字符串
* 支持格式: "[1,2,3]" 或 "1,2,3"
*
* @param fishKindIds 鱼类ID字符串
* @return 鱼类ID列表
*/
private List<Long> parseFishIds(String fishKindIds) {
if (StringUtils.isBlank(fishKindIds)) {
return Arrays.asList();
}
try {
// 移除方括号和空格
String cleanIds = fishKindIds.replaceAll("[\\[\\]\\s]", "");
if (StringUtils.isBlank(cleanIds)) {
return Arrays.asList();
}
return Arrays.stream(cleanIds.split(","))
.filter(StringUtils::isNotBlank)
.map(String::trim)
.map(Long::parseLong)
.collect(Collectors.toList());
} catch (NumberFormatException e) {
log.warn("解析鱼类ID失败: {}", fishKindIds, e);
return Arrays.asList();
}
}
/**
* 为塘口列表填充用户信息
*
* @param pondList 塘口列表
*/
private void enrichPondListWithUserInfo(List<PondVo> pondList) {
if (pondList == null || pondList.isEmpty()) {
return;
}
// 收集所有的用户ID
List<Long> userIds = pondList.stream()
.map(PondVo::getUserId)
.filter(userId -> userId != null)
.distinct()
.collect(Collectors.toList());
if (userIds.isEmpty()) {
return;
}
// 批量查询用户信息
List<AquUser> userList = aquUserMapper.selectBatchIds(userIds);
Map<Long, AquUser> userMap = userList.stream()
.collect(Collectors.toMap(AquUser::getId, user -> user, (existing, replacement) -> existing));
// 为每个塘口设置用户信息
for (PondVo pond : pondList) {
if (pond.getUserId() != null) {
AquUser user = userMap.get(pond.getUserId());
if (user != null) {
pond.setUserName(user.getUserName());
pond.setMobilePhone(user.getMobilePhone());
}
}
}
}
/**
* 根据用户关键词查询符合条件的用户ID列表
*
* @param userKeyword 用户搜索关键词(用户名或手机号)
* @return 符合条件的用户ID列表
*/
private List<Long> getMatchingUserIds(String userKeyword) {
if (StringUtils.isBlank(userKeyword)) {
return Arrays.asList();
}
LambdaQueryWrapper<AquUser> userQuery = Wrappers.lambdaQuery();
userQuery.like(AquUser::getUserName, userKeyword)
.or()
.like(AquUser::getMobilePhone, userKeyword);
List<AquUser> matchingUsers = aquUserMapper.selectList(userQuery);
return matchingUsers.stream()
.map(AquUser::getId)
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.fishery.mapper.DeviceBindRecordMapper">
</mapper>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.fishery.mapper.DeviceMapper">
</mapper>