Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -3,6 +3,7 @@ package com.shzg.common.utils;
|
|||||||
import com.shzg.common.utils.spring.SpringUtils;
|
import com.shzg.common.utils.spring.SpringUtils;
|
||||||
import com.shzg.project.system.service.ISysDeptService;
|
import com.shzg.project.system.service.ISysDeptService;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,7 +18,21 @@ public class DeptScopeUtils
|
|||||||
{
|
{
|
||||||
Long deptId = SecurityUtils.getDeptId();
|
Long deptId = SecurityUtils.getDeptId();
|
||||||
|
|
||||||
return SpringUtils.getBean(ISysDeptService.class)
|
// 查询子部门
|
||||||
|
List<Long> deptIds = SpringUtils.getBean(ISysDeptService.class)
|
||||||
.selectDeptAndChildIds(deptId);
|
.selectDeptAndChildIds(deptId);
|
||||||
|
|
||||||
|
// 防止返回null
|
||||||
|
if (deptIds == null)
|
||||||
|
{
|
||||||
|
deptIds = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deptIds.contains(deptId))
|
||||||
|
{
|
||||||
|
deptIds.add(deptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deptIds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import com.shzg.common.constant.CacheConstants;
|
import com.shzg.common.constant.CacheConstants;
|
||||||
import com.shzg.common.constant.Constants;
|
import com.shzg.common.constant.Constants;
|
||||||
import com.shzg.common.utils.ServletUtils;
|
import com.shzg.common.utils.ServletUtils;
|
||||||
@@ -19,100 +15,103 @@ import com.shzg.common.utils.ip.IpUtils;
|
|||||||
import com.shzg.common.utils.uuid.IdUtils;
|
import com.shzg.common.utils.uuid.IdUtils;
|
||||||
import com.shzg.framework.redis.RedisCache;
|
import com.shzg.framework.redis.RedisCache;
|
||||||
import com.shzg.framework.security.LoginUser;
|
import com.shzg.framework.security.LoginUser;
|
||||||
|
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
|
||||||
/**
|
import org.slf4j.Logger;
|
||||||
* token验证处理
|
import org.slf4j.LoggerFactory;
|
||||||
*
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
* @author ruoyi
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
*/
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class TokenService
|
public class TokenService {
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(TokenService.class);
|
private static final Logger log = LoggerFactory.getLogger(TokenService.class);
|
||||||
|
|
||||||
// 令牌自定义标识
|
|
||||||
@Value("${token.header}")
|
@Value("${token.header}")
|
||||||
private String header;
|
private String header;
|
||||||
|
|
||||||
// 令牌秘钥
|
|
||||||
@Value("${token.secret}")
|
@Value("${token.secret}")
|
||||||
private String secret;
|
private String secret;
|
||||||
|
|
||||||
// 令牌有效期(默认30分钟)
|
|
||||||
@Value("${token.expireTime}")
|
@Value("${token.expireTime}")
|
||||||
private int expireTime;
|
private int expireTime;
|
||||||
|
|
||||||
protected static final long MILLIS_SECOND = 1000;
|
protected static final long MILLIS_SECOND = 1000;
|
||||||
|
|
||||||
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
|
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
|
||||||
|
|
||||||
private static final Long MILLIS_MINUTE_TWENTY = 20 * 60 * 1000L;
|
private static final Long MILLIS_MINUTE_TWENTY = 20 * 60 * 1000L;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisCache redisCache;
|
private RedisCache redisCache;
|
||||||
|
|
||||||
/**
|
public LoginUser getLoginUser(HttpServletRequest request) {
|
||||||
* 获取用户身份信息
|
|
||||||
*
|
|
||||||
* @return 用户信息
|
|
||||||
*/
|
|
||||||
public LoginUser getLoginUser(HttpServletRequest request)
|
|
||||||
{
|
|
||||||
// 获取请求携带的令牌
|
|
||||||
String token = getToken(request);
|
String token = getToken(request);
|
||||||
if (StringUtils.isNotEmpty(token))
|
if (StringUtils.isNotEmpty(token)) {
|
||||||
{
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
Claims claims = parseToken(token);
|
Claims claims = parseToken(token);
|
||||||
// 解析对应的权限以及用户信息
|
|
||||||
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
|
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
|
||||||
String userKey = getTokenKey(uuid);
|
String userKey = getTokenKey(uuid);
|
||||||
LoginUser user = redisCache.getCacheObject(userKey);
|
return redisCache.getCacheObject(userKey);
|
||||||
return user;
|
} catch (Exception e) {
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("获取用户信息异常'{}'", e.getMessage());
|
log.error("获取用户信息异常'{}'", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public LoginUser getLoginUserByToken(String token) {
|
||||||
* 设置用户身份信息
|
|
||||||
*/
|
if (StringUtils.isEmpty(token)) {
|
||||||
public void setLoginUser(LoginUser loginUser)
|
return null;
|
||||||
{
|
}
|
||||||
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
|
|
||||||
{
|
try {
|
||||||
|
// 1. 解析JWT
|
||||||
|
Claims claims = parseToken(token);
|
||||||
|
|
||||||
|
if (claims == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 获取uuid(关键)
|
||||||
|
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(uuid)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 拼Redis key
|
||||||
|
String userKey = getTokenKey(uuid);
|
||||||
|
|
||||||
|
// 4. 查缓存
|
||||||
|
LoginUser loginUser = redisCache.getCacheObject(userKey);
|
||||||
|
|
||||||
|
return loginUser;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("WebSocket获取用户失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoginUser(LoginUser loginUser) {
|
||||||
|
if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) {
|
||||||
refreshToken(loginUser);
|
refreshToken(loginUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void delLoginUser(String token) {
|
||||||
* 删除用户身份信息
|
if (StringUtils.isNotEmpty(token)) {
|
||||||
*/
|
|
||||||
public void delLoginUser(String token)
|
|
||||||
{
|
|
||||||
if (StringUtils.isNotEmpty(token))
|
|
||||||
{
|
|
||||||
String userKey = getTokenKey(token);
|
String userKey = getTokenKey(token);
|
||||||
redisCache.deleteObject(userKey);
|
redisCache.deleteObject(userKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public String createToken(LoginUser loginUser) {
|
||||||
* 创建令牌
|
|
||||||
*
|
|
||||||
* @param loginUser 用户信息
|
|
||||||
* @return 令牌
|
|
||||||
*/
|
|
||||||
public String createToken(LoginUser loginUser)
|
|
||||||
{
|
|
||||||
String token = IdUtils.fastUUID();
|
String token = IdUtils.fastUUID();
|
||||||
loginUser.setToken(token);
|
loginUser.setToken(token);
|
||||||
setUserAgent(loginUser);
|
setUserAgent(loginUser);
|
||||||
@@ -121,46 +120,26 @@ public class TokenService
|
|||||||
Map<String, Object> claims = new HashMap<>();
|
Map<String, Object> claims = new HashMap<>();
|
||||||
claims.put(Constants.LOGIN_USER_KEY, token);
|
claims.put(Constants.LOGIN_USER_KEY, token);
|
||||||
claims.put(Constants.JWT_USERNAME, loginUser.getUsername());
|
claims.put(Constants.JWT_USERNAME, loginUser.getUsername());
|
||||||
|
|
||||||
return createToken(claims);
|
return createToken(claims);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void verifyToken(LoginUser loginUser) {
|
||||||
* 验证令牌有效期,相差不足20分钟,自动刷新缓存
|
|
||||||
*
|
|
||||||
* @param loginUser 登录信息
|
|
||||||
* @return 令牌
|
|
||||||
*/
|
|
||||||
public void verifyToken(LoginUser loginUser)
|
|
||||||
{
|
|
||||||
long expireTime = loginUser.getExpireTime();
|
long expireTime = loginUser.getExpireTime();
|
||||||
long currentTime = System.currentTimeMillis();
|
long currentTime = System.currentTimeMillis();
|
||||||
if (expireTime - currentTime <= MILLIS_MINUTE_TWENTY)
|
if (expireTime - currentTime <= MILLIS_MINUTE_TWENTY) {
|
||||||
{
|
|
||||||
refreshToken(loginUser);
|
refreshToken(loginUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void refreshToken(LoginUser loginUser) {
|
||||||
* 刷新令牌有效期
|
|
||||||
*
|
|
||||||
* @param loginUser 登录信息
|
|
||||||
*/
|
|
||||||
public void refreshToken(LoginUser loginUser)
|
|
||||||
{
|
|
||||||
loginUser.setLoginTime(System.currentTimeMillis());
|
loginUser.setLoginTime(System.currentTimeMillis());
|
||||||
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
|
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
|
||||||
// 根据uuid将loginUser缓存
|
|
||||||
String userKey = getTokenKey(loginUser.getToken());
|
String userKey = getTokenKey(loginUser.getToken());
|
||||||
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
|
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void setUserAgent(LoginUser loginUser) {
|
||||||
* 设置用户代理信息
|
|
||||||
*
|
|
||||||
* @param loginUser 登录信息
|
|
||||||
*/
|
|
||||||
public void setUserAgent(LoginUser loginUser)
|
|
||||||
{
|
|
||||||
String userAgent = ServletUtils.getRequest().getHeader("User-Agent");
|
String userAgent = ServletUtils.getRequest().getHeader("User-Agent");
|
||||||
String ip = IpUtils.getIpAddr();
|
String ip = IpUtils.getIpAddr();
|
||||||
loginUser.setIpaddr(ip);
|
loginUser.setIpaddr(ip);
|
||||||
@@ -169,64 +148,34 @@ public class TokenService
|
|||||||
loginUser.setOs(UserAgentUtils.getOperatingSystem(userAgent));
|
loginUser.setOs(UserAgentUtils.getOperatingSystem(userAgent));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private String createToken(Map<String, Object> claims) {
|
||||||
* 从数据声明生成令牌
|
return Jwts.builder()
|
||||||
*
|
|
||||||
* @param claims 数据声明
|
|
||||||
* @return 令牌
|
|
||||||
*/
|
|
||||||
private String createToken(Map<String, Object> claims)
|
|
||||||
{
|
|
||||||
String token = Jwts.builder()
|
|
||||||
.setClaims(claims)
|
.setClaims(claims)
|
||||||
.signWith(SignatureAlgorithm.HS512, secret).compact();
|
.signWith(SignatureAlgorithm.HS512, secret)
|
||||||
return token;
|
.compact();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private Claims parseToken(String token) {
|
||||||
* 从令牌中获取数据声明
|
|
||||||
*
|
|
||||||
* @param token 令牌
|
|
||||||
* @return 数据声明
|
|
||||||
*/
|
|
||||||
private Claims parseToken(String token)
|
|
||||||
{
|
|
||||||
return Jwts.parser()
|
return Jwts.parser()
|
||||||
.setSigningKey(secret)
|
.setSigningKey(secret)
|
||||||
.parseClaimsJws(token)
|
.parseClaimsJws(token)
|
||||||
.getBody();
|
.getBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public String getUsernameFromToken(String token) {
|
||||||
* 从令牌中获取用户名
|
|
||||||
*
|
|
||||||
* @param token 令牌
|
|
||||||
* @return 用户名
|
|
||||||
*/
|
|
||||||
public String getUsernameFromToken(String token)
|
|
||||||
{
|
|
||||||
Claims claims = parseToken(token);
|
Claims claims = parseToken(token);
|
||||||
return claims.getSubject();
|
return claims.getSubject();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private String getToken(HttpServletRequest request) {
|
||||||
* 获取请求token
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @return token
|
|
||||||
*/
|
|
||||||
private String getToken(HttpServletRequest request)
|
|
||||||
{
|
|
||||||
String token = request.getHeader(header);
|
String token = request.getHeader(header);
|
||||||
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
|
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) {
|
||||||
{
|
|
||||||
token = token.replace(Constants.TOKEN_PREFIX, "");
|
token = token.replace(Constants.TOKEN_PREFIX, "");
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTokenKey(String uuid)
|
private String getTokenKey(String uuid) {
|
||||||
{
|
|
||||||
return CacheConstants.LOGIN_TOKEN_KEY + uuid;
|
return CacheConstants.LOGIN_TOKEN_KEY + uuid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,4 +129,5 @@ public class SysDeptController extends BaseController
|
|||||||
deptService.checkDeptDataScope(deptId);
|
deptService.checkDeptDataScope(deptId);
|
||||||
return toAjax(deptService.deleteDeptById(deptId));
|
return toAjax(deptService.deleteDeptById(deptId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.shzg.project.system.mapper;
|
package com.shzg.project.system.mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import com.shzg.project.system.domain.SysDept;
|
import com.shzg.project.system.domain.SysDept;
|
||||||
|
|
||||||
@@ -132,4 +134,19 @@ public interface SysDeptMapper
|
|||||||
* @return 部门ID集合
|
* @return 部门ID集合
|
||||||
*/
|
*/
|
||||||
List<Long> selectDeptAndChildIds(Long deptId);
|
List<Long> selectDeptAndChildIds(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目总数(按权限)
|
||||||
|
*/
|
||||||
|
int countProjectByDeptIds(@Param("deptIds") List<Long> deptIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仓库总数(按权限)
|
||||||
|
*/
|
||||||
|
int countWarehouseByDeptIds(@Param("deptIds") List<Long> deptIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仓库列表(按权限)
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectWarehouseList(@Param("deptIds") List<Long> deptIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.shzg.project.system.service;
|
package com.shzg.project.system.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.shzg.framework.web.domain.TreeSelect;
|
import com.shzg.framework.web.domain.TreeSelect;
|
||||||
import com.shzg.project.system.domain.SysDept;
|
import com.shzg.project.system.domain.SysDept;
|
||||||
|
|
||||||
@@ -137,4 +139,20 @@ public interface ISysDeptService
|
|||||||
* @return 部门ID列表
|
* @return 部门ID列表
|
||||||
*/
|
*/
|
||||||
List<Long> selectDeptAndChildIds(Long deptId);
|
List<Long> selectDeptAndChildIds(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页统计
|
||||||
|
*/
|
||||||
|
Map<String, Object> getHomeStat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备统计
|
||||||
|
*/
|
||||||
|
Map<String, Object> getDeviceStat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仓库运行状态
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectWarehouseList();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package com.shzg.project.system.service.impl;
|
package com.shzg.project.system.service.impl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.shzg.common.utils.DeptScopeUtils;
|
||||||
import com.shzg.project.system.domain.SysUser;
|
import com.shzg.project.system.domain.SysUser;
|
||||||
import com.shzg.project.system.mapper.SysUserMapper;
|
import com.shzg.project.system.mapper.SysUserMapper;
|
||||||
|
import com.shzg.project.worn.mapper.MqttSensorDeviceMapper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.shzg.common.constant.UserConstants;
|
import com.shzg.common.constant.UserConstants;
|
||||||
@@ -40,6 +40,10 @@ public class SysDeptServiceImpl implements ISysDeptService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SysUserMapper userMapper;
|
private SysUserMapper userMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MqttSensorDeviceMapper deviceMapper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询部门管理数据
|
* 查询部门管理数据
|
||||||
*
|
*
|
||||||
@@ -360,4 +364,52 @@ public class SysDeptServiceImpl implements ISysDeptService
|
|||||||
{
|
{
|
||||||
return deptMapper.selectDeptAndChildIds(deptId);
|
return deptMapper.selectDeptAndChildIds(deptId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getHomeStat()
|
||||||
|
{
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
// 当前用户可见部门范围
|
||||||
|
List<Long> deptIds = DeptScopeUtils.getDeptScope();
|
||||||
|
|
||||||
|
// 项目总数(顶级部门)
|
||||||
|
int projectCount = deptMapper.countProjectByDeptIds(deptIds);
|
||||||
|
|
||||||
|
// 仓库总数(子部门)
|
||||||
|
int warehouseCount = deptMapper.countWarehouseByDeptIds(deptIds);
|
||||||
|
|
||||||
|
map.put("projectCount", projectCount);
|
||||||
|
map.put("warehouseCount", warehouseCount);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getDeviceStat()
|
||||||
|
{
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
// 当前用户权限范围(核心)
|
||||||
|
List<Long> deptIds = DeptScopeUtils.getDeptScope();
|
||||||
|
|
||||||
|
Map<String, Object> stat = deviceMapper.countDeviceStat(deptIds);
|
||||||
|
|
||||||
|
map.put("total", stat.get("total"));
|
||||||
|
map.put("online", stat.get("online"));
|
||||||
|
map.put("offline", stat.get("offline"));
|
||||||
|
map.put("onlineRate", stat.get("onlineRate"));
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> selectWarehouseList()
|
||||||
|
{
|
||||||
|
// 当前用户权限范围
|
||||||
|
List<Long> deptIds = DeptScopeUtils.getDeptScope();
|
||||||
|
|
||||||
|
return deptMapper.selectWarehouseList(deptIds);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public class SocketController {
|
|||||||
private IMqttSocketService mqttSocketService;
|
private IMqttSocketService mqttSocketService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制插座开关
|
* 控制智能排风插座开关
|
||||||
*/
|
*/
|
||||||
@PostMapping("/control")
|
@PostMapping("/control")
|
||||||
public AjaxResult control(@RequestParam String devEui,
|
public AjaxResult control(@RequestParam String devEui,
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.shzg.project.worn.controller;
|
||||||
|
|
||||||
|
import com.shzg.framework.web.controller.BaseController;
|
||||||
|
import com.shzg.framework.web.domain.AjaxResult;
|
||||||
|
import com.shzg.framework.web.page.TableDataInfo;
|
||||||
|
import com.shzg.project.system.domain.SysDept;
|
||||||
|
import com.shzg.project.system.service.ISysDeptService;
|
||||||
|
import com.shzg.project.worn.service.IMqttSensorEventService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/home")
|
||||||
|
public class SysHomeController extends BaseController
|
||||||
|
{
|
||||||
|
@Autowired
|
||||||
|
private ISysDeptService deptService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMqttSensorEventService eventService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页统计
|
||||||
|
*/
|
||||||
|
@GetMapping("/stat")
|
||||||
|
public AjaxResult stat()
|
||||||
|
{
|
||||||
|
Map<String, Object> data = deptService.getHomeStat();
|
||||||
|
return AjaxResult.success(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备统计(总数 / 在线 / 离线)
|
||||||
|
*/
|
||||||
|
@GetMapping("/device/stat")
|
||||||
|
public AjaxResult deviceStat()
|
||||||
|
{
|
||||||
|
Map<String, Object> data = deptService.getDeviceStat();
|
||||||
|
return AjaxResult.success(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警统计(今日告警 / 未处理告警)
|
||||||
|
*/
|
||||||
|
@GetMapping("/alarm/stat")
|
||||||
|
public AjaxResult alarmStat()
|
||||||
|
{
|
||||||
|
Map<String, Object> data = eventService.getAlarmStat();
|
||||||
|
return AjaxResult.success(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警趋势(近7天)
|
||||||
|
*/
|
||||||
|
@GetMapping("/alarm/trend")
|
||||||
|
public AjaxResult alarmTrend()
|
||||||
|
{
|
||||||
|
return AjaxResult.success(eventService.getAlarmTrend());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警类型占比
|
||||||
|
*/
|
||||||
|
@GetMapping("/alarm/type")
|
||||||
|
public AjaxResult alarmType()
|
||||||
|
{
|
||||||
|
return AjaxResult.success(eventService.getAlarmTypeStat());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仓库运行状态(全部仓库)
|
||||||
|
*/
|
||||||
|
@GetMapping("/warehouse/list")
|
||||||
|
public AjaxResult warehouseList()
|
||||||
|
{
|
||||||
|
List<Map<String, Object>> list = deptService.selectWarehouseList();
|
||||||
|
return AjaxResult.success(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,21 +19,29 @@ public class MqttSensorDevice extends BaseEntity
|
|||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** 设备唯一标识(DevEUI) */
|
/** 设备唯一标识(DevEUI) */
|
||||||
@Excel(name = "设备唯一标识", readConverterExp = "D=evEUI")
|
@Excel(name = "设备唯一标识")
|
||||||
private String devEui;
|
private String devEui;
|
||||||
|
|
||||||
/** 设备名称 */
|
/** 设备名称 */
|
||||||
@Excel(name = "设备名称")
|
@Excel(name = "设备名称")
|
||||||
private String deviceName;
|
private String deviceName;
|
||||||
|
|
||||||
/** 设备类型(smoke / env) */
|
/** 设备类型(smoke / env / socket / door 等) */
|
||||||
@Excel(name = "设备类型", readConverterExp = "s=moke,/=,e=nv")
|
@Excel(name = "设备类型")
|
||||||
private String deviceType;
|
private String deviceType;
|
||||||
|
|
||||||
/** 所属部门ID */
|
/** 所属部门ID */
|
||||||
@Excel(name = "所属部门ID")
|
@Excel(name = "所属部门ID")
|
||||||
private Long deptId;
|
private Long deptId;
|
||||||
|
|
||||||
|
/** 所属部门名称 */
|
||||||
|
@Excel(name = "所属部门名称")
|
||||||
|
private String deptName;
|
||||||
|
|
||||||
|
/** 🔥 上报周期(分钟) */
|
||||||
|
@Excel(name = "上报周期(分钟)")
|
||||||
|
private Integer reportIntervalMinute;
|
||||||
|
|
||||||
/** 状态(0正常 1停用) */
|
/** 状态(0正常 1停用) */
|
||||||
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
|
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
|
||||||
private String status;
|
private String status;
|
||||||
@@ -92,6 +100,26 @@ public class MqttSensorDevice extends BaseEntity
|
|||||||
return deptId;
|
return deptId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDeptName(String deptName)
|
||||||
|
{
|
||||||
|
this.deptName = deptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeptName()
|
||||||
|
{
|
||||||
|
return deptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReportIntervalMinute(Integer reportIntervalMinute)
|
||||||
|
{
|
||||||
|
this.reportIntervalMinute = reportIntervalMinute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getReportIntervalMinute()
|
||||||
|
{
|
||||||
|
return reportIntervalMinute;
|
||||||
|
}
|
||||||
|
|
||||||
public void setStatus(String status)
|
public void setStatus(String status)
|
||||||
{
|
{
|
||||||
this.status = status;
|
this.status = status;
|
||||||
@@ -120,6 +148,8 @@ public class MqttSensorDevice extends BaseEntity
|
|||||||
.append("deviceName", getDeviceName())
|
.append("deviceName", getDeviceName())
|
||||||
.append("deviceType", getDeviceType())
|
.append("deviceType", getDeviceType())
|
||||||
.append("deptId", getDeptId())
|
.append("deptId", getDeptId())
|
||||||
|
.append("deptName", getDeptName())
|
||||||
|
.append("reportIntervalMinute", getReportIntervalMinute())
|
||||||
.append("status", getStatus())
|
.append("status", getStatus())
|
||||||
.append("remark", getRemark())
|
.append("remark", getRemark())
|
||||||
.append("createBy", getCreateBy())
|
.append("createBy", getCreateBy())
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ public class MqttTopicConfig extends BaseEntity
|
|||||||
@Excel(name = "部门ID")
|
@Excel(name = "部门ID")
|
||||||
private Long deptId;
|
private Long deptId;
|
||||||
|
|
||||||
|
/** 所属部门名称 */
|
||||||
|
@Excel(name = "部门名称")
|
||||||
|
private String deptName;
|
||||||
|
|
||||||
/** 🔥 数据权限(部门ID集合) */
|
/** 🔥 数据权限(部门ID集合) */
|
||||||
private List<Long> deptIds;
|
private List<Long> deptIds;
|
||||||
|
|
||||||
@@ -91,6 +95,16 @@ public class MqttTopicConfig extends BaseEntity
|
|||||||
return deptId;
|
return deptId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDeptName(String deptName)
|
||||||
|
{
|
||||||
|
this.deptName = deptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeptName()
|
||||||
|
{
|
||||||
|
return deptName;
|
||||||
|
}
|
||||||
|
|
||||||
public void setDeptIds(List<Long> deptIds)
|
public void setDeptIds(List<Long> deptIds)
|
||||||
{
|
{
|
||||||
this.deptIds = deptIds;
|
this.deptIds = deptIds;
|
||||||
@@ -149,6 +163,7 @@ public class MqttTopicConfig extends BaseEntity
|
|||||||
.append("project", getProject())
|
.append("project", getProject())
|
||||||
.append("warehouse", getWarehouse())
|
.append("warehouse", getWarehouse())
|
||||||
.append("deptId", getDeptId())
|
.append("deptId", getDeptId())
|
||||||
|
.append("deptName", getDeptName())
|
||||||
.append("deptIds", getDeptIds())
|
.append("deptIds", getDeptIds())
|
||||||
.append("topicUp", getTopicUp())
|
.append("topicUp", getTopicUp())
|
||||||
.append("topicDownPrefix", getTopicDownPrefix())
|
.append("topicDownPrefix", getTopicDownPrefix())
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.shzg.project.worn.mapper;
|
package com.shzg.project.worn.mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.shzg.project.worn.domain.MqttSensorDevice;
|
import com.shzg.project.worn.domain.MqttSensorDevice;
|
||||||
import io.lettuce.core.dynamic.annotation.Param;
|
import io.lettuce.core.dynamic.annotation.Param;
|
||||||
|
|
||||||
@@ -67,4 +69,23 @@ public interface MqttSensorDeviceMapper
|
|||||||
*/
|
*/
|
||||||
MqttSensorDevice selectByDevEui(@Param("devEui") String devEui);
|
MqttSensorDevice selectByDevEui(@Param("devEui") String devEui);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备统计(按权限)
|
||||||
|
*/
|
||||||
|
Map<String, Object> countDeviceStat(@Param("deptIds") List<Long> deptIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新设备运行状态(0在线 1离线)
|
||||||
|
*
|
||||||
|
* @param device 设备
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateRuntimeStatus(MqttSensorDevice device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询超时离线设备
|
||||||
|
*
|
||||||
|
* @return 设备列表
|
||||||
|
*/
|
||||||
|
List<MqttSensorDevice> selectOfflineDeviceList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package com.shzg.project.worn.mapper;
|
package com.shzg.project.worn.mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.shzg.project.worn.domain.MqttSensorEvent;
|
import com.shzg.project.worn.domain.MqttSensorEvent;
|
||||||
|
import io.lettuce.core.dynamic.annotation.Param;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备事件Mapper接口
|
* 设备事件Mapper接口
|
||||||
@@ -58,4 +61,19 @@ public interface MqttSensorEventMapper
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public int deleteMqttSensorEventByIds(Long[] ids);
|
public int deleteMqttSensorEventByIds(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警统计(今日 / 未处理)- 按权限
|
||||||
|
*/
|
||||||
|
Map<String, Object> countAlarmStat(@Param("deptIds") List<Long> deptIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警趋势(按权限)
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectAlarmTrend(@Param("deptIds") List<Long> deptIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警类型占比(按权限)
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> selectAlarmTypeStat(@Param("deptIds") List<Long> deptIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.shzg.project.worn.domain.MqttSensorEvent;
|
|||||||
import com.shzg.project.worn.service.IDeviceStatusService;
|
import com.shzg.project.worn.service.IDeviceStatusService;
|
||||||
import com.shzg.project.worn.service.IMqttSensorDataService;
|
import com.shzg.project.worn.service.IMqttSensorDataService;
|
||||||
import com.shzg.project.worn.service.IMqttSensorEventService;
|
import com.shzg.project.worn.service.IMqttSensorEventService;
|
||||||
|
import com.shzg.project.worn.unit.DeviceStatusUtil;
|
||||||
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -35,10 +36,12 @@ public class DoorSensorHandler {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ISysDeptService deptService;
|
private ISysDeptService deptService;
|
||||||
|
|
||||||
// 状态服务(Redis去重)
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IDeviceStatusService deviceStatusService;
|
private IDeviceStatusService deviceStatusService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DeviceStatusUtil deviceStatusUtil;
|
||||||
|
|
||||||
public void handle(MqttSensorDevice device, String topic, String payload) {
|
public void handle(MqttSensorDevice device, String topic, String payload) {
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
@@ -67,7 +70,7 @@ public class DoorSensorHandler {
|
|||||||
devEui, device.getDeptId(), doorStatus, tamperStatus, battery);
|
devEui, device.getDeptId(), doorStatus, tamperStatus, battery);
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// 2️⃣ 数据入库(始终入库)
|
// 2️⃣ 数据入库
|
||||||
// =========================
|
// =========================
|
||||||
MqttSensorData data = new MqttSensorData();
|
MqttSensorData data = new MqttSensorData();
|
||||||
data.setDeviceId(device.getId());
|
data.setDeviceId(device.getId());
|
||||||
@@ -100,32 +103,12 @@ public class DoorSensorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// 4️⃣ Redis去重(核心)
|
// 4️⃣ 恢复在线
|
||||||
// =========================
|
// =========================
|
||||||
boolean changed = deviceStatusService.isStatusChanged(
|
deviceStatusUtil.handleOnline(device);
|
||||||
device.getId(),
|
|
||||||
"door",
|
|
||||||
status
|
|
||||||
);
|
|
||||||
|
|
||||||
// 状态没变化,直接返回(不产生事件、不推送)
|
|
||||||
if (!changed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// 5️⃣ 事件处理(只在变化时)
|
// 5️⃣ 查询部门名称
|
||||||
// =========================
|
|
||||||
if ("open".equals(status)) {
|
|
||||||
saveEvent(device, "door_open", "门已打开");
|
|
||||||
} else if ("close".equals(status)) {
|
|
||||||
saveEvent(device, "door_close", "门已关闭");
|
|
||||||
} else if ("tamper".equals(status)) {
|
|
||||||
saveEvent(device, "tamper", "设备被拆除");
|
|
||||||
}
|
|
||||||
|
|
||||||
// =========================
|
|
||||||
// 6️⃣ 查询部门名称
|
|
||||||
// =========================
|
// =========================
|
||||||
String deptName = null;
|
String deptName = null;
|
||||||
SysDept dept = deptService.selectDeptById(device.getDeptId());
|
SysDept dept = deptService.selectDeptById(device.getDeptId());
|
||||||
@@ -134,7 +117,7 @@ public class DoorSensorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// 7️⃣ WebSocket推送(只推变化)
|
// 6️⃣ WebSocket推送(周期上报也要推)
|
||||||
// =========================
|
// =========================
|
||||||
JSONObject ws = new JSONObject();
|
JSONObject ws = new JSONObject();
|
||||||
ws.put("type", "door");
|
ws.put("type", "door");
|
||||||
@@ -150,6 +133,30 @@ public class DoorSensorHandler {
|
|||||||
|
|
||||||
sessionManager.sendToDept(device.getDeptId(), ws.toJSONString());
|
sessionManager.sendToDept(device.getDeptId(), ws.toJSONString());
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// 7️⃣ Redis去重
|
||||||
|
// =========================
|
||||||
|
boolean changed = deviceStatusService.isStatusChanged(
|
||||||
|
device.getId(),
|
||||||
|
"door",
|
||||||
|
status
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// 8️⃣ 事件处理
|
||||||
|
// =========================
|
||||||
|
if ("open".equals(status)) {
|
||||||
|
saveEvent(device, "door_open", "门已打开");
|
||||||
|
} else if ("close".equals(status)) {
|
||||||
|
saveEvent(device, "door_close", "门已关闭");
|
||||||
|
} else if ("tamper".equals(status)) {
|
||||||
|
saveEvent(device, "tamper", "设备被拆除");
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[DOOR] 处理异常 payload={}", payload, e);
|
log.error("[DOOR] 处理异常 payload={}", payload, e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.shzg.project.system.domain.SysDept;
|
|||||||
import com.shzg.project.system.service.ISysDeptService;
|
import com.shzg.project.system.service.ISysDeptService;
|
||||||
import com.shzg.project.worn.domain.*;
|
import com.shzg.project.worn.domain.*;
|
||||||
import com.shzg.project.worn.service.*;
|
import com.shzg.project.worn.service.*;
|
||||||
|
import com.shzg.project.worn.unit.DeviceStatusUtil;
|
||||||
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -35,10 +36,13 @@ public class EnvSensorHandler {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ISysDeptService deptService;
|
private ISysDeptService deptService;
|
||||||
|
|
||||||
// 状态服务(Redis)
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IDeviceStatusService deviceStatusService;
|
private IDeviceStatusService deviceStatusService;
|
||||||
|
|
||||||
|
// ✅ 新增
|
||||||
|
@Autowired
|
||||||
|
private DeviceStatusUtil deviceStatusUtil;
|
||||||
|
|
||||||
public void handle(MqttSensorDevice device, String topic, String payload) {
|
public void handle(MqttSensorDevice device, String topic, String payload) {
|
||||||
|
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
@@ -59,13 +63,24 @@ public class EnvSensorHandler {
|
|||||||
|
|
||||||
TopicInfo topicInfo = parseTopic(topic);
|
TopicInfo topicInfo = parseTopic(topic);
|
||||||
|
|
||||||
|
// =========================
|
||||||
// 1️⃣ 入库
|
// 1️⃣ 入库
|
||||||
|
// =========================
|
||||||
saveData(device, topic, payload, topicInfo, v);
|
saveData(device, topic, payload, topicInfo, v);
|
||||||
|
|
||||||
// 2️⃣ 推送(周期数据必须推)
|
// =========================
|
||||||
|
// 2️⃣ 恢复在线
|
||||||
|
// =========================
|
||||||
|
deviceStatusUtil.handleOnline(device);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// 3️⃣ 推送(周期数据必须推)
|
||||||
|
// =========================
|
||||||
pushWebSocket(device, v);
|
pushWebSocket(device, v);
|
||||||
|
|
||||||
// 3️⃣ 事件检测(带去重)
|
// =========================
|
||||||
|
// 4️⃣ 事件检测(带去重)
|
||||||
|
// =========================
|
||||||
handleEvent(device, v);
|
handleEvent(device, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,9 +158,6 @@ public class EnvSensorHandler {
|
|||||||
return "normal";
|
return "normal";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用Redis去重
|
|
||||||
*/
|
|
||||||
private void changeStatus(MqttSensorDevice device,
|
private void changeStatus(MqttSensorDevice device,
|
||||||
String metric,
|
String metric,
|
||||||
String newStatus,
|
String newStatus,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.shzg.project.worn.domain.MqttSensorEvent;
|
|||||||
import com.shzg.project.worn.service.IDeviceStatusService;
|
import com.shzg.project.worn.service.IDeviceStatusService;
|
||||||
import com.shzg.project.worn.service.IMqttSensorDataService;
|
import com.shzg.project.worn.service.IMqttSensorDataService;
|
||||||
import com.shzg.project.worn.service.IMqttSensorEventService;
|
import com.shzg.project.worn.service.IMqttSensorEventService;
|
||||||
|
import com.shzg.project.worn.unit.DeviceStatusUtil;
|
||||||
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -35,10 +36,12 @@ public class SmartSocketHandler {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ISysDeptService deptService;
|
private ISysDeptService deptService;
|
||||||
|
|
||||||
// 状态去重服务
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IDeviceStatusService deviceStatusService;
|
private IDeviceStatusService deviceStatusService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DeviceStatusUtil deviceStatusUtil;
|
||||||
|
|
||||||
public void handle(MqttSensorDevice device, String topic, String payload) {
|
public void handle(MqttSensorDevice device, String topic, String payload) {
|
||||||
|
|
||||||
// ================== 基础校验 ==================
|
// ================== 基础校验 ==================
|
||||||
@@ -82,7 +85,7 @@ public class SmartSocketHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================== 入库(始终入库) ==================
|
// ================== 入库(有效数据) ==================
|
||||||
MqttSensorData data = new MqttSensorData();
|
MqttSensorData data = new MqttSensorData();
|
||||||
data.setDeviceId(device.getId());
|
data.setDeviceId(device.getId());
|
||||||
data.setDeptId(device.getDeptId());
|
data.setDeptId(device.getDeptId());
|
||||||
@@ -95,6 +98,9 @@ public class SmartSocketHandler {
|
|||||||
|
|
||||||
dataService.insertMqttSensorData(data);
|
dataService.insertMqttSensorData(data);
|
||||||
|
|
||||||
|
// ================== 恢复在线 ==================
|
||||||
|
deviceStatusUtil.handleOnline(device);
|
||||||
|
|
||||||
// ================== 状态字符串 ==================
|
// ================== 状态字符串 ==================
|
||||||
String statusStr = (switchStatus == 1 ? "on" : "off");
|
String statusStr = (switchStatus == 1 ? "on" : "off");
|
||||||
|
|
||||||
@@ -105,11 +111,6 @@ public class SmartSocketHandler {
|
|||||||
statusStr
|
statusStr
|
||||||
);
|
);
|
||||||
|
|
||||||
// 没变化直接返回(不写事件、不推送)
|
|
||||||
if (!changed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================== 查询部门 ==================
|
// ================== 查询部门 ==================
|
||||||
String deptName = null;
|
String deptName = null;
|
||||||
SysDept dept = deptService.selectDeptById(device.getDeptId());
|
SysDept dept = deptService.selectDeptById(device.getDeptId());
|
||||||
@@ -117,7 +118,7 @@ public class SmartSocketHandler {
|
|||||||
deptName = dept.getDeptName();
|
deptName = dept.getDeptName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================== WebSocket推送(只推变化) ==================
|
// ================== WebSocket推送 ==================
|
||||||
try {
|
try {
|
||||||
JSONObject msg = new JSONObject();
|
JSONObject msg = new JSONObject();
|
||||||
msg.put("type", "socket");
|
msg.put("type", "socket");
|
||||||
@@ -135,6 +136,10 @@ public class SmartSocketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ================== 事件记录(只在变化时) ==================
|
// ================== 事件记录(只在变化时) ==================
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MqttSensorEvent event = new MqttSensorEvent();
|
MqttSensorEvent event = new MqttSensorEvent();
|
||||||
event.setDeviceId(device.getId());
|
event.setDeviceId(device.getId());
|
||||||
event.setDeptId(device.getDeptId());
|
event.setDeptId(device.getDeptId());
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.shzg.project.worn.domain.MqttSensorEvent;
|
|||||||
import com.shzg.project.worn.service.IDeviceStatusService;
|
import com.shzg.project.worn.service.IDeviceStatusService;
|
||||||
import com.shzg.project.worn.service.IMqttSensorDataService;
|
import com.shzg.project.worn.service.IMqttSensorDataService;
|
||||||
import com.shzg.project.worn.service.IMqttSensorEventService;
|
import com.shzg.project.worn.service.IMqttSensorEventService;
|
||||||
|
import com.shzg.project.worn.unit.DeviceStatusUtil;
|
||||||
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -18,7 +19,7 @@ import java.math.BigDecimal;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 烟雾传感器 Handler
|
* 烟雾传感器 Handler(最终生产版)
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@@ -39,6 +40,9 @@ public class SmokeSensorHandler {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IDeviceStatusService deviceStatusService;
|
private IDeviceStatusService deviceStatusService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DeviceStatusUtil deviceStatusUtil;
|
||||||
|
|
||||||
public void handle(MqttSensorDevice device, String topic, String payload) {
|
public void handle(MqttSensorDevice device, String topic, String payload) {
|
||||||
|
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
@@ -85,7 +89,7 @@ public class SmokeSensorHandler {
|
|||||||
deptName = dept.getDeptName();
|
deptName = dept.getDeptName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================== 数据入库(始终入库) ==================
|
// ================== 数据入库 ==================
|
||||||
MqttSensorData data = new MqttSensorData();
|
MqttSensorData data = new MqttSensorData();
|
||||||
data.setDeviceId(device.getId());
|
data.setDeviceId(device.getId());
|
||||||
data.setDeptId(device.getDeptId());
|
data.setDeptId(device.getDeptId());
|
||||||
@@ -106,7 +110,10 @@ public class SmokeSensorHandler {
|
|||||||
|
|
||||||
dataService.insertMqttSensorData(data);
|
dataService.insertMqttSensorData(data);
|
||||||
|
|
||||||
// ================== 先判断状态 ==================
|
// ================== 🔥 恢复在线 ==================
|
||||||
|
deviceStatusUtil.handleOnline(device);
|
||||||
|
|
||||||
|
// ================== 状态判断 ==================
|
||||||
String newStatus;
|
String newStatus;
|
||||||
String eventType;
|
String eventType;
|
||||||
String desc;
|
String desc;
|
||||||
@@ -147,10 +154,8 @@ public class SmokeSensorHandler {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// ================== WebSocket推送 ==================
|
// ================== WebSocket推送 ==================
|
||||||
// 烟感这里建议周期数据继续推,事件去重即可
|
|
||||||
pushWebSocket(device, deptName, event, battery, concentration, temperature, newStatus);
|
pushWebSocket(device, deptName, event, battery, concentration, temperature, newStatus);
|
||||||
|
|
||||||
// 状态没变化,不重复写事件
|
|
||||||
if (!changed) {
|
if (!changed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -158,13 +163,18 @@ public class SmokeSensorHandler {
|
|||||||
// ================== 事件入库 ==================
|
// ================== 事件入库 ==================
|
||||||
insertEvent(device, eventType, desc, level);
|
insertEvent(device, eventType, desc, level);
|
||||||
|
|
||||||
|
// ================== 🔥 联动控制(核心扩展点) ==================
|
||||||
|
if ("alarm".equals(newStatus)) {
|
||||||
|
log.warn("[SMOKE] 触发联动(烟雾报警)deviceId={}", device.getId());
|
||||||
|
|
||||||
|
// 👉 这里后面接:
|
||||||
|
// socketService.openFan(device.getDeptId());
|
||||||
|
}
|
||||||
|
|
||||||
log.info("[SMOKE] 状态变化 deviceId={}, status={}, eventType={}",
|
log.info("[SMOKE] 状态变化 deviceId={}, status={}, eventType={}",
|
||||||
device.getId(), newStatus, eventType);
|
device.getId(), newStatus, eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* WebSocket推送
|
|
||||||
*/
|
|
||||||
private void pushWebSocket(MqttSensorDevice device,
|
private void pushWebSocket(MqttSensorDevice device,
|
||||||
String deptName,
|
String deptName,
|
||||||
String event,
|
String event,
|
||||||
@@ -197,9 +207,6 @@ public class SmokeSensorHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 事件入库
|
|
||||||
*/
|
|
||||||
private void insertEvent(MqttSensorDevice device,
|
private void insertEvent(MqttSensorDevice device,
|
||||||
String type,
|
String type,
|
||||||
String desc,
|
String desc,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.shzg.project.worn.domain.MqttSensorEvent;
|
|||||||
import com.shzg.project.worn.service.IDeviceStatusService;
|
import com.shzg.project.worn.service.IDeviceStatusService;
|
||||||
import com.shzg.project.worn.service.IMqttSensorDataService;
|
import com.shzg.project.worn.service.IMqttSensorDataService;
|
||||||
import com.shzg.project.worn.service.IMqttSensorEventService;
|
import com.shzg.project.worn.service.IMqttSensorEventService;
|
||||||
|
import com.shzg.project.worn.unit.DeviceStatusUtil;
|
||||||
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -33,10 +34,12 @@ public class WaterSensorHandler {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ISysDeptService deptService;
|
private ISysDeptService deptService;
|
||||||
|
|
||||||
// Redis状态去重
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IDeviceStatusService deviceStatusService;
|
private IDeviceStatusService deviceStatusService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DeviceStatusUtil deviceStatusUtil;
|
||||||
|
|
||||||
public void handle(MqttSensorDevice device, String topic, String payload) {
|
public void handle(MqttSensorDevice device, String topic, String payload) {
|
||||||
|
|
||||||
if (device == null) return;
|
if (device == null) return;
|
||||||
@@ -57,15 +60,18 @@ public class WaterSensorHandler {
|
|||||||
deptName = dept.getDeptName();
|
deptName = dept.getDeptName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================== 入库(始终入库) ==================
|
// ================== 入库 ==================
|
||||||
saveData(device, topic, payload, topicInfo, info);
|
saveData(device, topic, payload, topicInfo, info);
|
||||||
|
|
||||||
|
// ================== 恢复在线 ==================
|
||||||
|
deviceStatusUtil.handleOnline(device);
|
||||||
|
|
||||||
// ================== 状态计算 ==================
|
// ================== 状态计算 ==================
|
||||||
String status = (info.getWater() != null && info.getWater() == 1)
|
String status = (info.getWater() != null && info.getWater() == 1)
|
||||||
? "alarm"
|
? "alarm"
|
||||||
: "normal";
|
: "normal";
|
||||||
|
|
||||||
// ================== WebSocket(周期数据推送) ==================
|
// ================== WebSocket ==================
|
||||||
pushWebSocket(device, deptName, info, status);
|
pushWebSocket(device, deptName, info, status);
|
||||||
|
|
||||||
// ================== Redis去重 ==================
|
// ================== Redis去重 ==================
|
||||||
@@ -89,7 +95,6 @@ public class WaterSensorHandler {
|
|||||||
log.info("[WATER] 状态变化 deviceId={}, status={}", device.getId(), status);
|
log.info("[WATER] 状态变化 deviceId={}, status={}", device.getId(), status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ================== WebSocket ==================
|
// ================== WebSocket ==================
|
||||||
private void pushWebSocket(MqttSensorDevice device,
|
private void pushWebSocket(MqttSensorDevice device,
|
||||||
String deptName,
|
String deptName,
|
||||||
@@ -112,8 +117,7 @@ public class WaterSensorHandler {
|
|||||||
sessionManager.sendToDept(device.getDeptId(), msg.toJSONString());
|
sessionManager.sendToDept(device.getDeptId(), msg.toJSONString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================== 事件 ==================
|
||||||
// ================== 事件写入 ==================
|
|
||||||
private void triggerEvent(MqttSensorDevice device,
|
private void triggerEvent(MqttSensorDevice device,
|
||||||
String type,
|
String type,
|
||||||
String level,
|
String level,
|
||||||
@@ -132,7 +136,6 @@ public class WaterSensorHandler {
|
|||||||
|
|
||||||
eventService.insertMqttSensorEvent(event);
|
eventService.insertMqttSensorEvent(event);
|
||||||
|
|
||||||
// 推送告警
|
|
||||||
JSONObject msg = new JSONObject();
|
JSONObject msg = new JSONObject();
|
||||||
msg.put("type", "alarm");
|
msg.put("type", "alarm");
|
||||||
msg.put("deviceId", device.getId());
|
msg.put("deviceId", device.getId());
|
||||||
@@ -148,7 +151,6 @@ public class WaterSensorHandler {
|
|||||||
sessionManager.sendToDept(device.getDeptId(), msg.toJSONString());
|
sessionManager.sendToDept(device.getDeptId(), msg.toJSONString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ================== 入库 ==================
|
// ================== 入库 ==================
|
||||||
private void saveData(MqttSensorDevice device,
|
private void saveData(MqttSensorDevice device,
|
||||||
String topic,
|
String topic,
|
||||||
@@ -174,7 +176,6 @@ public class WaterSensorHandler {
|
|||||||
sensorDataService.insertMqttSensorData(data);
|
sensorDataService.insertMqttSensorData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ================== 工具 ==================
|
// ================== 工具 ==================
|
||||||
private JSONObject parseJson(String payload) {
|
private JSONObject parseJson(String payload) {
|
||||||
try {
|
try {
|
||||||
@@ -230,7 +231,6 @@ public class WaterSensorHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class TopicInfo {
|
private static class TopicInfo {
|
||||||
String project;
|
String project;
|
||||||
String warehouse;
|
String warehouse;
|
||||||
|
|||||||
@@ -65,4 +65,13 @@ public interface IMqttSensorDeviceService
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
MqttSensorDevice selectByDevEui(String devEui);
|
MqttSensorDevice selectByDevEui(String devEui);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新设备在线状态(0在线 1离线)
|
||||||
|
*
|
||||||
|
* @param deviceId 设备ID
|
||||||
|
* @param status 状态
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateRuntimeStatus(Long deviceId, String status);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.shzg.project.worn.service;
|
package com.shzg.project.worn.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.shzg.project.worn.domain.MqttSensorEvent;
|
import com.shzg.project.worn.domain.MqttSensorEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,4 +60,20 @@ public interface IMqttSensorEventService
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public int deleteMqttSensorEventById(Long id);
|
public int deleteMqttSensorEventById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警统计
|
||||||
|
*/
|
||||||
|
Map<String, Object> getAlarmStat();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警趋势(近7天)
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getAlarmTrend();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 告警类型占比
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> getAlarmTypeStat();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,4 +127,19 @@ public class MqttSensorDeviceServiceImpl implements IMqttSensorDeviceService
|
|||||||
|
|
||||||
return mqttSensorDeviceMapper.selectByDevEui(devEui.toLowerCase());
|
return mqttSensorDeviceMapper.selectByDevEui(devEui.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateRuntimeStatus(Long deviceId, String status)
|
||||||
|
{
|
||||||
|
if (deviceId == null || status == null || status.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MqttSensorDevice update = new MqttSensorDevice();
|
||||||
|
update.setId(deviceId);
|
||||||
|
update.setStatus(status);
|
||||||
|
update.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
|
||||||
|
return mqttSensorDeviceMapper.updateRuntimeStatus(update);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.shzg.project.worn.service.impl;
|
package com.shzg.project.worn.service.impl;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.shzg.common.utils.DateUtils;
|
import com.shzg.common.utils.DateUtils;
|
||||||
import com.shzg.common.utils.DeptScopeUtils;
|
import com.shzg.common.utils.DeptScopeUtils;
|
||||||
import com.shzg.common.utils.SecurityUtils;
|
import com.shzg.common.utils.SecurityUtils;
|
||||||
@@ -101,4 +104,41 @@ public class MqttSensorEventServiceImpl implements IMqttSensorEventService
|
|||||||
{
|
{
|
||||||
return mqttSensorEventMapper.deleteMqttSensorEventById(id);
|
return mqttSensorEventMapper.deleteMqttSensorEventById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MqttSensorEventMapper eventMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getAlarmStat()
|
||||||
|
{
|
||||||
|
// 当前用户权限范围
|
||||||
|
List<Long> deptIds = DeptScopeUtils.getDeptScope();
|
||||||
|
|
||||||
|
Map<String, Object> stat = eventMapper.countAlarmStat(deptIds);
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
|
||||||
|
result.put("today", stat == null ? 0 : stat.getOrDefault("today", 0));
|
||||||
|
result.put("unhandled", stat == null ? 0 : stat.getOrDefault("unhandled", 0));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getAlarmTrend()
|
||||||
|
{
|
||||||
|
// 当前用户权限范围
|
||||||
|
List<Long> deptIds = DeptScopeUtils.getDeptScope();
|
||||||
|
|
||||||
|
return eventMapper.selectAlarmTrend(deptIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> getAlarmTypeStat()
|
||||||
|
{
|
||||||
|
// 当前用户权限范围
|
||||||
|
List<Long> deptIds = DeptScopeUtils.getDeptScope();
|
||||||
|
|
||||||
|
return eventMapper.selectAlarmTypeStat(deptIds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.shzg.project.worn.service.*;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -33,24 +34,42 @@ public class MqttSocketServiceImpl implements IMqttSocketService {
|
|||||||
|
|
||||||
// ================== 1️⃣ 查设备 ==================
|
// ================== 1️⃣ 查设备 ==================
|
||||||
MqttSensorDevice device = deviceService.selectByDevEui(devEui);
|
MqttSensorDevice device = deviceService.selectByDevEui(devEui);
|
||||||
|
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
throw new RuntimeException("设备不存在: " + devEui);
|
throw new RuntimeException("设备不存在: " + devEui);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================== 2️⃣ 查Topic配置 ==================
|
// ================== 2️⃣ 查Topic ==================
|
||||||
MqttTopicConfig config = topicConfigService.selectByDeptId(device.getDeptId());
|
MqttTopicConfig config = topicConfigService.selectByDeptId(device.getDeptId());
|
||||||
|
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
throw new RuntimeException("未配置MQTT主题,deptId=" + device.getDeptId());
|
throw new RuntimeException("未配置MQTT主题,deptId=" + device.getDeptId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================== 3️⃣ 拼接topic ==================
|
|
||||||
String topic = config.getTopicDownPrefix() + "/" + devEui.toLowerCase();
|
String topic = config.getTopicDownPrefix() + "/" + devEui.toLowerCase();
|
||||||
|
|
||||||
// ================== 4️⃣ 构造指令 ==================
|
// ================== 3️⃣ 生成requestId ==================
|
||||||
String base64 = on ? "CAEA/w==" : "CAAA/w==";
|
|
||||||
|
|
||||||
String requestId = UUID.randomUUID().toString();
|
String requestId = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
// ================== 4️⃣ 构造指令 ==================
|
||||||
|
String base64;
|
||||||
|
|
||||||
|
String deviceType = device.getDeviceType();
|
||||||
|
|
||||||
|
if ("socket".equalsIgnoreCase(deviceType)) {
|
||||||
|
// 插座(WS513 / WS515)
|
||||||
|
base64 = on ? "CAEA/w==" : "CAAA/w==";
|
||||||
|
|
||||||
|
} else if ("switch".equalsIgnoreCase(deviceType)) {
|
||||||
|
// 开关(WS503)
|
||||||
|
// 控制 L1(第一路)
|
||||||
|
String hex = on ? "0811FF" : "0810FF";
|
||||||
|
base64 = Base64.getEncoder().encodeToString(hexStringToBytes(hex));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("未知设备类型: " + deviceType);
|
||||||
|
}
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
JSONObject json = new JSONObject();
|
||||||
json.put("confirmed", true);
|
json.put("confirmed", true);
|
||||||
json.put("fport", 85);
|
json.put("fport", 85);
|
||||||
@@ -59,13 +78,13 @@ public class MqttSocketServiceImpl implements IMqttSocketService {
|
|||||||
|
|
||||||
String payload = json.toJSONString();
|
String payload = json.toJSONString();
|
||||||
|
|
||||||
// ================== 5️⃣ 写指令记录(发送前) ==================
|
// ================== 5️⃣ 记录指令 ==================
|
||||||
MqttSensorCommand cmd = new MqttSensorCommand();
|
MqttSensorCommand cmd = new MqttSensorCommand();
|
||||||
cmd.setDeviceId(device.getId());
|
cmd.setDeviceId(device.getId());
|
||||||
cmd.setTopic(topic);
|
cmd.setTopic(topic);
|
||||||
cmd.setCommand(on ? "ON" : "OFF");
|
cmd.setCommand(on ? "ON" : "OFF");
|
||||||
cmd.setPayload(payload);
|
cmd.setPayload(payload);
|
||||||
cmd.setStatus("0"); // 0=待确认
|
cmd.setStatus("0"); // 待确认
|
||||||
cmd.setSendTime(new Date());
|
cmd.setSendTime(new Date());
|
||||||
cmd.setIsDelete("0");
|
cmd.setIsDelete("0");
|
||||||
cmd.setCreateTime(DateUtils.getNowDate());
|
cmd.setCreateTime(DateUtils.getNowDate());
|
||||||
@@ -75,9 +94,25 @@ public class MqttSocketServiceImpl implements IMqttSocketService {
|
|||||||
// ================== 6️⃣ 发送MQTT ==================
|
// ================== 6️⃣ 发送MQTT ==================
|
||||||
mqttPublishClient.publish(topic, payload);
|
mqttPublishClient.publish(topic, payload);
|
||||||
|
|
||||||
// ================== 7️⃣ 日志 ==================
|
// ================== 7️⃣ 打印日志 ==================
|
||||||
System.out.println("[SOCKET] 指令发送 devEui=" + devEui +
|
System.out.println("[SOCKET] 指令发送 devEui=" + devEui +
|
||||||
|
", type=" + deviceType +
|
||||||
", status=" + (on ? "ON" : "OFF") +
|
", status=" + (on ? "ON" : "OFF") +
|
||||||
", requestId=" + requestId);
|
", requestId=" + requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hex字符串转byte[]
|
||||||
|
*/
|
||||||
|
private byte[] hexStringToBytes(String hex) {
|
||||||
|
int len = hex.length();
|
||||||
|
byte[] data = new byte[len / 2];
|
||||||
|
for (int i = 0; i < len; i += 2) {
|
||||||
|
data[i / 2] = (byte) (
|
||||||
|
(Character.digit(hex.charAt(i), 16) << 4)
|
||||||
|
+ Character.digit(hex.charAt(i + 1), 16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.shzg.project.worn.unit;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.shzg.project.worn.domain.MqttSensorDevice;
|
||||||
|
import com.shzg.project.worn.mapper.MqttSensorDeviceMapper;
|
||||||
|
import com.shzg.project.worn.service.IMqttSensorDeviceService;
|
||||||
|
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备离线巡检任务
|
||||||
|
* 规则:按设备 report_interval_minute * 3 动态判定离线
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class DeviceOfflineCheckTask {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MqttSensorDeviceMapper deviceMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMqttSensorDeviceService deviceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MqttDeviceCache deviceCache;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebSocketSessionManager sessionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每5分钟巡检一次
|
||||||
|
*/
|
||||||
|
@Scheduled(initialDelay = 60 * 1000L, fixedDelay = 5 * 60 * 1000L)
|
||||||
|
public void checkOfflineDevices() {
|
||||||
|
|
||||||
|
List<MqttSensorDevice> offlineDevices = deviceMapper.selectOfflineDeviceList();
|
||||||
|
|
||||||
|
if (offlineDevices == null || offlineDevices.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean cacheChanged = false;
|
||||||
|
|
||||||
|
for (MqttSensorDevice device : offlineDevices) {
|
||||||
|
|
||||||
|
// ✅ 已经是离线状态,跳过(防止重复更新)
|
||||||
|
if ("1".equals(device.getStatus())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rows = deviceService.updateRuntimeStatus(device.getId(), "1");
|
||||||
|
if (rows <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheChanged = true;
|
||||||
|
|
||||||
|
// 推送离线消息
|
||||||
|
pushOfflineMessage(device);
|
||||||
|
|
||||||
|
log.info("[DEVICE] 判定离线 deviceId={}, devEui={}, interval={}分钟",
|
||||||
|
device.getId(),
|
||||||
|
device.getDevEui(),
|
||||||
|
device.getReportIntervalMinute());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ 只有发生变化才刷新缓存
|
||||||
|
if (cacheChanged) {
|
||||||
|
deviceCache.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推送设备离线消息
|
||||||
|
*/
|
||||||
|
private void pushOfflineMessage(MqttSensorDevice device) {
|
||||||
|
|
||||||
|
if (device == null || device.getDeptId() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject msg = new JSONObject();
|
||||||
|
msg.put("type", "device_offline");
|
||||||
|
msg.put("deviceId", device.getId());
|
||||||
|
msg.put("devEui", device.getDevEui());
|
||||||
|
msg.put("deviceName", device.getDeviceName());
|
||||||
|
msg.put("deviceType", device.getDeviceType());
|
||||||
|
msg.put("deptId", device.getDeptId());
|
||||||
|
msg.put("deptName", device.getDeptName());
|
||||||
|
msg.put("deviceStatus", 1);
|
||||||
|
msg.put("statusDesc", "离线");
|
||||||
|
msg.put("time", System.currentTimeMillis());
|
||||||
|
|
||||||
|
sessionManager.sendToDept(device.getDeptId(), msg.toJSONString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package com.shzg.project.worn.unit;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.shzg.common.utils.DateUtils;
|
||||||
|
import com.shzg.project.worn.domain.MqttSensorDevice;
|
||||||
|
import com.shzg.project.worn.service.IMqttSensorDeviceService;
|
||||||
|
import com.shzg.project.worn.unit.MqttDeviceCache;
|
||||||
|
import com.shzg.project.worn.websocket.manager.WebSocketSessionManager;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备状态工具类(在线 / 离线统一处理)
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class DeviceStatusUtil {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMqttSensorDeviceService deviceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebSocketSessionManager sessionManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MqttDeviceCache deviceCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 🔥 设备恢复在线(只在“有效消息”后调用)
|
||||||
|
*/
|
||||||
|
public void handleOnline(MqttSensorDevice device) {
|
||||||
|
|
||||||
|
if (device == null || device.getId() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ 已经在线,直接返回
|
||||||
|
if ("0".equals(device.getStatus())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rows = deviceService.updateRuntimeStatus(device.getId(), "0");
|
||||||
|
if (rows <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("[DEVICE] 恢复在线 deviceId={}, devEui={}",
|
||||||
|
device.getId(), device.getDevEui());
|
||||||
|
|
||||||
|
// 推送WebSocket
|
||||||
|
pushOnlineMessage(device);
|
||||||
|
|
||||||
|
// 刷新缓存
|
||||||
|
deviceCache.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推送在线消息
|
||||||
|
*/
|
||||||
|
private void pushOnlineMessage(MqttSensorDevice device) {
|
||||||
|
|
||||||
|
if (device.getDeptId() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject msg = new JSONObject();
|
||||||
|
msg.put("type", "device_online");
|
||||||
|
msg.put("deviceId", device.getId());
|
||||||
|
msg.put("devEui", device.getDevEui());
|
||||||
|
msg.put("deviceName", device.getDeviceName());
|
||||||
|
msg.put("deviceType", device.getDeviceType());
|
||||||
|
msg.put("deptId", device.getDeptId());
|
||||||
|
msg.put("deptName", device.getDeptName());
|
||||||
|
msg.put("deviceStatus", 0);
|
||||||
|
msg.put("statusDesc", "在线");
|
||||||
|
msg.put("time", System.currentTimeMillis());
|
||||||
|
|
||||||
|
sessionManager.sendToDept(device.getDeptId(), msg.toJSONString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.shzg.project.worn.websocket.endpoint;
|
package com.shzg.project.worn.websocket.endpoint;
|
||||||
|
|
||||||
|
import com.shzg.framework.security.LoginUser;
|
||||||
|
import com.shzg.framework.security.service.TokenService;
|
||||||
import com.shzg.project.system.domain.SysDept;
|
import com.shzg.project.system.domain.SysDept;
|
||||||
import com.shzg.project.system.mapper.SysDeptMapper;
|
import com.shzg.project.system.mapper.SysDeptMapper;
|
||||||
import com.shzg.project.worn.websocket.domain.WsUserInfo;
|
import com.shzg.project.worn.websocket.domain.WsUserInfo;
|
||||||
@@ -8,10 +10,15 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.websocket.*;
|
import javax.websocket.CloseReason;
|
||||||
|
import javax.websocket.OnClose;
|
||||||
|
import javax.websocket.OnError;
|
||||||
|
import javax.websocket.OnOpen;
|
||||||
|
import javax.websocket.Session;
|
||||||
import javax.websocket.server.ServerEndpoint;
|
import javax.websocket.server.ServerEndpoint;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.URLDecoder;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -23,6 +30,7 @@ public class WornWebSocketServer {
|
|||||||
|
|
||||||
private static WebSocketSessionManager sessionManager;
|
private static WebSocketSessionManager sessionManager;
|
||||||
private static SysDeptMapper deptMapper;
|
private static SysDeptMapper deptMapper;
|
||||||
|
private static TokenService tokenService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public void setSessionManager(WebSocketSessionManager manager) {
|
public void setSessionManager(WebSocketSessionManager manager) {
|
||||||
@@ -34,112 +42,164 @@ public class WornWebSocketServer {
|
|||||||
WornWebSocketServer.deptMapper = mapper;
|
WornWebSocketServer.deptMapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setTokenService(TokenService service) {
|
||||||
|
WornWebSocketServer.tokenService = service;
|
||||||
|
}
|
||||||
|
|
||||||
@OnOpen
|
@OnOpen
|
||||||
public void onOpen(Session session) {
|
public void onOpen(Session session) {
|
||||||
|
|
||||||
log.info("[WebSocket] 连接建立 sessionId={}", session.getId());
|
log.info("[WebSocket] 连接建立 sessionId={}", session.getId());
|
||||||
|
|
||||||
String query = session.getQueryString();
|
String query = session.getQueryString();
|
||||||
|
if (query == null || !query.contains("token=")) {
|
||||||
if (query == null || !query.contains("deptId")) {
|
closeSession(session, "missing token");
|
||||||
closeSession(session, "missing deptId");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Long deptId;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
deptId = parseDeptId(query);
|
// ===== 1. 解析token =====
|
||||||
} catch (Exception e) {
|
String token = parseToken(query);
|
||||||
closeSession(session, "invalid deptId");
|
if (token == null || token.trim().isEmpty()) {
|
||||||
|
closeSession(session, "invalid token");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SysDept> deptList = deptMapper.selectDeptAndChildren(deptId, null);
|
// ===== 2. 获取登录用户 =====
|
||||||
|
LoginUser loginUser = tokenService.getLoginUserByToken(token);
|
||||||
Set<Long> deptIds = new HashSet<>();
|
if (loginUser == null) {
|
||||||
for (SysDept dept : deptList) {
|
closeSession(session, "invalid token");
|
||||||
deptIds.add(dept.getDeptId());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 构造用户(当前写死)=====
|
Long userId = loginUser.getUserId();
|
||||||
|
Long deptId = loginUser.getDeptId();
|
||||||
|
String userName = loginUser.getUsername();
|
||||||
|
|
||||||
|
boolean isAdmin = false;
|
||||||
|
if (loginUser.getUser() != null) {
|
||||||
|
isAdmin = loginUser.getUser().isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deptId == null) {
|
||||||
|
closeSession(session, "deptId is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 3. 计算部门范围(🔥重点修改)=====
|
||||||
|
Set<Long> deptIds = new HashSet<>();
|
||||||
|
|
||||||
|
if (isAdmin) {
|
||||||
|
// 🔥 管理员:全部部门
|
||||||
|
SysDept queryDept = new SysDept();
|
||||||
|
List<SysDept> allDept = deptMapper.selectDeptList(queryDept);
|
||||||
|
if (allDept != null && !allDept.isEmpty()) {
|
||||||
|
for (SysDept d : allDept) {
|
||||||
|
if (d != null && d.getDeptId() != null) {
|
||||||
|
deptIds.add(d.getDeptId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 普通用户:当前部门 + 子部门
|
||||||
|
List<SysDept> deptList = deptMapper.selectDeptAndChildren(deptId, null);
|
||||||
|
|
||||||
|
if (deptList != null && !deptList.isEmpty()) {
|
||||||
|
for (SysDept dept : deptList) {
|
||||||
|
if (dept != null && dept.getDeptId() != null) {
|
||||||
|
deptIds.add(dept.getDeptId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deptIds.add(deptId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 4. 构造用户信息 =====
|
||||||
WsUserInfo userInfo = new WsUserInfo();
|
WsUserInfo userInfo = new WsUserInfo();
|
||||||
userInfo.setUserId(1L);
|
userInfo.setUserId(userId);
|
||||||
userInfo.setUserName("test");
|
userInfo.setUserName(userName);
|
||||||
userInfo.setAdmin(false);
|
userInfo.setAdmin(isAdmin);
|
||||||
userInfo.setDeptIds(deptIds);
|
userInfo.setDeptIds(deptIds);
|
||||||
|
|
||||||
// ===== 获取IP(新增)=====
|
// ===== 5. 获取IP =====
|
||||||
String ip = getIp(session);
|
String ip = getIp(session);
|
||||||
|
|
||||||
// 存入 session(给 manager 用)
|
|
||||||
session.getUserProperties().put("ip", ip);
|
session.getUserProperties().put("ip", ip);
|
||||||
|
|
||||||
// ===== 注册连接(关键:接入限流)=====
|
// ===== 6. 注册连接 =====
|
||||||
boolean success = sessionManager.register(session, userInfo);
|
boolean success = sessionManager.register(session, userInfo);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
log.warn("[WebSocket] 连接被拒绝(限流)sessionId={}, ip={}", session.getId(), ip);
|
log.warn("[WebSocket] 连接被拒绝(限流)sessionId={}, ip={}", session.getId(), ip);
|
||||||
closeSession(session, "too many connections");
|
closeSession(session, "too many connections");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("[WebSocket] 注册成功 sessionId={}, ip={}, deptIds={}",
|
log.info("[WebSocket] 注册成功 sessionId={}, userId={}, userName={}, ip={}, deptIds={}",
|
||||||
session.getId(), ip, deptIds);
|
session.getId(), userId, userName, ip, deptIds);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[WebSocket] 连接异常 sessionId={}", session.getId(), e);
|
||||||
|
closeSession(session, "error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClose
|
@OnClose
|
||||||
public void onClose(Session session) {
|
public void onClose(Session session) {
|
||||||
sessionManager.remove(session);
|
sessionManager.remove(session);
|
||||||
|
log.info("[WebSocket] 连接关闭 sessionId={}", session.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnError
|
@OnError
|
||||||
public void onError(Session session, Throwable error) {
|
public void onError(Session session, Throwable error) {
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
sessionManager.remove(session);
|
sessionManager.remove(session);
|
||||||
|
log.error("[WebSocket] 异常 sessionId={}", session.getId(), error);
|
||||||
|
} else {
|
||||||
|
log.error("[WebSocket] 异常", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Long parseDeptId(String query) {
|
private String parseToken(String query) throws Exception {
|
||||||
|
|
||||||
String[] params = query.split("&");
|
String[] params = query.split("&");
|
||||||
|
|
||||||
for (String param : params) {
|
for (String param : params) {
|
||||||
if (param.startsWith("deptId=")) {
|
if (param.startsWith("token=")) {
|
||||||
return Long.parseLong(param.substring(7));
|
String token = param.substring(6);
|
||||||
|
token = URLDecoder.decode(token, "UTF-8");
|
||||||
|
|
||||||
|
if (token.startsWith("Bearer ")) {
|
||||||
|
token = token.substring(7);
|
||||||
}
|
}
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("token not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException("deptId not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取客户端IP
|
|
||||||
*/
|
|
||||||
private String getIp(Session session) {
|
private String getIp(Session session) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 标准方式(部分容器支持)
|
|
||||||
Object addr = session.getUserProperties().get("javax.websocket.endpoint.remoteAddress");
|
Object addr = session.getUserProperties().get("javax.websocket.endpoint.remoteAddress");
|
||||||
|
|
||||||
if (addr instanceof InetSocketAddress) {
|
if (addr instanceof InetSocketAddress) {
|
||||||
return ((InetSocketAddress) addr).getAddress().getHostAddress();
|
InetSocketAddress inetSocketAddress = (InetSocketAddress) addr;
|
||||||
|
if (inetSocketAddress.getAddress() != null) {
|
||||||
|
return inetSocketAddress.getAddress().getHostAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[WebSocket] 获取客户端IP失败 sessionId={}", session.getId(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
|
|
||||||
// fallback
|
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeSession(Session session, String reason) {
|
private void closeSession(Session session, String reason) {
|
||||||
try {
|
try {
|
||||||
|
if (session != null && session.isOpen()) {
|
||||||
session.close(new CloseReason(
|
session.close(new CloseReason(
|
||||||
CloseReason.CloseCodes.CANNOT_ACCEPT,
|
CloseReason.CloseCodes.CANNOT_ACCEPT,
|
||||||
reason
|
reason
|
||||||
));
|
));
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("关闭失败", e);
|
log.error("[WebSocket] 关闭连接失败 sessionId={}", session != null ? session.getId() : "null", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,4 +175,89 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
WHERE FIND_IN_SET(#{deptId}, ancestors)
|
WHERE FIND_IN_SET(#{deptId}, ancestors)
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="countProjectByDeptIds" resultType="int">
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM sys_dept d
|
||||||
|
WHERE d.del_flag = '0'
|
||||||
|
AND d.status = '0'
|
||||||
|
AND d.parent_id != 0
|
||||||
|
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM sys_dept c
|
||||||
|
WHERE c.parent_id = d.dept_id
|
||||||
|
AND c.del_flag = '0'
|
||||||
|
)
|
||||||
|
|
||||||
|
<!-- ✅ 权限范围 -->
|
||||||
|
AND d.dept_id IN
|
||||||
|
<foreach collection="deptIds" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="countWarehouseByDeptIds" resultType="int">
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM sys_dept d
|
||||||
|
WHERE d.del_flag = '0'
|
||||||
|
AND d.status = '0'
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM sys_dept c
|
||||||
|
WHERE c.parent_id = d.dept_id
|
||||||
|
AND c.del_flag = '0'
|
||||||
|
)
|
||||||
|
|
||||||
|
AND d.dept_id IN
|
||||||
|
<foreach collection="deptIds" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectWarehouseList" resultType="map">
|
||||||
|
SELECT
|
||||||
|
w.dept_id AS deptId,
|
||||||
|
w.dept_name AS warehouseName,
|
||||||
|
|
||||||
|
/* 上级(项目) */
|
||||||
|
p.dept_name AS parentName,
|
||||||
|
|
||||||
|
/* 在线率 */
|
||||||
|
CASE
|
||||||
|
WHEN COUNT(d.id) = 0 THEN 0
|
||||||
|
ELSE ROUND(
|
||||||
|
SUM(CASE WHEN d.status = 0 THEN 1 ELSE 0 END) * 1.0 / COUNT(d.id) * 100,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
END AS onlineRate
|
||||||
|
|
||||||
|
FROM sys_dept w
|
||||||
|
|
||||||
|
/* 上级 */
|
||||||
|
LEFT JOIN sys_dept p
|
||||||
|
ON w.parent_id = p.dept_id
|
||||||
|
|
||||||
|
/* 设备 */
|
||||||
|
LEFT JOIN mqtt_sensor_device d
|
||||||
|
ON d.dept_id = w.dept_id
|
||||||
|
AND d.is_delete = 0
|
||||||
|
|
||||||
|
WHERE w.del_flag = '0'
|
||||||
|
|
||||||
|
/* ✅ 只查仓库(叶子节点) */
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM sys_dept c
|
||||||
|
WHERE c.parent_id = w.dept_id
|
||||||
|
AND c.del_flag = '0'
|
||||||
|
)
|
||||||
|
|
||||||
|
/* ✅ 权限控制(核心) */
|
||||||
|
AND w.dept_id IN
|
||||||
|
<foreach collection="deptIds" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
|
||||||
|
GROUP BY w.dept_id
|
||||||
|
|
||||||
|
ORDER BY w.dept_id DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -2,14 +2,18 @@
|
|||||||
<!DOCTYPE mapper
|
<!DOCTYPE mapper
|
||||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
|
||||||
<mapper namespace="com.shzg.project.worn.mapper.MqttSensorDeviceMapper">
|
<mapper namespace="com.shzg.project.worn.mapper.MqttSensorDeviceMapper">
|
||||||
|
|
||||||
|
<!-- ================= resultMap ================= -->
|
||||||
<resultMap type="MqttSensorDevice" id="MqttSensorDeviceResult">
|
<resultMap type="MqttSensorDevice" id="MqttSensorDeviceResult">
|
||||||
<result property="id" column="id"/>
|
<result property="id" column="id"/>
|
||||||
<result property="devEui" column="dev_eui"/>
|
<result property="devEui" column="dev_eui"/>
|
||||||
<result property="deviceName" column="device_name"/>
|
<result property="deviceName" column="device_name"/>
|
||||||
<result property="deviceType" column="device_type"/>
|
<result property="deviceType" column="device_type"/>
|
||||||
<result property="deptId" column="dept_id"/>
|
<result property="deptId" column="dept_id"/>
|
||||||
|
<result property="deptName" column="dept_name"/>
|
||||||
|
<result property="reportIntervalMinute" column="report_interval_minute"/>
|
||||||
<result property="status" column="status"/>
|
<result property="status" column="status"/>
|
||||||
<result property="remark" column="remark"/>
|
<result property="remark" column="remark"/>
|
||||||
<result property="createBy" column="create_by"/>
|
<result property="createBy" column="create_by"/>
|
||||||
@@ -19,27 +23,62 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="isDelete" column="is_delete"/>
|
<result property="isDelete" column="is_delete"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- ================= 公共查询SQL ================= -->
|
||||||
<sql id="selectMqttSensorDeviceVo">
|
<sql id="selectMqttSensorDeviceVo">
|
||||||
select id, dev_eui, device_name, device_type, dept_id, status, remark, create_by, create_time, update_by, update_time, is_delete from mqtt_sensor_device
|
select
|
||||||
|
d.id,
|
||||||
|
d.dev_eui,
|
||||||
|
d.device_name,
|
||||||
|
d.device_type,
|
||||||
|
d.dept_id,
|
||||||
|
dept.dept_name,
|
||||||
|
d.report_interval_minute,
|
||||||
|
d.status,
|
||||||
|
d.remark,
|
||||||
|
d.create_by,
|
||||||
|
d.create_time,
|
||||||
|
d.update_by,
|
||||||
|
d.update_time,
|
||||||
|
d.is_delete
|
||||||
|
from mqtt_sensor_device d
|
||||||
|
left join sys_dept dept on d.dept_id = dept.dept_id
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
<!-- ================= 查询列表 ================= -->
|
||||||
<select id="selectMqttSensorDeviceList" parameterType="MqttSensorDevice" resultMap="MqttSensorDeviceResult">
|
<select id="selectMqttSensorDeviceList" parameterType="MqttSensorDevice" resultMap="MqttSensorDeviceResult">
|
||||||
<include refid="selectMqttSensorDeviceVo"/>
|
<include refid="selectMqttSensorDeviceVo"/>
|
||||||
<where>
|
<where>
|
||||||
<if test="devEui != null and devEui != ''"> and dev_eui = #{devEui}</if>
|
<if test="devEui != null and devEui != ''">
|
||||||
<if test="deviceName != null and deviceName != ''"> and device_name like concat('%', #{deviceName}, '%')</if>
|
and d.dev_eui = #{devEui}
|
||||||
<if test="deviceType != null and deviceType != ''"> and device_type = #{deviceType}</if>
|
</if>
|
||||||
<if test="deptId != null "> and dept_id = #{deptId}</if>
|
<if test="deviceName != null and deviceName != ''">
|
||||||
<if test="status != null and status != ''"> and status = #{status}</if>
|
and d.device_name like concat('%', #{deviceName}, '%')
|
||||||
<if test="isDelete != null and isDelete != ''"> and is_delete = #{isDelete}</if>
|
</if>
|
||||||
|
<if test="deviceType != null and deviceType != ''">
|
||||||
|
and d.device_type = #{deviceType}
|
||||||
|
</if>
|
||||||
|
<if test="deptId != null">
|
||||||
|
and d.dept_id = #{deptId}
|
||||||
|
</if>
|
||||||
|
<if test="reportIntervalMinute != null">
|
||||||
|
and d.report_interval_minute = #{reportIntervalMinute}
|
||||||
|
</if>
|
||||||
|
<if test="status != null and status != ''">
|
||||||
|
and d.status = #{status}
|
||||||
|
</if>
|
||||||
|
<if test="isDelete != null and isDelete != ''">
|
||||||
|
and d.is_delete = #{isDelete}
|
||||||
|
</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- ================= 根据ID查询 ================= -->
|
||||||
<select id="selectMqttSensorDeviceById" parameterType="Long" resultMap="MqttSensorDeviceResult">
|
<select id="selectMqttSensorDeviceById" parameterType="Long" resultMap="MqttSensorDeviceResult">
|
||||||
<include refid="selectMqttSensorDeviceVo"/>
|
<include refid="selectMqttSensorDeviceVo"/>
|
||||||
where id = #{id}
|
where d.id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- ================= 新增 ================= -->
|
||||||
<insert id="insertMqttSensorDevice" parameterType="MqttSensorDevice" useGeneratedKeys="true" keyProperty="id">
|
<insert id="insertMqttSensorDevice" parameterType="MqttSensorDevice" useGeneratedKeys="true" keyProperty="id">
|
||||||
insert into mqtt_sensor_device
|
insert into mqtt_sensor_device
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
@@ -47,6 +86,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="deviceName != null">device_name,</if>
|
<if test="deviceName != null">device_name,</if>
|
||||||
<if test="deviceType != null">device_type,</if>
|
<if test="deviceType != null">device_type,</if>
|
||||||
<if test="deptId != null">dept_id,</if>
|
<if test="deptId != null">dept_id,</if>
|
||||||
|
<if test="reportIntervalMinute != null">report_interval_minute,</if>
|
||||||
<if test="status != null">status,</if>
|
<if test="status != null">status,</if>
|
||||||
<if test="remark != null">remark,</if>
|
<if test="remark != null">remark,</if>
|
||||||
<if test="createBy != null">create_by,</if>
|
<if test="createBy != null">create_by,</if>
|
||||||
@@ -60,6 +100,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="deviceName != null">#{deviceName},</if>
|
<if test="deviceName != null">#{deviceName},</if>
|
||||||
<if test="deviceType != null">#{deviceType},</if>
|
<if test="deviceType != null">#{deviceType},</if>
|
||||||
<if test="deptId != null">#{deptId},</if>
|
<if test="deptId != null">#{deptId},</if>
|
||||||
|
<if test="reportIntervalMinute != null">#{reportIntervalMinute},</if>
|
||||||
<if test="status != null">#{status},</if>
|
<if test="status != null">#{status},</if>
|
||||||
<if test="remark != null">#{remark},</if>
|
<if test="remark != null">#{remark},</if>
|
||||||
<if test="createBy != null">#{createBy},</if>
|
<if test="createBy != null">#{createBy},</if>
|
||||||
@@ -70,6 +111,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</trim>
|
</trim>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<!-- ================= 修改 ================= -->
|
||||||
<update id="updateMqttSensorDevice" parameterType="MqttSensorDevice">
|
<update id="updateMqttSensorDevice" parameterType="MqttSensorDevice">
|
||||||
update mqtt_sensor_device
|
update mqtt_sensor_device
|
||||||
<trim prefix="SET" suffixOverrides=",">
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
@@ -77,6 +119,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="deviceName != null">device_name = #{deviceName},</if>
|
<if test="deviceName != null">device_name = #{deviceName},</if>
|
||||||
<if test="deviceType != null">device_type = #{deviceType},</if>
|
<if test="deviceType != null">device_type = #{deviceType},</if>
|
||||||
<if test="deptId != null">dept_id = #{deptId},</if>
|
<if test="deptId != null">dept_id = #{deptId},</if>
|
||||||
|
<if test="reportIntervalMinute != null">report_interval_minute = #{reportIntervalMinute},</if>
|
||||||
<if test="status != null">status = #{status},</if>
|
<if test="status != null">status = #{status},</if>
|
||||||
<if test="remark != null">remark = #{remark},</if>
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
<if test="createBy != null">create_by = #{createBy},</if>
|
<if test="createBy != null">create_by = #{createBy},</if>
|
||||||
@@ -88,6 +131,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
where id = #{id}
|
where id = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="updateRuntimeStatus" parameterType="MqttSensorDevice">
|
||||||
|
update mqtt_sensor_device
|
||||||
|
set status = #{status},
|
||||||
|
update_time = #{updateTime}
|
||||||
|
where id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- ================= 删除 ================= -->
|
||||||
<delete id="deleteMqttSensorDeviceById" parameterType="Long">
|
<delete id="deleteMqttSensorDeviceById" parameterType="Long">
|
||||||
delete from mqtt_sensor_device where id = #{id}
|
delete from mqtt_sensor_device where id = #{id}
|
||||||
</delete>
|
</delete>
|
||||||
@@ -99,10 +150,55 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
|
<!-- ================= 根据DevEUI查询 ================= -->
|
||||||
<select id="selectByDevEui" parameterType="String" resultMap="MqttSensorDeviceResult">
|
<select id="selectByDevEui" parameterType="String" resultMap="MqttSensorDeviceResult">
|
||||||
<include refid="selectMqttSensorDeviceVo"/>
|
<include refid="selectMqttSensorDeviceVo"/>
|
||||||
WHERE dev_eui = #{devEui}
|
where d.dev_eui = #{devEui}
|
||||||
AND is_delete = '0'
|
and d.is_delete = '0'
|
||||||
LIMIT 1
|
limit 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="countDeviceStat" resultType="map">
|
||||||
|
SELECT
|
||||||
|
COUNT(1) AS total,
|
||||||
|
COALESCE(SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END),0) AS online,
|
||||||
|
COALESCE(SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END),0) AS offline,
|
||||||
|
CASE
|
||||||
|
WHEN COUNT(1) = 0 THEN 0
|
||||||
|
ELSE ROUND(
|
||||||
|
SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) / COUNT(1) * 100,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
END AS onlineRate
|
||||||
|
FROM mqtt_sensor_device
|
||||||
|
WHERE is_delete = 0
|
||||||
|
AND dept_id IN
|
||||||
|
<foreach collection="deptIds" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectOfflineDeviceList" resultMap="MqttSensorDeviceResult">
|
||||||
|
<include refid="selectMqttSensorDeviceVo"/>
|
||||||
|
where d.is_delete = '0'
|
||||||
|
and d.status = '0'
|
||||||
|
and (
|
||||||
|
exists (
|
||||||
|
select 1
|
||||||
|
from mqtt_sensor_data sd
|
||||||
|
where sd.device_id = d.id
|
||||||
|
and sd.is_delete = '0'
|
||||||
|
)
|
||||||
|
and (
|
||||||
|
select max(sd.create_time)
|
||||||
|
from mqtt_sensor_data sd
|
||||||
|
where sd.device_id = d.id
|
||||||
|
and sd.is_delete = '0'
|
||||||
|
) < DATE_SUB(
|
||||||
|
NOW(),
|
||||||
|
INTERVAL (IFNULL(d.report_interval_minute, 10) * 3) MINUTE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -115,4 +115,71 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
|
<select id="countAlarmStat" resultType="map">
|
||||||
|
SELECT
|
||||||
|
/* 今日告警次数:今天新增的 alarm 事件数 */
|
||||||
|
(
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM mqtt_sensor_event
|
||||||
|
WHERE is_delete = 0
|
||||||
|
AND event_type = 'alarm'
|
||||||
|
AND DATE(create_time) = CURDATE()
|
||||||
|
AND dept_id IN
|
||||||
|
<foreach collection="deptIds" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
) AS today,
|
||||||
|
|
||||||
|
/* 未处理告警数:每个设备最新事件仍然是 alarm 的数量 */
|
||||||
|
(
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM mqtt_sensor_event e
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT device_id, MAX(create_time) AS max_time
|
||||||
|
FROM mqtt_sensor_event
|
||||||
|
WHERE is_delete = 0
|
||||||
|
AND dept_id IN
|
||||||
|
<foreach collection="deptIds" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
GROUP BY device_id
|
||||||
|
) t
|
||||||
|
ON e.device_id = t.device_id
|
||||||
|
AND e.create_time = t.max_time
|
||||||
|
WHERE e.is_delete = 0
|
||||||
|
AND e.event_type = 'alarm'
|
||||||
|
) AS unhandled
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAlarmTrend" resultType="map">
|
||||||
|
SELECT
|
||||||
|
DATE(create_time) AS date,
|
||||||
|
COUNT(1) AS count
|
||||||
|
FROM mqtt_sensor_event
|
||||||
|
WHERE is_delete = 0
|
||||||
|
AND event_type = 'alarm'
|
||||||
|
AND create_time >= DATE_SUB(CURDATE(), INTERVAL 6 DAY)
|
||||||
|
AND dept_id IN
|
||||||
|
<foreach collection="deptIds" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
GROUP BY DATE(create_time)
|
||||||
|
ORDER BY date
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAlarmTypeStat" resultType="map">
|
||||||
|
SELECT
|
||||||
|
event_desc AS name,
|
||||||
|
COUNT(1) AS value
|
||||||
|
FROM mqtt_sensor_event
|
||||||
|
WHERE is_delete = 0
|
||||||
|
AND event_type = 'alarm'
|
||||||
|
AND dept_id IN
|
||||||
|
<foreach collection="deptIds" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
GROUP BY event_desc
|
||||||
|
ORDER BY value DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
<!DOCTYPE mapper
|
<!DOCTYPE mapper
|
||||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
|
||||||
<mapper namespace="com.shzg.project.worn.mapper.MqttTopicConfigMapper">
|
<mapper namespace="com.shzg.project.worn.mapper.MqttTopicConfigMapper">
|
||||||
|
|
||||||
<!-- ================== ResultMap ================== -->
|
<!-- ================== ResultMap ================== -->
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
<result property="project" column="project" />
|
<result property="project" column="project" />
|
||||||
<result property="warehouse" column="warehouse" />
|
<result property="warehouse" column="warehouse" />
|
||||||
<result property="deptId" column="dept_id" />
|
<result property="deptId" column="dept_id" />
|
||||||
|
<result property="deptName" column="dept_name" /> <!-- ✅新增 -->
|
||||||
<result property="topicUp" column="topic_up" />
|
<result property="topicUp" column="topic_up" />
|
||||||
<result property="topicDownPrefix" column="topic_down_prefix" />
|
<result property="topicDownPrefix" column="topic_down_prefix" />
|
||||||
<result property="status" column="status" />
|
<result property="status" column="status" />
|
||||||
@@ -21,26 +23,53 @@
|
|||||||
<result property="isDelete" column="is_delete" />
|
<result property="isDelete" column="is_delete" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<!-- ================== 基础查询SQL ================== -->
|
<!-- ================== 基础查询SQL(连表) ================== -->
|
||||||
<sql id="selectMqttTopicConfigVo">
|
<sql id="selectMqttTopicConfigVo">
|
||||||
select id, project, warehouse, dept_id, topic_up, topic_down_prefix,
|
select
|
||||||
status, remark, create_by, create_time, update_by, update_time, is_delete
|
t.id,
|
||||||
from mqtt_topic_config
|
t.project,
|
||||||
|
t.warehouse,
|
||||||
|
t.dept_id,
|
||||||
|
d.dept_name,
|
||||||
|
t.topic_up,
|
||||||
|
t.topic_down_prefix,
|
||||||
|
t.status,
|
||||||
|
t.remark,
|
||||||
|
t.create_by,
|
||||||
|
t.create_time,
|
||||||
|
t.update_by,
|
||||||
|
t.update_time,
|
||||||
|
t.is_delete
|
||||||
|
from mqtt_topic_config t
|
||||||
|
left join sys_dept d on t.dept_id = d.dept_id
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<!-- ================== 列表查询(支持数据隔离) ================== -->
|
<!-- ================== 列表查询(支持数据隔离) ================== -->
|
||||||
<select id="selectMqttTopicConfigList" parameterType="MqttTopicConfig" resultMap="MqttTopicConfigResult">
|
<select id="selectMqttTopicConfigList" parameterType="MqttTopicConfig" resultMap="MqttTopicConfigResult">
|
||||||
<include refid="selectMqttTopicConfigVo"/>
|
<include refid="selectMqttTopicConfigVo"/>
|
||||||
<where>
|
<where>
|
||||||
<if test="project != null and project != ''">and project = #{project}</if>
|
<if test="project != null and project != ''">
|
||||||
<if test="warehouse != null and warehouse != ''">and warehouse = #{warehouse}</if>
|
and t.project = #{project}
|
||||||
<if test="topicUp != null and topicUp != ''">and topic_up = #{topicUp}</if>
|
</if>
|
||||||
<if test="topicDownPrefix != null and topicDownPrefix != ''">and topic_down_prefix = #{topicDownPrefix}</if>
|
<if test="warehouse != null and warehouse != ''">
|
||||||
<if test="status != null and status != ''">and status = #{status}</if>
|
and t.warehouse = #{warehouse}
|
||||||
<if test="isDelete != null and isDelete != ''">and is_delete = #{isDelete}</if>
|
</if>
|
||||||
|
<if test="topicUp != null and topicUp != ''">
|
||||||
|
and t.topic_up = #{topicUp}
|
||||||
|
</if>
|
||||||
|
<if test="topicDownPrefix != null and topicDownPrefix != ''">
|
||||||
|
and t.topic_down_prefix = #{topicDownPrefix}
|
||||||
|
</if>
|
||||||
|
<if test="status != null and status != ''">
|
||||||
|
and t.status = #{status}
|
||||||
|
</if>
|
||||||
|
<if test="isDelete != null and isDelete != ''">
|
||||||
|
and t.is_delete = #{isDelete}
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<!-- 🔥 数据权限 -->
|
||||||
<if test="deptIds != null and deptIds.size() > 0">
|
<if test="deptIds != null and deptIds.size() > 0">
|
||||||
and dept_id in
|
and t.dept_id in
|
||||||
<foreach collection="deptIds" item="deptId" open="(" separator="," close=")">
|
<foreach collection="deptIds" item="deptId" open="(" separator="," close=")">
|
||||||
#{deptId}
|
#{deptId}
|
||||||
</foreach>
|
</foreach>
|
||||||
@@ -51,20 +80,20 @@
|
|||||||
<!-- ================== 根据ID查询 ================== -->
|
<!-- ================== 根据ID查询 ================== -->
|
||||||
<select id="selectMqttTopicConfigById" parameterType="Long" resultMap="MqttTopicConfigResult">
|
<select id="selectMqttTopicConfigById" parameterType="Long" resultMap="MqttTopicConfigResult">
|
||||||
<include refid="selectMqttTopicConfigVo"/>
|
<include refid="selectMqttTopicConfigVo"/>
|
||||||
where id = #{id}
|
where t.id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- ================== 查询启用的Topic(MQTT用) ================== -->
|
<!-- ================== 查询启用的Topic(MQTT用) ================== -->
|
||||||
<select id="selectEnabledMqttTopicConfigList" resultMap="MqttTopicConfigResult">
|
<select id="selectEnabledMqttTopicConfigList" parameterType="MqttTopicConfig" resultMap="MqttTopicConfigResult">
|
||||||
<include refid="selectMqttTopicConfigVo"/>
|
<include refid="selectMqttTopicConfigVo"/>
|
||||||
where status = '0'
|
where t.status = '0'
|
||||||
and is_delete = '0'
|
and t.is_delete = '0'
|
||||||
and topic_up is not null
|
and t.topic_up is not null
|
||||||
and topic_up != ''
|
and t.topic_up != ''
|
||||||
|
|
||||||
<!-- 🔥 防止跨项目订阅 -->
|
<!-- 🔥 数据隔离 -->
|
||||||
<if test="deptIds != null and deptIds.size() > 0">
|
<if test="deptIds != null and deptIds.size() > 0">
|
||||||
and dept_id in
|
and t.dept_id in
|
||||||
<foreach collection="deptIds" item="deptId" open="(" separator="," close=")">
|
<foreach collection="deptIds" item="deptId" open="(" separator="," close=")">
|
||||||
#{deptId}
|
#{deptId}
|
||||||
</foreach>
|
</foreach>
|
||||||
@@ -122,12 +151,11 @@
|
|||||||
where id = #{id}
|
where id = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<!-- ================== 删除(单个) ================== -->
|
<!-- ================== 删除 ================== -->
|
||||||
<delete id="deleteMqttTopicConfigById" parameterType="Long">
|
<delete id="deleteMqttTopicConfigById" parameterType="Long">
|
||||||
delete from mqtt_topic_config where id = #{id}
|
delete from mqtt_topic_config where id = #{id}
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<!-- ================== 批量删除================== -->
|
|
||||||
<delete id="deleteMqttTopicConfigByIds">
|
<delete id="deleteMqttTopicConfigByIds">
|
||||||
delete from mqtt_topic_config where id in
|
delete from mqtt_topic_config where id in
|
||||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||||
@@ -135,11 +163,12 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<select id="selectByDeptId" resultMap="MqttTopicConfigResult">
|
<!-- ================== 根据部门查询 ================== -->
|
||||||
|
<select id="selectByDeptId" parameterType="Long" resultMap="MqttTopicConfigResult">
|
||||||
<include refid="selectMqttTopicConfigVo"/>
|
<include refid="selectMqttTopicConfigVo"/>
|
||||||
where dept_id = #{deptId}
|
where t.dept_id = #{deptId}
|
||||||
and status = '0'
|
and t.status = '0'
|
||||||
and is_delete = '0'
|
and t.is_delete = '0'
|
||||||
limit 1
|
limit 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user