forked from dyf/fys-Multi-tenant
Compare commits
35 Commits
4d9038567f
...
5f36c25550
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f36c25550 | |||
| 9058dcfcb1 | |||
| 3e19cd9db2 | |||
| 397f227bfb | |||
| 1b2bf542fa | |||
| 7d4bc1f8ad | |||
| 630c6a8a35 | |||
| 11e48acc81 | |||
| 540a6fc1da | |||
| aeea8f9072 | |||
| b463e97d28 | |||
| e1b147b6be | |||
| 23b48cfb06 | |||
| 4106260e5f | |||
| 07449e4a1e | |||
| b278a3087e | |||
| dca5a6c48d | |||
| 15b3348989 | |||
| 9fbb0aefcf | |||
| 4004aa1090 | |||
| 39c8375f08 | |||
| 64c81ac44e | |||
| 41eb3d9a33 | |||
| 8597dc5a9f | |||
| 01a1a6e25b | |||
| 1722f92328 | |||
| ee8840d657 | |||
| 9b84296419 | |||
| d48c7b389e | |||
| ccdc25595d | |||
| f1aad91421 | |||
| 8a127b9d2d | |||
| b8af6b511c | |||
| 6bc1d5b20b | |||
| 801b0267e6 |
@ -4,15 +4,24 @@ import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import com.fuyuanshen.app.model.AppRegisterBody;
|
||||
import com.fuyuanshen.app.model.AppSmsLoginBody;
|
||||
import com.fuyuanshen.app.service.AppLoginService;
|
||||
import com.fuyuanshen.app.service.AppRegisterService;
|
||||
import com.fuyuanshen.common.core.constant.Constants;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.constant.SystemConstants;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.domain.model.AppPasswordLoginBody;
|
||||
import com.fuyuanshen.common.core.domain.model.RegisterBody;
|
||||
import com.fuyuanshen.common.core.domain.model.SmsLoginBody;
|
||||
import com.fuyuanshen.common.core.enums.LoginType;
|
||||
import com.fuyuanshen.common.core.utils.*;
|
||||
import com.fuyuanshen.common.encrypt.annotation.ApiEncrypt;
|
||||
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||
import com.fuyuanshen.common.ratelimiter.annotation.RateLimiter;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||
import com.fuyuanshen.common.tenant.helper.TenantHelper;
|
||||
import com.fuyuanshen.system.domain.bo.SysTenantBo;
|
||||
@ -29,6 +38,7 @@ import com.fuyuanshen.web.domain.vo.TenantListVo;
|
||||
import com.fuyuanshen.web.service.IAuthStrategy;
|
||||
import com.fuyuanshen.web.service.SysRegisterService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.sms4j.api.SmsBlend;
|
||||
@ -38,9 +48,13 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.fuyuanshen.common.core.constant.GlobalConstants.DEVICE_SHARE_CODES_KEY;
|
||||
|
||||
/**
|
||||
* APP认证
|
||||
*
|
||||
@ -54,7 +68,7 @@ import java.util.List;
|
||||
public class AppAuthController {
|
||||
|
||||
private final AppLoginService loginService;
|
||||
private final SysRegisterService registerService;
|
||||
private final AppRegisterService registerService;
|
||||
private final ISysConfigService configService;
|
||||
private final ISysTenantService tenantService;
|
||||
private final ISysClientService clientService;
|
||||
@ -70,16 +84,34 @@ public class AppAuthController {
|
||||
@PostMapping("/login")
|
||||
public R<LoginVo> login(@RequestBody AppSmsLoginBody appSmsLoginBody) {
|
||||
// SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class);
|
||||
ValidatorUtils.validate(appSmsLoginBody);
|
||||
SmsLoginBody loginBody = new SmsLoginBody();
|
||||
loginBody.setPhonenumber(appSmsLoginBody.getPhonenumber());
|
||||
loginBody.setSmsCode(appSmsLoginBody.getSmsCode());
|
||||
loginBody.setTenantId(appSmsLoginBody.getTenantId());
|
||||
loginBody.setClientId("ca839698e245d60aa2f0e59bd52b34f8");
|
||||
loginBody.setGrantType("appSms");
|
||||
String loginType = appSmsLoginBody.getLoginType();
|
||||
String body = "";
|
||||
// 授权类型和客户端id
|
||||
String clientId = loginBody.getClientId();
|
||||
String grantType = loginBody.getGrantType();
|
||||
String clientId = "";
|
||||
String grantType = "";
|
||||
String tenantId = appSmsLoginBody.getTenantId();
|
||||
ValidatorUtils.validate(appSmsLoginBody);
|
||||
if("2".equals(loginType)){
|
||||
AppPasswordLoginBody loginBody = new AppPasswordLoginBody();
|
||||
loginBody.setUsername(appSmsLoginBody.getPhonenumber());
|
||||
loginBody.setPassword(appSmsLoginBody.getLoginPassword());
|
||||
loginBody.setClientId("835b15335d389c9fcfdf99421fa8019b");
|
||||
loginBody.setGrantType("appPassword");
|
||||
clientId = loginBody.getClientId();
|
||||
grantType = loginBody.getGrantType();
|
||||
body = JsonUtils.toJsonString(loginBody);
|
||||
}else{
|
||||
SmsLoginBody loginBody = new SmsLoginBody();
|
||||
loginBody.setPhonenumber(appSmsLoginBody.getPhonenumber());
|
||||
loginBody.setSmsCode(appSmsLoginBody.getSmsCode());
|
||||
loginBody.setTenantId(appSmsLoginBody.getTenantId());
|
||||
loginBody.setClientId("ca839698e245d60aa2f0e59bd52b34f8");
|
||||
loginBody.setGrantType("appSms");
|
||||
clientId = loginBody.getClientId();
|
||||
grantType = loginBody.getGrantType();
|
||||
body = JsonUtils.toJsonString(loginBody);
|
||||
}
|
||||
|
||||
SysClientVo client = clientService.queryByClientId(clientId);
|
||||
// 查询不到 client 或 client 内不包含 grantType
|
||||
if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
|
||||
@ -89,25 +121,14 @@ public class AppAuthController {
|
||||
return R.fail(MessageUtils.message("auth.grant.type.blocked"));
|
||||
}
|
||||
// 校验租户
|
||||
loginService.checkTenant(loginBody.getTenantId());
|
||||
// loginService.checkTenant(loginBody.getTenantId());
|
||||
loginService.checkTenant(tenantId);
|
||||
// 登录
|
||||
String body = JsonUtils.toJsonString(loginBody);
|
||||
LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
|
||||
return R.ok(loginVo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public R<Void> logout() {
|
||||
loginService.logout();
|
||||
return R.ok("退出成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注销
|
||||
*/
|
||||
@ -117,16 +138,68 @@ public class AppAuthController {
|
||||
return R.ok("用户注销成功");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
@ApiEncrypt
|
||||
@PostMapping("/register")
|
||||
public R<Void> register(@Validated @RequestBody RegisterBody user) {
|
||||
if (!configService.selectRegisterEnabled(user.getTenantId())) {
|
||||
return R.fail("当前系统没有开启注册功能!");
|
||||
public R<Void> register(@Validated @RequestBody AppRegisterBody body) {
|
||||
registerService.register(body);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 找回密码
|
||||
*/
|
||||
@PostMapping("/forgetPassword")
|
||||
public R<Void> forgetPassword(@Validated @RequestBody AppRegisterBody body) {
|
||||
registerService.forgetPassword(body);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户注册短信验证码
|
||||
*
|
||||
* @param phonenumber 用户手机号
|
||||
*/
|
||||
@SaIgnore
|
||||
@RateLimiter(key = "#phonenumber", time = 60, count = 1)
|
||||
@GetMapping("/registerSmsCode")
|
||||
public R<Void> registerSmsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
|
||||
String key = GlobalConstants.REGISTER_CODE_KEY + phonenumber;
|
||||
String code = RandomUtil.randomNumbers(4);
|
||||
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
|
||||
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
|
||||
map.put("code", code);
|
||||
SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
|
||||
SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, map);
|
||||
if (!smsResponse.isSuccess()) {
|
||||
return R.fail(smsResponse.getData().toString());
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 找回密码短信验证码
|
||||
*
|
||||
* @param phonenumber 用户手机号
|
||||
*/
|
||||
@SaIgnore
|
||||
@RateLimiter(key = "#phonenumber", time = 60, count = 1)
|
||||
@GetMapping("/forgetPasswordSmsCode")
|
||||
public R<Void> forgetPasswordSmsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
|
||||
String key = GlobalConstants.FORGET_PASSWORD_CODE_KEY + phonenumber;
|
||||
String code = RandomUtil.randomNumbers(4);
|
||||
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
|
||||
LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
|
||||
map.put("code", code);
|
||||
SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
|
||||
SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, map);
|
||||
if (!smsResponse.isSuccess()) {
|
||||
return R.fail(smsResponse.getData().toString());
|
||||
}
|
||||
registerService.register(user);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
package com.fuyuanshen.app.controller;
|
||||
|
||||
import com.fuyuanshen.app.model.AppRegisterBody;
|
||||
import com.fuyuanshen.app.model.AppUpdatePasswordBody;
|
||||
import com.fuyuanshen.app.service.AppLoginService;
|
||||
import com.fuyuanshen.app.service.AppRegisterService;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* APP我的
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/userCenter")
|
||||
public class AppUserCenterController {
|
||||
|
||||
private final AppLoginService loginService;
|
||||
private final AppRegisterService registerService;
|
||||
/**
|
||||
* 用户注销
|
||||
*/
|
||||
@PostMapping("/cancelAccount")
|
||||
public R<Void> cancelAccount() {
|
||||
loginService.cancelAccount();
|
||||
return R.ok("用户注销成功");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*/
|
||||
@PostMapping("/updatePassword")
|
||||
public R<Void> updatePassword(@Validated @RequestBody AppUpdatePasswordBody body) {
|
||||
registerService.updatePassword(body);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public R<Void> logout() {
|
||||
loginService.logout();
|
||||
return R.ok("退出成功");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.fuyuanshen.app.model;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AppRegisterBody {
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
@NotBlank(message = "{user.phonenumber.not.blank}")
|
||||
private String phonenumber;
|
||||
|
||||
/**
|
||||
* 短信code
|
||||
*/
|
||||
private String smsCode;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@NotBlank(message = "租户ID不能为空")
|
||||
private String tenantId;
|
||||
|
||||
|
||||
/**
|
||||
* 登录密码
|
||||
*/
|
||||
private String password;
|
||||
}
|
||||
@ -14,7 +14,6 @@ public class AppSmsLoginBody {
|
||||
/**
|
||||
* 短信code
|
||||
*/
|
||||
@NotBlank(message = "{sms.code.not.blank}")
|
||||
private String smsCode;
|
||||
|
||||
/**
|
||||
@ -23,4 +22,14 @@ public class AppSmsLoginBody {
|
||||
@NotBlank(message = "租户ID不能为空")
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 登录方式 1:手机验证码登录 2:密码登录
|
||||
*/
|
||||
@NotBlank(message = "登录方式不能为空")
|
||||
private String loginType;
|
||||
|
||||
/**
|
||||
* 登录密码
|
||||
*/
|
||||
private String loginPassword;
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package com.fuyuanshen.app.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AppUpdatePasswordBody {
|
||||
|
||||
/**
|
||||
* 登录密码
|
||||
*/
|
||||
private String password;
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
package com.fuyuanshen.app.service;
|
||||
|
||||
import cn.hutool.crypto.digest.BCrypt;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.fuyuanshen.app.domain.AppUser;
|
||||
import com.fuyuanshen.app.mapper.AppUserMapper;
|
||||
import com.fuyuanshen.app.model.AppRegisterBody;
|
||||
import com.fuyuanshen.app.model.AppUpdatePasswordBody;
|
||||
import com.fuyuanshen.common.core.constant.Constants;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.domain.model.RegisterBody;
|
||||
import com.fuyuanshen.common.core.enums.UserType;
|
||||
import com.fuyuanshen.common.core.exception.user.CaptchaException;
|
||||
import com.fuyuanshen.common.core.exception.user.CaptchaExpireException;
|
||||
import com.fuyuanshen.common.core.exception.user.UserException;
|
||||
import com.fuyuanshen.common.core.utils.MessageUtils;
|
||||
import com.fuyuanshen.common.core.utils.ServletUtils;
|
||||
import com.fuyuanshen.common.core.utils.SpringUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.log.event.LogininforEvent;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||
import com.fuyuanshen.common.tenant.helper.TenantHelper;
|
||||
import com.fuyuanshen.common.web.config.properties.CaptchaProperties;
|
||||
import com.fuyuanshen.system.domain.SysUser;
|
||||
import com.fuyuanshen.system.domain.bo.SysUserBo;
|
||||
import com.fuyuanshen.system.mapper.SysUserMapper;
|
||||
import com.fuyuanshen.system.service.ISysUserService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 注册校验方法
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class AppRegisterService {
|
||||
|
||||
private final IAppUserService userService;
|
||||
private final AppUserMapper userMapper;
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
public void register(AppRegisterBody registerBody) {
|
||||
String tenantId = registerBody.getTenantId();
|
||||
String username = registerBody.getPhonenumber();
|
||||
String password = registerBody.getPassword();
|
||||
|
||||
boolean codeValidate = validateRegisterSmsCode(tenantId, username, registerBody.getSmsCode());
|
||||
if (!codeValidate) {
|
||||
throw new CaptchaException();
|
||||
}
|
||||
|
||||
// 校验用户类型是否存在
|
||||
String userType = UserType.APP_USER.getUserType();
|
||||
|
||||
boolean exist = TenantHelper.dynamic(tenantId, () -> {
|
||||
return userMapper.exists(new LambdaQueryWrapper<AppUser>()
|
||||
.eq(AppUser::getUserName, username));
|
||||
});
|
||||
if (exist) {
|
||||
throw new UserException("user.register.save.error", username);
|
||||
}
|
||||
AppUser appUser = new AppUser();
|
||||
appUser.setPhonenumber(username);
|
||||
appUser.setUserName(username);
|
||||
appUser.setStatus("0");
|
||||
appUser.setLoginDate(new Date());
|
||||
appUser.setLoginIp(ServletUtils.getClientIP());
|
||||
appUser.setTenantId(tenantId);
|
||||
appUser.setPassword(password);
|
||||
appUser.setUserType(userType);
|
||||
userMapper.insert(appUser);
|
||||
recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册校验短信验证码
|
||||
*/
|
||||
private boolean validateRegisterSmsCode(String tenantId, String phonenumber, String smsCode) {
|
||||
String code = RedisUtils.getCacheObject(GlobalConstants.REGISTER_CODE_KEY + phonenumber);
|
||||
if (StringUtils.isBlank(code)) {
|
||||
recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
|
||||
throw new CaptchaExpireException();
|
||||
}
|
||||
return code.equals(smsCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 忘记密码校验验证码
|
||||
*/
|
||||
private boolean validateForgetPasswordCode(String tenantId, String phonenumber, String smsCode) {
|
||||
String code = RedisUtils.getCacheObject(GlobalConstants.FORGET_PASSWORD_CODE_KEY + phonenumber);
|
||||
if (StringUtils.isBlank(code)) {
|
||||
recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
|
||||
throw new CaptchaExpireException();
|
||||
}
|
||||
return code.equals(smsCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录登录信息
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
* @param username 用户名
|
||||
* @param status 状态
|
||||
* @param message 消息内容
|
||||
* @return
|
||||
*/
|
||||
private void recordLogininfor(String tenantId, String username, String status, String message) {
|
||||
LogininforEvent logininforEvent = new LogininforEvent();
|
||||
logininforEvent.setTenantId(tenantId);
|
||||
logininforEvent.setUsername(username);
|
||||
logininforEvent.setStatus(status);
|
||||
logininforEvent.setMessage(message);
|
||||
logininforEvent.setRequest(ServletUtils.getRequest());
|
||||
SpringUtils.context().publishEvent(logininforEvent);
|
||||
}
|
||||
|
||||
public void forgetPassword(AppRegisterBody registerBody) {
|
||||
String tenantId = registerBody.getTenantId();
|
||||
String username = registerBody.getPhonenumber();
|
||||
String password = registerBody.getPassword();
|
||||
boolean codeValidate = validateForgetPasswordCode(tenantId, username, registerBody.getSmsCode());
|
||||
if (!codeValidate) {
|
||||
throw new CaptchaException();
|
||||
}
|
||||
boolean exist = TenantHelper.dynamic(tenantId, () -> {
|
||||
return userMapper.exists(new LambdaQueryWrapper<AppUser>()
|
||||
.eq(AppUser::getUserName, username));
|
||||
});
|
||||
if (!exist) {
|
||||
throw new UserException("用户不存在");
|
||||
}
|
||||
|
||||
UpdateWrapper<AppUser> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("user_name", username)
|
||||
.set("password", password);
|
||||
userMapper.update(updateWrapper);
|
||||
}
|
||||
|
||||
public void updatePassword(AppUpdatePasswordBody body) {
|
||||
String username = AppLoginHelper.getUsername();
|
||||
String password = body.getPassword();
|
||||
UpdateWrapper<AppUser> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("user_name", username)
|
||||
.set("password", password);
|
||||
userMapper.update(updateWrapper);
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@ package com.fuyuanshen.global.mqtt.config;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import com.fuyuanshen.global.mqtt.receiver.ReceiverMessageHandler;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -55,4 +56,10 @@ public class MqttInboundConfiguration {
|
||||
public MessageHandler messageHandler(){
|
||||
return receiverMessageHandler;
|
||||
}
|
||||
|
||||
// @Bean
|
||||
// @ServiceActivator(inputChannel = "messageInboundChannel") // 确保通道名称正确
|
||||
// public MessageHandler deviceAlarmMessageHandler() {
|
||||
// return new DeviceAlrmMessageHandler();
|
||||
// }
|
||||
}
|
||||
@ -4,11 +4,14 @@ import cn.hutool.core.thread.ThreadUtil;
|
||||
import com.baomidou.lock.LockInfo;
|
||||
import com.baomidou.lock.LockTemplate;
|
||||
import com.baomidou.lock.executor.RedissonLockExecutor;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -48,14 +51,6 @@ public class RedisKeyExpirationListener implements MessageListener {
|
||||
handleFunctionAccessExpired(element);
|
||||
}
|
||||
if(expiredKey.endsWith(DEVICE_ONLINE_STATUS_KEY_PREFIX)) {
|
||||
// threadPoolTaskExecutor.execute(() -> {
|
||||
// log.info("设备离线:{}", expiredKey);
|
||||
// String element = expiredKey.substring(GlobalConstants.GLOBAL_REDIS_KEY.length() + DEVICE_KEY_PREFIX.length(), expiredKey.length() - DEVICE_ONLINE_STATUS_KEY_PREFIX.length());
|
||||
// UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
|
||||
// deviceUpdateWrapper.eq("device_imei", element);
|
||||
// deviceUpdateWrapper.set("online_status", 0);
|
||||
// deviceMapper.update(deviceUpdateWrapper);
|
||||
// });
|
||||
|
||||
threadPoolTaskExecutor.execute(() -> {
|
||||
log.info("设备离线:{}", expiredKey);
|
||||
@ -69,10 +64,14 @@ public class RedisKeyExpirationListener implements MessageListener {
|
||||
|
||||
if (lockInfo != null) {
|
||||
try {
|
||||
UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
|
||||
deviceUpdateWrapper.eq("device_imei", element);
|
||||
deviceUpdateWrapper.set("online_status", 0);
|
||||
deviceMapper.update(deviceUpdateWrapper);
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ message + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
String deviceOnlineStatusRedis = RedisUtils.getCacheObject(deviceOnlineStatusRedisKey);
|
||||
if(StringUtils.isBlank(deviceOnlineStatusRedis)){
|
||||
UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
|
||||
deviceUpdateWrapper.eq("device_imei", element);
|
||||
deviceUpdateWrapper.set("online_status", 0);
|
||||
deviceMapper.update(deviceUpdateWrapper);
|
||||
}
|
||||
} finally {
|
||||
//释放锁
|
||||
lockTemplate.releaseLock(lockInfo);
|
||||
|
||||
@ -49,12 +49,12 @@ public class ReceiverMessageHandler implements MessageHandler {
|
||||
String[] subStr = receivedTopic.split("/");
|
||||
String deviceImei = subStr[1];
|
||||
if(StringUtils.isNotBlank(deviceImei)){
|
||||
String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
|
||||
String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY;
|
||||
RedisUtils.offerDeduplicated(queueKey,dedupKey,deviceImei, Duration.ofHours(24));
|
||||
//在线状态
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(62));
|
||||
// String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
|
||||
// String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY;
|
||||
// RedisUtils.offerDeduplicated(queueKey,dedupKey,deviceImei, Duration.ofHours(24));
|
||||
}
|
||||
|
||||
String state = payloadDict.getStr("state");
|
||||
|
||||
@ -1,8 +1,18 @@
|
||||
package com.fuyuanshen.global.mqtt.rule.bjq;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.domain.model.LoginUser;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.core.utils.date.DurationUtils;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceAlarmBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo;
|
||||
import com.fuyuanshen.equipment.service.DeviceService;
|
||||
import com.fuyuanshen.equipment.service.IDeviceAlarmService;
|
||||
import com.fuyuanshen.global.mqtt.base.MqttMessageRule;
|
||||
import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
@ -13,9 +23,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
|
||||
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
|
||||
|
||||
/**
|
||||
@ -26,6 +38,10 @@ import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
|
||||
@Slf4j
|
||||
public class BjqAlarmRule implements MqttMessageRule {
|
||||
|
||||
private final IDeviceAlarmService deviceAlarmService;
|
||||
private final DeviceService deviceService;
|
||||
|
||||
|
||||
@Override
|
||||
public String getCommandType() {
|
||||
return LightingCommandTypeConstants.ALARM_MESSAGE;
|
||||
@ -38,14 +54,21 @@ public class BjqAlarmRule implements MqttMessageRule {
|
||||
Object[] convertArr = context.getConvertArr();
|
||||
|
||||
String convertValue = convertArr[1].toString();
|
||||
if(StringUtils.isNotBlank(convertValue)){
|
||||
if (StringUtils.isNotBlank(convertValue)) {
|
||||
// 将设备状态信息存储到Redis中
|
||||
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX;
|
||||
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX;
|
||||
|
||||
// 存储到Redis
|
||||
RedisUtils.setCacheObject(deviceRedisKey, convertValue);
|
||||
}
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
|
||||
|
||||
// 保存告警信息
|
||||
String deviceImei = context.getDeviceImei();
|
||||
// 设备告警状态 0:解除告警 1:报警产生
|
||||
Byte state = (Byte) convertArr[1];
|
||||
savaAlarm(deviceImei, state);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理告警命令时出错", e);
|
||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20));
|
||||
@ -53,4 +76,51 @@ public class BjqAlarmRule implements MqttMessageRule {
|
||||
}
|
||||
|
||||
|
||||
public void savaAlarm(String deviceImei, Byte state) {
|
||||
DeviceAlarmVo deviceAlarmVo = deviceAlarmService.queryLatestByDeviceImei(deviceImei);
|
||||
DeviceAlarmBo deviceAlarmBo = new DeviceAlarmBo();
|
||||
|
||||
// 解除告警
|
||||
if (state == 0) {
|
||||
if (deviceAlarmVo != null) {
|
||||
if (deviceAlarmVo.getFinishTime() == null) {
|
||||
BeanUtil.copyProperties(deviceAlarmVo, deviceAlarmBo);
|
||||
deviceAlarmBo.setFinishTime(new Date());
|
||||
String durationBetween = DurationUtils.getDurationBetween(deviceAlarmVo.getStartTime(), deviceAlarmBo.getFinishTime());
|
||||
deviceAlarmBo.setDurationTime(durationBetween);
|
||||
// 0已处理,1未处理
|
||||
deviceAlarmBo.setTreatmentState(0);
|
||||
deviceAlarmService.updateByBo(deviceAlarmBo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 报警产生
|
||||
if (state == 1) {
|
||||
if (deviceAlarmVo == null || deviceAlarmVo.getFinishTime() != null) {
|
||||
|
||||
Device device = deviceService.selectDeviceByImei(deviceImei);
|
||||
deviceAlarmBo.setDeviceId(device.getId());
|
||||
deviceAlarmBo.setDeviceImei(deviceImei);
|
||||
// 0-强制报警,1-撞击闯入,2-自动报警,3-电子围栏告警
|
||||
deviceAlarmBo.setDeviceAction(0);
|
||||
deviceAlarmBo.setStartTime(new Date());
|
||||
// 0已处理,1未处理
|
||||
deviceAlarmBo.setTreatmentState(1);
|
||||
|
||||
// LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
// deviceAlarmBo.setCreateBy(loginUser.getUserId());
|
||||
deviceAlarmBo.setTenantId(device.getTenantId());
|
||||
|
||||
String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(location)) {
|
||||
JSONObject jsonObject = JSONObject.parseObject(location);
|
||||
deviceAlarmBo.setLocation(jsonObject.getString("address"));
|
||||
}
|
||||
deviceAlarmService.insertByBo(deviceAlarmBo);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
package com.fuyuanshen.global.queue;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -15,6 +19,8 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class MqttMessageConsumer {
|
||||
@ -27,7 +33,7 @@ public class MqttMessageConsumer {
|
||||
private ExecutorService messageProcessorPool = Executors.newFixedThreadPool(10);
|
||||
|
||||
// 初始化方法,启动消息监听
|
||||
// @PostConstruct
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
log.info("启动MQTT消息消费者...");
|
||||
// 启动消息获取线程
|
||||
@ -62,7 +68,7 @@ public class MqttMessageConsumer {
|
||||
public void consumeMessages() {
|
||||
String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
|
||||
String threadName = Thread.currentThread().getName();
|
||||
log.info("消息消费者线程 {} 开始监听队列: {}", threadName, queueKey);
|
||||
// log.info("消息消费者线程 {} 开始监听队列: {}", threadName, queueKey);
|
||||
|
||||
try {
|
||||
while (!Thread.currentThread().isInterrupted() && !messageConsumerPool.isShutdown()) {
|
||||
@ -75,7 +81,7 @@ public class MqttMessageConsumer {
|
||||
);
|
||||
|
||||
if (message != null) {
|
||||
log.info("线程 {} 从队列中获取到消息,提交到处理线程池: {}", threadName, message);
|
||||
// log.info("线程 {} 从队列中获取到消息,提交到处理线程池: {}", threadName, message);
|
||||
// 将消息处理任务提交到处理线程池
|
||||
messageProcessorPool.submit(() -> processMessage(message));
|
||||
}
|
||||
@ -92,15 +98,23 @@ public class MqttMessageConsumer {
|
||||
String threadName = Thread.currentThread().getName();
|
||||
try {
|
||||
log.info("业务处理线程 {} 开始处理消息: {}", threadName, message);
|
||||
|
||||
// 实现具体的业务逻辑
|
||||
// 例如更新数据库、发送通知等
|
||||
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("device_imei", message)
|
||||
.set("online_status", 1);
|
||||
deviceMapper.update(updateWrapper);
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ message + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
String deviceOnlineStatusRedis = RedisUtils.getCacheObject(deviceOnlineStatusRedisKey);
|
||||
if(StringUtils.isBlank(deviceOnlineStatusRedis)){
|
||||
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("device_imei", message)
|
||||
.set("online_status", 1);
|
||||
deviceMapper.update(updateWrapper);
|
||||
}
|
||||
// QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
|
||||
// queryWrapper.eq("device_imei", message);
|
||||
// queryWrapper.eq("online_status", 1);
|
||||
// Long count = deviceMapper.selectCount(queryWrapper);
|
||||
// if(count == 0){
|
||||
//
|
||||
// }
|
||||
// 模拟业务处理耗时
|
||||
Thread.sleep(200);
|
||||
// Thread.sleep(200);
|
||||
|
||||
log.info("业务处理线程 {} 完成消息处理: {}", threadName, message);
|
||||
} catch (Exception e) {
|
||||
|
||||
@ -67,7 +67,7 @@ public class DeviceShareController extends BaseController {
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/permission")
|
||||
public R<Void> permission(@Validated(AddGroup.class) @RequestBody AppDeviceShareBo bo) {
|
||||
return toAjax(deviceShareService.deviceShare(bo));
|
||||
return toAjax(deviceShareService.permission(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,110 @@
|
||||
package com.fuyuanshen.web.controller.device.fence;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo;
|
||||
import com.fuyuanshen.equipment.service.IDeviceFenceAccessRecordService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
||||
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 围栏进出记录
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/api/equipment/fenceAccessRecord")
|
||||
public class DeviceFenceAccessRecordController extends BaseController {
|
||||
|
||||
private final IDeviceFenceAccessRecordService deviceFenceAccessRecordService;
|
||||
|
||||
|
||||
/**
|
||||
* 查询围栏进出记录列表
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:fenceAccessRecord:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<DeviceFenceAccessRecordVo> list(DeviceFenceAccessRecordBo bo, PageQuery pageQuery) {
|
||||
return deviceFenceAccessRecordService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 导出围栏进出记录列表
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:fenceAccessRecord:export")
|
||||
@Log(title = "导出围栏进出记录列表", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(DeviceFenceAccessRecordBo bo, HttpServletResponse response) {
|
||||
List<DeviceFenceAccessRecordVo> list = deviceFenceAccessRecordService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "围栏进出记录", DeviceFenceAccessRecordVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取围栏进出记录详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:fenceAccessRecord:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<DeviceFenceAccessRecordVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(deviceFenceAccessRecordService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增围栏进出记录
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:fenceAccessRecord:add")
|
||||
@Log(title = "围栏进出记录", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody DeviceFenceAccessRecordBo bo) {
|
||||
return toAjax(deviceFenceAccessRecordService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改围栏进出记录
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:fenceAccessRecord:edit")
|
||||
@Log(title = "围栏进出记录", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody DeviceFenceAccessRecordBo bo) {
|
||||
return toAjax(deviceFenceAccessRecordService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除围栏进出记录
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:fenceAccessRecord:remove")
|
||||
@Log(title = "围栏进出记录", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(deviceFenceAccessRecordService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,126 @@
|
||||
package com.fuyuanshen.web.controller.device.fence;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceGeoFenceBo;
|
||||
import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse;
|
||||
import com.fuyuanshen.equipment.domain.query.FenceCheckRequest;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo;
|
||||
import com.fuyuanshen.equipment.service.IDeviceGeoFenceService;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 电子围栏
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/api/equipment/geoFence")
|
||||
public class DeviceGeoFenceController extends BaseController {
|
||||
|
||||
private final IDeviceGeoFenceService deviceGeoFenceService;
|
||||
|
||||
|
||||
/**
|
||||
* 查询电子围栏列表
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:geoFence:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<DeviceGeoFenceVo> list(DeviceGeoFenceBo bo, PageQuery pageQuery) {
|
||||
return deviceGeoFenceService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 导出电子围栏列表
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:geoFence:export")
|
||||
@Log(title = "导出电子围栏列表", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(DeviceGeoFenceBo bo, HttpServletResponse response) {
|
||||
List<DeviceGeoFenceVo> list = deviceGeoFenceService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "电子围栏", DeviceGeoFenceVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取电子围栏详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:geoFence:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<DeviceGeoFenceVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(deviceGeoFenceService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增电子围栏
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:geoFence:add")
|
||||
@Log(title = "电子围栏", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody DeviceGeoFenceBo bo) {
|
||||
return toAjax(deviceGeoFenceService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改电子围栏
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:geoFence:edit")
|
||||
@Log(title = "电子围栏", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody DeviceGeoFenceBo bo) {
|
||||
return toAjax(deviceGeoFenceService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除电子围栏
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("fys-equipment:geoFence:remove")
|
||||
@Log(title = "电子围栏", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(deviceGeoFenceService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 电子围栏-位置检查
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/check")
|
||||
public ResponseEntity<FenceCheckResponse> checkPosition(
|
||||
@Valid @RequestBody FenceCheckRequest request) {
|
||||
FenceCheckResponse response = deviceGeoFenceService.checkPosition(request);
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
// package com.fuyuanshen.web.handler.mqtt;
|
||||
//
|
||||
// import cn.hutool.core.lang.Dict;
|
||||
// import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
// import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||
// import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
// import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
|
||||
// import com.fuyuanshen.global.mqtt.base.MqttRuleEngine;
|
||||
// import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
// import lombok.extern.slf4j.Slf4j;
|
||||
// import org.apache.commons.lang3.StringUtils;
|
||||
// import org.springframework.beans.factory.annotation.Autowired;
|
||||
// import org.springframework.messaging.Message;
|
||||
// import org.springframework.messaging.MessageHandler;
|
||||
// import org.springframework.messaging.MessageHeaders;
|
||||
// import org.springframework.messaging.MessagingException;
|
||||
// import org.springframework.stereotype.Service;
|
||||
//
|
||||
// import java.time.Duration;
|
||||
// import java.util.Objects;
|
||||
//
|
||||
// import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||
//
|
||||
// /**
|
||||
// * @author: 默苍璃
|
||||
// * @date: 2025-09-1609:28
|
||||
// */
|
||||
// @Service
|
||||
// @Slf4j
|
||||
// public class DeviceAlrmMessageHandler implements MessageHandler {
|
||||
//
|
||||
// @Autowired
|
||||
// private MqttRuleEngine ruleEngine;
|
||||
//
|
||||
// @Override
|
||||
// public void handleMessage(Message<?> message) throws MessagingException {
|
||||
//
|
||||
// // 处理新类型的消息
|
||||
// Object payload = message.getPayload();
|
||||
// MessageHeaders headers = message.getHeaders();
|
||||
// String receivedTopic = Objects.requireNonNull(headers.get("mqtt_receivedTopic")).toString();
|
||||
//
|
||||
// log.info("设备强制报警消息处理器 - MQTT payload= {} \n receivedTopic = {}", payload, receivedTopic);
|
||||
//
|
||||
// // 解析消息并执行相应逻辑
|
||||
// Dict payloadDict = JsonUtils.parseMap(payload.toString());
|
||||
// if (payloadDict != null) {
|
||||
// // 根据主题或消息内容执行不同的处理逻辑
|
||||
// processMessage(receivedTopic, payloadDict);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void processMessage(String topic, Dict payloadDict) {
|
||||
// // 实现具体的业务逻辑
|
||||
// // 可以根据不同的主题执行不同的操作
|
||||
// if (topic.contains("newTopic")) {
|
||||
// // 处理特定主题的消息
|
||||
// handleNewTopicMessage(payloadDict);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void handleNewTopicMessage(Dict payloadDict) {
|
||||
// // 实现新主题消息的具体处理逻辑
|
||||
// String deviceImei = payloadDict.getStr("imei");
|
||||
// if (StringUtils.isNotBlank(deviceImei)) {
|
||||
// // 更新设备状态到Redis
|
||||
// String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY +
|
||||
// DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX;
|
||||
// RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(62));
|
||||
//
|
||||
// // 执行规则引擎
|
||||
// MqttRuleContext context = new MqttRuleContext();
|
||||
// context.setDeviceImei(deviceImei);
|
||||
// context.setPayloadDict(payloadDict);
|
||||
// // 设置命令类型
|
||||
// context.setCommandType((byte) 0x02); // 根据实际需要设置命令类型
|
||||
//
|
||||
// boolean ruleExecuted = ruleEngine.executeRule(context);
|
||||
// if (!ruleExecuted) {
|
||||
// log.warn("未找到匹配的规则来处理新主题消息,设备IMEI: {}", deviceImei);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
@ -212,6 +212,46 @@ public class DeviceShareService {
|
||||
LambdaQueryWrapper<AppDeviceBindRecord> qw = new LambdaQueryWrapper<>();
|
||||
qw.eq(AppDeviceBindRecord::getDeviceId, bo.getDeviceId());
|
||||
AppDeviceBindRecord bindRecord = appDeviceBindRecordMapper.selectOne(qw);
|
||||
if (bindRecord == null) {
|
||||
throw new ServiceException("设备未绑定");
|
||||
}
|
||||
Long userId = bindRecord.getBindingUserId();
|
||||
|
||||
LambdaQueryWrapper<AppDeviceShare> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(AppDeviceShare::getDeviceId, bo.getDeviceId());
|
||||
lqw.eq(AppDeviceShare::getPhonenumber, bo.getPhonenumber());
|
||||
Long count = appDeviceShareMapper.selectCount(lqw);
|
||||
if (count > 0) {
|
||||
|
||||
UpdateWrapper<AppDeviceShare> uw = new UpdateWrapper<>();
|
||||
uw.eq("device_id", bo.getDeviceId());
|
||||
uw.eq("phonenumber", bo.getPhonenumber());
|
||||
uw.set("permission", bo.getPermission());
|
||||
uw.set("update_by", userId);
|
||||
uw.set("update_time", new Date());
|
||||
|
||||
return appDeviceShareMapper.update(uw);
|
||||
} else {
|
||||
AppDeviceShare appDeviceShare = new AppDeviceShare();
|
||||
appDeviceShare.setDeviceId(bo.getDeviceId());
|
||||
appDeviceShare.setPhonenumber(bo.getPhonenumber());
|
||||
appDeviceShare.setPermission(bo.getPermission());
|
||||
appDeviceShare.setCreateBy(userId);
|
||||
return appDeviceShareMapper.insert(appDeviceShare);
|
||||
}
|
||||
}
|
||||
|
||||
public int permission(AppDeviceShareBo bo) {
|
||||
Device device = deviceMapper.selectById(bo.getDeviceId());
|
||||
if (device == null) {
|
||||
throw new ServiceException("设备不存在");
|
||||
}
|
||||
LambdaQueryWrapper<AppDeviceBindRecord> qw = new LambdaQueryWrapper<>();
|
||||
qw.eq(AppDeviceBindRecord::getDeviceId, bo.getDeviceId());
|
||||
AppDeviceBindRecord bindRecord = appDeviceBindRecordMapper.selectOne(qw);
|
||||
if (bindRecord == null) {
|
||||
throw new ServiceException("设备未绑定");
|
||||
}
|
||||
Long userId = bindRecord.getBindingUserId();
|
||||
|
||||
LambdaQueryWrapper<AppDeviceShare> lqw = new LambdaQueryWrapper<>();
|
||||
|
||||
@ -182,12 +182,14 @@ public class DeviceBizService {
|
||||
|
||||
QueryWrapper<AppDeviceBindRecord> bindRecordQueryWrapper = new QueryWrapper<>();
|
||||
bindRecordQueryWrapper.eq("device_id", device.getId());
|
||||
bindRecordQueryWrapper.eq("communication_mode", 0);
|
||||
AppDeviceBindRecord appDeviceBindRecord = appDeviceBindRecordMapper.selectOne(bindRecordQueryWrapper);
|
||||
if (appDeviceBindRecord != null) {
|
||||
UpdateWrapper<AppDeviceBindRecord> deviceUpdateWrapper = new UpdateWrapper<>();
|
||||
deviceUpdateWrapper.eq("device_id", device.getId())
|
||||
.set("binding_status", BindingStatusEnum.BOUND.getCode())
|
||||
.set("binding_user_id", userId)
|
||||
.set("communication_mode", 0)
|
||||
.set("update_time", new Date())
|
||||
.set("binding_time", new Date());
|
||||
return appDeviceBindRecordMapper.update(null, deviceUpdateWrapper);
|
||||
@ -196,6 +198,7 @@ public class DeviceBizService {
|
||||
bindRecord.setDeviceId(device.getId());
|
||||
bindRecord.setBindingUserId(userId);
|
||||
bindRecord.setBindingTime(new Date());
|
||||
bindRecord.setCommunicationMode(0);
|
||||
bindRecord.setCreateBy(userId);
|
||||
appDeviceBindRecordMapper.insert(bindRecord);
|
||||
}
|
||||
@ -225,6 +228,7 @@ public class DeviceBizService {
|
||||
deviceUpdateWrapper.eq("device_id", device.getId())
|
||||
.eq("binding_user_id", userId)
|
||||
.set("binding_user_id", userId)
|
||||
.set("communication_mode", 1)
|
||||
.set("binding_time", new Date());
|
||||
return appDeviceBindRecordMapper.update(null, deviceUpdateWrapper);
|
||||
} else {
|
||||
@ -232,6 +236,7 @@ public class DeviceBizService {
|
||||
bindRecord.setDeviceId(device.getId());
|
||||
bindRecord.setBindingUserId(userId);
|
||||
bindRecord.setBindingTime(new Date());
|
||||
bindRecord.setCommunicationMode(1);
|
||||
bindRecord.setCreateBy(userId);
|
||||
appDeviceBindRecordMapper.insert(bindRecord);
|
||||
}
|
||||
|
||||
@ -0,0 +1,138 @@
|
||||
package com.fuyuanshen.web.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.crypto.digest.BCrypt;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.fuyuanshen.app.domain.AppUser;
|
||||
import com.fuyuanshen.app.domain.vo.AppUserVo;
|
||||
import com.fuyuanshen.app.mapper.AppUserMapper;
|
||||
import com.fuyuanshen.app.service.AppLoginService;
|
||||
import com.fuyuanshen.common.core.constant.Constants;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.constant.SystemConstants;
|
||||
import com.fuyuanshen.common.core.domain.model.AppLoginUser;
|
||||
import com.fuyuanshen.common.core.domain.model.AppPasswordLoginBody;
|
||||
import com.fuyuanshen.common.core.domain.model.LoginUser;
|
||||
import com.fuyuanshen.common.core.domain.model.PasswordLoginBody;
|
||||
import com.fuyuanshen.common.core.enums.LoginType;
|
||||
import com.fuyuanshen.common.core.enums.UserType;
|
||||
import com.fuyuanshen.common.core.exception.user.CaptchaException;
|
||||
import com.fuyuanshen.common.core.exception.user.CaptchaExpireException;
|
||||
import com.fuyuanshen.common.core.exception.user.UserException;
|
||||
import com.fuyuanshen.common.core.utils.MessageUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.core.utils.ValidatorUtils;
|
||||
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||
import com.fuyuanshen.common.tenant.helper.TenantHelper;
|
||||
import com.fuyuanshen.common.web.config.properties.CaptchaProperties;
|
||||
import com.fuyuanshen.system.domain.SysUser;
|
||||
import com.fuyuanshen.system.domain.vo.SysClientVo;
|
||||
import com.fuyuanshen.system.domain.vo.SysUserVo;
|
||||
import com.fuyuanshen.system.mapper.SysUserMapper;
|
||||
import com.fuyuanshen.web.domain.vo.LoginVo;
|
||||
import com.fuyuanshen.web.service.IAuthStrategy;
|
||||
import com.fuyuanshen.web.service.SysLoginService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* APP密码认证策略
|
||||
*
|
||||
* @author Michelle.Chung
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("appPassword" + IAuthStrategy.BASE_NAME)
|
||||
@RequiredArgsConstructor
|
||||
public class AppPasswordAuthStrategy implements IAuthStrategy {
|
||||
|
||||
private final CaptchaProperties captchaProperties;
|
||||
private final AppLoginService loginService;
|
||||
private final AppUserMapper appUserMapper;
|
||||
|
||||
@Override
|
||||
public LoginVo login(String body, SysClientVo client) {
|
||||
AppPasswordLoginBody loginBody = JsonUtils.parseObject(body, AppPasswordLoginBody.class);
|
||||
ValidatorUtils.validate(loginBody);
|
||||
String tenantId = loginBody.getTenantId();
|
||||
String username = loginBody.getUsername();
|
||||
String password = loginBody.getPassword();
|
||||
AppLoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
|
||||
AppUserVo user = loadUserByUsername(username);
|
||||
loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !password.equals(user.getPassword()));
|
||||
|
||||
// 此处可根据登录用户的数据不同 自行创建 loginUser
|
||||
return loginService.buildLoginUser(user);
|
||||
});
|
||||
|
||||
loginUser.setClientKey(client.getClientKey());
|
||||
loginUser.setDeviceType(client.getDeviceType());
|
||||
SaLoginParameter model = new SaLoginParameter();
|
||||
model.setDeviceType(client.getDeviceType());
|
||||
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
|
||||
// 例如: 后台用户30分钟过期 app用户1天过期
|
||||
model.setTimeout(client.getTimeout());
|
||||
model.setActiveTimeout(client.getActiveTimeout());
|
||||
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
|
||||
// 生成token
|
||||
AppLoginHelper.login(loginUser, model);
|
||||
|
||||
LoginVo loginVo = new LoginVo();
|
||||
loginVo.setAccessToken(StpUtil.getTokenValue());
|
||||
loginVo.setExpireIn(StpUtil.getTokenTimeout());
|
||||
loginVo.setClientId(client.getClientId());
|
||||
return loginVo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验验证码
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param code 验证码
|
||||
* @param uuid 唯一标识
|
||||
*/
|
||||
private void validateCaptcha(String tenantId, String username, String code, String uuid) {
|
||||
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "");
|
||||
String captcha = RedisUtils.getCacheObject(verifyKey);
|
||||
RedisUtils.deleteObject(verifyKey);
|
||||
if (captcha == null) {
|
||||
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
|
||||
throw new CaptchaExpireException();
|
||||
}
|
||||
if (!code.equalsIgnoreCase(captcha)) {
|
||||
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
|
||||
throw new CaptchaException();
|
||||
}
|
||||
}
|
||||
|
||||
private AppUserVo loadUserByUsername(String username) {
|
||||
// SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
|
||||
// if (ObjectUtil.isNull(user)) {
|
||||
// log.info("登录用户:{} 不存在.", username);
|
||||
// throw new UserException("user.not.exists", username);
|
||||
// } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
|
||||
// log.info("登录用户:{} 已被停用.", username);
|
||||
// throw new UserException("user.blocked", username);
|
||||
// }
|
||||
// return user;
|
||||
|
||||
AppUserVo user = appUserMapper.selectVoOne(new LambdaQueryWrapper<AppUser>()
|
||||
.eq(AppUser::getPhonenumber, username)
|
||||
.eq(AppUser::getUserType, UserType.APP_USER.getUserType()));
|
||||
if (ObjectUtil.isNull(user)) {
|
||||
log.info("登录用户:{} 不存在.", username);
|
||||
throw new UserException("user.not.exists", username);
|
||||
|
||||
} else if (SystemConstants.DISABLE.equals(user.getStatus())) {
|
||||
log.info("登录用户:{} 已被停用.", username);
|
||||
throw new UserException("user.blocked", username);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
@ -303,6 +303,6 @@ mqtt:
|
||||
password: #YtvpSfCNG
|
||||
url: tcp://47.120.79.150:2883
|
||||
subClientId: fys_subClient
|
||||
subTopic: worker/location/#
|
||||
subTopic: A/#
|
||||
pubTopic: B/#
|
||||
pubClientId: fys_pubClient
|
||||
@ -17,6 +17,16 @@ public interface GlobalConstants {
|
||||
*/
|
||||
String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:";
|
||||
|
||||
/**
|
||||
* 忘记密码验证码 redis key
|
||||
*/
|
||||
String FORGET_PASSWORD_CODE_KEY = GLOBAL_REDIS_KEY + "forget_password_codes:";
|
||||
|
||||
/**
|
||||
* 注册验证码 redis key
|
||||
*/
|
||||
String REGISTER_CODE_KEY = GLOBAL_REDIS_KEY + "register_codes:";
|
||||
|
||||
/**
|
||||
* 设备分享验证码 redis key
|
||||
*/
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package com.fuyuanshen.common.core.domain.model;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
/**
|
||||
* 密码登录对象
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class AppPasswordLoginBody extends LoginBody {
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@NotBlank(message = "{user.username.not.blank}")
|
||||
@Length(min = 2, max = 30, message = "{user.username.length.valid}")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户密码
|
||||
*/
|
||||
@NotBlank(message = "{user.password.not.blank}")
|
||||
// @Length(min = 5, max = 30, message = "{user.password.length.valid}")
|
||||
private String password;
|
||||
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
package com.fuyuanshen.common.core.utils.date;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 持续时间工具类
|
||||
* 提供计算两个日期之间差值的方法,并以时分秒格式返回
|
||||
*
|
||||
* @author fys
|
||||
*/
|
||||
public class DurationUtils {
|
||||
|
||||
/**
|
||||
* 计算两个日期之间的差值,返回时分秒格式的字符串
|
||||
* 格式为 "X小时 Y分钟 Z秒"
|
||||
*
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 时分秒格式的时间差字符串
|
||||
*/
|
||||
public static String getDurationBetween(Date startDate, Date endDate) {
|
||||
if (startDate == null || endDate == null) {
|
||||
return "0小时 0分钟 0秒";
|
||||
}
|
||||
|
||||
long diffInMillis = Math.abs(endDate.getTime() - startDate.getTime());
|
||||
long hours = TimeUnit.MILLISECONDS.toHours(diffInMillis);
|
||||
long minutes = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
|
||||
long seconds = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60;
|
||||
|
||||
return String.format("%d小时 %d分钟 %d秒", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个日期之间的差值,返回时分秒格式的字符串
|
||||
* 仅显示非零单位
|
||||
*
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 时分秒格式的时间差字符串,仅显示非零单位
|
||||
*/
|
||||
public static String getDurationBetweenPretty(Date startDate, Date endDate) {
|
||||
if (startDate == null || endDate == null) {
|
||||
return "0秒";
|
||||
}
|
||||
|
||||
long diffInMillis = Math.abs(endDate.getTime() - startDate.getTime());
|
||||
long hours = TimeUnit.MILLISECONDS.toHours(diffInMillis);
|
||||
long minutes = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
|
||||
long seconds = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60;
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
if (hours > 0) {
|
||||
result.append(hours).append("小时 ");
|
||||
}
|
||||
if (minutes > 0) {
|
||||
result.append(minutes).append("分钟 ");
|
||||
}
|
||||
if (seconds > 0 || result.length() == 0) {
|
||||
result.append(seconds).append("秒");
|
||||
}
|
||||
|
||||
return result.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算指定毫秒数的持续时间,返回时分秒格式的字符串
|
||||
*
|
||||
* @param millis 毫秒数
|
||||
* @return 时分秒格式的持续时间字符串
|
||||
*/
|
||||
public static String getDurationFromMillis(long millis) {
|
||||
long absMillis = Math.abs(millis);
|
||||
long hours = TimeUnit.MILLISECONDS.toHours(absMillis);
|
||||
long minutes = TimeUnit.MILLISECONDS.toMinutes(absMillis) % 60;
|
||||
long seconds = TimeUnit.MILLISECONDS.toSeconds(absMillis) % 60;
|
||||
|
||||
return String.format("%d小时 %d分钟 %d秒", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算指定毫秒数的持续时间,返回时分秒格式的字符串
|
||||
* 仅显示非零单位
|
||||
*
|
||||
* @param millis 毫秒数
|
||||
* @return 时分秒格式的持续时间字符串,仅显示非零单位
|
||||
*/
|
||||
public static String getDurationFromMillisPretty(long millis) {
|
||||
long absMillis = Math.abs(millis);
|
||||
long hours = TimeUnit.MILLISECONDS.toHours(absMillis);
|
||||
long minutes = TimeUnit.MILLISECONDS.toMinutes(absMillis) % 60;
|
||||
long seconds = TimeUnit.MILLISECONDS.toSeconds(absMillis) % 60;
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
if (hours > 0) {
|
||||
result.append(hours).append("小时 ");
|
||||
}
|
||||
if (minutes > 0) {
|
||||
result.append(minutes).append("分钟 ");
|
||||
}
|
||||
if (seconds > 0 || result.length() == 0) {
|
||||
result.append(seconds).append("秒");
|
||||
}
|
||||
|
||||
return result.toString().trim();
|
||||
}
|
||||
}
|
||||
@ -50,5 +50,6 @@ public class AppDeviceBindRecord extends TenantEntity {
|
||||
*/
|
||||
private Date bindingTime;
|
||||
|
||||
private Integer communicationMode;
|
||||
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ public class AppDeviceShareBo extends BaseEntity {
|
||||
/**
|
||||
* 分享时间
|
||||
*/
|
||||
private Date shareStartTime;
|
||||
private Date shareEndTime;
|
||||
private String shareStartTime;
|
||||
private String shareEndTime;
|
||||
|
||||
}
|
||||
|
||||
@ -109,4 +109,9 @@ public class AppDeviceShareVo implements Serializable {
|
||||
* 告警状态(0解除告警,1告警)
|
||||
*/
|
||||
private String alarmStatus;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private String createTime;
|
||||
}
|
||||
|
||||
@ -72,9 +72,12 @@
|
||||
and ad.device_id = #{bo.deviceId}
|
||||
</if>
|
||||
<if test="bo.shareUser != null">
|
||||
and u.user_name = #{bo.shareUser}
|
||||
and ad.phonenumber like concat('%',#{bo.shareUser},'%')
|
||||
</if>
|
||||
<if test="bo.shareStartTime != null and bo.hareEndTime != null">
|
||||
<if test="bo.phonenumber != null">
|
||||
and ad.phonenumber like concat('%',#{bo.phonenumber},'%')
|
||||
</if>
|
||||
<if test="bo.shareStartTime != null and bo.shareEndTime != null">
|
||||
and ad.create_time between #{bo.shareStartTime} and #{bo.shareEndTime}
|
||||
</if>
|
||||
</where>
|
||||
|
||||
@ -0,0 +1,105 @@
|
||||
package com.fuyuanshen.equipment.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceStatusVo;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceStatusBo;
|
||||
import com.fuyuanshen.equipment.service.IDeviceFenceStatusService;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 设备进入围栏状态
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-15
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/equipment/fenceStatus")
|
||||
public class DeviceFenceStatusController extends BaseController {
|
||||
|
||||
private final IDeviceFenceStatusService deviceFenceStatusService;
|
||||
|
||||
/**
|
||||
* 查询设备进入围栏状态列表
|
||||
*/
|
||||
@SaCheckPermission("equipment:fenceStatus:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<DeviceFenceStatusVo> list(DeviceFenceStatusBo bo, PageQuery pageQuery) {
|
||||
return deviceFenceStatusService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出设备进入围栏状态列表
|
||||
*/
|
||||
@SaCheckPermission("equipment:fenceStatus:export")
|
||||
@Log(title = "设备进入围栏状态", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(DeviceFenceStatusBo bo, HttpServletResponse response) {
|
||||
List<DeviceFenceStatusVo> list = deviceFenceStatusService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "设备进入围栏状态", DeviceFenceStatusVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备进入围栏状态详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("equipment:fenceStatus:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<DeviceFenceStatusVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(deviceFenceStatusService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增设备进入围栏状态
|
||||
*/
|
||||
@SaCheckPermission("equipment:fenceStatus:add")
|
||||
@Log(title = "设备进入围栏状态", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody DeviceFenceStatusBo bo) {
|
||||
return toAjax(deviceFenceStatusService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改设备进入围栏状态
|
||||
*/
|
||||
@SaCheckPermission("equipment:fenceStatus:edit")
|
||||
@Log(title = "设备进入围栏状态", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody DeviceFenceStatusBo bo) {
|
||||
return toAjax(deviceFenceStatusService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备进入围栏状态
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("equipment:fenceStatus:remove")
|
||||
@Log(title = "设备进入围栏状态", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(deviceFenceStatusService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,8 @@ package com.fuyuanshen.equipment.domain;
|
||||
|
||||
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import io.github.linpeilie.annotations.AutoMapping;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@ -66,12 +68,12 @@ public class DeviceAlarm extends TenantEntity {
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
private Long longitude;
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
private Long latitude;
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 报警位置
|
||||
@ -97,7 +99,15 @@ public class DeviceAlarm extends TenantEntity {
|
||||
* 0已处理,1未处理
|
||||
* treatment_state
|
||||
*/
|
||||
private Long treatmentState;
|
||||
private Integer treatmentState;
|
||||
|
||||
|
||||
/**
|
||||
* 设备IMEI
|
||||
* device_imei
|
||||
*/
|
||||
@Schema(title = "设备IMEI")
|
||||
@AutoMapping(target = "deviceImei")
|
||||
private String deviceImei;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
package com.fuyuanshen.equipment.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 围栏进出记录对象 device_fence_access_record
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("device_fence_access_record")
|
||||
public class DeviceFenceAccessRecord extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
private Long fenceId;
|
||||
|
||||
/**
|
||||
* 设备标识
|
||||
*/
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
*/
|
||||
private Long eventType;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 定位精度
|
||||
*/
|
||||
private Long accuracy;
|
||||
|
||||
/**
|
||||
* 事件时间
|
||||
*/
|
||||
private Date eventTime;
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.fuyuanshen.equipment.domain;
|
||||
|
||||
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 设备进入围栏状态对象 device_fence_status
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("device_fence_status")
|
||||
public class DeviceFenceStatus extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
private Long fenceId;
|
||||
|
||||
/**
|
||||
* 状态: 0-在围栏外, 1-在围栏内
|
||||
*/
|
||||
private Long status;
|
||||
|
||||
/**
|
||||
* 上次检查时间
|
||||
*/
|
||||
private Date lastCheckTime;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package com.fuyuanshen.equipment.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 电子围栏对象 device_geo_fence
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("device_geo_fence")
|
||||
public class DeviceGeoFence extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 围栏唯一标识
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 围栏名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 围栏描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 围栏区域类型, 0 POLYGON, 1 CIRCLE
|
||||
*/
|
||||
private Long areaType;
|
||||
|
||||
/**
|
||||
* 围栏坐标数据
|
||||
*/
|
||||
private String coordinates;
|
||||
|
||||
/**
|
||||
* 圆形围栏半径(米)
|
||||
*/
|
||||
private Long radius;
|
||||
|
||||
/**
|
||||
* 是否激活
|
||||
*/
|
||||
private Long isActive;
|
||||
|
||||
|
||||
}
|
||||
@ -59,8 +59,8 @@ public class DeviceType extends TenantEntity {
|
||||
@Schema(title = "联网方式", example = "0:无;1:4G;2:WIFI")
|
||||
private String networkWay;
|
||||
|
||||
@Schema(title = "通讯方式", example = "0:4G;1:蓝牙,2 4G&蓝牙")
|
||||
private String communicationMode;
|
||||
@Schema(title = "通讯方式", example = "通讯方式 0:4G;1:蓝牙,2 4G&蓝牙")
|
||||
private Integer communicationMode;
|
||||
|
||||
/**
|
||||
* 创建人名称
|
||||
|
||||
@ -2,6 +2,7 @@ package com.fuyuanshen.equipment.domain.bo;
|
||||
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
||||
import com.fuyuanshen.equipment.domain.DeviceAlarm;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
@ -19,7 +20,7 @@ import java.util.Date;
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = DeviceAlarm.class, reverseConvertGenerate = false)
|
||||
public class DeviceAlarmBo extends BaseEntity {
|
||||
public class DeviceAlarmBo extends TenantEntity {
|
||||
|
||||
/**
|
||||
* ID
|
||||
@ -35,6 +36,7 @@ public class DeviceAlarmBo extends BaseEntity {
|
||||
/**
|
||||
* 报警事项
|
||||
* device_action
|
||||
* 0-强制报警,1-撞击闯入,2-自动报警,3-电子围栏告警
|
||||
*/
|
||||
private Integer deviceAction;
|
||||
|
||||
@ -61,7 +63,7 @@ public class DeviceAlarmBo extends BaseEntity {
|
||||
private String dataSource;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
* 内容(报警信息)
|
||||
*/
|
||||
private String content;
|
||||
|
||||
@ -99,7 +101,7 @@ public class DeviceAlarmBo extends BaseEntity {
|
||||
/**
|
||||
* 报警持续时间
|
||||
*/
|
||||
private Long durationTime;
|
||||
private String durationTime;
|
||||
|
||||
/**
|
||||
* 报警查询时间
|
||||
|
||||
@ -6,6 +6,7 @@ import com.fuyuanshen.equipment.domain.DeviceChargeDischarge;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.Date;
|
||||
@ -44,13 +45,25 @@ public class DeviceChargeDischargeBo extends BaseEntity {
|
||||
* 开始时间
|
||||
*/
|
||||
@NotNull(message = "开始时间不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date startTime;
|
||||
|
||||
// 添加字符串类型的setter方法来处理前端传递的字符串日期
|
||||
public void setStartTime(String startTime) {
|
||||
this.startTime = DateUtil.parseDate(startTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date endTime;
|
||||
|
||||
// 添加字符串类型的setter方法来处理前端传递的字符串日期
|
||||
public void setEndTime(String endTime) {
|
||||
this.endTime = DateUtil.parseDate(endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 起始电量百分比(0-100)
|
||||
*/
|
||||
|
||||
@ -0,0 +1,93 @@
|
||||
package com.fuyuanshen.equipment.domain.bo;
|
||||
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import com.fuyuanshen.equipment.domain.DeviceFenceAccessRecord;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
/**
|
||||
* 围栏进出记录业务对象 device_fence_access_record
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = DeviceFenceAccessRecord.class, reverseConvertGenerate = false)
|
||||
public class DeviceFenceAccessRecordBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 记录ID
|
||||
*/
|
||||
@NotNull(message = "记录ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
@NotNull(message = "围栏ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long fenceId;
|
||||
|
||||
/**
|
||||
* 设备标识
|
||||
*/
|
||||
@NotBlank(message = "设备标识不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
*/
|
||||
@NotNull(message = "事件类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long eventType;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
@NotNull(message = "纬度不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
@NotNull(message = "经度不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 定位精度
|
||||
*/
|
||||
private Long accuracy;
|
||||
|
||||
/**
|
||||
* 事件时间
|
||||
*/
|
||||
@NotNull(message = "事件时间不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Date eventTime;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private String beginTime;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private String endTime;
|
||||
|
||||
/**
|
||||
* 记录创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.fuyuanshen.equipment.domain.bo;
|
||||
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.equipment.domain.DeviceFenceStatus;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
/**
|
||||
* 设备进入围栏状态业务对象 device_fence_status
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = DeviceFenceStatus.class, reverseConvertGenerate = false)
|
||||
public class DeviceFenceStatusBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@NotNull(message = "不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
@NotBlank(message = "设备ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
@NotNull(message = "围栏ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long fenceId;
|
||||
|
||||
/**
|
||||
* 状态: 0-在围栏外, 1-在围栏内
|
||||
*/
|
||||
@NotNull(message = "状态: 0-在围栏外, 1-在围栏内不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long status;
|
||||
|
||||
/**
|
||||
* 上次检查时间
|
||||
*/
|
||||
@NotNull(message = "上次检查时间不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Date lastCheckTime;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.fuyuanshen.equipment.domain.bo;
|
||||
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
import com.fuyuanshen.equipment.domain.DeviceGeoFence;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
/**
|
||||
* 电子围栏业务对象 device_geo_fence
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = DeviceGeoFence.class, reverseConvertGenerate = false)
|
||||
public class DeviceGeoFenceBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 围栏唯一标识
|
||||
*/
|
||||
@NotNull(message = "围栏唯一标识不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 围栏名称
|
||||
*/
|
||||
@NotBlank(message = "围栏名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 围栏描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 围栏区域类型, 0 POLYGON, 1 CIRCLE
|
||||
*/
|
||||
@NotNull(message = "围栏区域类型, 0 POLYGON, 1 CIRCLE不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long areaType;
|
||||
|
||||
/**
|
||||
* 围栏坐标数据
|
||||
*/
|
||||
@NotBlank(message = "围栏坐标数据不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String coordinates;
|
||||
|
||||
/**
|
||||
* 圆形围栏半径(米)
|
||||
*/
|
||||
private Long radius;
|
||||
|
||||
/**
|
||||
* 是否激活
|
||||
*/
|
||||
private Long isActive;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
}
|
||||
@ -23,7 +23,7 @@ public class AppDeviceBo {
|
||||
private String deviceMac;
|
||||
|
||||
/**
|
||||
* 通讯方式 0:4G; 1:蓝牙
|
||||
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||
*/
|
||||
@NotNull(message = "通讯方式不能为空", groups = { EditGroup.class })
|
||||
private Integer communicationMode;
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
package com.fuyuanshen.equipment.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 围栏位置检查响应结果
|
||||
*
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-1110:11
|
||||
*/
|
||||
|
||||
@Data
|
||||
public class FenceCheckResponse {
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 检查时间
|
||||
*/
|
||||
private Long checkTime;
|
||||
|
||||
/**
|
||||
* 进入围栏列表
|
||||
*/
|
||||
private List<FenceInfo> enteredFences;
|
||||
|
||||
/**
|
||||
* 离开围栏列表
|
||||
*/
|
||||
private List<FenceInfo> exitedFences;
|
||||
|
||||
/**
|
||||
* 当前所在围栏列表
|
||||
*/
|
||||
private List<FenceInfo> currentFences;
|
||||
|
||||
/**
|
||||
* 围栏信息
|
||||
*/
|
||||
@Data
|
||||
public static class FenceInfo {
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
private Long fenceId;
|
||||
|
||||
/**
|
||||
* 围栏名称
|
||||
*/
|
||||
private String fenceName;
|
||||
|
||||
/**
|
||||
* 围栏类型
|
||||
*/
|
||||
private Integer fenceType;
|
||||
}
|
||||
}
|
||||
@ -21,13 +21,13 @@ public class DeviceTypeForm {
|
||||
private Boolean isSupportBle;
|
||||
|
||||
@Schema(title = "定位方式", example = "0:无;1:GPS;2:基站;3:wifi;4:北斗")
|
||||
private String locateMode;
|
||||
private Integer locateMode;
|
||||
|
||||
@Schema(title = "联网方式", example = "0:无;1:4G;2:WIFI")
|
||||
private String networkWay;
|
||||
private Integer networkWay;
|
||||
|
||||
@Schema(title = "通讯方式", example = "0:4G;1:蓝牙")
|
||||
private String communicationMode;
|
||||
@Schema(title = "通讯方式", example = "通讯方式 0:4G;1:蓝牙,2 4G&蓝牙")
|
||||
private Integer communicationMode;
|
||||
|
||||
/**
|
||||
* 型号字典用于APP页面跳转
|
||||
|
||||
@ -59,7 +59,7 @@ public class APPDeviceQueryCriteria1 {
|
||||
@Schema(name = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙")
|
||||
@Schema(name = "通讯方式", example = "通讯方式 0:4G;1:蓝牙,2 4G&蓝牙")
|
||||
private Integer communicationMode;
|
||||
|
||||
}
|
||||
|
||||
@ -82,9 +82,10 @@ public class DeviceQueryCriteria extends BaseEntity {
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 通讯方式 0:4G;1:蓝牙
|
||||
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||
* communication_mode
|
||||
*/
|
||||
@Schema(title = "通讯方式", example = "0:4G;1:蓝牙,2 4G&蓝牙")
|
||||
private Integer communicationMode;
|
||||
|
||||
/* app绑定用户id */
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
package com.fuyuanshen.equipment.domain.query;
|
||||
|
||||
/**
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-1110:10
|
||||
*/
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 围栏位置检查请求参数
|
||||
*/
|
||||
@Data
|
||||
public class FenceCheckRequest {
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
@NotNull(message = "设备ID不能为空")
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
@NotNull(message = "纬度不能为空")
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
@NotNull(message = "经度不能为空")
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 定位精度(米)
|
||||
*/
|
||||
private Long accuracy;
|
||||
|
||||
}
|
||||
@ -49,7 +49,7 @@ public class AlarmInformationVo {
|
||||
private Integer alarmManual = 0;
|
||||
|
||||
/**
|
||||
* 电子围栏
|
||||
*
|
||||
*/
|
||||
private Integer fenceElectronic = 0;
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ public class AppDeviceVo implements Serializable {
|
||||
private String deviceMac;
|
||||
|
||||
/**
|
||||
* 通讯方式 0:4G;1:蓝牙
|
||||
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||
*/
|
||||
private Integer communicationMode;
|
||||
|
||||
|
||||
@ -26,6 +26,11 @@ public class DataOverviewVo {
|
||||
*/
|
||||
private Integer bindingNew = 0;
|
||||
|
||||
/**
|
||||
* 已绑定设备
|
||||
*/
|
||||
private Integer binding = 0;
|
||||
|
||||
/**
|
||||
* 异常设备
|
||||
*/
|
||||
|
||||
@ -10,6 +10,7 @@ import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
|
||||
import com.fuyuanshen.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
@ -45,7 +46,7 @@ public class DeviceAlarmVo implements Serializable {
|
||||
|
||||
/**
|
||||
* 报警事项
|
||||
* 0-强制报警,1-撞击闯入,2-手动报警,3-电子围栏告警,4-强制告警
|
||||
* 0-强制报警,1-撞击闯入,2-自动报警,3-电子围栏告警
|
||||
*/
|
||||
@ExcelProperty(value = "报警事项")
|
||||
private Integer deviceAction;
|
||||
@ -134,4 +135,5 @@ public class DeviceAlarmVo implements Serializable {
|
||||
@Schema(name = "设备图片")
|
||||
private String devicePic;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,107 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
|
||||
import com.fuyuanshen.common.excel.convert.ExcelDictConvert;
|
||||
import com.fuyuanshen.equipment.domain.DeviceFenceAccessRecord;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 围栏进出记录视图对象 device_fence_access_record
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = DeviceFenceAccessRecord.class)
|
||||
public class DeviceFenceAccessRecordVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录ID
|
||||
*/
|
||||
// @ExcelProperty(value = "记录ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
// @ExcelProperty(value = "围栏ID")
|
||||
private Long fenceId;
|
||||
|
||||
/**
|
||||
* 围栏名称
|
||||
*/
|
||||
@ExcelProperty(value = "围栏名称")
|
||||
private String fenceName;
|
||||
|
||||
/**
|
||||
* 设备标识
|
||||
*/
|
||||
// @ExcelProperty(value = "设备标识")
|
||||
private Long deviceId;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@ExcelProperty(value = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
// @ExcelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 事件类型
|
||||
*/
|
||||
@ExcelProperty(value = "事件类型", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "1=进入围栏,2=离开围栏")
|
||||
private Long eventType;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
@ExcelProperty(value = "纬度")
|
||||
private Long latitude;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
@ExcelProperty(value = "经度")
|
||||
private Long longitude;
|
||||
|
||||
/**
|
||||
* 定位精度
|
||||
*/
|
||||
@ExcelProperty(value = "定位精度")
|
||||
private Long accuracy;
|
||||
|
||||
/**
|
||||
* 事件时间
|
||||
*/
|
||||
@ExcelProperty(value = "事件时间")
|
||||
private Date eventTime;
|
||||
|
||||
/**
|
||||
* 记录创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "记录创建时间")
|
||||
private Date createTime;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fuyuanshen.equipment.domain.DeviceFenceStatus;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
|
||||
import com.fuyuanshen.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 设备进入围栏状态视图对象 device_fence_status
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-15
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = DeviceFenceStatus.class)
|
||||
public class DeviceFenceStatusVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ExcelProperty(value = "")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备ID
|
||||
*/
|
||||
@ExcelProperty(value = "设备ID")
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
@ExcelProperty(value = "围栏ID")
|
||||
private Long fenceId;
|
||||
|
||||
/**
|
||||
* 状态: 0-在围栏外, 1-在围栏内
|
||||
*/
|
||||
@ExcelProperty(value = "状态: 0-在围栏外, 1-在围栏内")
|
||||
private Long status;
|
||||
|
||||
/**
|
||||
* 上次检查时间
|
||||
*/
|
||||
@ExcelProperty(value = "上次检查时间")
|
||||
private Date lastCheckTime;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
|
||||
import com.fuyuanshen.common.excel.convert.ExcelDictConvert;
|
||||
import com.fuyuanshen.equipment.domain.DeviceGeoFence;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 电子围栏视图对象 device_geo_fence
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = DeviceGeoFence.class)
|
||||
public class DeviceGeoFenceVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 围栏唯一标识
|
||||
*/
|
||||
@ExcelProperty(value = "围栏唯一标识")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 围栏名称
|
||||
*/
|
||||
@ExcelProperty(value = "围栏名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 围栏描述
|
||||
*/
|
||||
@ExcelProperty(value = "围栏描述")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 围栏区域类型, 0 POLYGON, 1 CIRCLE
|
||||
*/
|
||||
@ExcelProperty(value = "围栏区域类型, 0 POLYGON, 1 CIRCLE")
|
||||
private Integer areaType;
|
||||
|
||||
/**
|
||||
* 围栏坐标数据
|
||||
*/
|
||||
@ExcelProperty(value = "围栏坐标数据")
|
||||
private String coordinates;
|
||||
|
||||
/**
|
||||
* 圆形围栏半径(米)
|
||||
*/
|
||||
@ExcelProperty(value = "圆形围栏半径(米)")
|
||||
private Long radius;
|
||||
|
||||
/**
|
||||
* 是否激活
|
||||
*/
|
||||
@ExcelProperty(value = "是否激活")
|
||||
private Long isActive;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@ExcelProperty(value = "创建人")
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ExcelProperty(value = "更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
}
|
||||
@ -27,7 +27,7 @@ public class WebDeviceVo implements Serializable {
|
||||
private String deviceMac;
|
||||
|
||||
/**
|
||||
* 通讯方式 0:4G;1:蓝牙
|
||||
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||
*/
|
||||
private Integer communicationMode;
|
||||
|
||||
|
||||
@ -25,4 +25,13 @@ public interface DeviceAlarmMapper extends BaseMapperPlus<DeviceAlarm, DeviceAla
|
||||
*/
|
||||
Page<DeviceAlarmVo> selectVoPage( Page pageQuery,@Param("bo") DeviceAlarmBo bo);
|
||||
|
||||
/**
|
||||
* 根据设备IMEI查询最新的一条告警数据
|
||||
*
|
||||
* @param deviceImei 设备IMEI
|
||||
* @return 设备告警
|
||||
*/
|
||||
DeviceAlarmVo selectLatestByDeviceImei(@Param("deviceImei") String deviceImei);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package com.fuyuanshen.equipment.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import com.fuyuanshen.equipment.domain.DeviceFenceAccessRecord;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 围栏进出记录Mapper接口
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
public interface DeviceFenceAccessRecordMapper extends BaseMapperPlus<DeviceFenceAccessRecord, DeviceFenceAccessRecordVo> {
|
||||
|
||||
/**
|
||||
* 分页查询围栏进出记录列表(包含围栏名称和设备名称)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param wrapper 查询条件
|
||||
* @return 围栏进出记录分页列表
|
||||
*/
|
||||
Page<DeviceFenceAccessRecordVo> selectVoPageWithFenceAndDeviceName(Page<DeviceFenceAccessRecord> page, @Param(Constants.WRAPPER) Wrapper<DeviceFenceAccessRecord> wrapper);
|
||||
|
||||
List<DeviceFenceAccessRecordVo> selectVoPageWithFenceAndDeviceName(@Param(Constants.WRAPPER) Wrapper<DeviceFenceAccessRecord> wrapper);
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.fuyuanshen.equipment.mapper;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.DeviceFenceStatus;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceStatusVo;
|
||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 设备进入围栏状态Mapper接口
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-15
|
||||
*/
|
||||
public interface DeviceFenceStatusMapper extends BaseMapperPlus<DeviceFenceStatus, DeviceFenceStatusVo> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.fuyuanshen.equipment.mapper;
|
||||
|
||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import com.fuyuanshen.equipment.domain.DeviceGeoFence;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo;
|
||||
|
||||
/**
|
||||
* 电子围栏Mapper接口
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
public interface DeviceGeoFenceMapper extends BaseMapperPlus<DeviceGeoFence, DeviceGeoFenceVo> {
|
||||
|
||||
}
|
||||
@ -109,4 +109,12 @@ public interface DeviceMapper extends BaseMapper<Device> {
|
||||
int getUsageDataForMonth(@Param("deviceId") Long deviceId,
|
||||
@Param("year") int year,
|
||||
@Param("month") int month);
|
||||
|
||||
/**
|
||||
* 根据设备IMEI查询设备
|
||||
*
|
||||
* @param deviceImei 设备IMEI
|
||||
* @return 设备信息
|
||||
*/
|
||||
Device selectDeviceByImei(@Param("deviceImei") String deviceImei);
|
||||
}
|
||||
@ -144,4 +144,12 @@ public interface DeviceService extends IService<Device> {
|
||||
* @return
|
||||
*/
|
||||
List<Map<String, Object>> getEquipmentUsageData(Long deviceTypeId, Integer range);
|
||||
|
||||
/**
|
||||
* 根据设备IMEI查询设备
|
||||
*
|
||||
* @param deviceImei 设备IMEI
|
||||
* @return 设备信息
|
||||
*/
|
||||
Device selectDeviceByImei(String deviceImei);
|
||||
}
|
||||
@ -65,4 +65,14 @@ public interface IDeviceAlarmService {
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 根据设备IMEI查询最新的一条告警数据
|
||||
*
|
||||
* @param deviceImei 设备IMEI
|
||||
* @return 设备告警
|
||||
*/
|
||||
DeviceAlarmVo queryLatestByDeviceImei(String deviceImei);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
package com.fuyuanshen.equipment.service;
|
||||
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 围栏进出记录Service接口
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
public interface IDeviceFenceAccessRecordService {
|
||||
|
||||
/**
|
||||
* 查询围栏进出记录
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 围栏进出记录
|
||||
*/
|
||||
DeviceFenceAccessRecordVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询围栏进出记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 围栏进出记录分页列表
|
||||
*/
|
||||
TableDataInfo<DeviceFenceAccessRecordVo> queryPageList(DeviceFenceAccessRecordBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的围栏进出记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 围栏进出记录列表
|
||||
*/
|
||||
List<DeviceFenceAccessRecordVo> queryList(DeviceFenceAccessRecordBo bo);
|
||||
|
||||
/**
|
||||
* 新增围栏进出记录
|
||||
*
|
||||
* @param bo 围栏进出记录
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(DeviceFenceAccessRecordBo bo);
|
||||
|
||||
/**
|
||||
* 修改围栏进出记录
|
||||
*
|
||||
* @param bo 围栏进出记录
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(DeviceFenceAccessRecordBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除围栏进出记录信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package com.fuyuanshen.equipment.service;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceStatusVo;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceStatusBo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备进入围栏状态Service接口
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-15
|
||||
*/
|
||||
public interface IDeviceFenceStatusService {
|
||||
|
||||
/**
|
||||
* 查询设备进入围栏状态
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 设备进入围栏状态
|
||||
*/
|
||||
DeviceFenceStatusVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询设备进入围栏状态列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 设备进入围栏状态分页列表
|
||||
*/
|
||||
TableDataInfo<DeviceFenceStatusVo> queryPageList(DeviceFenceStatusBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的设备进入围栏状态列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 设备进入围栏状态列表
|
||||
*/
|
||||
List<DeviceFenceStatusVo> queryList(DeviceFenceStatusBo bo);
|
||||
|
||||
/**
|
||||
* 新增设备进入围栏状态
|
||||
*
|
||||
* @param bo 设备进入围栏状态
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(DeviceFenceStatusBo bo);
|
||||
|
||||
/**
|
||||
* 修改设备进入围栏状态
|
||||
*
|
||||
* @param bo 设备进入围栏状态
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(DeviceFenceStatusBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除设备进入围栏状态信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
|
||||
/**
|
||||
* 查询设备在特定围栏的最新状态
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @param fenceId 围栏ID
|
||||
* @return 最新状态记录,如果不存在则返回null
|
||||
*/
|
||||
DeviceFenceStatusVo getLatestStatusByDeviceAndFence(String deviceId, Long fenceId);
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package com.fuyuanshen.equipment.service;
|
||||
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceGeoFenceBo;
|
||||
import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse;
|
||||
import com.fuyuanshen.equipment.domain.query.FenceCheckRequest;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 电子围栏Service接口
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
public interface IDeviceGeoFenceService {
|
||||
|
||||
/**
|
||||
* 查询电子围栏
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 电子围栏
|
||||
*/
|
||||
DeviceGeoFenceVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询电子围栏列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 电子围栏分页列表
|
||||
*/
|
||||
TableDataInfo<DeviceGeoFenceVo> queryPageList(DeviceGeoFenceBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的电子围栏列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 电子围栏列表
|
||||
*/
|
||||
List<DeviceGeoFenceVo> queryList(DeviceGeoFenceBo bo);
|
||||
|
||||
/**
|
||||
* 新增电子围栏
|
||||
*
|
||||
* @param bo 电子围栏
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(DeviceGeoFenceBo bo);
|
||||
|
||||
/**
|
||||
* 修改电子围栏
|
||||
*
|
||||
* @param bo 电子围栏
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(DeviceGeoFenceBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除电子围栏信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 检查设备位置与围栏的关系
|
||||
*
|
||||
* @param request 位置检查请求
|
||||
* @return 位置检查结果
|
||||
*/
|
||||
FenceCheckResponse checkPosition(FenceCheckRequest request);
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package com.fuyuanshen.equipment.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
@ -102,11 +103,13 @@ public class DeviceAlarmServiceImpl implements IDeviceAlarmService {
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(DeviceAlarmBo bo) {
|
||||
DeviceAlarm add = MapstructUtils.convert(bo, DeviceAlarm.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
DeviceAlarm deviceAlarm = new DeviceAlarm();
|
||||
// DeviceAlarm add = MapstructUtils.convert(bo, DeviceAlarm.class);
|
||||
BeanUtil.copyProperties(bo, deviceAlarm);
|
||||
validEntityBeforeSave(deviceAlarm);
|
||||
boolean flag = baseMapper.insert(deviceAlarm) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
bo.setId(deviceAlarm.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
@ -145,4 +148,17 @@ public class DeviceAlarmServiceImpl implements IDeviceAlarmService {
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据设备IMEI查询最新的一条告警数据
|
||||
*
|
||||
* @param deviceImei 设备IMEI
|
||||
* @return 设备告警
|
||||
*/
|
||||
@Override
|
||||
public DeviceAlarmVo queryLatestByDeviceImei(String deviceImei) {
|
||||
return baseMapper.selectLatestByDeviceImei(deviceImei);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,143 @@
|
||||
package com.fuyuanshen.equipment.service.impl;
|
||||
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.fuyuanshen.equipment.domain.DeviceFenceAccessRecord;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceFenceAccessRecordMapper;
|
||||
import com.fuyuanshen.equipment.service.IDeviceFenceAccessRecordService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 围栏进出记录Service业务层处理
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class DeviceFenceAccessRecordServiceImpl implements IDeviceFenceAccessRecordService {
|
||||
|
||||
private final DeviceFenceAccessRecordMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询围栏进出记录
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 围栏进出记录
|
||||
*/
|
||||
@Override
|
||||
public DeviceFenceAccessRecordVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询围栏进出记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 围栏进出记录分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<DeviceFenceAccessRecordVo> queryPageList(DeviceFenceAccessRecordBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<DeviceFenceAccessRecord> lqw = buildQueryWrapper(bo);
|
||||
Page<DeviceFenceAccessRecordVo> result = baseMapper.selectVoPageWithFenceAndDeviceName(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询符合条件的围栏进出记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 围栏进出记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<DeviceFenceAccessRecordVo> queryList(DeviceFenceAccessRecordBo bo) {
|
||||
LambdaQueryWrapper<DeviceFenceAccessRecord> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoPageWithFenceAndDeviceName(lqw);
|
||||
}
|
||||
|
||||
|
||||
private LambdaQueryWrapper<DeviceFenceAccessRecord> buildQueryWrapper(DeviceFenceAccessRecordBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<DeviceFenceAccessRecord> lqw = Wrappers.lambdaQuery();
|
||||
// lqw.orderByAsc(DeviceFenceAccessRecord::getId);
|
||||
lqw.eq(bo.getFenceId() != null, DeviceFenceAccessRecord::getFenceId, bo.getFenceId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDeviceId()), DeviceFenceAccessRecord::getDeviceId, bo.getDeviceId());
|
||||
lqw.eq(bo.getUserId() != null, DeviceFenceAccessRecord::getUserId, bo.getUserId());
|
||||
lqw.eq(bo.getEventType() != null, DeviceFenceAccessRecord::getEventType, bo.getEventType());
|
||||
lqw.eq(bo.getLatitude() != null, DeviceFenceAccessRecord::getLatitude, bo.getLatitude());
|
||||
lqw.eq(bo.getLongitude() != null, DeviceFenceAccessRecord::getLongitude, bo.getLongitude());
|
||||
lqw.eq(bo.getAccuracy() != null, DeviceFenceAccessRecord::getAccuracy, bo.getAccuracy());
|
||||
lqw.eq(bo.getEventTime() != null, DeviceFenceAccessRecord::getEventTime, bo.getEventTime());
|
||||
lqw.eq(bo.getCreateTime() != null, DeviceFenceAccessRecord::getCreateTime, bo.getCreateTime());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新增围栏进出记录
|
||||
*
|
||||
* @param bo 围栏进出记录
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(DeviceFenceAccessRecordBo bo) {
|
||||
DeviceFenceAccessRecord add = MapstructUtils.convert(bo, DeviceFenceAccessRecord.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改围栏进出记录
|
||||
*
|
||||
* @param bo 围栏进出记录
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(DeviceFenceAccessRecordBo bo) {
|
||||
DeviceFenceAccessRecord update = MapstructUtils.convert(bo, DeviceFenceAccessRecord.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(DeviceFenceAccessRecord entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除围栏进出记录信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
package com.fuyuanshen.equipment.service.impl;
|
||||
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceStatusBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceStatusVo;
|
||||
import com.fuyuanshen.equipment.domain.DeviceFenceStatus;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceFenceStatusMapper;
|
||||
import com.fuyuanshen.equipment.service.IDeviceFenceStatusService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 设备进入围栏状态Service业务层处理
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-15
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class DeviceFenceStatusServiceImpl implements IDeviceFenceStatusService {
|
||||
|
||||
private final DeviceFenceStatusMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询设备进入围栏状态
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 设备进入围栏状态
|
||||
*/
|
||||
@Override
|
||||
public DeviceFenceStatusVo queryById(Long id){
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询设备进入围栏状态列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 设备进入围栏状态分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<DeviceFenceStatusVo> queryPageList(DeviceFenceStatusBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<DeviceFenceStatus> lqw = buildQueryWrapper(bo);
|
||||
Page<DeviceFenceStatusVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的设备进入围栏状态列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 设备进入围栏状态列表
|
||||
*/
|
||||
@Override
|
||||
public List<DeviceFenceStatusVo> queryList(DeviceFenceStatusBo bo) {
|
||||
LambdaQueryWrapper<DeviceFenceStatus> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<DeviceFenceStatus> buildQueryWrapper(DeviceFenceStatusBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<DeviceFenceStatus> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(DeviceFenceStatus::getId);
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDeviceId()), DeviceFenceStatus::getDeviceId, bo.getDeviceId());
|
||||
lqw.eq(bo.getFenceId() != null, DeviceFenceStatus::getFenceId, bo.getFenceId());
|
||||
lqw.eq(bo.getStatus() != null, DeviceFenceStatus::getStatus, bo.getStatus());
|
||||
lqw.eq(bo.getLastCheckTime() != null, DeviceFenceStatus::getLastCheckTime, bo.getLastCheckTime());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增设备进入围栏状态
|
||||
*
|
||||
* @param bo 设备进入围栏状态
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(DeviceFenceStatusBo bo) {
|
||||
DeviceFenceStatus add = MapstructUtils.convert(bo, DeviceFenceStatus.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改设备进入围栏状态
|
||||
*
|
||||
* @param bo 设备进入围栏状态
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(DeviceFenceStatusBo bo) {
|
||||
DeviceFenceStatus update = MapstructUtils.convert(bo, DeviceFenceStatus.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(DeviceFenceStatus entity){
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除设备进入围栏状态信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询设备在特定围栏的最新状态
|
||||
*/
|
||||
@Override
|
||||
public DeviceFenceStatusVo getLatestStatusByDeviceAndFence(String deviceId, Long fenceId) {
|
||||
LambdaQueryWrapper<DeviceFenceStatus> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(DeviceFenceStatus::getDeviceId, deviceId);
|
||||
lqw.eq(DeviceFenceStatus::getFenceId, fenceId);
|
||||
lqw.orderByDesc(DeviceFenceStatus::getLastCheckTime);
|
||||
lqw.last("LIMIT 1");
|
||||
DeviceFenceStatus status = baseMapper.selectOne(lqw);
|
||||
return MapstructUtils.convert(status, DeviceFenceStatusVo.class);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,266 @@
|
||||
package com.fuyuanshen.equipment.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.fuyuanshen.equipment.domain.DeviceGeoFence;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceStatusBo;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceGeoFenceBo;
|
||||
import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse;
|
||||
import com.fuyuanshen.equipment.domain.query.FenceCheckRequest;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceStatusVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceGeoFenceMapper;
|
||||
import com.fuyuanshen.equipment.service.IDeviceFenceAccessRecordService;
|
||||
import com.fuyuanshen.equipment.service.IDeviceFenceStatusService;
|
||||
import com.fuyuanshen.equipment.service.IDeviceGeoFenceService;
|
||||
import com.fuyuanshen.equipment.utils.map.GeoFenceChecker;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 电子围栏Service业务层处理
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService {
|
||||
|
||||
private final DeviceGeoFenceMapper baseMapper;
|
||||
|
||||
private final IDeviceFenceStatusService fenceStatusService; // 添加此行
|
||||
|
||||
private final IDeviceFenceAccessRecordService fenceAccessRecordService; // 添加此行
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 查询电子围栏
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 电子围栏
|
||||
*/
|
||||
@Override
|
||||
public DeviceGeoFenceVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询电子围栏列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 电子围栏分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<DeviceGeoFenceVo> queryPageList(DeviceGeoFenceBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<DeviceGeoFence> lqw = buildQueryWrapper(bo);
|
||||
Page<DeviceGeoFenceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的电子围栏列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 电子围栏列表
|
||||
*/
|
||||
@Override
|
||||
public List<DeviceGeoFenceVo> queryList(DeviceGeoFenceBo bo) {
|
||||
LambdaQueryWrapper<DeviceGeoFence> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<DeviceGeoFence> buildQueryWrapper(DeviceGeoFenceBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<DeviceGeoFence> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(DeviceGeoFence::getId);
|
||||
lqw.like(StringUtils.isNotBlank(bo.getName()), DeviceGeoFence::getName, bo.getName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDescription()), DeviceGeoFence::getDescription, bo.getDescription());
|
||||
lqw.eq(bo.getAreaType() != null, DeviceGeoFence::getAreaType, bo.getAreaType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getCoordinates()), DeviceGeoFence::getCoordinates, bo.getCoordinates());
|
||||
lqw.eq(bo.getRadius() != null, DeviceGeoFence::getRadius, bo.getRadius());
|
||||
lqw.eq(bo.getIsActive() != null, DeviceGeoFence::getIsActive, bo.getIsActive());
|
||||
lqw.eq(bo.getCreateBy() != null, DeviceGeoFence::getCreateBy, bo.getCreateBy());
|
||||
lqw.eq(bo.getCreateTime() != null, DeviceGeoFence::getCreateTime, bo.getCreateTime());
|
||||
lqw.eq(bo.getUpdateTime() != null, DeviceGeoFence::getUpdateTime, bo.getUpdateTime());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新增电子围栏
|
||||
*
|
||||
* @param bo 电子围栏
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(DeviceGeoFenceBo bo) {
|
||||
DeviceGeoFence add = MapstructUtils.convert(bo, DeviceGeoFence.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改电子围栏
|
||||
*
|
||||
* @param bo 电子围栏
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(DeviceGeoFenceBo bo) {
|
||||
DeviceGeoFence update = MapstructUtils.convert(bo, DeviceGeoFence.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(DeviceGeoFence entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除电子围栏信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查设备位置与围栏的关系
|
||||
*
|
||||
* @param request 位置检查请求
|
||||
* @return 位置检查结果
|
||||
*/
|
||||
@Override
|
||||
public FenceCheckResponse checkPosition(FenceCheckRequest request) {
|
||||
// 1. 获取所有激活的围栏
|
||||
DeviceGeoFenceBo bo = new DeviceGeoFenceBo();
|
||||
bo.setIsActive(1L); // 假设1表示激活状态
|
||||
List<DeviceGeoFenceVo> activeFences = queryList(bo);
|
||||
|
||||
// 2. 初始化响应对象
|
||||
FenceCheckResponse response = new FenceCheckResponse();
|
||||
response.setDeviceId(request.getDeviceId());
|
||||
response.setCheckTime(System.currentTimeMillis());
|
||||
response.setEnteredFences(new ArrayList<>());
|
||||
response.setExitedFences(new ArrayList<>());
|
||||
response.setCurrentFences(new ArrayList<>());
|
||||
|
||||
// 3. 遍历所有激活的围栏
|
||||
for (DeviceGeoFenceVo fence : activeFences) {
|
||||
// 解析围栏坐标
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
List<GeoFenceChecker.Coordinate> coordinateList = new ArrayList<>();
|
||||
try {
|
||||
coordinateList = objectMapper.readValue(fence.getCoordinates(),
|
||||
new TypeReference<List<GeoFenceChecker.Coordinate>>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("坐标数据解析失败: {}", e.getMessage());
|
||||
continue; // 解析失败则跳过该围栏
|
||||
}
|
||||
|
||||
// 检查设备是否在围栏内
|
||||
boolean pointInFence = GeoFenceChecker.isPointInFence(
|
||||
request.getLatitude(),
|
||||
request.getLongitude(),
|
||||
fence.getAreaType(),
|
||||
coordinateList,
|
||||
fence.getRadius());
|
||||
|
||||
// 创建围栏信息对象
|
||||
FenceCheckResponse.FenceInfo fenceInfo = new FenceCheckResponse.FenceInfo();
|
||||
fenceInfo.setFenceId(fence.getId());
|
||||
fenceInfo.setFenceName(fence.getName());
|
||||
fenceInfo.setFenceType(fence.getAreaType());
|
||||
|
||||
// // 查询设备在该围栏的历史状态
|
||||
// DeviceFenceStatusBo statusQuery = new DeviceFenceStatusBo();
|
||||
// statusQuery.setDeviceId(request.getDeviceId());
|
||||
// statusQuery.setFenceId(fence.getId());
|
||||
// List<DeviceFenceStatusVo> statusHistory = fenceStatusService.queryList(statusQuery);
|
||||
//
|
||||
// // 获取最新的状态记录
|
||||
// DeviceFenceStatusVo latestStatus = statusHistory.stream()
|
||||
// .max(Comparator.comparing(DeviceFenceStatusVo::getLastCheckTime))
|
||||
// .orElse(null);
|
||||
|
||||
// 查询设备在该围栏的最新状态
|
||||
DeviceFenceStatusVo latestStatus = fenceStatusService.getLatestStatusByDeviceAndFence(
|
||||
request.getDeviceId(), fence.getId());
|
||||
|
||||
// 判断设备与围栏的关系变化 1=进入围栏,2=离开围栏
|
||||
Long previousStatus = latestStatus != null ? latestStatus.getStatus() : 2L; // 默认在围栏外
|
||||
Long currentStatus = pointInFence ? 1L : 2L; // 当前状态:1-在围栏内,2-在围栏外
|
||||
|
||||
// 如果状态发生变化,则记录
|
||||
if (!previousStatus.equals(currentStatus)) {
|
||||
// 创建新的状态记录
|
||||
DeviceFenceStatusBo newStatus = new DeviceFenceStatusBo();
|
||||
newStatus.setDeviceId(request.getDeviceId());
|
||||
newStatus.setFenceId(fence.getId());
|
||||
newStatus.setStatus(currentStatus);
|
||||
newStatus.setLastCheckTime(new Date());
|
||||
|
||||
// 保存状态记录
|
||||
fenceStatusService.insertByBo(newStatus);
|
||||
|
||||
// 添加围栏进出记录
|
||||
DeviceFenceAccessRecordBo recordBo = new DeviceFenceAccessRecordBo();
|
||||
recordBo.setDeviceId(request.getDeviceId());
|
||||
recordBo.setFenceId(fence.getId());
|
||||
recordBo.setLatitude(request.getLatitude());
|
||||
recordBo.setLongitude(request.getLongitude());
|
||||
recordBo.setEventTime(new Date());
|
||||
// 1表示进入围栏,2表示离开围栏
|
||||
recordBo.setEventType(currentStatus);
|
||||
fenceAccessRecordService.insertByBo(recordBo);
|
||||
|
||||
// 根据状态变化更新响应
|
||||
if (currentStatus == 1L) {
|
||||
// 设备进入围栏
|
||||
response.getEnteredFences().add(fenceInfo);
|
||||
} else {
|
||||
// 设备离开围栏
|
||||
response.getExitedFences().add(fenceInfo);
|
||||
}
|
||||
} else if (currentStatus == 1L) {
|
||||
// 状态未变,但设备仍在围栏内
|
||||
response.getCurrentFences().add(fenceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -40,7 +40,9 @@ import com.fuyuanshen.equipment.service.DeviceAssignmentsService;
|
||||
import com.fuyuanshen.equipment.service.DeviceService;
|
||||
import com.fuyuanshen.equipment.service.DeviceTypeGrantsService;
|
||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||
import com.fuyuanshen.system.domain.vo.SysRoleVo;
|
||||
import com.fuyuanshen.system.service.ISysOssService;
|
||||
import com.fuyuanshen.system.service.ISysRoleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@ -67,6 +69,8 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
|
||||
public static final String USER_ID_SEPARATOR = ":";
|
||||
|
||||
private final ISysRoleService roleService;
|
||||
|
||||
@Value("${file.device.pic}")
|
||||
private String filePath;
|
||||
@Value("${file.device.ip}")
|
||||
@ -109,6 +113,16 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
if (username.equals("admin")) {
|
||||
criteria.setIsAdmin(true);
|
||||
}
|
||||
// 角色管理员
|
||||
Long userId = LoginHelper.getUserId();
|
||||
List<SysRoleVo> roles = roleService.selectRolesAuthByUserId(userId);
|
||||
if (CollectionUtil.isNotEmpty(roles)) {
|
||||
for (SysRoleVo role : roles) {
|
||||
if (role.getRoleKey().equals("admin")) {
|
||||
criteria.setIsAdmin(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IPage<Device> devices = deviceMapper.findAll(criteria, page);
|
||||
|
||||
@ -238,7 +252,8 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
|
||||
DeviceTypeQueryCriteria deviceTypeQueryCriteria = new DeviceTypeQueryCriteria();
|
||||
deviceTypeQueryCriteria.setDeviceTypeId(deviceAssignments.getDeviceId());
|
||||
deviceTypeQueryCriteria.setCustomerId(LoginHelper.getUserId());
|
||||
// 被授权的客户
|
||||
// deviceTypeQueryCriteria.setCustomerId(LoginHelper.getUserId());
|
||||
List<DeviceType> deviceTypes = deviceTypeMapper.findAll(deviceTypeQueryCriteria);
|
||||
if (deviceTypes.isEmpty()) {
|
||||
throw new Exception("设备类型不存在!!!");
|
||||
@ -252,9 +267,13 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
|
||||
// 处理上传的图片
|
||||
if (deviceForm.getFile() != null) {
|
||||
SysOssVo upload = ossService.upload(deviceForm.getFile());
|
||||
// 设置图片路径
|
||||
deviceForm.setDevicePic(upload.getUrl());
|
||||
SysOssVo oss = ossService.upload(deviceForm.getFile());
|
||||
// 强制将HTTP替换为HTTPS
|
||||
if (oss.getUrl() != null && oss.getUrl().startsWith("http://")) {
|
||||
oss.setUrl(oss.getUrl().replaceFirst("^http://", "https://"));
|
||||
}
|
||||
deviceForm.setDevicePic(oss.getUrl());
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
@ -650,7 +669,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
* 获取设备使用数据
|
||||
*
|
||||
* @param deviceTypeId 设备ID
|
||||
* @param range 时间范围 1:半年 2:一年
|
||||
* @param range 时间范围 1:半年 2:一年
|
||||
* @return 每月使用数据列表
|
||||
*/
|
||||
@Override
|
||||
@ -660,4 +679,9 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device selectDeviceByImei(String deviceImei) {
|
||||
return baseMapper.selectDeviceByImei(deviceImei);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@ import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceTypeGrantsMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
|
||||
import com.fuyuanshen.equipment.service.DeviceTypeService;
|
||||
import com.fuyuanshen.system.domain.vo.SysRoleVo;
|
||||
import com.fuyuanshen.system.service.ISysRoleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -43,6 +45,8 @@ public class DeviceTypeServiceImpl extends ServiceImpl<DeviceTypeMapper, DeviceT
|
||||
private final DeviceTypeGrantsMapper deviceTypeGrantsMapper;
|
||||
private final DeviceAssignmentsMapper deviceAssignmentsMapper;
|
||||
|
||||
private final ISysRoleService roleService;
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询设备类型
|
||||
@ -54,8 +58,23 @@ public class DeviceTypeServiceImpl extends ServiceImpl<DeviceTypeMapper, DeviceT
|
||||
@Override
|
||||
public TableDataInfo<DeviceType> queryAll(DeviceTypeQueryCriteria criteria, Page<DeviceType> page) {
|
||||
// 管理员
|
||||
String username = LoginHelper.getUsername();
|
||||
if (!username.equals("admin")) {
|
||||
// String username = LoginHelper.getUsername();
|
||||
// if (!username.equals("admin")) {
|
||||
// criteria.setCustomerId(LoginHelper.getUserId());
|
||||
// }
|
||||
// 角色管理员
|
||||
Long userId = LoginHelper.getUserId();
|
||||
List<SysRoleVo> roles = roleService.selectRolesAuthByUserId(userId);
|
||||
boolean isAdmin = false;
|
||||
if (CollectionUtil.isNotEmpty(roles)) {
|
||||
for (SysRoleVo role : roles) {
|
||||
if (role.getRoleKey().contains("admin")) {
|
||||
isAdmin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isAdmin) {
|
||||
criteria.setCustomerId(LoginHelper.getUserId());
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package com.fuyuanshen.equipment.utils.map;
|
||||
|
||||
/**
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-1110:27
|
||||
*/
|
||||
public class Coordinate {
|
||||
private double lat;
|
||||
private double lng;
|
||||
|
||||
// 构造函数
|
||||
public Coordinate() {}
|
||||
|
||||
public Coordinate(double lat, double lng) {
|
||||
this.lat = lat;
|
||||
this.lng = lng;
|
||||
}
|
||||
|
||||
// getter和setter方法
|
||||
public double getLat() { return lat; }
|
||||
public void setLat(double lat) { this.lat = lat; }
|
||||
public double getLng() { return lng; }
|
||||
public void setLng(double lng) { this.lng = lng; }
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
package com.fuyuanshen.equipment.utils.map;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-1110:13
|
||||
*/
|
||||
public class GeoFenceChecker {
|
||||
|
||||
/**
|
||||
* 点是否在围栏内
|
||||
*
|
||||
* @param pointLat 点的纬度
|
||||
* @param pointLng 点的经度
|
||||
* @param fenceType 围栏类型:0 POLYGON 或 1 CIRCLE
|
||||
* @param coordinates 围栏坐标点列表
|
||||
* @param radius 圆形围栏半径(米),仅对CIRCLE类型有效
|
||||
* @return true表示在围栏内,false表示在围栏外
|
||||
*/
|
||||
public static boolean isPointInFence(double pointLat, double pointLng,
|
||||
Integer fenceType,
|
||||
List<Coordinate> coordinates,
|
||||
Long radius) {
|
||||
if (fenceType == 0) {
|
||||
return isPointInPolygon(pointLat, pointLng, coordinates);
|
||||
} else if (fenceType == 1) {
|
||||
if (coordinates == null || coordinates.isEmpty() || radius == null) {
|
||||
return false;
|
||||
}
|
||||
// 圆形围栏只有一个坐标点(圆心)
|
||||
Coordinate center = coordinates.get(0);
|
||||
return isPointInCircle(pointLat, pointLng, center.lat, center.lng, radius);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用射线投射算法判断点是否在多边形内
|
||||
*
|
||||
* @param pointLat 点的纬度
|
||||
* @param pointLng 点的经度
|
||||
* @param polygon 多边形顶点坐标列表
|
||||
* @return true表示在多边形内,false表示在多边形外
|
||||
*/
|
||||
public static boolean isPointInPolygon(double pointLat, double pointLng,
|
||||
List<Coordinate> polygon) {
|
||||
if (polygon == null || polygon.size() < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int intersectCount = 0;
|
||||
int vertexCount = polygon.size();
|
||||
|
||||
// 遍历多边形的每条边
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
Coordinate p1 = polygon.get(i);
|
||||
Coordinate p2 = polygon.get((i + 1) % vertexCount);
|
||||
|
||||
// 检查点是否在边的y范围内
|
||||
if (p1.lat != p2.lat &&
|
||||
(pointLat >= Math.min(p1.lat, p2.lat)) &&
|
||||
(pointLat < Math.max(p1.lat, p2.lat))) {
|
||||
|
||||
// 计算边与从点发出的水平射线的交点经度
|
||||
double intersectLng = (pointLat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng;
|
||||
|
||||
// 如果交点在点的右侧,则计数加1
|
||||
if (pointLng < intersectLng) {
|
||||
intersectCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 奇数个交点表示点在多边形内
|
||||
return intersectCount % 2 == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断点是否在圆形内
|
||||
*
|
||||
* @param pointLat 点的纬度
|
||||
* @param pointLng 点的经度
|
||||
* @param centerLat 圆心纬度
|
||||
* @param centerLng 圆心经度
|
||||
* @param radius 半径(米)
|
||||
* @return true表示在圆内,false表示在圆外
|
||||
*/
|
||||
public static boolean isPointInCircle(double pointLat, double pointLng,
|
||||
double centerLat, double centerLng,
|
||||
Long radius) {
|
||||
double distance = calculateDistance(pointLat, pointLng, centerLat, centerLng);
|
||||
return distance <= radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两点间距离(使用Haversine公式)
|
||||
*
|
||||
* @param lat1 点1纬度
|
||||
* @param lng1 点1经度
|
||||
* @param lat2 点2纬度
|
||||
* @param lng2 点2经度
|
||||
* @return 距离(米)
|
||||
*/
|
||||
public static double calculateDistance(double lat1, double lng1, double lat2, double lng2) {
|
||||
final double EARTH_RADIUS = 6371000; // 地球半径(米)
|
||||
|
||||
double dLat = Math.toRadians(lat2 - lat1);
|
||||
double dLng = Math.toRadians(lng2 - lng1);
|
||||
|
||||
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
|
||||
Math.sin(dLng / 2) * Math.sin(dLng / 2);
|
||||
|
||||
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
|
||||
return EARTH_RADIUS * c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 坐标点类
|
||||
*/
|
||||
public static class Coordinate {
|
||||
public double lat;
|
||||
public double lng;
|
||||
|
||||
public Coordinate() {
|
||||
}
|
||||
|
||||
public Coordinate(double lat, double lng) {
|
||||
this.lat = lat;
|
||||
this.lng = lng;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,17 +6,21 @@
|
||||
|
||||
<!-- 查询设备告警列表 -->
|
||||
<select id="selectVoPage" resultType="com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo">
|
||||
select da.*, d.device_mac as deviceMac, d.device_imei as deviceImei,
|
||||
select da.*, d.device_mac as deviceMac, d.device_imei as deviceImei,d.device_name as deviceName,
|
||||
d.device_type as deviceType,
|
||||
d.type_name as deviceTypeName, d.device_pic as devicePic
|
||||
from device_alarm da
|
||||
left join device d on da.device_id = d.id
|
||||
left join device_type dt on dt.id = da.device_type
|
||||
left join device_type dt on dt.id = d.device_type
|
||||
<where>
|
||||
<if test="bo.content != null">
|
||||
and d.device_name like concat('%', #{bo.content}, '%') or dt.type_name like concat('%', #{bo.content}, '%')
|
||||
</if>
|
||||
<if test="bo.deviceName != null">
|
||||
and da.device_name = #{bo.deviceName}
|
||||
and d.device_name like concat('%', #{bo.deviceName}, '%')
|
||||
</if>
|
||||
<if test="bo.deviceType != null">
|
||||
and da.device_type = #{bo.deviceType}
|
||||
and dt.id = #{bo.deviceType}
|
||||
</if>
|
||||
<if test="bo.deviceAction != null">
|
||||
and da.device_action = #{bo.deviceAction}
|
||||
@ -30,4 +34,20 @@
|
||||
</where>
|
||||
</select>
|
||||
|
||||
|
||||
<!-- 根据设备IMEI查询最新的一条告警数据 -->
|
||||
<select id="selectLatestByDeviceImei" resultType="com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo">
|
||||
select *, d.device_mac as deviceMac, d.device_imei as deviceImei,
|
||||
d.type_name as deviceTypeName, d.device_pic as devicePic
|
||||
from device_alarm da
|
||||
left join device d on da.device_id = d.id
|
||||
left join device_type dt on dt.id = da.device_type
|
||||
<where>
|
||||
da.device_imei = #{deviceImei}
|
||||
</where>
|
||||
order by da.create_time desc
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.fuyuanshen.equipment.mapper.DeviceFenceAccessRecordMapper">
|
||||
|
||||
<!-- 修改后的分页查询围栏进出记录列表 -->
|
||||
<select id="selectVoPageWithFenceAndDeviceName"
|
||||
resultType="com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo">
|
||||
SELECT r.id,
|
||||
r.fence_id,
|
||||
f.name AS fence_name,
|
||||
r.device_id,
|
||||
d.device_name,
|
||||
r.user_id,
|
||||
r.event_type,
|
||||
r.latitude,
|
||||
r.longitude,
|
||||
r.accuracy,
|
||||
r.event_time,
|
||||
r.create_time
|
||||
FROM device_fence_access_record r
|
||||
LEFT JOIN device_geo_fence f ON r.fence_id = f.id
|
||||
LEFT JOIN device d ON r.device_id = d.id
|
||||
${ew.customSqlSegment}
|
||||
ORDER BY r.id ASC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.fuyuanshen.equipment.mapper.DeviceFenceStatusMapper">
|
||||
|
||||
</mapper>
|
||||
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.fuyuanshen.equipment.mapper.DeviceGeoFenceMapper">
|
||||
|
||||
</mapper>
|
||||
@ -251,12 +251,13 @@
|
||||
dt.pc_model_dictionary detailPageUrl,
|
||||
ap.name personnelBy,
|
||||
d.device_status,
|
||||
d.online_status,
|
||||
c.binding_time
|
||||
from device d
|
||||
inner join device_type dt on d.device_type = dt.id
|
||||
inner join app_device_bind_record c on d.id = c.device_id
|
||||
inner join app_device_bind_record c on d.id = c.device_id and c.communication_mode = 0
|
||||
left join app_personnel_info ap on ap.device_id = d.id
|
||||
where dt.communication_mode in(0,2)
|
||||
where dt.communication_mode in (0, 2)
|
||||
<if test="criteria.deviceType != null">
|
||||
and d.device_type = #{criteria.deviceType}
|
||||
</if>
|
||||
@ -325,6 +326,9 @@
|
||||
(SELECT COUNT(1) FROM device WHERE DATE (create_time) = CURDATE() AND binding_status = 1 ) AS bindingNew, (
|
||||
SELECT COUNT (1)
|
||||
FROM device
|
||||
WHERE binding_status = 1 ) AS binding, (
|
||||
SELECT COUNT (1)
|
||||
FROM device
|
||||
WHERE online_status = 2) AS equipmentAbnormal
|
||||
</select>
|
||||
|
||||
@ -347,13 +351,13 @@
|
||||
|
||||
<!-- 获取告警信息 -->
|
||||
<select id="getAlarmInformation" resultType="com.fuyuanshen.equipment.domain.vo.AlarmInformationVo">
|
||||
SELECT (SELECT COUNT(1) FROM device_alarm WHERE treatment_state = 0) AS alarmsTotal
|
||||
SELECT (SELECT COUNT(1) FROM device_alarm) AS alarmsTotal
|
||||
, (SELECT COUNT(1)
|
||||
FROM device_alarm
|
||||
WHERE treatment_state = 0) AS processingAlarm
|
||||
WHERE treatment_state = 0) AS processingAlarm
|
||||
, (SELECT COUNT(1)
|
||||
FROM device_alarm
|
||||
WHERE treatment_state = 0 AND
|
||||
WHERE
|
||||
DATE (create_time) = CURDATE()) AS alarmsTotalToday
|
||||
, (
|
||||
SELECT COUNT (1)
|
||||
@ -419,4 +423,11 @@
|
||||
AND MONTH (dl.create_time) = #{month}
|
||||
</select>
|
||||
|
||||
<!-- 根据设备IMEI查询设备 -->
|
||||
<select id="selectDeviceByImei" resultType="com.fuyuanshen.equipment.domain.Device">
|
||||
SELECT *
|
||||
FROM device
|
||||
WHERE device_imei = #{deviceImei}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user