fix: 微信小程序接口对接修改,联调测试问题修复。
This commit is contained in:
@@ -18,9 +18,27 @@ import com.intc.common.core.validate.EditGroup;
|
||||
import com.intc.common.log.enums.BusinessType;
|
||||
import com.intc.common.excel.utils.ExcelUtil;
|
||||
import com.intc.fishery.domain.vo.AquUserVo;
|
||||
import com.intc.fishery.domain.vo.UserChildVo;
|
||||
import com.intc.fishery.domain.bo.AquUserBo;
|
||||
import com.intc.fishery.domain.bo.ReqUpdateWarnPhone;
|
||||
import com.intc.fishery.domain.bo.ReqChangeName;
|
||||
import com.intc.fishery.domain.bo.ReqUpdatePhone;
|
||||
import com.intc.fishery.domain.bo.ReqAddUserChild;
|
||||
import com.intc.fishery.domain.bo.ReqId;
|
||||
import com.intc.fishery.domain.AquUser;
|
||||
import com.intc.fishery.domain.UserRelation;
|
||||
import com.intc.fishery.service.IAquUserService;
|
||||
import com.intc.fishery.mapper.AquUserMapper;
|
||||
import com.intc.fishery.mapper.UserRelationMapper;
|
||||
import com.intc.system.service.ISysUserService;
|
||||
import com.intc.system.domain.bo.SysUserBo;
|
||||
import com.intc.common.mybatis.core.page.TableDataInfo;
|
||||
import com.intc.common.satoken.utils.LoginHelper;
|
||||
import com.intc.common.core.utils.StringUtils;
|
||||
import com.intc.common.json.utils.JsonUtils;
|
||||
import com.intc.common.core.constant.GlobalConstants;
|
||||
import com.intc.common.redis.utils.RedisUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
|
||||
/**
|
||||
* 养殖用户管理
|
||||
@@ -35,6 +53,9 @@ import com.intc.common.mybatis.core.page.TableDataInfo;
|
||||
public class AquUserController extends BaseController {
|
||||
|
||||
private final IAquUserService aquUserService;
|
||||
private final AquUserMapper aquUserMapper;
|
||||
private final UserRelationMapper userRelationMapper;
|
||||
private final ISysUserService sysUserService;
|
||||
|
||||
/**
|
||||
* 查询养殖用户管理列表
|
||||
@@ -102,4 +123,341 @@ public class AquUserController extends BaseController {
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(aquUserService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取报警电话列表
|
||||
*
|
||||
* @return 报警电话列表
|
||||
*/
|
||||
@GetMapping("/list_warn_phone")
|
||||
public R<List<String>> getWarnPhone() {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null || userId < 0) {
|
||||
return R.fail("用户未登录");
|
||||
}
|
||||
|
||||
// 查询用户的报警电话 JSON字段
|
||||
AquUserVo user = aquUserService.queryById(userId);
|
||||
if (user == null) {
|
||||
return R.fail("用户不存在");
|
||||
}
|
||||
|
||||
String warnPhoneJson = user.getWarnPhoneJson();
|
||||
if (StringUtils.isEmpty(warnPhoneJson)) {
|
||||
return R.fail("不存在报警电话列表");
|
||||
}
|
||||
|
||||
// 反序列化JSON为List<String>
|
||||
try {
|
||||
List<String> warnPhones = JsonUtils.parseArray(warnPhoneJson, String.class);
|
||||
return R.ok(warnPhones);
|
||||
} catch (Exception e) {
|
||||
return R.fail("报警电话数据格式错误");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子用户列表
|
||||
*
|
||||
* @return 子用户列表
|
||||
*/
|
||||
@GetMapping("/list_user_child")
|
||||
public R<List<UserChildVo>> getListUserChild() {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null || userId < 0) {
|
||||
return R.fail("用户未登录");
|
||||
}
|
||||
|
||||
// 查询该用户的所有子账号
|
||||
List<UserChildVo> list = userRelationMapper.selectChildUsersByParentId(userId);
|
||||
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取父用户列表
|
||||
*
|
||||
* @return 父用户列表
|
||||
*/
|
||||
@GetMapping("/list_user_parent")
|
||||
public R<List<UserChildVo>> getListUserParent() {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null || userId < 0) {
|
||||
return R.fail("用户未登录");
|
||||
}
|
||||
|
||||
// 查询该用户的所有父账号
|
||||
List<UserChildVo> list = userRelationMapper.selectParentUsersByChildId(userId);
|
||||
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加子用户
|
||||
*
|
||||
* @param request 子用户手机号
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/add_user_child")
|
||||
public R<Void> addUserChild(@Validated @RequestBody ReqAddUserChild request) {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null || userId < 0) {
|
||||
return R.fail("用户未登录");
|
||||
}
|
||||
|
||||
// 根据手机号查询子用户
|
||||
AquUser childUser = aquUserMapper.selectOne(
|
||||
new LambdaQueryWrapper<AquUser>()
|
||||
.eq(AquUser::getMobilePhone, request.getMobilePhone())
|
||||
.select(AquUser::getId)
|
||||
);
|
||||
|
||||
if (childUser == null) {
|
||||
return R.fail("该手机号用户不存在");
|
||||
}
|
||||
|
||||
Long childUserId = childUser.getId();
|
||||
|
||||
// 检查是否已存在该子账号关系
|
||||
long count = userRelationMapper.selectCount(
|
||||
new LambdaQueryWrapper<UserRelation>()
|
||||
.eq(UserRelation::getParentUserId, userId)
|
||||
.eq(UserRelation::getChildUserId, childUserId)
|
||||
);
|
||||
|
||||
if (count > 0) {
|
||||
return R.fail("子账号已添加,无需重复添加");
|
||||
}
|
||||
|
||||
// 创建子账号关系
|
||||
UserRelation relation = new UserRelation();
|
||||
relation.setParentUserId(userId);
|
||||
relation.setChildUserId(childUserId);
|
||||
boolean success = userRelationMapper.insert(relation) > 0;
|
||||
|
||||
return toAjax(success);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除子用户
|
||||
*
|
||||
* @param request 关系ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@DeleteMapping("/delete_user_child")
|
||||
public R<Void> deleteUserChild(@Validated @RequestBody ReqId request) {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null || userId < 0) {
|
||||
return R.fail("用户未登录");
|
||||
}
|
||||
|
||||
// 查询子账号关系,验证权限
|
||||
UserRelation userRelation = userRelationMapper.selectOne(
|
||||
new LambdaQueryWrapper<UserRelation>()
|
||||
.eq(UserRelation::getId, request.getId())
|
||||
.select(UserRelation::getId, UserRelation::getParentUserId, UserRelation::getChildUserId)
|
||||
);
|
||||
|
||||
if (userRelation == null) {
|
||||
return R.fail("子账号关系不存在");
|
||||
}
|
||||
|
||||
// 验证是否是当前用户的子账号
|
||||
if (!userRelation.getParentUserId().equals(userId)) {
|
||||
return R.fail("无权删除该子账号");
|
||||
}
|
||||
|
||||
// 删除子账号关系
|
||||
int count = userRelationMapper.deleteById(request.getId());
|
||||
if (count == 0) {
|
||||
return R.fail("删除失败");
|
||||
}
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新报警电话列表
|
||||
*
|
||||
* @param request 报警电话列表
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/update_warn_phone")
|
||||
public R<Void> updateWarnPhone(@Validated @RequestBody ReqUpdateWarnPhone request) {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null || userId < 0) {
|
||||
return R.fail("用户未登录");
|
||||
}
|
||||
|
||||
// 查询用户信息,获取当前用户的手机号
|
||||
AquUserVo user = aquUserService.queryById(userId);
|
||||
if (user == null) {
|
||||
return R.fail("用户不存在");
|
||||
}
|
||||
|
||||
String oldMobilePhone = user.getMobilePhone();
|
||||
if (StringUtils.isEmpty(oldMobilePhone)) {
|
||||
return R.fail("用户手机号不存在,无权操作");
|
||||
}
|
||||
|
||||
// 验证报警电话列表是否包含用户自己的手机号
|
||||
List<String> listPhone = request.getListPhone();
|
||||
boolean containUser = false;
|
||||
for (String phone : listPhone) {
|
||||
if (phone.equals(oldMobilePhone)) {
|
||||
containUser = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!containUser) {
|
||||
return R.fail("报警电话必须包含自己手机号");
|
||||
}
|
||||
|
||||
// 序列化为JSON字符串
|
||||
String warnPhoneJson = JsonUtils.toJsonString(listPhone);
|
||||
|
||||
// 更新数据库
|
||||
AquUserBo updateBo = new AquUserBo();
|
||||
updateBo.setId(userId);
|
||||
updateBo.setWarnPhoneJson(warnPhoneJson);
|
||||
boolean success = aquUserService.updateByBo(updateBo);
|
||||
|
||||
return toAjax(success);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户名
|
||||
*
|
||||
* @param request 更新用户名请求
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/update_user_name")
|
||||
public R<Void> updateUserName(@Validated @RequestBody ReqChangeName request) {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null || userId < 0) {
|
||||
return R.fail("用户未登录");
|
||||
}
|
||||
|
||||
// 更新 AquUserBo 的用户名(长度验证已在 ReqChangeName 中处理)
|
||||
AquUserBo updateBo = new AquUserBo();
|
||||
updateBo.setId(userId);
|
||||
updateBo.setUserName(request.getNewName());
|
||||
boolean success = aquUserService.updateByBo(updateBo);
|
||||
|
||||
// 同时更新 SysUserBo 的昵称
|
||||
if (success) {
|
||||
SysUserBo sysUserBo = new SysUserBo();
|
||||
sysUserBo.setUserId(userId);
|
||||
sysUserBo.setNickName(request.getNewName());
|
||||
sysUserService.updateUser(sysUserBo);
|
||||
}
|
||||
|
||||
return toAjax(success);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新手机号
|
||||
*
|
||||
* @param request 更新手机号请求
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/update_mobile_phone")
|
||||
public R<Void> updateMobilePhone(@Validated @RequestBody ReqUpdatePhone request) {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null || userId < 0) {
|
||||
return R.fail("用户未登录");
|
||||
}
|
||||
|
||||
// 查询用户信息
|
||||
AquUserVo user = aquUserService.queryById(userId);
|
||||
if (user == null) {
|
||||
return R.fail("用户不存在");
|
||||
}
|
||||
|
||||
String oldMobilePhone = user.getMobilePhone();
|
||||
if (StringUtils.isEmpty(oldMobilePhone)) {
|
||||
return R.fail("用户手机号不存在,无权操作");
|
||||
}
|
||||
|
||||
// 验证旧手机号是否匹配
|
||||
if (!request.getOldMobilePhone().equals(oldMobilePhone)) {
|
||||
return R.fail("旧手机号不匹配");
|
||||
}
|
||||
|
||||
// 如果新旧手机号相同,直接返回成功
|
||||
if (request.getOldMobilePhone().equals(request.getNewMobilePhone())) {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
// 检查新手机号是否已被注册
|
||||
long count = aquUserMapper.selectCount(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<AquUser>()
|
||||
.eq(AquUser::getMobilePhone, request.getNewMobilePhone())
|
||||
);
|
||||
if (count > 0) {
|
||||
return R.fail("新手机号已被注册");
|
||||
}
|
||||
|
||||
// 验证短信验证码
|
||||
String codeKey = GlobalConstants.CAPTCHA_CODE_KEY + request.getNewMobilePhone();
|
||||
String cachedCode = RedisUtils.getCacheObject(codeKey);
|
||||
if (StringUtils.isBlank(cachedCode)) {
|
||||
return R.fail("短信验证码已过期");
|
||||
}
|
||||
if (!cachedCode.equals(request.getSmsCode())) {
|
||||
return R.fail("短信验证码错误");
|
||||
}
|
||||
|
||||
// 处理报警电话列表:替换旧手机号为新手机号,并移除重复的新手机号
|
||||
String warnPhoneJson = user.getWarnPhoneJson();
|
||||
List<String> listWarnPhone = new java.util.ArrayList<>();
|
||||
if (StringUtils.isNotEmpty(warnPhoneJson)) {
|
||||
try {
|
||||
listWarnPhone = JsonUtils.parseArray(warnPhoneJson, String.class);
|
||||
if (listWarnPhone == null) {
|
||||
listWarnPhone = new java.util.ArrayList<>();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
listWarnPhone = new java.util.ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
// 移除列表中所有的新手机号(避免重复)
|
||||
listWarnPhone.removeIf(phone -> phone.equals(request.getNewMobilePhone()));
|
||||
|
||||
// 将旧手机号替换为新手机号
|
||||
for (int i = 0; i < listWarnPhone.size(); i++) {
|
||||
if (listWarnPhone.get(i).equals(oldMobilePhone)) {
|
||||
listWarnPhone.set(i, request.getNewMobilePhone());
|
||||
}
|
||||
}
|
||||
|
||||
// 序列化报警电话列表
|
||||
String newWarnPhoneJson = JsonUtils.toJsonString(listWarnPhone);
|
||||
|
||||
// 更新数据库:手机号和报警电话列表
|
||||
AquUserBo updateBo = new AquUserBo();
|
||||
updateBo.setId(userId);
|
||||
updateBo.setMobilePhone(request.getNewMobilePhone());
|
||||
updateBo.setWarnPhoneJson(newWarnPhoneJson);
|
||||
boolean success = aquUserService.updateByBo(updateBo);
|
||||
|
||||
if (success) {
|
||||
// 删除已使用的验证码
|
||||
RedisUtils.deleteObject(codeKey);
|
||||
// 也删除旧手机号的验证码(如果存在)
|
||||
RedisUtils.deleteObject(GlobalConstants.CAPTCHA_CODE_KEY + request.getOldMobilePhone());
|
||||
}
|
||||
|
||||
return toAjax(success);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.intc.fishery.domain.vo.PublicDeviceSwitchSimpleVo;
|
||||
import com.intc.fishery.domain.vo.PublicDeviceBaseData;
|
||||
import com.intc.fishery.domain.vo.PublicDeviceLinkedCtrl;
|
||||
import com.intc.fishery.domain.vo.PublicDeviceDeadInfo;
|
||||
import com.intc.fishery.domain.vo.PublicDeviceTypeAndSerialNum;
|
||||
import com.intc.fishery.domain.bo.ReqId;
|
||||
import com.intc.fishery.domain.bo.ReqSetOxyTempWarnCall;
|
||||
import com.intc.fishery.domain.bo.ReqSetOxyWarnValue;
|
||||
@@ -46,6 +47,7 @@ import com.intc.fishery.mapper.PondMapper;
|
||||
import com.intc.fishery.mapper.LinkedCtrlMapper;
|
||||
import com.intc.fishery.mapper.DeviceCorrectRecordMapper;
|
||||
import com.intc.fishery.constant.DefineDeviceWarnCode;
|
||||
import com.intc.common.core.config.properties.DeviceTypeProperties;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -73,6 +75,7 @@ public class DeviceController extends BaseController {
|
||||
private final PondMapper pondMapper;
|
||||
private final LinkedCtrlMapper linkedCtrlMapper;
|
||||
private final DeviceCorrectRecordMapper deviceCorrectRecordMapper;
|
||||
private final DeviceTypeProperties deviceTypeProperties;
|
||||
|
||||
/**
|
||||
* 查询设备管理列表
|
||||
@@ -133,7 +136,7 @@ public class DeviceController extends BaseController {
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("fishery:device:remove")
|
||||
// @SaCheckPermission("fishery:device:remove")
|
||||
@Log(title = "设备管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@@ -976,4 +979,60 @@ public class DeviceController extends BaseController {
|
||||
|
||||
return R.ok(deviceBaseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查设备二维码,解析设备类型和序列号
|
||||
* 二维码格式:pk=xxxxx&dn=xxxxx
|
||||
*
|
||||
* @param rootUserId 用户ID(预留参数)
|
||||
* @param qrCode 设备二维码内容
|
||||
* @return 设备类型和序列号
|
||||
*/
|
||||
@GetMapping("/check_device_qrcode")
|
||||
public R<PublicDeviceTypeAndSerialNum> checkDeviceQrcode(
|
||||
@RequestParam("rootUserId") Long rootUserId,
|
||||
@RequestParam("qrCode") String qrCode) {
|
||||
|
||||
// 验证二维码不能为空
|
||||
if (qrCode == null || qrCode.trim().isEmpty()) {
|
||||
return R.fail("二维码格式错误");
|
||||
}
|
||||
|
||||
// 解析二维码,格式:pk=xxxxx&dn=xxxxx
|
||||
String[] parts = qrCode.trim().split("&");
|
||||
if (parts.length != 2) {
|
||||
return R.fail("二维码格式错误");
|
||||
}
|
||||
|
||||
String pkPart = parts[0].trim();
|
||||
String dnPart = parts[1].trim();
|
||||
|
||||
// 验证格式前缀
|
||||
if (!pkPart.startsWith("pk=") || !dnPart.startsWith("dn=")) {
|
||||
return R.fail("二维码格式错误");
|
||||
}
|
||||
|
||||
// 提取实际值
|
||||
String pk = pkPart.substring(3);
|
||||
String dn = dnPart.substring(3);
|
||||
|
||||
// 验证长度
|
||||
if (pk.length() < 10 || dn.length() < 10) {
|
||||
return R.fail("二维码格式错误");
|
||||
}
|
||||
|
||||
// 根据ProductKey判断设备类型
|
||||
Integer deviceType = deviceTypeProperties.getDeviceTypeByProductKey(pk);
|
||||
|
||||
if (deviceType == null) {
|
||||
return R.fail("二维码格式错误");
|
||||
}
|
||||
|
||||
// 构建返回结果
|
||||
PublicDeviceTypeAndSerialNum result = new PublicDeviceTypeAndSerialNum();
|
||||
result.setDeviceType(deviceType);
|
||||
result.setSerialNum(dn);
|
||||
|
||||
return R.ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intc.common.log.enums.BusinessType;
|
||||
import com.intc.common.excel.utils.ExcelUtil;
|
||||
import com.intc.fishery.domain.bo.PondBo;
|
||||
import com.intc.fishery.domain.bo.ReqChangePond;
|
||||
import com.intc.fishery.domain.bo.ReqTurnOpen;
|
||||
import com.intc.fishery.service.IPondService;
|
||||
import com.intc.common.mybatis.core.page.TableDataInfo;
|
||||
import com.intc.common.satoken.utils.LoginHelper;
|
||||
@@ -184,7 +185,23 @@ public class PondController extends BaseController {
|
||||
@PathVariable Long pondId) {
|
||||
PondDeviceListVo result = new PondDeviceListVo();
|
||||
|
||||
// 1. 查询塘口下的所有设备
|
||||
// 1. 查询塘口信息
|
||||
Pond pond = pondMapper.selectOne(
|
||||
new LambdaQueryWrapper<Pond>()
|
||||
.eq(Pond::getId, pondId)
|
||||
.select(Pond::getId, Pond::getPondName, Pond::getKeepNightOpen)
|
||||
);
|
||||
|
||||
if (pond == null) {
|
||||
return R.fail("塘口不存在");
|
||||
}
|
||||
|
||||
// 设置塘口信息
|
||||
result.setPondId(pond.getId());
|
||||
result.setPondName(pond.getPondName());
|
||||
result.setKeepNightOpen(pond.getKeepNightOpen());
|
||||
|
||||
// 2. 查询塘口下的所有设备
|
||||
List<Device> devices = deviceMapper.selectList(
|
||||
new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getPondId, pondId)
|
||||
@@ -198,12 +215,12 @@ public class PondController extends BaseController {
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
// 2. 收集所有设备ID,用于查询联动控制和故障码
|
||||
// 3. 收集所有设备ID,用于查询联动控制和故障码
|
||||
List<Long> deviceIds = devices.stream()
|
||||
.map(Device::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 3. 批量查询所有设备的联动控制
|
||||
// 4. 批量查询所有设备的联动控制
|
||||
List<LinkedCtrl> allLinkedCtrls = linkedCtrlMapper.selectList(
|
||||
new LambdaQueryWrapper<LinkedCtrl>()
|
||||
.in(LinkedCtrl::getDeviceId, deviceIds)
|
||||
@@ -211,14 +228,14 @@ public class PondController extends BaseController {
|
||||
java.util.Map<Long, List<LinkedCtrl>> linkedCtrlsByDevice = allLinkedCtrls.stream()
|
||||
.collect(Collectors.groupingBy(LinkedCtrl::getDeviceId));
|
||||
|
||||
// 4. 批量查询塘口的所有开关
|
||||
// 5. 批量查询塘口的所有开关
|
||||
List<DeviceSwitch> allSwitches = deviceSwitchMapper.selectList(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.eq(DeviceSwitch::getPondId, pondId)
|
||||
.orderByAsc(DeviceSwitch::getIndex)
|
||||
);
|
||||
|
||||
// 5. 收集开关ID,查询定时控制
|
||||
// 6. 收集开关ID,查询定时控制
|
||||
List<Long> switchIds = allSwitches.stream()
|
||||
.map(DeviceSwitch::getId)
|
||||
.collect(Collectors.toList());
|
||||
@@ -232,11 +249,11 @@ public class PondController extends BaseController {
|
||||
.collect(Collectors.groupingBy(TimingCtrl::getSwitchId));
|
||||
}
|
||||
|
||||
// 6. 按设备ID分组开关
|
||||
// 7. 按设备ID分组开关
|
||||
java.util.Map<Long, List<DeviceSwitch>> switchesByDevice = allSwitches.stream()
|
||||
.collect(Collectors.groupingBy(DeviceSwitch::getDeviceId));
|
||||
|
||||
// 7. 批量查询故障码
|
||||
// 8. 批量查询故障码
|
||||
Set<Long> controllerIds = devices.stream()
|
||||
.filter(d -> d.getDeviceType() != null && d.getDeviceType() == 2)
|
||||
.map(Device::getId)
|
||||
@@ -249,7 +266,7 @@ public class PondController extends BaseController {
|
||||
);
|
||||
}
|
||||
|
||||
// 8. 处理探测器列表 (包含: deviceType=1 + deviceType=2且isOxygenUsed=1)
|
||||
// 9. 处理探测器列表 (包含: deviceType=1 + deviceType=2且isOxygenUsed=1)
|
||||
List<DeviceVo> detectorList = new ArrayList<>();
|
||||
for (Device device : devices) {
|
||||
// 水质检测仪 或 开启溶氧检测的测控一体机
|
||||
@@ -283,7 +300,7 @@ public class PondController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
// 9. 处理控制器列表 (仅测控一体机 deviceType=2)
|
||||
// 10. 处理控制器列表 (仅测控一体机 deviceType=2)
|
||||
List<DeviceWithSwitchVo> controllerList = new ArrayList<>();
|
||||
for (Device device : devices) {
|
||||
if (device.getDeviceType() != null && device.getDeviceType() == 2) {
|
||||
@@ -865,8 +882,8 @@ public class PondController extends BaseController {
|
||||
// 如果塘口没有变化,直接返回
|
||||
Long oldPondId = device.getPondId();
|
||||
Long newPondId = (request.getPondId() != null && request.getPondId() > 0) ? request.getPondId() : null;
|
||||
|
||||
if ((oldPondId == null && newPondId == null) ||
|
||||
|
||||
if ((oldPondId == null && newPondId == null) ||
|
||||
(oldPondId != null && oldPondId.equals(newPondId))) {
|
||||
return R.ok();
|
||||
}
|
||||
@@ -944,4 +961,56 @@ public class PondController extends BaseController {
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置塘口夜间防误关开关
|
||||
* 开启后,夜间时段(21:00-次日6:00)内不会因为故障而关闭设备
|
||||
*
|
||||
* @param request 请求对象(包含塘口ID和开关状态)
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/keep_night_open")
|
||||
public R<Void> setKeepNightOpen(
|
||||
@Validated @RequestBody ReqTurnOpen request) {
|
||||
|
||||
// 验证塘口ID
|
||||
if (request.getId() == null || request.getId() <= 0) {
|
||||
return R.fail("塘口ID不能为空");
|
||||
}
|
||||
|
||||
// 查询塘口信息
|
||||
Pond pond = pondMapper.selectOne(
|
||||
new LambdaQueryWrapper<Pond>()
|
||||
.eq(Pond::getId, request.getId())
|
||||
.select(Pond::getId, Pond::getUserId, Pond::getPondName, Pond::getKeepNightOpen)
|
||||
);
|
||||
|
||||
// 验证塘口存在性和权限
|
||||
if (pond == null) {
|
||||
return R.fail("塘口不存在或无权限访问");
|
||||
}
|
||||
|
||||
// 如果开关状态没有变化,直接返回
|
||||
if (pond.getKeepNightOpen() != null && pond.getKeepNightOpen().equals(request.getIsOpen())) {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
// 更新夜间防误关开关
|
||||
boolean updated = pondMapper.update(null,
|
||||
new LambdaUpdateWrapper<Pond>()
|
||||
.eq(Pond::getId, request.getId())
|
||||
.set(Pond::getKeepNightOpen, request.getIsOpen())
|
||||
) > 0;
|
||||
|
||||
if (!updated) {
|
||||
return R.fail("更新失败");
|
||||
}
|
||||
|
||||
// TODO: 记录操作日志
|
||||
// String op = request.getIsOpen() == 1 ? "开启" : "关闭";
|
||||
// CacheData.AddMessageOpRecordUser(rootUserId, userId, "塘口操作",
|
||||
// String.format("塘口(%s)夜间防误关:%s", pond.getPondName(), op));
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,22 @@ import com.intc.common.core.validate.AddGroup;
|
||||
import com.intc.common.core.validate.EditGroup;
|
||||
import com.intc.common.log.enums.BusinessType;
|
||||
import com.intc.fishery.domain.vo.TimingCtrlVo;
|
||||
import com.intc.fishery.domain.vo.PublicTimeCtrl;
|
||||
import com.intc.fishery.domain.bo.TimingCtrlBo;
|
||||
import com.intc.fishery.domain.bo.ReqId;
|
||||
import com.intc.fishery.domain.bo.ReqAddTimeCtrl;
|
||||
import com.intc.fishery.service.ITimingCtrlService;
|
||||
import com.intc.common.mybatis.core.page.TableDataInfo;
|
||||
import com.intc.fishery.mapper.TimingCtrlMapper;
|
||||
import com.intc.fishery.mapper.DeviceSwitchMapper;
|
||||
import com.intc.fishery.mapper.DeviceMapper;
|
||||
import com.intc.fishery.domain.TimingCtrl;
|
||||
import com.intc.fishery.domain.DeviceSwitch;
|
||||
import com.intc.fishery.domain.Device;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import java.util.Calendar;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 开关定时控制
|
||||
@@ -34,6 +47,9 @@ import com.intc.common.mybatis.core.page.TableDataInfo;
|
||||
public class TimingCtrlController extends BaseController {
|
||||
|
||||
private final ITimingCtrlService timingCtrlService;
|
||||
private final TimingCtrlMapper timingCtrlMapper;
|
||||
private final DeviceSwitchMapper deviceSwitchMapper;
|
||||
private final DeviceMapper deviceMapper;
|
||||
|
||||
/**
|
||||
* 查询开关定时控制列表
|
||||
@@ -101,4 +117,151 @@ public class TimingCtrlController extends BaseController {
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(timingCtrlService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定开关的定时控制列表
|
||||
*
|
||||
* @param request 请求对象(包含开关ID)
|
||||
* @return 定时控制列表
|
||||
*/
|
||||
@PutMapping("/list")
|
||||
public R<List<PublicTimeCtrl>> getTimeCtrlList(
|
||||
@Validated @RequestBody ReqId request) {
|
||||
|
||||
// 查询指定开关的所有定时控制,按创建时间降序排列
|
||||
List<TimingCtrl> timingCtrls = timingCtrlMapper.selectList(
|
||||
new LambdaQueryWrapper<TimingCtrl>()
|
||||
.eq(TimingCtrl::getSwitchId, request.getId())
|
||||
.orderByDesc(TimingCtrl::getCreateTime)
|
||||
);
|
||||
|
||||
// 转换为VO列表
|
||||
List<PublicTimeCtrl> list = timingCtrls.stream()
|
||||
.map(tc -> {
|
||||
PublicTimeCtrl vo = new PublicTimeCtrl();
|
||||
vo.setId(tc.getId());
|
||||
vo.setSwitchId(tc.getSwitchId());
|
||||
vo.setOpenTime(tc.getOpenTime());
|
||||
vo.setCloseTime(tc.getCloseTime());
|
||||
vo.setLoopType(tc.getLoopType());
|
||||
vo.setIsOpen(tc.getIsOpen());
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加定时控制
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
public R<Void> addTimeCtrl(
|
||||
@Validated @RequestBody ReqAddTimeCtrl request) {
|
||||
|
||||
// 验证开启和关闭时间不能相同
|
||||
if (request.getOpenTime().equals(request.getCloseTime())) {
|
||||
return R.fail("开启和关闭时间不能相同");
|
||||
}
|
||||
|
||||
// 将时间转换为今天的具体时刻
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
Date dateToday = calendar.getTime();
|
||||
|
||||
// 设置开启时间
|
||||
Calendar openCal = Calendar.getInstance();
|
||||
openCal.setTime(dateToday);
|
||||
Calendar reqOpenCal = Calendar.getInstance();
|
||||
reqOpenCal.setTime(request.getOpenTime());
|
||||
openCal.set(Calendar.HOUR_OF_DAY, reqOpenCal.get(Calendar.HOUR_OF_DAY));
|
||||
openCal.set(Calendar.MINUTE, reqOpenCal.get(Calendar.MINUTE));
|
||||
Date openTime = openCal.getTime();
|
||||
|
||||
// 设置关闭时间
|
||||
Calendar closeCal = Calendar.getInstance();
|
||||
closeCal.setTime(dateToday);
|
||||
Calendar reqCloseCal = Calendar.getInstance();
|
||||
reqCloseCal.setTime(request.getCloseTime());
|
||||
closeCal.set(Calendar.HOUR_OF_DAY, reqCloseCal.get(Calendar.HOUR_OF_DAY));
|
||||
closeCal.set(Calendar.MINUTE, reqCloseCal.get(Calendar.MINUTE));
|
||||
Date closeTime = closeCal.getTime();
|
||||
|
||||
// 如果开启时间大于关闭时间,则关闭时间加1天
|
||||
if (openTime.after(closeTime)) {
|
||||
closeCal.add(Calendar.DAY_OF_MONTH, 1);
|
||||
closeTime = closeCal.getTime();
|
||||
}
|
||||
|
||||
// 查询开关信息,包括关联的设备信息
|
||||
DeviceSwitch deviceSwitch = deviceSwitchMapper.selectOne(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.eq(DeviceSwitch::getId, request.getId())
|
||||
.select(DeviceSwitch::getId, DeviceSwitch::getSwitchName,
|
||||
DeviceSwitch::getPondId, DeviceSwitch::getDeviceId, DeviceSwitch::getIsOpen)
|
||||
);
|
||||
|
||||
if (deviceSwitch == null) {
|
||||
return R.fail("开关不存在");
|
||||
}
|
||||
|
||||
// 查询设备信息
|
||||
Device device = deviceMapper.selectOne(
|
||||
new LambdaQueryWrapper<Device>()
|
||||
.eq(Device::getId, deviceSwitch.getDeviceId())
|
||||
.select(Device::getId, Device::getUserId, Device::getDeviceName,
|
||||
Device::getWarnCode, Device::getDeadTime)
|
||||
);
|
||||
|
||||
if (device == null) {
|
||||
return R.fail("开关不存在");
|
||||
}
|
||||
|
||||
// 检查设备是否过期
|
||||
if (device.getDeadTime() != null && device.getDeadTime().before(new Date())) {
|
||||
return R.fail("设备服务已过期");
|
||||
}
|
||||
|
||||
// 检查开关是否绑定了塘口
|
||||
if (deviceSwitch.getPondId() == null || deviceSwitch.getPondId() <= 0) {
|
||||
return R.fail("开关未绑定塘口");
|
||||
}
|
||||
|
||||
// 检查定时控制数量是否超限4个
|
||||
long count = timingCtrlMapper.selectCount(
|
||||
new LambdaQueryWrapper<TimingCtrl>()
|
||||
.eq(TimingCtrl::getSwitchId, request.getId())
|
||||
);
|
||||
|
||||
if (count >= 4) {
|
||||
return R.fail("定时控制数量不得超过4个");
|
||||
}
|
||||
|
||||
// 创建定时控制记录
|
||||
TimingCtrl timingCtrl = new TimingCtrl();
|
||||
timingCtrl.setSwitchId(request.getId());
|
||||
timingCtrl.setOpenTime(openTime);
|
||||
timingCtrl.setCloseTime(closeTime);
|
||||
timingCtrl.setLoopType(request.getLoopType().longValue());
|
||||
timingCtrl.setIsOpen(0L); // 默认未启用
|
||||
|
||||
// 插入数据库
|
||||
int result = timingCtrlMapper.insert(timingCtrl);
|
||||
|
||||
if (result > 0) {
|
||||
// TODO: 记录操作日志
|
||||
// CacheData.AddMessageOpRecordUser(rootUserId, userId, "开关定时控制",
|
||||
// String.format("%s(%s)新增定时控制。",
|
||||
// device.getDeviceName(), deviceSwitch.getSwitchName()));
|
||||
return R.ok();
|
||||
} else {
|
||||
return R.fail("添加失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.intc.fishery.domain.bo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 添加定时控制请求对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-14
|
||||
*/
|
||||
@Data
|
||||
public class ReqAddTimeCtrl implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 开关ID
|
||||
*/
|
||||
@NotNull(message = "开关ID不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 开启时间(只包含时分)
|
||||
*/
|
||||
@NotNull(message = "开启时间不能为空")
|
||||
@JsonFormat(pattern = "HH:mm")
|
||||
private Date openTime;
|
||||
|
||||
/**
|
||||
* 关闭时间(只包含时分)
|
||||
*/
|
||||
@NotNull(message = "关闭时间不能为空")
|
||||
@JsonFormat(pattern = "HH:mm")
|
||||
private Date closeTime;
|
||||
|
||||
/**
|
||||
* 循环类型
|
||||
*/
|
||||
@NotNull(message = "循环类型不能为空")
|
||||
private Integer loopType;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.intc.fishery.domain.bo;
|
||||
|
||||
import com.intc.common.core.constant.RegexConstants;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 添加子用户请求对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-14
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "添加子用户请求对象")
|
||||
public class ReqAddUserChild implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 子用户手机号
|
||||
*/
|
||||
@Schema(description = "子用户手机号")
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Pattern(regexp = RegexConstants.MOBILE, message = "手机号格式不正确")
|
||||
private String mobilePhone;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.intc.fishery.domain.bo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
import com.intc.common.core.constant.RegexConstants;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 更新手机号请求对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-14
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "更新手机号请求对象")
|
||||
public class ReqUpdatePhone implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 旧手机号
|
||||
*/
|
||||
@Schema(description = "旧手机号")
|
||||
@NotBlank(message = "旧手机号不能为空")
|
||||
@Pattern(regexp = RegexConstants.MOBILE, message = "旧手机号格式不正确")
|
||||
private String oldMobilePhone;
|
||||
|
||||
/**
|
||||
* 新手机号
|
||||
*/
|
||||
@Schema(description = "新手机号")
|
||||
@NotBlank(message = "新手机号不能为空")
|
||||
@Pattern(regexp = RegexConstants.MOBILE, message = "新手机号格式不正确")
|
||||
private String newMobilePhone;
|
||||
|
||||
/**
|
||||
* 短信验证码
|
||||
*/
|
||||
@Schema(description = "短信验证码")
|
||||
@NotBlank(message = "短信验证码不能为空")
|
||||
private String smsCode;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.intc.fishery.domain.bo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
import com.intc.common.core.constant.RegexConstants;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 更新报警电话请求对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-14
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "更新报警电话请求对象")
|
||||
public class ReqUpdateWarnPhone implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 报警电话列表
|
||||
*/
|
||||
@Schema(description = "报警电话列表")
|
||||
@NotEmpty(message = "报警电话列表不能为空")
|
||||
private List<@Pattern(regexp = RegexConstants.MOBILE, message = "手机号格式不正确") String> listPhone;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.intc.fishery.domain.bo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
import com.intc.common.core.constant.RegexConstants;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 验证短信验证码请求对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-14
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "验证短信验证码请求对象")
|
||||
public class ReqVerifySmsCode implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@Schema(description = "手机号")
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Pattern(regexp = RegexConstants.MOBILE, message = "手机号格式不正确")
|
||||
private String mobilePhone;
|
||||
|
||||
/**
|
||||
* 短信验证码
|
||||
*/
|
||||
@Schema(description = "短信验证码")
|
||||
@NotBlank(message = "短信验证码不能为空")
|
||||
private String smsCode;
|
||||
}
|
||||
@@ -18,6 +18,21 @@ public class PondDeviceListVo implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 塘口ID
|
||||
*/
|
||||
private Long pondId;
|
||||
|
||||
/**
|
||||
* 塘口名称
|
||||
*/
|
||||
private String pondName;
|
||||
|
||||
/**
|
||||
* 夜间防误关(0-关闭,1-开启)
|
||||
*/
|
||||
private Integer keepNightOpen;
|
||||
|
||||
/**
|
||||
* 探测器列表(水质检测仪)
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 设备类型和序列号视图对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-14
|
||||
*/
|
||||
@Data
|
||||
public class PublicDeviceTypeAndSerialNum implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 设备类型(1-水质检测仪,2-控制一体机)
|
||||
*/
|
||||
private Integer deviceType;
|
||||
|
||||
/**
|
||||
* 设备序列号
|
||||
*/
|
||||
private String serialNum;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 定时控制视图对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-14
|
||||
*/
|
||||
@Data
|
||||
public class PublicTimeCtrl implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 开关ID
|
||||
*/
|
||||
private Long switchId;
|
||||
|
||||
/**
|
||||
* 开启时间
|
||||
*/
|
||||
@JsonFormat(pattern = "HH:mm:ss")
|
||||
private Date openTime;
|
||||
|
||||
/**
|
||||
* 关闭时间
|
||||
*/
|
||||
@JsonFormat(pattern = "HH:mm:ss")
|
||||
private Date closeTime;
|
||||
|
||||
/**
|
||||
* 循环类型
|
||||
*/
|
||||
private Long loopType;
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private Long isOpen;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.intc.fishery.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 子用户关系视图对象
|
||||
*
|
||||
* @author intc
|
||||
* @date 2026-01-14
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "子用户关系视图对象")
|
||||
public class UserChildVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 关系表主键id
|
||||
*/
|
||||
@Schema(description = "关系表主键id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 子账号用户id
|
||||
*/
|
||||
@Schema(description = "子账号用户id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 子账号用户名
|
||||
*/
|
||||
@Schema(description = "子账号用户名")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 子账号手机号
|
||||
*/
|
||||
@Schema(description = "子账号手机号")
|
||||
private String mobilePhone;
|
||||
|
||||
/**
|
||||
* 关系创建时间
|
||||
*/
|
||||
@Schema(description = "关系创建时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createdTime;
|
||||
}
|
||||
@@ -2,7 +2,12 @@ package com.intc.fishery.mapper;
|
||||
|
||||
import com.intc.fishery.domain.UserRelation;
|
||||
import com.intc.fishery.domain.vo.UserRelationVo;
|
||||
import com.intc.fishery.domain.vo.UserChildVo;
|
||||
import com.intc.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 养殖用户子账号Mapper接口
|
||||
@@ -12,4 +17,30 @@ import com.intc.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
*/
|
||||
public interface UserRelationMapper extends BaseMapperPlus<UserRelation, UserRelationVo> {
|
||||
|
||||
/**
|
||||
* 查询用户的子账号列表
|
||||
*
|
||||
* @param parentUserId 父级用户ID
|
||||
* @return 子账号列表
|
||||
*/
|
||||
@Select("SELECT r.id, r.child_user_id as userId, u.user_name as userName, " +
|
||||
"u.mobile_phone as mobilePhone, r.create_time as createdTime " +
|
||||
"FROM aqu_user_relation r " +
|
||||
"LEFT JOIN aqu_user u ON r.child_user_id = u.id " +
|
||||
"WHERE r.parent_user_id = #{parentUserId}")
|
||||
List<UserChildVo> selectChildUsersByParentId(@Param("parentUserId") Long parentUserId);
|
||||
|
||||
/**
|
||||
* 查询用户的父账号列表
|
||||
*
|
||||
* @param childUserId 子用户ID
|
||||
* @return 父账号列表
|
||||
*/
|
||||
@Select("SELECT r.id, r.parent_user_id as userId, u.user_name as userName, " +
|
||||
"u.mobile_phone as mobilePhone, r.create_time as createdTime " +
|
||||
"FROM aqu_user_relation r " +
|
||||
"LEFT JOIN aqu_user u ON r.parent_user_id = u.id " +
|
||||
"WHERE r.child_user_id = #{childUserId}")
|
||||
List<UserChildVo> selectParentUsersByChildId(@Param("childUserId") Long childUserId);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,31 @@
|
||||
package com.intc.fishery.service.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.intc.common.core.utils.MapstructUtils;
|
||||
import com.intc.common.core.utils.StringUtils;
|
||||
import com.intc.common.mybatis.core.page.PageQuery;
|
||||
import com.intc.common.mybatis.core.page.TableDataInfo;
|
||||
import com.intc.fishery.domain.AquUser;
|
||||
import com.intc.fishery.domain.Device;
|
||||
import com.intc.fishery.domain.DeviceCorrectRecord;
|
||||
import com.intc.fishery.domain.DeviceSwitch;
|
||||
import com.intc.fishery.domain.LinkedCtrl;
|
||||
import com.intc.fishery.domain.Pond;
|
||||
import com.intc.fishery.domain.TimingCtrl;
|
||||
import com.intc.fishery.domain.bo.DeviceBo;
|
||||
import com.intc.fishery.domain.vo.DeviceVo;
|
||||
import com.intc.fishery.mapper.DeviceCorrectRecordMapper;
|
||||
import com.intc.fishery.mapper.DeviceMapper;
|
||||
import com.intc.fishery.mapper.DeviceSwitchMapper;
|
||||
import com.intc.fishery.mapper.LinkedCtrlMapper;
|
||||
import com.intc.fishery.mapper.TimingCtrlMapper;
|
||||
import com.intc.fishery.service.IDeviceService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
@@ -36,6 +45,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class DeviceServiceImpl implements IDeviceService {
|
||||
|
||||
private final DeviceMapper baseMapper;
|
||||
private final DeviceCorrectRecordMapper deviceCorrectRecordMapper;
|
||||
private final DeviceSwitchMapper deviceSwitchMapper;
|
||||
private final LinkedCtrlMapper linkedCtrlMapper;
|
||||
private final TimingCtrlMapper timingCtrlMapper;
|
||||
|
||||
/**
|
||||
* 查询设备管理
|
||||
@@ -206,16 +219,79 @@ public class DeviceServiceImpl implements IDeviceService {
|
||||
|
||||
/**
|
||||
* 校验并批量删除设备管理信息
|
||||
* 删除顺序:校准记录 -> 定时控制 -> 开关(先解除联动控制引用)-> 联动控制 -> 设备
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
|
||||
// 1. 删除设备关联的校准记录
|
||||
deviceCorrectRecordMapper.delete(
|
||||
new LambdaQueryWrapper<DeviceCorrectRecord>()
|
||||
.in(DeviceCorrectRecord::getDeviceId, ids)
|
||||
);
|
||||
|
||||
// 2. 查询设备关联的开关
|
||||
List<DeviceSwitch> switches = deviceSwitchMapper.selectList(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.in(DeviceSwitch::getDeviceId, ids)
|
||||
);
|
||||
|
||||
if (!switches.isEmpty()) {
|
||||
// 收集开关ID
|
||||
List<Long> switchIds = switches.stream()
|
||||
.map(DeviceSwitch::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 3. 删除开关关联的定时控制
|
||||
timingCtrlMapper.delete(
|
||||
new LambdaQueryWrapper<TimingCtrl>()
|
||||
.in(TimingCtrl::getSwitchId, switchIds)
|
||||
);
|
||||
|
||||
// 收集开关关联的联动控制ID
|
||||
List<Long> linkedCtrlIds = switches.stream()
|
||||
.map(DeviceSwitch::getLinkedCtrlId)
|
||||
.filter(id -> id != null && id > 0)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 4. 解除开关与联动控制的绑定
|
||||
deviceSwitchMapper.update(null,
|
||||
new LambdaUpdateWrapper<DeviceSwitch>()
|
||||
.set(DeviceSwitch::getLinkedCtrlId, null)
|
||||
.in(DeviceSwitch::getDeviceId, ids)
|
||||
);
|
||||
|
||||
// 5. 删除联动控制(如果有)
|
||||
if (!linkedCtrlIds.isEmpty()) {
|
||||
linkedCtrlMapper.delete(
|
||||
new LambdaQueryWrapper<LinkedCtrl>()
|
||||
.in(LinkedCtrl::getId, linkedCtrlIds)
|
||||
);
|
||||
}
|
||||
|
||||
// 6. 删除开关
|
||||
deviceSwitchMapper.delete(
|
||||
new LambdaQueryWrapper<DeviceSwitch>()
|
||||
.in(DeviceSwitch::getDeviceId, ids)
|
||||
);
|
||||
}
|
||||
|
||||
// 7. 删除设备本身关联的联动控制
|
||||
linkedCtrlMapper.delete(
|
||||
new LambdaQueryWrapper<LinkedCtrl>()
|
||||
.in(LinkedCtrl::getDeviceId, ids)
|
||||
);
|
||||
|
||||
// 8. 最后删除设备
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user