Compare commits
20 Commits
040e44984e
...
dyf-device
Author | SHA1 | Date | |
---|---|---|---|
8597dc5a9f | |||
01a1a6e25b | |||
1722f92328 | |||
ee8840d657 | |||
9b84296419 | |||
d48c7b389e | |||
ccdc25595d | |||
f1aad91421 | |||
e2274bdf09 | |||
8a127b9d2d | |||
b8af6b511c | |||
6bc1d5b20b | |||
228e26df7f | |||
801b0267e6 | |||
fcbde4322d | |||
832234269d | |||
7e87971c0b | |||
ebd8668178 | |||
5e3307d2b0 | |||
d5a9a92f9f |
@ -5,6 +5,7 @@ import cn.hutool.core.util.RandomUtil;
|
||||
import com.fuyuanshen.app.domain.bo.AppDeviceShareBo;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceShareDetailVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceShareVo;
|
||||
import com.fuyuanshen.app.service.AppDeviceShareService;
|
||||
import com.fuyuanshen.app.service.IAppDeviceShareService;
|
||||
import com.fuyuanshen.common.core.constant.Constants;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
@ -45,7 +46,7 @@ public class AppDeviceShareController extends BaseController {
|
||||
|
||||
private final IAppDeviceShareService deviceShareService;
|
||||
|
||||
private final DeviceShareService appDeviceShareService;
|
||||
private final AppDeviceShareService appDeviceShareService;
|
||||
|
||||
/**
|
||||
* 分享管理列表
|
||||
|
@ -0,0 +1,119 @@
|
||||
package com.fuyuanshen.app.controller.device;
|
||||
|
||||
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
||||
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
|
||||
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
|
||||
import com.fuyuanshen.web.service.device.DeviceBJQBizService;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* HBY210设备控制类
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/app/hby/device")
|
||||
public class AppDeviceHBYController extends BaseController {
|
||||
|
||||
private final DeviceBJQBizService appDeviceService;
|
||||
|
||||
/**
|
||||
* 获取设备详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public R<AppDeviceDetailVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(appDeviceService.getInfo(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员信息登记
|
||||
*/
|
||||
@PostMapping(value = "/registerPersonInfo")
|
||||
// @FunctionAccessAnnotation("registerPersonInfo")
|
||||
public R<Void> registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) {
|
||||
return toAjax(appDeviceService.registerPersonInfo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送信息
|
||||
*/
|
||||
@PostMapping(value = "/sendMessage")
|
||||
@FunctionAccessBatcAnnotation(value = "sendMessage", timeOut = 30, batchMaxTimeOut = 40)
|
||||
public R<Void> sendMessage(@RequestBody AppDeviceSendMsgBo bo) {
|
||||
return toAjax(appDeviceService.sendMessage(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送报警信息
|
||||
*/
|
||||
@PostMapping(value = "/sendAlarmMessage")
|
||||
@FunctionAccessBatcAnnotation(value = "sendAlarmMessage", timeOut = 5, batchMaxTimeOut = 10)
|
||||
public R<Void> sendAlarmMessage(@RequestBody AppDeviceSendMsgBo bo) {
|
||||
return toAjax(appDeviceService.sendAlarmMessage(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传设备logo图片
|
||||
*/
|
||||
@PostMapping("/uploadLogo")
|
||||
@FunctionAccessAnnotation("uploadLogo")
|
||||
public R<Void> upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) {
|
||||
|
||||
MultipartFile file = bo.getFile();
|
||||
if(file.getSize()>1024*1024*2){
|
||||
return R.warn("图片不能大于2M");
|
||||
}
|
||||
appDeviceService.uploadDeviceLogo(bo);
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 灯光模式
|
||||
* 0(关灯),1(强光模式),2(弱光模式), 3(爆闪模式), 4(泛光模式)
|
||||
*/
|
||||
// @FunctionAccessAnnotation("lightModeSettings")
|
||||
@PostMapping("/lightModeSettings")
|
||||
public R<Void> lightModeSettings(@RequestBody DeviceInstructDto params) {
|
||||
// params 转 JSONObject
|
||||
appDeviceService.lightModeSettings(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 灯光亮度设置
|
||||
*
|
||||
*/
|
||||
// @FunctionAccessAnnotation("lightBrightnessSettings")
|
||||
@PostMapping("/lightBrightnessSettings")
|
||||
public R<Void> lightBrightnessSettings(@RequestBody DeviceInstructDto params) {
|
||||
appDeviceService.lightBrightnessSettings(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 激光模式设置
|
||||
*
|
||||
*/
|
||||
@PostMapping("/laserModeSettings")
|
||||
// @FunctionAccessAnnotation("laserModeSettings")
|
||||
public R<Void> laserModeSettings(@RequestBody DeviceInstructDto params) {
|
||||
appDeviceService.laserModeSettings(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
@ -5,6 +5,7 @@ import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
||||
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
|
||||
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
@ -29,6 +30,7 @@ public class AppDeviceXinghanController extends BaseController {
|
||||
/**
|
||||
* 人员信息登记
|
||||
*/
|
||||
@Log(title = "xinghan指令-人员信息登记")
|
||||
@PostMapping(value = "/registerPersonInfo")
|
||||
// @FunctionAccessAnnotation("registerPersonInfo")
|
||||
public R<Void> registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) {
|
||||
@ -38,6 +40,7 @@ public class AppDeviceXinghanController extends BaseController {
|
||||
/**
|
||||
* 发送紧急通知
|
||||
*/
|
||||
@Log(title = "xinghan指令-发送紧急通知")
|
||||
@PostMapping(value = "/sendAlarmMessage")
|
||||
@FunctionAccessBatcAnnotation(value = "sendAlarmMessage", timeOut = 5, batchMaxTimeOut = 10)
|
||||
public R<Void> sendAlarmMessage(@RequestBody AppDeviceSendMsgBo bo) {
|
||||
@ -47,6 +50,7 @@ public class AppDeviceXinghanController extends BaseController {
|
||||
/**
|
||||
* 上传设备logo图片
|
||||
*/
|
||||
@Log(title = "xinghan指令-上传设备logo图片")
|
||||
@PostMapping("/uploadLogo")
|
||||
@FunctionAccessAnnotation("uploadLogo")
|
||||
public R<Void> upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) {
|
||||
@ -64,6 +68,7 @@ public class AppDeviceXinghanController extends BaseController {
|
||||
* 静电预警档位
|
||||
* 3,2,1,0,分别表示高档/中档/低挡/关闭
|
||||
*/
|
||||
@Log(title = "xinghan指令-静电预警档位")
|
||||
@PostMapping("/DetectGradeSettings")
|
||||
public R<Void> DetectGradeSettings(@RequestBody DeviceInstructDto params) {
|
||||
// params 转 JSONObject
|
||||
@ -75,6 +80,7 @@ public class AppDeviceXinghanController extends BaseController {
|
||||
* 照明档位
|
||||
* 照明档位,2,1,0,分别表示弱光/强光/关闭
|
||||
*/
|
||||
@Log(title = "xinghan指令-照明档位")
|
||||
@PostMapping("/LightGradeSettings")
|
||||
public R<Void> LightGradeSettings(@RequestBody DeviceInstructDto params) {
|
||||
// params 转 JSONObject
|
||||
@ -86,6 +92,7 @@ public class AppDeviceXinghanController extends BaseController {
|
||||
* SOS档位s
|
||||
* SOS档位,2,1,0, 分别表示红蓝模式/爆闪模式/关闭
|
||||
*/
|
||||
@Log(title = "xinghan指令-SOS档位s")
|
||||
@PostMapping("/SOSGradeSettings")
|
||||
public R<Void> SOSGradeSettings(@RequestBody DeviceInstructDto params) {
|
||||
// params 转 JSONObject
|
||||
@ -97,6 +104,7 @@ public class AppDeviceXinghanController extends BaseController {
|
||||
* 静止报警状态
|
||||
* 静止报警状态,0-未静止报警,1-正在静止报警。
|
||||
*/
|
||||
@Log(title = "xinghan指令-静止报警状态")
|
||||
@PostMapping("/ShakeBitSettings")
|
||||
public R<Void> ShakeBitSettings(@RequestBody DeviceInstructDto params) {
|
||||
// params 转 JSONObject
|
||||
|
@ -18,4 +18,9 @@ public class AppFileDto {
|
||||
*/
|
||||
private MultipartFile[] files;
|
||||
|
||||
/**
|
||||
* 多设备id
|
||||
*/
|
||||
private Long[] deviceIds;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,262 @@
|
||||
package com.fuyuanshen.app.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.app.domain.AppDeviceShare;
|
||||
import com.fuyuanshen.app.domain.AppPersonnelInfo;
|
||||
import com.fuyuanshen.app.domain.bo.AppDeviceShareBo;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceShareDetailVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceShareVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
|
||||
import com.fuyuanshen.app.mapper.AppDeviceShareMapper;
|
||||
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.domain.DeviceType;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
|
||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
|
||||
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AppDeviceShareService {
|
||||
|
||||
private final AppDeviceShareMapper appDeviceShareMapper;
|
||||
|
||||
private final DeviceMapper deviceMapper;
|
||||
|
||||
private final DeviceTypeMapper deviceTypeMapper;
|
||||
|
||||
private final AppPersonnelInfoMapper appPersonnelInfoMapper;
|
||||
|
||||
public TableDataInfo<AppDeviceShareVo> queryPageList(AppDeviceShareBo bo, PageQuery pageQuery) {
|
||||
Long userId = AppLoginHelper.getUserId();
|
||||
bo.setCreateBy(userId);
|
||||
Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||
Page<AppDeviceShareVo> result = appDeviceShareMapper.selectAppDeviceShareList(bo, page);
|
||||
List<AppDeviceShareVo> records = result.getRecords();
|
||||
records.forEach(AppDeviceShareService::buildDeviceStatus);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
public TableDataInfo<AppDeviceShareVo> queryWebPageList(AppDeviceShareBo bo, PageQuery pageQuery) {
|
||||
// Long userId = AppLoginHelper.getUserId();
|
||||
// bo.setCreateBy(userId);
|
||||
Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||
Page<AppDeviceShareVo> result = appDeviceShareMapper.selectWebDeviceShareList(bo, page);
|
||||
List<AppDeviceShareVo> records = result.getRecords();
|
||||
records.forEach(AppDeviceShareService::buildDeviceStatus);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
private static void buildDeviceStatus(AppDeviceShareVo item) {
|
||||
// 设备在线状态
|
||||
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(onlineStatus)) {
|
||||
|
||||
item.setOnlineStatus(1);
|
||||
} else {
|
||||
item.setOnlineStatus(0);
|
||||
}
|
||||
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX);
|
||||
// 获取电量
|
||||
if (StringUtils.isNotBlank(deviceStatus)) {
|
||||
JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
|
||||
item.setBattery(jsonObject.getString("batteryPercentage"));
|
||||
} else {
|
||||
item.setBattery("0");
|
||||
}
|
||||
|
||||
String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_LOCATION_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(location)) {
|
||||
JSONObject jsonObject = JSONObject.parseObject(location);
|
||||
item.setLatitude(jsonObject.getString("latitude"));
|
||||
item.setLongitude(jsonObject.getString("longitude"));
|
||||
}
|
||||
|
||||
String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(alarmStatus)) {
|
||||
item.setAlarmStatus(alarmStatus);
|
||||
}
|
||||
}
|
||||
|
||||
public AppDeviceShareDetailVo getInfo(Long id) {
|
||||
|
||||
LambdaQueryWrapper<AppDeviceShare> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(AppDeviceShare::getId, id);
|
||||
List<AppDeviceShareVo> appDeviceShareVos = appDeviceShareMapper.selectVoList(queryWrapper);
|
||||
if (appDeviceShareVos == null || appDeviceShareVos.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AppDeviceShareVo shareVo = appDeviceShareVos.get(0);
|
||||
AppDeviceShareDetailVo shareDetailVo = new AppDeviceShareDetailVo();
|
||||
shareDetailVo.setId(shareVo.getId());
|
||||
shareDetailVo.setDeviceId(shareVo.getDeviceId());
|
||||
shareDetailVo.setPhonenumber(shareVo.getPhonenumber());
|
||||
shareDetailVo.setPermission(shareVo.getPermission());
|
||||
|
||||
Device device = deviceMapper.selectById(shareVo.getDeviceId());
|
||||
shareDetailVo.setDeviceName(device.getDeviceName());
|
||||
shareDetailVo.setDeviceImei(device.getDeviceImei());
|
||||
shareDetailVo.setDeviceMac(device.getDeviceMac());
|
||||
|
||||
DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
|
||||
if (deviceType != null) {
|
||||
shareDetailVo.setCommunicationMode(Integer.valueOf(deviceType.getCommunicationMode()));
|
||||
}
|
||||
shareDetailVo.setDevicePic(device.getDevicePic());
|
||||
shareDetailVo.setTypeName(deviceType.getTypeName());
|
||||
shareDetailVo.setBluetoothName(device.getBluetoothName());
|
||||
shareDetailVo.setDeviceStatus(device.getDeviceStatus());
|
||||
shareDetailVo.setSendMsg(device.getSendMsg());
|
||||
|
||||
LambdaQueryWrapper<AppPersonnelInfo> qw = new LambdaQueryWrapper<>();
|
||||
qw.eq(AppPersonnelInfo::getDeviceId, device.getId());
|
||||
List<AppPersonnelInfoVo> appPersonnelInfoVos = appPersonnelInfoMapper.selectVoList(qw);
|
||||
if (appPersonnelInfoVos != null && !appPersonnelInfoVos.isEmpty()) {
|
||||
shareDetailVo.setPersonnelInfo(appPersonnelInfoVos.get(0));
|
||||
}
|
||||
// 设备在线状态
|
||||
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(onlineStatus)) {
|
||||
shareDetailVo.setOnlineStatus(1);
|
||||
} else {
|
||||
shareDetailVo.setOnlineStatus(0);
|
||||
}
|
||||
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX);
|
||||
// 获取电量
|
||||
if (StringUtils.isNotBlank(deviceStatus)) {
|
||||
JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
|
||||
shareDetailVo.setMainLightMode(jsonObject.getString("mainLightMode"));
|
||||
shareDetailVo.setLaserLightMode(jsonObject.getString("laserLightMode"));
|
||||
shareDetailVo.setBatteryPercentage(jsonObject.getString("batteryPercentage"));
|
||||
shareDetailVo.setChargeState(jsonObject.getString("chargeState"));
|
||||
shareDetailVo.setBatteryRemainingTime(jsonObject.getString("batteryRemainingTime"));
|
||||
} else {
|
||||
shareDetailVo.setBatteryPercentage("0");
|
||||
}
|
||||
|
||||
// 获取经度纬度
|
||||
String locationKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
|
||||
String locationInfo = RedisUtils.getCacheObject(locationKey);
|
||||
if (StringUtils.isNotBlank(locationInfo)) {
|
||||
JSONObject jsonObject = JSONObject.parseObject(locationInfo);
|
||||
shareDetailVo.setLongitude(jsonObject.get("longitude").toString());
|
||||
shareDetailVo.setLatitude(jsonObject.get("latitude").toString());
|
||||
shareDetailVo.setAddress((String) jsonObject.get("address"));
|
||||
}
|
||||
|
||||
|
||||
String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(alarmStatus)) {
|
||||
shareDetailVo.setAlarmStatus(alarmStatus);
|
||||
}
|
||||
|
||||
String lightBrightness = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX);
|
||||
if (StringUtils.isNotBlank(lightBrightness)) {
|
||||
shareDetailVo.setLightBrightness(lightBrightness);
|
||||
}
|
||||
|
||||
return shareDetailVo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验短信验证码
|
||||
*/
|
||||
private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) {
|
||||
String code = RedisUtils.getCacheObject(GlobalConstants.DEVICE_SHARE_CODES_KEY + phonenumber);
|
||||
if (StringUtils.isBlank(code)) {
|
||||
throw new ServiceException("验证码失效");
|
||||
}
|
||||
return code.equals(smsCode);
|
||||
}
|
||||
|
||||
public int deviceShare(AppDeviceShareBo bo) {
|
||||
boolean flag = validateSmsCode(AppLoginHelper.getTenantId(), bo.getPhonenumber(), bo.getSmsCode());
|
||||
if (!flag) {
|
||||
throw new ServiceException("验证码错误");
|
||||
}
|
||||
|
||||
Device device = deviceMapper.selectById(bo.getDeviceId());
|
||||
if (device == null) {
|
||||
throw new ServiceException("设备不存在");
|
||||
}
|
||||
Long userId = AppLoginHelper.getUserId();
|
||||
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 remove(Long[] ids) {
|
||||
return appDeviceShareMapper.deleteByIds(Arrays.asList(ids));
|
||||
}
|
||||
|
||||
public TableDataInfo<AppDeviceShareVo> otherDeviceShareList(AppDeviceShareBo bo, PageQuery pageQuery) {
|
||||
String username = AppLoginHelper.getUsername();
|
||||
bo.setPhonenumber(username);
|
||||
Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||
IPage<AppDeviceShareVo> result = appDeviceShareMapper.otherDeviceShareList(bo, page);
|
||||
List<AppDeviceShareVo> records = result.getRecords();
|
||||
|
||||
records.forEach(AppDeviceShareService::buildDeviceStatus);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询设备分享列表(web)
|
||||
*
|
||||
* @param bo
|
||||
* @param pageQuery
|
||||
* @return
|
||||
*/
|
||||
public TableDataInfo<AppDeviceShareVo> queryWebList(AppDeviceShareBo bo, PageQuery pageQuery) {
|
||||
Page<AppDeviceShareVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||
Page<AppDeviceShareVo> result = appDeviceShareMapper.selectWebDeviceShareList(bo, page);
|
||||
List<AppDeviceShareVo> records = result.getRecords();
|
||||
records.forEach(AppDeviceShareService::buildDeviceStatus);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
}
|
@ -54,7 +54,7 @@ public class XinghanBootLogoRule implements MqttMessageRule {
|
||||
|
||||
@Override
|
||||
public void execute(MqttRuleContext ctx) {
|
||||
final String functionAccessKey = FUNCTION_ACCESS_KEY + ctx.getDeviceImei();
|
||||
final String functionAccessKey = FUNCTION_ACCESS_KEY + "LOGO:" + ctx.getDeviceImei();
|
||||
try {
|
||||
MqttXinghanLogoJson payload = objectMapper.convertValue(
|
||||
ctx.getPayloadDict(), MqttXinghanLogoJson.class);
|
||||
|
@ -60,7 +60,7 @@ public class XinghanDeviceDataRule implements MqttMessageRule {
|
||||
|
||||
@Override
|
||||
public void execute(MqttRuleContext context) {
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + "DATA:" + context.getDeviceImei();
|
||||
try {
|
||||
// Latitude, longitude
|
||||
//主灯档位,激光灯档位,电量百分比,充电状态,电池剩余续航时间
|
||||
|
@ -48,7 +48,7 @@ public class XinghanSendAlarmMessageRule implements MqttMessageRule {
|
||||
|
||||
@Override
|
||||
public void execute(MqttRuleContext ctx) {
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + ctx.getDeviceImei();
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + "ALARM:" + ctx.getDeviceImei();
|
||||
try {
|
||||
XinghanSendAlarmMessageRule.MqttXinghanAlarmMsgJson payload = objectMapper.convertValue(
|
||||
ctx.getPayloadDict(), XinghanSendAlarmMessageRule.MqttXinghanAlarmMsgJson.class);
|
||||
|
@ -47,7 +47,7 @@ public class XinghanSendMsgRule implements MqttMessageRule {
|
||||
|
||||
@Override
|
||||
public void execute(MqttRuleContext ctx) {
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + ctx.getDeviceImei();
|
||||
String functionAccess = FUNCTION_ACCESS_KEY + "MSG:" + ctx.getDeviceImei();
|
||||
try {
|
||||
XinghanSendMsgRule.MqttXinghanMsgJson payload = objectMapper.convertValue(
|
||||
ctx.getPayloadDict(), XinghanSendMsgRule.MqttXinghanMsgJson.class);
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.fuyuanshen.global.queue;
|
||||
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
|
||||
public class MqttMessageQueueConstants {
|
||||
public static final String MQTT_MESSAGE_QUEUE_KEY = "mqtt:message:queue";
|
||||
public static final String MQTT_MESSAGE_DEDUP_KEY = "mqtt:message:dedup";
|
||||
public static final String MQTT_MESSAGE_QUEUE_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "mqtt:message:queue";
|
||||
public static final String MQTT_MESSAGE_DEDUP_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "mqtt:message:dedup";
|
||||
}
|
||||
|
@ -0,0 +1,160 @@
|
||||
package com.fuyuanshen.web.controller.device;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.log.annotation.Log;
|
||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
||||
import com.fuyuanshen.web.domain.Dto.DeviceDebugEditDto;
|
||||
import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto;
|
||||
import com.fuyuanshen.web.domain.vo.DeviceInfoVo;
|
||||
import com.fuyuanshen.web.service.device.DeviceBizService;
|
||||
import com.fuyuanshen.web.service.device.DeviceDebugService;
|
||||
import com.fuyuanshen.web.service.device.DeviceXinghanBizService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 联调中心
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-08-28
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("api/device/debug")
|
||||
public class DeviceDebugController extends BaseController {
|
||||
|
||||
private final DeviceBizService appDeviceService;
|
||||
private final DeviceXinghanBizService deviceXinghanBizService;
|
||||
private final DeviceDebugService deviceDebugService;
|
||||
|
||||
/**
|
||||
* 查询设备列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<WebDeviceVo> list(DeviceQueryCriteria bo, PageQuery pageQuery) {
|
||||
return appDeviceService.queryWebDeviceList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*/
|
||||
@Log(title = "批量上传文件")
|
||||
@PostMapping("/addFile")
|
||||
public R<Void> uploadFile(@Validated @ModelAttribute AppFileDto bo) throws IOException {
|
||||
return toAjax(deviceDebugService.addFileHash(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作视频添加
|
||||
*/
|
||||
@Log(title = "批量添加操作视频")
|
||||
@PostMapping("/addVideo")
|
||||
public R<Void> addOperationVideo(@RequestBody AppOperationVideoBo bo) {
|
||||
return toAjax(deviceDebugService.addVideoList(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传设备logo图片
|
||||
*/
|
||||
@Log(title = "批量上传设备logo图片")
|
||||
@PostMapping("/addLogo")
|
||||
@FunctionAccessAnnotation("uploadLogo")
|
||||
public R<Void> uploadLogo670(@Validated @ModelAttribute DeviceDebugLogoUploadDto bo) {
|
||||
|
||||
MultipartFile file = bo.getFile();
|
||||
if(file.getSize()>1024*1024*2){
|
||||
return R.warn("图片不能大于2M");
|
||||
}
|
||||
deviceXinghanBizService.uploadDeviceLogoBatch(bo);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备详情
|
||||
*/
|
||||
@Operation(summary = "设备详情")
|
||||
@GetMapping(value = "/detail/{id}")
|
||||
public R<DeviceInfoVo> getDeviceInfo(@PathVariable Long id) {
|
||||
return R.ok(deviceDebugService.getDeviceInfo(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改设备联调信息
|
||||
*/
|
||||
@Log(title = "修改设备联调信息")
|
||||
@PostMapping("/editDebug")
|
||||
public R<Void> editDeviceDebug(@Validated @ModelAttribute DeviceDebugEditDto bo) throws Exception {
|
||||
// 1. 基础参数必填校验
|
||||
validateDeviceDebugEdit(bo);
|
||||
|
||||
// 修改上传设备说明
|
||||
if (bo.getExplanationFiles() != null) {
|
||||
AppFileDto appFileDto = new AppFileDto();
|
||||
appFileDto.setDeviceIds(new Long[]{ bo.getDeviceId() });
|
||||
appFileDto.setFileType(1L);
|
||||
appFileDto.setFiles(bo.getExplanationFiles());
|
||||
deviceDebugService.addFileHash(appFileDto);
|
||||
}
|
||||
// 修改上传设备参数
|
||||
if (bo.getParameterFiles() != null) {
|
||||
AppFileDto appFileDto = new AppFileDto();
|
||||
appFileDto.setDeviceIds(new Long[]{ bo.getDeviceId() });
|
||||
appFileDto.setFileType(2L);
|
||||
appFileDto.setFiles(bo.getParameterFiles());
|
||||
deviceDebugService.addFileHash(appFileDto);
|
||||
}
|
||||
// 修改操作视频
|
||||
if (bo.getVideoUrl().isEmpty()) {
|
||||
AppOperationVideoBo appOperationVideoBo = new AppOperationVideoBo();
|
||||
appOperationVideoBo.setDeviceIds(new Long[]{ bo.getDeviceId() });
|
||||
appOperationVideoBo.setVideoUrl(bo.getVideoUrl());
|
||||
deviceDebugService.addVideoList(appOperationVideoBo);
|
||||
}
|
||||
// 修改设备logo 每个型号设备走不同协议无法共用同一个上传
|
||||
// if(bo.getLogoFile() != null){
|
||||
// MultipartFile file = bo.getLogoFile();
|
||||
// if(file.getSize()>1024*1024*2){
|
||||
// return R.warn("图片不能大于2M");
|
||||
// }
|
||||
// AppDeviceLogoUploadDto bo1 = new AppDeviceLogoUploadDto();
|
||||
// bo1.setDeviceId(bo.getDeviceId());
|
||||
// bo1.setDeviceImei(bo.getDeviceImei());
|
||||
// bo1.setFile(file);
|
||||
// deviceXinghanBizService.uploadDeviceLogo(bo1);
|
||||
// }
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/* ------------------ 私有复用 ------------------ */
|
||||
|
||||
private void validateDeviceDebugEdit(DeviceDebugEditDto bo) {
|
||||
if (bo.getDeviceId() == null || bo.getDeviceId() == 0L) {
|
||||
throw new ServiceException("请选择设备");
|
||||
}
|
||||
// if (bo.getDeviceImei().isEmpty()) {
|
||||
// throw new ServiceException("设备 IMEI 不能为空");
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
@ -40,7 +40,7 @@ import static com.fuyuanshen.common.core.constant.GlobalConstants.DEVICE_SHARE_C
|
||||
@RequestMapping("api/equipment/share")
|
||||
public class DeviceShareController extends BaseController {
|
||||
|
||||
private final DeviceShareService appDeviceShareService;
|
||||
private final DeviceShareService deviceShareService;
|
||||
|
||||
|
||||
/**
|
||||
@ -48,7 +48,7 @@ public class DeviceShareController extends BaseController {
|
||||
*/
|
||||
@GetMapping("/deviceShareList")
|
||||
public TableDataInfo<AppDeviceShareVo> list(AppDeviceShareBo bo, PageQuery pageQuery) {
|
||||
return appDeviceShareService.queryWebPageList(bo, pageQuery);
|
||||
return deviceShareService.queryWebPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
|
||||
@ -58,7 +58,16 @@ public class DeviceShareController extends BaseController {
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/deviceShare")
|
||||
public R<Void> deviceShare(@Validated(AddGroup.class) @RequestBody AppDeviceShareBo bo) {
|
||||
return toAjax(appDeviceShareService.deviceShare(bo));
|
||||
return toAjax(deviceShareService.deviceShare(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限管理
|
||||
*/
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/permission")
|
||||
public R<Void> permission(@Validated(AddGroup.class) @RequestBody AppDeviceShareBo bo) {
|
||||
return toAjax(deviceShareService.permission(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,7 +78,7 @@ public class DeviceShareController extends BaseController {
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(appDeviceShareService.remove(ids));
|
||||
return toAjax(deviceShareService.remove(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,106 @@
|
||||
package com.fuyuanshen.web.controller.device;
|
||||
|
||||
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
||||
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
|
||||
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation;
|
||||
import com.fuyuanshen.common.web.core.BaseController;
|
||||
import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
|
||||
import com.fuyuanshen.web.service.device.DeviceXinghanBizService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 设备控制类 HBY670
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/api/xinghan/device")
|
||||
public class DeviceXinghanController extends BaseController {
|
||||
|
||||
private final DeviceXinghanBizService deviceXinghanBizService;
|
||||
|
||||
/**
|
||||
* 人员信息登记
|
||||
*/
|
||||
@PostMapping(value = "/registerPersonInfo")
|
||||
// @FunctionAccessAnnotation("registerPersonInfo")
|
||||
public R<Void> registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) {
|
||||
return toAjax(deviceXinghanBizService.registerPersonInfo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送紧急通知
|
||||
*/
|
||||
@PostMapping(value = "/sendAlarmMessage")
|
||||
@FunctionAccessBatcAnnotation(value = "sendAlarmMessage", timeOut = 5, batchMaxTimeOut = 10)
|
||||
public R<Void> sendAlarmMessage(@RequestBody AppDeviceSendMsgBo bo) {
|
||||
return toAjax(deviceXinghanBizService.sendAlarmMessage(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传设备logo图片
|
||||
*/
|
||||
@PostMapping("/uploadLogo")
|
||||
@FunctionAccessAnnotation("uploadLogo")
|
||||
public R<Void> upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) {
|
||||
|
||||
MultipartFile file = bo.getFile();
|
||||
if(file.getSize()>1024*1024*2){
|
||||
return R.warn("图片不能大于2M");
|
||||
}
|
||||
deviceXinghanBizService.uploadDeviceLogo(bo);
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 静电预警档位
|
||||
* 3,2,1,0,分别表示高档/中档/低挡/关闭
|
||||
*/
|
||||
@PostMapping("/DetectGradeSettings")
|
||||
public R<Void> DetectGradeSettings(@RequestBody DeviceInstructDto params) {
|
||||
// params 转 JSONObject
|
||||
deviceXinghanBizService.upDetectGradeSettings(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 照明档位
|
||||
* 照明档位,2,1,0,分别表示弱光/强光/关闭
|
||||
*/
|
||||
@PostMapping("/LightGradeSettings")
|
||||
public R<Void> LightGradeSettings(@RequestBody DeviceInstructDto params) {
|
||||
// params 转 JSONObject
|
||||
deviceXinghanBizService.upLightGradeSettings(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* SOS档位
|
||||
* SOS档位,2,1,0, 分别表示红蓝模式/爆闪模式/关闭
|
||||
*/
|
||||
@PostMapping("/SOSGradeSettings")
|
||||
public R<Void> SOSGradeSettings(@RequestBody DeviceInstructDto params) {
|
||||
// params 转 JSONObject
|
||||
deviceXinghanBizService.upSOSGradeSettings(params);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 静止报警状态
|
||||
* 静止报警状态,0-未静止报警,1-正在静止报警。
|
||||
*/
|
||||
@PostMapping("/ShakeBitSettings")
|
||||
public R<Void> ShakeBitSettings(@RequestBody DeviceInstructDto params) {
|
||||
// params 转 JSONObject
|
||||
deviceXinghanBizService.upShakeBitSettings(params);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
@ -61,13 +61,15 @@ public class HomePageController {
|
||||
/**
|
||||
* 获取设备使用数据
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @param deviceTypeId 设备ID (可选)
|
||||
* @param range 时间范围 1:半年 2:一年
|
||||
* @return 每月使用数据列表
|
||||
*/
|
||||
@GetMapping("/getEquipmentUsageData/{deviceId}/{range}")
|
||||
public R<List<Map<String, Object>>> getEquipmentUsageData(@PathVariable Long deviceId, @PathVariable Integer range) {
|
||||
return R.ok(deviceService.getEquipmentUsageData(deviceId, range));
|
||||
@GetMapping("/getEquipmentUsageData/{range}")
|
||||
public R<List<Map<String, Object>>> getEquipmentUsageData(@PathVariable Integer range,
|
||||
@RequestParam(required = false) Long deviceTypeId) {
|
||||
return R.ok(deviceService.getEquipmentUsageData(deviceTypeId, range));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,109 @@
|
||||
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,125 @@
|
||||
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,34 @@
|
||||
package com.fuyuanshen.web.domain.Dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class DeviceDebugEditDto {
|
||||
/**
|
||||
* 设备主键列表
|
||||
*/
|
||||
private Long deviceId;
|
||||
/**
|
||||
* 设备 IMEI
|
||||
*/
|
||||
//private String deviceImei;
|
||||
/**
|
||||
* 上传 logo 图片
|
||||
*/
|
||||
//private MultipartFile LogoFile; // 同一张图
|
||||
/**
|
||||
* 参数文件
|
||||
*/
|
||||
private MultipartFile[] parameterFiles;
|
||||
/**
|
||||
* 说明文件
|
||||
*/
|
||||
private MultipartFile[] explanationFiles;
|
||||
/**
|
||||
* 视频链接
|
||||
*/
|
||||
private String videoUrl;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.fuyuanshen.web.domain.Dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class DeviceDebugLogoUploadDto {
|
||||
/**
|
||||
* 设备主键列表
|
||||
*/
|
||||
private List<Long> deviceIds; // 设备主键列表
|
||||
/**
|
||||
* 上传 图片
|
||||
*/
|
||||
private MultipartFile file; // 同一张图
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.fuyuanshen.web.domain.vo;
|
||||
|
||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备信息 视图对象
|
||||
*
|
||||
* @author Michelle.Chung
|
||||
*/
|
||||
@Data
|
||||
public class DeviceInfoVo {
|
||||
/**
|
||||
* 设备业务文件
|
||||
*/
|
||||
private List<AppFileVo> appBusinessFileVoList;
|
||||
/**
|
||||
* 设备操作视频
|
||||
*/
|
||||
private List<AppOperationVideoVo> appOperationVideoVoList;
|
||||
}
|
@ -2,15 +2,18 @@ package com.fuyuanshen.web.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.app.domain.AppDeviceBindRecord;
|
||||
import com.fuyuanshen.app.domain.AppDeviceShare;
|
||||
import com.fuyuanshen.app.domain.AppPersonnelInfo;
|
||||
import com.fuyuanshen.app.domain.bo.AppDeviceShareBo;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceShareDetailVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppDeviceShareVo;
|
||||
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
|
||||
import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper;
|
||||
import com.fuyuanshen.app.mapper.AppDeviceShareMapper;
|
||||
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
|
||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
@ -50,6 +53,8 @@ public class DeviceShareService {
|
||||
|
||||
private final AppPersonnelInfoMapper appPersonnelInfoMapper;
|
||||
|
||||
private final AppDeviceBindRecordMapper appDeviceBindRecordMapper;
|
||||
|
||||
public TableDataInfo<AppDeviceShareVo> queryPageList(AppDeviceShareBo bo, PageQuery pageQuery) {
|
||||
Long userId = AppLoginHelper.getUserId();
|
||||
bo.setCreateBy(userId);
|
||||
@ -185,7 +190,7 @@ public class DeviceShareService {
|
||||
/**
|
||||
* 校验短信验证码
|
||||
*/
|
||||
private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) {
|
||||
private boolean validateSmsCode(String phonenumber, String smsCode) {
|
||||
String code = RedisUtils.getCacheObject(GlobalConstants.DEVICE_SHARE_CODES_KEY + phonenumber);
|
||||
if (StringUtils.isBlank(code)) {
|
||||
throw new ServiceException("验证码失效");
|
||||
@ -194,16 +199,61 @@ public class DeviceShareService {
|
||||
}
|
||||
|
||||
public int deviceShare(AppDeviceShareBo bo) {
|
||||
boolean flag = validateSmsCode(AppLoginHelper.getTenantId(), bo.getPhonenumber(), bo.getSmsCode());
|
||||
if (!flag) {
|
||||
throw new ServiceException("验证码错误");
|
||||
}
|
||||
|
||||
Device device = deviceMapper.selectById(bo.getDeviceId());
|
||||
if (device == null) {
|
||||
throw new ServiceException("设备不存在");
|
||||
}
|
||||
Long userId = AppLoginHelper.getUserId();
|
||||
|
||||
boolean flag = validateSmsCode( bo.getPhonenumber(), bo.getSmsCode());
|
||||
if (!flag) {
|
||||
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<>();
|
||||
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<>();
|
||||
lqw.eq(AppDeviceShare::getDeviceId, bo.getDeviceId());
|
||||
lqw.eq(AppDeviceShare::getPhonenumber, bo.getPhonenumber());
|
||||
|
@ -181,12 +181,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);
|
||||
@ -195,6 +197,7 @@ public class DeviceBizService {
|
||||
bindRecord.setDeviceId(device.getId());
|
||||
bindRecord.setBindingUserId(userId);
|
||||
bindRecord.setBindingTime(new Date());
|
||||
bindRecord.setCommunicationMode(0);
|
||||
bindRecord.setCreateBy(userId);
|
||||
appDeviceBindRecordMapper.insert(bindRecord);
|
||||
}
|
||||
@ -224,6 +227,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 {
|
||||
@ -231,6 +235,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,150 @@
|
||||
package com.fuyuanshen.web.service.device;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||
import com.fuyuanshen.app.service.IAppBusinessFileService;
|
||||
import com.fuyuanshen.app.service.IAppOperationVideoService;
|
||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.equipment.service.DeviceService;
|
||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||
import com.fuyuanshen.system.service.ISysOssService;
|
||||
import com.fuyuanshen.web.domain.vo.DeviceInfoVo;
|
||||
import com.fuyuanshen.web.util.FileHashUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 设备调试服务
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeviceDebugService {
|
||||
private final ISysOssService sysOssService;
|
||||
|
||||
private final IAppBusinessFileService appBusinessFileService;
|
||||
private final IAppOperationVideoService appOperationVideoService;
|
||||
private final DeviceService deviceService;
|
||||
|
||||
/**
|
||||
* 文件上传并添加文件信息哈希去重
|
||||
* @param bo
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean addFileHash(AppFileDto bo) throws IOException {
|
||||
MultipartFile[] files = bo.getFiles();
|
||||
if (files == null || files.length == 0) {
|
||||
throw new ServiceException("请选择要上传的文件");
|
||||
}
|
||||
if (files.length > 5) {
|
||||
throw new ServiceException("最多只能上传5个文件");
|
||||
}
|
||||
if (bo.getDeviceIds() == null || bo.getDeviceIds().length == 0) {
|
||||
throw new ServiceException("请选择你要上传的设备");
|
||||
}
|
||||
|
||||
Map<String, Long> hash2OssId = new LinkedHashMap<>(files.length);
|
||||
for (MultipartFile file : files) {
|
||||
// 1. 计算文件哈希
|
||||
String hash = FileHashUtil.hash(file);
|
||||
|
||||
// 2. 先根据 hash 查库(秒传)
|
||||
SysOssVo exist = sysOssService.selectByHash(hash);
|
||||
Long ossId;
|
||||
if (exist != null) {
|
||||
// 2.1 已存在,直接复用
|
||||
ossId = exist.getOssId();
|
||||
hash2OssId.putIfAbsent(hash, ossId);
|
||||
} else {
|
||||
// 2.2 不存在,真正上传
|
||||
SysOssVo upload = sysOssService.upload(file);
|
||||
if (upload == null) {
|
||||
return false;
|
||||
}
|
||||
ossId = upload.getOssId();
|
||||
hash2OssId.putIfAbsent(hash, ossId);
|
||||
// 2.3 把 hash 写回记录(供下次去重)
|
||||
sysOssService.updateHashById(ossId, hash);
|
||||
}
|
||||
}
|
||||
// 4. 组装业务中间表
|
||||
List<AppBusinessFile> bizList = new ArrayList<>(bo.getDeviceIds().length * hash2OssId.size());
|
||||
Long userId = AppLoginHelper.getUserId();
|
||||
for (Long deviceId : bo.getDeviceIds()) {
|
||||
for (Long ossId : hash2OssId.values()) {
|
||||
// 3. 关联业务表
|
||||
AppBusinessFile appFile = new AppBusinessFile();
|
||||
appFile.setFileId(ossId);
|
||||
appFile.setBusinessId(deviceId);
|
||||
appFile.setFileType(bo.getFileType());
|
||||
appFile.setCreateBy(userId);
|
||||
bizList.add(appFile);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isEmpty(bizList)) { // 空集合直接返回
|
||||
throw new ServiceException("请选择要上传的文件");
|
||||
}
|
||||
return appBusinessFileService.insertBatch(bizList);
|
||||
}
|
||||
|
||||
public Boolean addVideoList(AppOperationVideoBo bo){
|
||||
if (bo.getVideoUrl().isEmpty()) {
|
||||
throw new ServiceException("请输入视频地址");
|
||||
}
|
||||
if (bo.getDeviceIds() == null || bo.getDeviceIds().length == 0) {
|
||||
throw new ServiceException("请选择你要上传的设备");
|
||||
}
|
||||
List<AppOperationVideo> bizList = new ArrayList<>(bo.getDeviceIds().length);
|
||||
for (Long deviceId : bo.getDeviceIds()) {
|
||||
|
||||
AppOperationVideo appVideo = new AppOperationVideo();
|
||||
appVideo.setVideoName(bo.getVideoName());
|
||||
appVideo.setDeviceId(deviceId);
|
||||
appVideo.setVideoUrl(bo.getVideoUrl());
|
||||
bizList.add(appVideo);
|
||||
}
|
||||
if (CollUtil.isEmpty(bizList)) { // 空集合直接返回
|
||||
throw new ServiceException("请选择要上传的视频");
|
||||
}
|
||||
return appOperationVideoService.insertBatch(bizList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备详情
|
||||
* @param deviceId
|
||||
* @return
|
||||
*/
|
||||
public DeviceInfoVo getDeviceInfo(Long deviceId) {
|
||||
if(deviceId == null || deviceId <= 0L) {
|
||||
throw new ServiceException("请选择设备");
|
||||
}
|
||||
DeviceInfoVo vo = new DeviceInfoVo();
|
||||
var device = deviceService.getById(deviceId);
|
||||
AppBusinessFileBo fileBo = new AppBusinessFileBo();
|
||||
fileBo.setBusinessId(deviceId);
|
||||
AppOperationVideoBo videoBo = new AppOperationVideoBo();
|
||||
videoBo.setDeviceId(deviceId);
|
||||
vo.setAppBusinessFileVoList(appBusinessFileService.queryAppFileList(fileBo));
|
||||
vo.setAppOperationVideoVoList(appOperationVideoService.queryList(videoBo));
|
||||
return vo;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package com.fuyuanshen.web.service.device;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.fuyuanshen.app.domain.AppPersonnelInfo;
|
||||
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
|
||||
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
||||
@ -27,13 +28,17 @@ import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
|
||||
import com.fuyuanshen.global.mqtt.config.MqttGateway;
|
||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
|
||||
import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
|
||||
import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.buildArr;
|
||||
@ -142,6 +147,67 @@ public class DeviceXinghanBizService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量上传设备logo
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void uploadDeviceLogoBatch(DeviceDebugLogoUploadDto batchDto) {
|
||||
if (CollectionUtils.isEmpty(batchDto.getDeviceIds())) {
|
||||
throw new ServiceException("设备列表为空");
|
||||
}
|
||||
|
||||
// 1. 一次性把设备查出来(N -> 1)
|
||||
QueryWrapper<Device> query = new QueryWrapper<>();
|
||||
query.in("id", batchDto.getDeviceIds());
|
||||
List<Device> devices = deviceMapper.selectList(query);
|
||||
if (devices.size() != batchDto.getDeviceIds().size()) {
|
||||
throw new ServiceException("部分设备不存在");
|
||||
}
|
||||
|
||||
// 2. 图片只转换一次(160*80 固定尺寸)
|
||||
byte[] largeData;
|
||||
try {
|
||||
largeData = ImageToCArrayConverter.convertImageToCArray(
|
||||
batchDto.getFile().getInputStream(), 160, 80, 25600);
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("图片解析失败");
|
||||
}
|
||||
int[] picArray = convertHexToDecimal(largeData);
|
||||
|
||||
// 3. 过滤离线设备 & 组装指令
|
||||
List<Device> onlineDevices = devices.stream()
|
||||
.filter(d -> !isDeviceOffline(d.getDeviceImei()))
|
||||
.toList();
|
||||
onlineDevices.forEach(d -> {
|
||||
String redisKey = GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + d.getDeviceImei() + DEVICE_BOOT_LOGO_KEY_PREFIX;
|
||||
|
||||
// 如果 Redis 里已存在,直接跳过
|
||||
if (RedisUtils.getCacheObject(redisKey) != null) {
|
||||
return; // 跳过本次循环
|
||||
}
|
||||
|
||||
RedisUtils.setCacheObject(
|
||||
redisKey,
|
||||
Arrays.toString(picArray),
|
||||
Duration.ofSeconds(5 * 60L));
|
||||
// 3.2 MQTT 下发
|
||||
Map<String, Object> payload =
|
||||
Collections.singletonMap("ins_PicTrans", Collections.singletonList(0));
|
||||
String topic = MqttConstants.GLOBAL_PUB_KEY + d.getDeviceImei();
|
||||
String json = JsonUtils.toJsonString(payload);
|
||||
|
||||
try {
|
||||
mqttGateway.sendMsgToMqtt(topic, 1, json);
|
||||
} catch (Exception e) {
|
||||
log.error("上传开机画面失败, topic={}, payload={}", topic, json, e);
|
||||
throw new ServiceException("上传LOGO失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
recordDeviceLog(d.getId(), d.getDeviceName(), "上传开机画面", "上传开机画面", AppLoginHelper.getUserId());
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员登记
|
||||
* @param bo
|
||||
|
@ -0,0 +1,28 @@
|
||||
package com.fuyuanshen.web.util;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.HexFormat;
|
||||
|
||||
/**
|
||||
* 文件哈希工具类
|
||||
*/
|
||||
public class FileHashUtil {
|
||||
private static final String ALGORITHM = "SHA-256";
|
||||
|
||||
public static String hash(MultipartFile file) throws IOException {
|
||||
MessageDigest digest = DigestUtils.getDigest(ALGORITHM);
|
||||
try (InputStream in = file.getInputStream()) {
|
||||
byte[] buf = new byte[8192];
|
||||
int len;
|
||||
while ((len = in.read(buf)) != -1) {
|
||||
digest.update(buf, 0, len);
|
||||
}
|
||||
}
|
||||
return HexFormat.of().formatHex(digest.digest());
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -45,5 +45,10 @@ public class AppOperationVideoBo extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 多设备id
|
||||
*/
|
||||
private Long[] deviceIds;
|
||||
|
||||
|
||||
}
|
||||
|
@ -109,4 +109,9 @@ public class AppDeviceShareVo implements Serializable {
|
||||
* 告警状态(0解除告警,1告警)
|
||||
*/
|
||||
private String alarmStatus;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private String createTime;
|
||||
}
|
||||
|
@ -19,6 +19,10 @@ public class AppFileVo {
|
||||
* 文件名称
|
||||
*/
|
||||
private String fileName;
|
||||
/**
|
||||
* 文件类型(1:操作说明,2:产品参数)
|
||||
*/
|
||||
private Long fileType;
|
||||
/**
|
||||
* 文件url
|
||||
*/
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.fuyuanshen.app.service;
|
||||
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
@ -50,6 +51,14 @@ public interface IAppBusinessFileService {
|
||||
*/
|
||||
Boolean insertByBo(AppBusinessFileBo bo);
|
||||
|
||||
/**
|
||||
* 批量新增app业务文件
|
||||
*
|
||||
* @param bo 批量新增app业务文件
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertBatch(Collection<AppBusinessFile> bo);
|
||||
|
||||
/**
|
||||
* 修改app业务文件
|
||||
*
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.fuyuanshen.app.service;
|
||||
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
@ -49,6 +51,14 @@ public interface IAppOperationVideoService {
|
||||
*/
|
||||
Boolean insertByBo(AppOperationVideoBo bo);
|
||||
|
||||
/**
|
||||
* 批量新增操作视频
|
||||
*
|
||||
* @param bo 批量新增操作视频
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertBatch(Collection<AppOperationVideo> bo);
|
||||
|
||||
/**
|
||||
* 修改操作视频
|
||||
*
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.fuyuanshen.app.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
@ -100,6 +101,20 @@ public class AppBusinessFileServiceImpl implements IAppBusinessFileService {
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertBatch(Collection<AppBusinessFile> bo) {
|
||||
// 1. 去重后的 businessId 集合
|
||||
List<Long> businessIds = bo.stream()
|
||||
.map(AppBusinessFile::getBusinessId)
|
||||
.distinct()
|
||||
.toList();
|
||||
QueryWrapper<AppBusinessFile> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.in("business_id", businessIds);
|
||||
queryWrapper.eq("file_type", bo.stream().findFirst().orElseThrow().getFileType());
|
||||
baseMapper.delete(queryWrapper);
|
||||
return baseMapper.insertBatch(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改app业务文件
|
||||
*
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.fuyuanshen.app.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
@ -97,6 +99,19 @@ public class AppOperationVideoServiceImpl implements IAppOperationVideoService {
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertBatch(Collection<AppOperationVideo> bo) {
|
||||
// 1. 去重后的 businessId 集合
|
||||
List<Long> deviceIds = bo.stream()
|
||||
.map(AppOperationVideo::getDeviceId)
|
||||
.distinct()
|
||||
.toList();
|
||||
QueryWrapper<AppOperationVideo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.in("device_id", deviceIds);
|
||||
baseMapper.delete(queryWrapper);
|
||||
return baseMapper.insertBatch(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改操作视频
|
||||
*
|
||||
|
@ -5,7 +5,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<mapper namespace="com.fuyuanshen.app.mapper.AppBusinessFileMapper">
|
||||
|
||||
<select id="queryAppFileList" resultType="com.fuyuanshen.app.domain.vo.AppFileVo">
|
||||
select a.id,a.business_id,a.file_id,b.file_name,b.url fileUrl from app_business_file a left join sys_oss b on a.file_id = b.oss_id
|
||||
select a.id,a.business_id,a.file_id,a.file_type,b.file_name,b.url fileUrl from app_business_file a left join sys_oss b on a.file_id = b.oss_id
|
||||
where 1=1
|
||||
<if test="businessId != null">
|
||||
and a.business_id = #{businessId}
|
||||
|
@ -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="criteria.shareStartTime != null and criteria.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,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 Long latitude;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
private Long longitude;
|
||||
|
||||
/**
|
||||
* 定位精度
|
||||
*/
|
||||
private Long accuracy;
|
||||
|
||||
/**
|
||||
* 事件时间
|
||||
*/
|
||||
private Date eventTime;
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
|
||||
}
|
@ -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,83 @@
|
||||
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 Date createTime;
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -21,6 +21,18 @@ public class AlarmInformationVo {
|
||||
*/
|
||||
private Integer processingAlarm = 0;
|
||||
|
||||
|
||||
/**
|
||||
* 今日报警总数
|
||||
*/
|
||||
private Integer alarmsTotalToday = 0;
|
||||
|
||||
/**
|
||||
* 今日总处理报警
|
||||
*/
|
||||
private Integer processingAlarmToday = 0;
|
||||
|
||||
|
||||
/**
|
||||
* 强制报警
|
||||
*/
|
||||
@ -37,7 +49,7 @@ public class AlarmInformationVo {
|
||||
private Integer alarmManual = 0;
|
||||
|
||||
/**
|
||||
* 电子围栏
|
||||
*
|
||||
*/
|
||||
private Integer fenceElectronic = 0;
|
||||
|
||||
|
@ -26,6 +26,11 @@ public class DataOverviewVo {
|
||||
*/
|
||||
private Integer bindingNew = 0;
|
||||
|
||||
/**
|
||||
* 已绑定设备
|
||||
*/
|
||||
private Integer binding = 0;
|
||||
|
||||
/**
|
||||
* 异常设备
|
||||
*/
|
||||
|
@ -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,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;
|
||||
|
||||
|
||||
}
|
@ -26,4 +26,24 @@ public class EquipmentClassificationVo {
|
||||
*/
|
||||
private Integer devices4GAndBluetooth = 0;
|
||||
|
||||
/**
|
||||
* 设备总数
|
||||
*/
|
||||
private Integer total;
|
||||
|
||||
|
||||
/**
|
||||
* 计算设备总数
|
||||
*
|
||||
* @return 设备总数
|
||||
*/
|
||||
public Integer getTotal() {
|
||||
if (total == null) {
|
||||
total = (equipment4G == null ? 0 : equipment4G) +
|
||||
(deviceBluetooth == null ? 0 : deviceBluetooth) +
|
||||
(devices4GAndBluetooth == null ? 0 : devices4GAndBluetooth);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.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> {
|
||||
|
||||
}
|
@ -99,11 +99,11 @@ public interface DeviceMapper extends BaseMapper<Device> {
|
||||
/**
|
||||
* 获取设备使用数据
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @param deviceTypeId 设备ID
|
||||
* @param range 时间范围 1:半年 2:一年
|
||||
* @return 每月使用数据列表
|
||||
*/
|
||||
List<Map<String, Object>> getEquipmentUsageData(Long deviceId, Integer range);
|
||||
List<Map<String, Object>> getEquipmentUsageData(@Param("deviceTypeId") Long deviceTypeId, @Param("range") Integer range);
|
||||
|
||||
// 在DeviceMapper.java中添加方法
|
||||
int getUsageDataForMonth(@Param("deviceId") Long deviceId,
|
||||
|
@ -139,9 +139,9 @@ public interface DeviceService extends IService<Device> {
|
||||
/**
|
||||
* 获取设备使用数据
|
||||
*
|
||||
* @param deviceId
|
||||
* @param deviceTypeId
|
||||
* @param range
|
||||
* @return
|
||||
*/
|
||||
List<Map<String, Object>> getEquipmentUsageData(Long deviceId, Integer range);
|
||||
List<Map<String, Object>> getEquipmentUsageData(Long deviceTypeId, Integer range);
|
||||
}
|
||||
|
@ -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,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);
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
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,203 @@
|
||||
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.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.mapper.DeviceGeoFenceMapper;
|
||||
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.ArrayList;
|
||||
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 DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService {
|
||||
|
||||
private final DeviceGeoFenceMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询电子围栏
|
||||
*
|
||||
* @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());
|
||||
|
||||
// 这里需要实现具体的围栏判断逻辑
|
||||
// 根据您之前提供的算法实现点在围栏内的判断
|
||||
|
||||
for (DeviceGeoFenceVo fence : activeFences) {
|
||||
String coordinates = fence.getCoordinates();
|
||||
|
||||
// 在需要转换的地方
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
List<GeoFenceChecker.Coordinate> coordinateList = List.of();
|
||||
try {
|
||||
coordinateList = objectMapper.readValue(coordinates,
|
||||
new TypeReference<List<GeoFenceChecker.Coordinate>>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
// 处理解析异常
|
||||
log.error("坐标数据解析失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
FenceCheckResponse.FenceInfo fenceInfo = new FenceCheckResponse.FenceInfo();
|
||||
List<FenceCheckResponse.FenceInfo> list = new ArrayList<>();
|
||||
boolean pointInFence = GeoFenceChecker.isPointInFence(request.getLatitude(), request.getLongitude(), fence.getAreaType(), coordinateList, fence.getRadius());
|
||||
if (pointInFence) {
|
||||
fenceInfo.setFenceId(fence.getId());
|
||||
fenceInfo.setFenceName(fence.getName());
|
||||
fenceInfo.setFenceType(fence.getAreaType());
|
||||
response.setEnteredFences(list);
|
||||
response.getEnteredFences().add(fenceInfo);
|
||||
} else {
|
||||
response.setExitedFences(list);
|
||||
response.getExitedFences().add(fenceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -238,7 +238,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("设备类型不存在!!!");
|
||||
@ -630,6 +631,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
@Override
|
||||
public EquipmentClassificationVo getEquipmentClassification() {
|
||||
EquipmentClassificationVo equipmentClassification = deviceMapper.getEquipmentClassification();
|
||||
equipmentClassification.getTotal();
|
||||
return equipmentClassification;
|
||||
}
|
||||
|
||||
@ -648,13 +650,13 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
/**
|
||||
* 获取设备使用数据
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @param deviceTypeId 设备ID
|
||||
* @param range 时间范围 1:半年 2:一年
|
||||
* @return 每月使用数据列表
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getEquipmentUsageData(Long deviceId, Integer range) {
|
||||
List<Map<String, Object>> equipmentUsageData = deviceMapper.getEquipmentUsageData(deviceId, range);
|
||||
public List<Map<String, Object>> getEquipmentUsageData(Long deviceTypeId, Integer range) {
|
||||
List<Map<String, Object>> equipmentUsageData = deviceMapper.getEquipmentUsageData(deviceTypeId, range);
|
||||
return equipmentUsageData;
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?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
|
||||
<where>
|
||||
${ew.customSqlSegment}
|
||||
</where>
|
||||
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.DeviceGeoFenceMapper">
|
||||
|
||||
</mapper>
|
@ -254,9 +254,9 @@
|
||||
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 = 0
|
||||
where dt.communication_mode in (0, 2)
|
||||
<if test="criteria.deviceType != null">
|
||||
and d.device_type = #{criteria.deviceType}
|
||||
</if>
|
||||
@ -321,11 +321,14 @@
|
||||
<!-- 获取数据总览 -->
|
||||
<select id="getDataOverview" resultType="com.fuyuanshen.equipment.domain.vo.DataOverviewVo">
|
||||
SELECT (SELECT COUNT(1) FROM device) AS devicesNumber,
|
||||
(SELECT COUNT(1) FROM device WHERE device_status = 1) AS equipmentOnline,
|
||||
(SELECT COUNT(1) FROM device WHERE DATE (create_time) = CURDATE()) AS bindingNew, (
|
||||
(SELECT COUNT(1) FROM device WHERE online_status = 1) AS equipmentOnline,
|
||||
(SELECT COUNT(1) FROM device WHERE DATE (create_time) = CURDATE() AND binding_status = 1 ) AS bindingNew, (
|
||||
SELECT COUNT (1)
|
||||
FROM device
|
||||
WHERE device_status = 2) AS equipmentAbnormal
|
||||
WHERE binding_status = 1 ) AS binding, (
|
||||
SELECT COUNT (1)
|
||||
FROM device
|
||||
WHERE online_status = 2) AS equipmentAbnormal
|
||||
</select>
|
||||
|
||||
<!-- 获取设备分类 -->
|
||||
@ -347,55 +350,67 @@
|
||||
|
||||
<!-- 获取告警信息 -->
|
||||
<select id="getAlarmInformation" resultType="com.fuyuanshen.equipment.domain.vo.AlarmInformationVo">
|
||||
SELECT (SELECT COUNT(1) FROM device_alarm WHERE treatment_state = 0 AND DATE (create_time) = CURDATE()) AS alarmsTotal, (
|
||||
SELECT (SELECT COUNT(1) FROM device_alarm WHERE treatment_state = 0) AS alarmsTotal
|
||||
, (SELECT COUNT(1)
|
||||
FROM device_alarm
|
||||
WHERE treatment_state = 0) AS processingAlarm
|
||||
, (SELECT COUNT(1)
|
||||
FROM device_alarm
|
||||
WHERE treatment_state = 0 AND
|
||||
DATE (create_time) = CURDATE()) AS alarmsTotalToday
|
||||
, (
|
||||
SELECT COUNT (1)
|
||||
FROM device_alarm
|
||||
WHERE treatment_state = 0
|
||||
AND DATE (create_time) = CURDATE()) AS processingAlarm
|
||||
AND DATE (create_time) = CURDATE()) AS processingAlarmToday
|
||||
, (
|
||||
SELECT COUNT (1)
|
||||
FROM device_alarm
|
||||
WHERE device_action = 0
|
||||
AND DATE (create_time) = CURDATE()) AS alarmForced
|
||||
) AS alarmForced
|
||||
, (
|
||||
SELECT COUNT (1)
|
||||
FROM device_alarm
|
||||
WHERE device_action = 1
|
||||
AND DATE (create_time) = CURDATE()) AS intrusionImpact
|
||||
) AS intrusionImpact
|
||||
, (
|
||||
SELECT COUNT (1)
|
||||
FROM device_alarm
|
||||
WHERE device_action = 2
|
||||
AND DATE (create_time) = CURDATE()) AS alarmManual
|
||||
) AS alarmManual
|
||||
, (
|
||||
SELECT COUNT (1)
|
||||
FROM device_alarm
|
||||
WHERE device_action = 3 AND DATE (create_time) = CURDATE()) AS fenceElectronic
|
||||
WHERE device_action = 3) AS fenceElectronic
|
||||
|
||||
</select>
|
||||
|
||||
<!-- 获取设备使用数据 -->
|
||||
<select id="getEquipmentUsageData" resultType="map">
|
||||
SELECT COUNT(CASE WHEN MONTH (dl.create_time) = 1 THEN 1 END) AS m1,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 2 THEN 1 END) AS m2,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 3 THEN 1 END) AS m3,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 4 THEN 1 END) AS m4,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 5 THEN 1 END) AS m5,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 6 THEN 1 END) AS m6,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 7 THEN 1 END) AS m7,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 8 THEN 1 END) AS m8,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 9 THEN 1 END) AS m9,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 10 THEN 1 END) AS m10,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 11 THEN 1 END) AS m11,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 12 THEN 1 END) AS m12
|
||||
SELECT COUNT(CASE WHEN MONTH (dl.create_time) = 1 THEN 1 END) AS m1,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 2 THEN 1 END) AS m2,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 3 THEN 1 END) AS m3,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 4 THEN 1 END) AS m4,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 5 THEN 1 END) AS m5,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 6 THEN 1 END) AS m6,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 7 THEN 1 END) AS m7,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 8 THEN 1 END) AS m8,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 9 THEN 1 END) AS m9,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 10 THEN 1 END) AS m10,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 11 THEN 1 END) AS m11,
|
||||
COUNT(CASE WHEN MONTH (dl.create_time) = 12 THEN 1 END) AS m12
|
||||
FROM device_log dl
|
||||
LEFT JOIN device d ON dl.device_id = d.id
|
||||
LEFT JOIN device_type dt ON d.device_type = dt.id
|
||||
WHERE dt.id = #{deviceId}
|
||||
AND (
|
||||
LEFT JOIN device d ON dl.device_id = d.id
|
||||
LEFT JOIN device_type dt ON d.device_type = dt.id
|
||||
<where>
|
||||
<if test="deviceTypeId != null">
|
||||
dt.id = #{deviceTypeId}
|
||||
</if>
|
||||
AND (
|
||||
(#{range} = 1 AND dl.create_time >= DATE_SUB(NOW(), INTERVAL 6 MONTH)) OR
|
||||
(#{range} = 2 AND dl.create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH))
|
||||
)
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="getUsageDataForMonth" resultType="java.lang.Integer">
|
||||
|
@ -27,7 +27,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
and dr.device_id = #{criteria.deviceId}
|
||||
</if>
|
||||
<if test="criteria.repairPart != null">
|
||||
and dr.repairPart like concat('%', TRIM(#{criteria.repairPart}), '%')
|
||||
and dr.repair_part like concat('%', TRIM(#{criteria.repairPart}), '%')
|
||||
</if>
|
||||
<!-- 时间段条件 -->
|
||||
<if test="criteria.repairBeginTime != null">
|
||||
|
@ -51,5 +51,9 @@ public class SysOss extends TenantEntity {
|
||||
* 服务商
|
||||
*/
|
||||
private String service;
|
||||
/**
|
||||
* 内容哈希
|
||||
*/
|
||||
private String fileHash;
|
||||
|
||||
}
|
||||
|
@ -50,5 +50,9 @@ public class SysOssBo extends BaseEntity {
|
||||
* 服务商
|
||||
*/
|
||||
private String service;
|
||||
/**
|
||||
* 内容哈希
|
||||
*/
|
||||
private String fileHash;
|
||||
|
||||
}
|
||||
|
@ -72,6 +72,10 @@ public class SysOssVo implements Serializable {
|
||||
* 服务商
|
||||
*/
|
||||
private String service;
|
||||
/**
|
||||
* 内容哈希
|
||||
*/
|
||||
private String fileHash;
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,16 @@
|
||||
package com.fuyuanshen.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.fuyuanshen.common.mybatis.annotation.DataColumn;
|
||||
import com.fuyuanshen.common.mybatis.annotation.DataPermission;
|
||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import com.fuyuanshen.system.domain.SysOss;
|
||||
import com.fuyuanshen.system.domain.SysUser;
|
||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 文件上传 数据层
|
||||
@ -12,4 +19,20 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
*/
|
||||
@Mapper
|
||||
public interface SysOssMapper extends BaseMapperPlus<SysOss, SysOssVo> {
|
||||
|
||||
/**
|
||||
* 用内容哈希查询文件
|
||||
*
|
||||
* @param fileHash 内容哈希
|
||||
* @return 文件信息
|
||||
*/
|
||||
SysOssVo selectByHash(String fileHash);
|
||||
|
||||
/**
|
||||
* 根据主键更新内容哈希
|
||||
*
|
||||
* @param ossId 主键
|
||||
* @return 结果
|
||||
*/
|
||||
int updateHashById(long ossId,String fileHash);
|
||||
}
|
||||
|
@ -44,6 +44,22 @@ public interface ISysOssService {
|
||||
*/
|
||||
SysOssVo getById(Long ossId);
|
||||
|
||||
/**
|
||||
* 根据文件 hash 值从缓存或数据库中获取 SysOssVo 对象
|
||||
*
|
||||
* @param fileHash 文件 hash 值
|
||||
* @return 匹配的 SysOssVo 列表
|
||||
*/
|
||||
SysOssVo selectByHash(String fileHash);
|
||||
|
||||
/**
|
||||
* 更新文件 hash 值
|
||||
*
|
||||
* @param ossId OSS对象ID
|
||||
* @param fileHash 文件 hash 值
|
||||
*/
|
||||
int updateHashById(long ossId,String fileHash);
|
||||
|
||||
/**
|
||||
* 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库
|
||||
*
|
||||
|
@ -162,6 +162,16 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
return baseMapper.selectVoById(ossId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysOssVo selectByHash(String fileHash) {
|
||||
return baseMapper.selectByHash(fileHash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateHashById(long ossId, String fileHash) {
|
||||
return baseMapper.updateHashById(ossId,fileHash);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文件下载方法,支持一次性下载完整文件
|
||||
|
@ -2,4 +2,11 @@
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.fuyuanshen.system.mapper.SysOssMapper">
|
||||
|
||||
<select id="selectByHash" resultType="com.fuyuanshen.system.domain.vo.SysOssVo">
|
||||
select oss_id,file_name,original_name,file_suffix,url,service,file_hash from sys_oss WHERE file_hash = #{fileHash} LIMIT 1
|
||||
</select>
|
||||
|
||||
<update id="updateHashById">
|
||||
UPDATE sys_oss SET file_hash = #{fileHash} WHERE oss_id = #{ossId}
|
||||
</update>
|
||||
</mapper>
|
||||
|
Reference in New Issue
Block a user