fix: 微信小程序接口对接修改。

This commit is contained in:
tianyongbao
2026-01-12 00:33:59 +08:00
parent e8fbb37062
commit 750e5351b3
13 changed files with 531 additions and 25 deletions

View File

@@ -71,7 +71,7 @@ public class DeviceController extends BaseController {
/**
* 新增设备管理
*/
@SaCheckPermission("fishery:device:add")
// @SaCheckPermission("fishery:device:add")
@Log(title = "设备管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()

View File

@@ -38,7 +38,7 @@ public class MessageOpRecordController extends BaseController {
/**
* 查询用户操作记录列表
*/
@SaCheckPermission("fishery:messageOpRecord:list")
// @SaCheckPermission("fishery:messageOpRecord:list")
@GetMapping("/list")
public TableDataInfo<MessageOpRecordVo> list(MessageOpRecordBo bo, PageQuery pageQuery) {
return messageOpRecordService.queryPageList(bo, pageQuery);

View File

@@ -1,7 +1,9 @@
package com.intc.fishery.controller;
import java.util.List;
import java.util.Map;
import com.intc.common.excel.utils.ExcelUtil;
import com.intc.common.satoken.utils.LoginHelper;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
@@ -38,7 +40,7 @@ public class MessageWarnController extends BaseController {
/**
* 查询设备告警记录列表
*/
@SaCheckPermission("fishery:messageWarn:list")
// @SaCheckPermission("fishery:messageWarn:list")
@GetMapping("/list")
public TableDataInfo<MessageWarnVo> list(MessageWarnBo bo, PageQuery pageQuery) {
return messageWarnService.queryPageList(bo, pageQuery);
@@ -101,4 +103,21 @@ public class MessageWarnController extends BaseController {
@PathVariable Long[] ids) {
return toAjax(messageWarnService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 已读一条消息
*/
@PutMapping("/read")
public R<Void> readMessage(@RequestParam("id") Long id) {
return toAjax(messageWarnService.readMessage(id));
}
/**
* 已读全部消息
*/
@PutMapping("/read/all")
public R<Void> readAllMessages() {
Long userId = LoginHelper.getUserId();
return toAjax(messageWarnService.readAllMessages(userId));
}
}

View File

@@ -39,7 +39,7 @@ public class PayOrderController extends BaseController {
/**
* 查询充值订单列表
*/
@SaCheckPermission("fishery:payOrder:list")
// @SaCheckPermission("fishery:payOrder:list")
@GetMapping("/list")
public TableDataInfo<PayOrderVo> list(PayOrderBo bo, PageQuery pageQuery) {
return payOrderService.queryPageList(bo, pageQuery);

View File

@@ -69,7 +69,7 @@ public class PondController extends BaseController {
*
* @param id 主键
*/
@SaCheckPermission("fishery:pond:query")
// @SaCheckPermission("fishery:pond:query")
@GetMapping("/{id}")
public R<PondVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
@@ -120,7 +120,7 @@ public class PondController extends BaseController {
/**
* 修改塘口管理
*/
@SaCheckPermission("fishery:pond:edit")
// @SaCheckPermission("fishery:pond:edit")
@Log(title = "塘口管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
@@ -133,7 +133,7 @@ public class PondController extends BaseController {
*
* @param ids 主键串
*/
@SaCheckPermission("fishery:pond:remove")
// @SaCheckPermission("fishery:pond:remove")
@Log(title = "塘口管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")

View File

@@ -65,4 +65,20 @@ public interface IMessageWarnService {
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 已读一条消息
*
* @param id 消息ID
* @return 是否成功
*/
Boolean readMessage(Long id);
/**
* 已读全部消息
*
* @param userId 用户ID
* @return 是否成功
*/
Boolean readAllMessages(Long userId);
}

View File

@@ -197,4 +197,38 @@ public class MessageWarnServiceImpl implements IMessageWarnService {
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 已读一条消息
*
* @param id 消息ID
* @return 是否成功
*/
@Override
public Boolean readMessage(Long id) {
MessageWarn messageWarn = baseMapper.selectById(id);
if (messageWarn == null) {
return false;
}
messageWarn.setIsRead(1);
return baseMapper.updateById(messageWarn) > 0;
}
/**
* 已读全部消息
*
* @param userId 用户ID
* @return 是否成功
*/
@Override
public Boolean readAllMessages(Long userId) {
MessageWarn update = new MessageWarn();
update.setIsRead(1);
LambdaQueryWrapper<MessageWarn> wrapper = Wrappers.lambdaQuery(MessageWarn.class)
.eq(MessageWarn::getUserId, userId)
.eq(MessageWarn::getIsRead, 0);
return baseMapper.update(update, wrapper) > 0;
}
}

View File

@@ -47,6 +47,13 @@ public class AliyunIotProperties {
*/
private String categoryKey;
/**
* 设备类型到产品Key的映射
* 1: 水质检测仪
* 2: 控制一体机
*/
private DeviceTypeMapping deviceType = new DeviceTypeMapping();
/**
* MQTT 配置(可选,用于设备直连)
*/
@@ -158,4 +165,39 @@ public class AliyunIotProperties {
private Integer reconnectDelay = 30000;
}
/**
* 设备类型映射配置
*/
@Data
public static class DeviceTypeMapping {
/**
* 水质检测仪 ProductKey
*/
private String waterQualityMonitor;
/**
* 控制一体机 ProductKey
*/
private String controlIntegrated;
/**
* 根据设备类型获取 ProductKey
* @param deviceType 1-水质检测仪, 2-控制一体机
* @return ProductKey
*/
public String getProductKeyByType(Integer deviceType) {
if (deviceType == null) {
return null;
}
switch (deviceType) {
case 1:
return waterQualityMonitor;
case 2:
return controlIntegrated;
default:
return null;
}
}
}
}

View File

@@ -3,7 +3,13 @@ package com.intc.iot.controller;
import com.intc.common.core.domain.R;
import com.intc.common.mybatis.core.page.PageQuery;
import com.intc.common.mybatis.core.page.TableDataInfo;
import com.intc.common.satoken.utils.LoginHelper;
import com.intc.common.web.core.BaseController;
import com.intc.fishery.domain.Device;
import com.intc.fishery.mapper.DeviceMapper;
import com.intc.fishery.mapper.PondMapper;
import com.intc.iot.config.AliyunIotProperties;
import com.intc.iot.domain.bo.AddDeviceDetectorBo;
import com.intc.iot.domain.bo.DeviceRealtimeDataBo;
import com.intc.iot.domain.vo.DeviceRealtimeDataVo;
import com.intc.iot.service.DeviceDataService;
@@ -23,6 +29,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.Map;
/**
@@ -37,6 +44,8 @@ import java.util.Map;
@Tag(name = "生活物联网平台管理", description = "阿里云飞燕平台对接接口")
public class IotController extends BaseController {
private final AliyunIotProperties aliyunIotProperties;
@Autowired(required = false)
private IotDeviceService iotDeviceService;
@@ -64,6 +73,12 @@ public class IotController extends BaseController {
@Autowired(required = false)
private javax.jms.Connection amqpConnection;
@Autowired(required = false)
private DeviceMapper deviceMapper;
@Autowired(required = false)
private PondMapper pondMapper;
@Operation(summary = "测试接口")
@GetMapping("/test")
public R<String> test() {
@@ -74,7 +89,7 @@ public class IotController extends BaseController {
@GetMapping("/amqp/status")
public R<Map<String, Object>> getAmqpStatus() {
Map<String, Object> status = new java.util.HashMap<>();
if (amqpConnection == null) {
status.put("configured", false);
status.put("connected", false);
@@ -94,7 +109,7 @@ public class IotController extends BaseController {
status.put("message", "AMQP 连接已关闭或异常: " + e.getMessage());
}
}
return R.ok(status);
}
@@ -111,7 +126,7 @@ public class IotController extends BaseController {
String virtualHost = AliyunAmqpSignUtil.generateVirtualHost(accessKeyId);
String username = AliyunAmqpSignUtil.generateUsername(accessKeyId);
String password = AliyunAmqpSignUtil.generatePassword(accessKeySecret, consumerGroupId);
Map<String, Object> config = new java.util.HashMap<>();
config.put("host", host);
config.put("port", 5672);
@@ -119,14 +134,14 @@ public class IotController extends BaseController {
config.put("username", username);
config.put("password", password);
config.put("consumerGroupId", consumerGroupId);
return R.ok(config);
} catch (Exception e) {
log.error("生成 AMQP 配置失败", e);
return R.fail("生成配置失败: " + e.getMessage());
}
}
@Operation(summary = "根据 ProductKey 和 DeviceName 查询设备信息")
@GetMapping("/device/find")
public R<Map<String, Object>> findDeviceByProductKeyAndName(
@@ -143,7 +158,7 @@ public class IotController extends BaseController {
return R.fail("查询设备信息失败: " + e.getMessage());
}
}
@Operation(summary = "查询设备列表")
@GetMapping("/device/list")
public R<Map<String, Object>> queryDeviceList(
@@ -261,19 +276,93 @@ public class IotController extends BaseController {
}
}
@Operation(summary = "查询设备当前状态")
@Operation(summary = "查询设备当前状态(从物联网平台)")
@GetMapping("/device/status")
public R<com.intc.iot.domain.IotDeviceStatus> queryDeviceStatus(
@Parameter(description = "产品Key") @RequestParam String productKey,
@Parameter(description = "设备名称") @RequestParam String deviceName) {
public R<Integer> queryDeviceStatus(
@Parameter(description = "设备类型1-水质检测仪, 2-控制一体机)") @RequestParam Integer devicetype,
@Parameter(description = "设备编号/设备名称") @RequestParam String serialnum) {
try {
if (deviceStatusService == null) {
return R.fail("设备状态服务未启用");
if (iotDeviceService == null) {
return R.fail("飞燕平台配置未启用");
}
com.intc.iot.domain.IotDeviceStatus status = deviceStatusService.queryDeviceStatus(productKey, deviceName);
return R.ok(status);
// 根据设备类型获取 ProductKey
String productKey = aliyunIotProperties.getDeviceType().getProductKeyByType(devicetype);
if (productKey == null || productKey.isEmpty()) {
return R.fail("未配置该设备类型的 ProductKey请检查配置文件deviceType: " + devicetype + "");
}
// 先查询设备信息获取 iotId
Map<String, Object> deviceInfo = iotDeviceService.findDeviceByProductKeyAndName(productKey, serialnum);
// 检查返回结果
if (deviceInfo == null || !Boolean.TRUE.equals(deviceInfo.get("success"))) {
String errorMsg = deviceInfo != null ? (String) deviceInfo.get("errorMessage") : "查询失败";
return R.fail("未找到该设备ProductKey: " + productKey + ", DeviceName: " + serialnum + ", 原因: " + errorMsg);
}
// 从返回结构中提取设备信息
Map<String, Object> data = (Map<String, Object>) deviceInfo.get("data");
if (data == null || !data.containsKey("deviceList")) {
return R.fail("设备信息格式异常");
}
java.util.List<?> deviceList = (java.util.List<?>) data.get("deviceList");
if (deviceList == null || deviceList.isEmpty()) {
return R.fail("未找到该设备ProductKey: " + productKey + ", DeviceName: " + serialnum);
}
// 获取第一个设备对象
Object deviceObj = deviceList.get(0);
String iotId = null;
// 尝试从设备对象中提取 iotId
if (deviceObj instanceof Map) {
iotId = (String) ((Map<?, ?>) deviceObj).get("iotId");
} else {
// 如果是 SDK 对象,尝试通过反射获取
try {
java.lang.reflect.Method method = deviceObj.getClass().getMethod("getIotId");
iotId = (String) method.invoke(deviceObj);
} catch (Exception ex) {
log.error("无法从设备对象中获取 iotId: {}", ex.getMessage());
}
}
if (iotId == null || iotId.isEmpty()) {
return R.fail("设备 iotId 为空");
}
// 查询设备详情(包含在线状态)
Map<String, Object> deviceDetail = iotDeviceService.queryDeviceInfo(iotId);
// 从设备详情中提取状态并转换为前端需要的状态码
Object detailData = deviceDetail.get("data");
Integer statusCode = 0; // 默认为设备未激活
if (detailData instanceof Map) {
Map<?, ?> detailMap = (Map<?, ?>) detailData;
Object statusObj = detailMap.get("status");
if (statusObj != null) {
String statusStr = statusObj.toString();
// 根据物联网平台返回的状态转换为前端状态码
// 0-未激活, 1-在线, 3-离线, 8-禁用
if ("ONLINE".equalsIgnoreCase(statusStr) || "online".equals(statusStr)) {
statusCode = 1;
} else if ("OFFLINE".equalsIgnoreCase(statusStr) || "offline".equals(statusStr)) {
statusCode = 3;
} else if ("UNACTIVE".equalsIgnoreCase(statusStr) || "unactive".equals(statusStr)) {
statusCode = 0;
} else if ("DISABLE".equalsIgnoreCase(statusStr) || "disable".equals(statusStr)) {
statusCode = 8;
}
}
}
// 直接返回状态码给前端
return R.ok(statusCode);
} catch (Exception e) {
log.error("查询设备状态失败: {}", e.getMessage());
log.error("查询设备状态失败: {}", e.getMessage(), e);
return R.fail("查询设备状态失败: " + e.getMessage());
}
}
@@ -465,13 +554,13 @@ public class IotController extends BaseController {
com.intc.iot.domain.VmsNoticeResponse response = vmsNoticeService.sendTtsCall(
phoneNumber, paramsMap, outId != null ? outId : "TEST"
);
Map<String, Object> result = new java.util.HashMap<>();
result.put("success", response.isSuccess());
result.put("code", response.getCode());
result.put("message", response.getMessage());
result.put("callId", response.getCallId());
return R.ok(result);
} catch (Exception e) {
log.error("发送语音通知失败: {}", e.getMessage());
@@ -582,4 +671,248 @@ public class IotController extends BaseController {
return R.fail("清理失败: " + e.getMessage());
}
}
// ======================== 设备管理相关接口 ========================
@Operation(summary = "添加设备探测器(水质检测仪)")
@PostMapping("/device/add_device_detector")
public R<Void> addDeviceDetector(@RequestBody AddDeviceDetectorBo bo) {
try {
if (iotDeviceService == null) {
return R.fail("飞燕平台配置未启用");
}
if (deviceMapper == null) {
return R.fail("设备数据库服务未启用");
}
// 获取当前登录用户ID
Long userId = LoginHelper.getUserId();
if (userId == null) {
return R.fail("未登录或登录已过期");
}
// 验证塘口是否存在且属于当前用户
if (bo.getPondId() != null && bo.getPondId() > 0 && pondMapper != null) {
long count = pondMapper.selectCount(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.intc.fishery.domain.Pond>()
.eq(com.intc.fishery.domain.Pond::getUserId, userId)
.eq(com.intc.fishery.domain.Pond::getId, bo.getPondId())
);
if (count == 0) {
return R.fail("塘口不存在或无权限访问");
}
}
// 检查设备是否已被绑定
Device existDevice = deviceMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Device>()
.eq(Device::getDeviceType, 1) // 1-水质检测仪
.eq(Device::getSerialNum, bo.getSerialNum())
);
if (existDevice != null && existDevice.getUserId() != null) {
return R.fail("该设备号已被绑定");
}
// 获取水质检测仪的 ProductKey
String productKey = aliyunIotProperties.getDeviceType().getWaterQualityMonitor();
if (productKey == null || productKey.isEmpty()) {
return R.fail("未配置水质检测仪的 ProductKey");
}
// 查询设备基础信息
Map<String, Object> deviceInfo = iotDeviceService.findDeviceByProductKeyAndName(productKey, bo.getSerialNum());
if (deviceInfo == null || !Boolean.TRUE.equals(deviceInfo.get("success"))) {
return R.fail("设备不存在");
}
// 提取设备数据
Map<String, Object> data = (Map<String, Object>) deviceInfo.get("data");
if (data == null || !data.containsKey("deviceList")) {
return R.fail("设备信息格式异常");
}
java.util.List<?> deviceList = (java.util.List<?>) data.get("deviceList");
if (deviceList == null || deviceList.isEmpty()) {
return R.fail("设备不存在");
}
Object deviceObj = deviceList.get(0);
String iotId = null;
String status = null;
// 提取 iotId 和 status
if (deviceObj instanceof Map) {
Map<?, ?> deviceMap = (Map<?, ?>) deviceObj;
iotId = (String) deviceMap.get("iotId");
Object statusObj = deviceMap.get("status");
status = statusObj != null ? statusObj.toString() : null;
} else {
try {
iotId = (String) deviceObj.getClass().getMethod("getIotId").invoke(deviceObj);
Object statusObj = deviceObj.getClass().getMethod("getStatus").invoke(deviceObj);
status = statusObj != null ? statusObj.toString() : null;
} catch (Exception ex) {
log.error("无法从设备对象中获取信息: {}", ex.getMessage());
}
}
if (iotId == null || iotId.isEmpty()) {
return R.fail("设备 iotId 为空");
}
// 检查设备状态
if (status != null) {
if ("UNACTIVE".equalsIgnoreCase(status)) {
return R.fail("设备未激活");
}
if ("DISABLE".equalsIgnoreCase(status)) {
return R.fail("设备禁用");
}
}
// 设置盐度补偿
Map<String, Object> properties = new java.util.HashMap<>();
properties.put("salinitySet", bo.getSalinityCompensation());
String propertiesJson = cn.hutool.json.JSONUtil.toJsonStr(properties);
Map<String, Object> setResult = iotDeviceService.setDeviceProperty(iotId, propertiesJson);
if (setResult == null || !Boolean.TRUE.equals(setResult.get("success"))) {
return R.fail("设置盐度补偿失败");
}
// 获取设备属性
Map<String, Object> deviceProperties = iotDeviceService.queryDeviceProperties(iotId);
// 初始化警告码:默认探头未校准 (0x0001)
int warnCode = 0x0001;
// 计算设备数量,用于生成设备名称
long deviceCount = deviceMapper.selectCount(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Device>()
.eq(Device::getUserId, userId)
.eq(Device::getDeviceType, 1)
);
// 创建或更新设备信息
Date now = new Date();
boolean isNew = (existDevice == null);
Device device = isNew ? new Device() : existDevice;
if (isNew) {
device.setIotId(iotId);
device.setSerialNum(bo.getSerialNum());
device.setDeviceType(1); // 1-水质检测仪
device.setDeadTime(new Date(now.getTime() + 365L * 24 * 60 * 60 * 1000)); // 一年后到期
device.setIsOxygenUsed(1);
} else {
// 检查是否已过期
if (device.getDeadTime() != null && now.after(device.getDeadTime())) {
warnCode |= 0x0040; // 设备时间到期 (0x0040)
}
}
// 设置基本信息
device.setUserId(userId);
device.setDeviceName("溶解氧" + (deviceCount + 1));
device.setBindTime(now);
device.setPondId(bo.getPondId() != null && bo.getPondId() > 0 ? bo.getPondId() : null);
device.setSalinityCompensation(bo.getSalinityCompensation());
device.setOxyWarnLower(bo.getOxyWarnLower());
device.setOxyWarnCallOpen(1);
device.setOxyWarnCallNoDis(1);
device.setTempWarnCallOpen(0);
device.setTempWarnCallNoDis(0);
// 解析并设置设备属性
if (deviceProperties != null && Boolean.TRUE.equals(deviceProperties.get("success"))) {
Object propData = deviceProperties.get("data");
if (propData instanceof Map) {
Map<?, ?> propMap = (Map<?, ?>) propData;
Object listObj = propMap.get("list");
if (listObj instanceof java.util.List) {
java.util.List<?> propList = (java.util.List<?>) listObj;
for (Object item : propList) {
if (item instanceof Map) {
Map<?, ?> prop = (Map<?, ?>) item;
String attribute = (String) prop.get("identifier");
Object value = prop.get("value");
if (attribute != null && value != null) {
switch (attribute) {
case "dissolvedOxygen": // 溶解氧
device.setValueDissolvedOxygen(Double.parseDouble(value.toString()));
break;
case "currentTemperature": // 温度
device.setValueTemperature(Double.parseDouble(value.toString()));
break;
case "dosat": // 饱和度
device.setValueSaturability(Double.parseDouble(value.toString()));
break;
case "PH":
device.setValuePh(Double.parseDouble(value.toString()));
break;
case "salinity": // 盐度
device.setValueSalinity(Double.parseDouble(value.toString()));
break;
case "sensorErrorCode": // 警告码
try {
int errorCode = Integer.parseInt(value.toString());
warnCode |= errorCode;
} catch (NumberFormatException e) {
log.warn("无法解析警告码: {}", value);
}
break;
case "Tcorrect": // 设备校准状态
try {
int tcorrect = Integer.parseInt(value.toString());
if (tcorrect == 1) {
warnCode &= ~0x0001; // 清除未校准标记
}
} catch (NumberFormatException e) {
log.warn("无法解析校准状态: {}", value);
}
break;
case "ICCID": // 物联网卡号
device.setIccId(value.toString());
break;
case "Treference": // 参比值
device.setTreference(Double.parseDouble(value.toString()));
break;
case "Tfluorescence": // 荧光值
device.setTfluorescence(Double.parseDouble(value.toString()));
break;
}
}
}
}
}
}
}
// 如果设备离线,添加离线警告
if (status != null && "OFFLINE".equalsIgnoreCase(status)) {
warnCode |= 0x0080; // 设备离线 (0x0080)
}
device.setWarnCode(warnCode);
// 验证 ICCID 是否存在
if (device.getIccId() == null || device.getIccId().isEmpty()) {
return R.fail("设备缺少物联网卡号(ICCID)");
}
// 保存到数据库
if (isNew) {
deviceMapper.insert(device);
log.info("新设备添加成功: userId={}, iotId={}, serialNum={}", userId, iotId, bo.getSerialNum());
} else {
deviceMapper.updateById(device);
log.info("设备更新成功: userId={}, iotId={}, serialNum={}", userId, iotId, bo.getSerialNum());
}
return R.ok();
} catch (Exception e) {
log.error("添加设备失败: {}", e.getMessage(), e);
return R.fail("添加设备失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,49 @@
package com.intc.iot.domain.bo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 添加设备探测器业务对象
*
* @author intc
*/
@Data
@Schema(description = "添加设备探测器请求对象")
public class AddDeviceDetectorBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 设备编号/序列号
*/
@Schema(description = "设备编号/序列号")
@NotBlank(message = "设备编号不能为空")
private String serialNum;
/**
* 塘口ID
*/
@Schema(description = "塘口ID")
private Long pondId;
/**
* 盐度补偿值
*/
@Schema(description = "盐度补偿值")
@NotNull(message = "盐度补偿值不能为空")
private Double salinityCompensation;
/**
* 溶解氧报警下限
*/
@Schema(description = "溶解氧报警下限")
@NotNull(message = "溶解氧报警下限不能为空")
private Double oxyWarnLower;
}