forked from dyf/fys-Multi-tenant
Compare commits
19 Commits
7eb5e6095a
...
2d59397de5
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d59397de5 | |||
| b7c81419a4 | |||
| 3859c20081 | |||
| 3bdabb04e2 | |||
| e124694e67 | |||
| e528cd04e9 | |||
| 735199b9e0 | |||
| a69c665d8b | |||
| 5a52129fd0 | |||
| 9c98fa9077 | |||
| 89f08c2d91 | |||
| 135e6d6899 | |||
| e2821566c8 | |||
| 5b3a92c80d | |||
| 9d642f4913 | |||
| f07ec53645 | |||
| 74b0059aca | |||
| 8e66f1ca28 | |||
| 1b33356a2a |
@ -71,6 +71,8 @@ public class RedisKeyExpirationListener implements MessageListener {
|
||||
deviceUpdateWrapper.eq("device_imei", element);
|
||||
deviceUpdateWrapper.set("online_status", 0);
|
||||
deviceMapper.update(deviceUpdateWrapper);
|
||||
}else{
|
||||
RedisUtils.deleteObject(deviceOnlineStatusRedisKey);
|
||||
}
|
||||
} finally {
|
||||
//释放锁
|
||||
|
||||
@ -54,7 +54,7 @@ public class ReceiverMessageHandler implements MessageHandler {
|
||||
RedisUtils.offerDeduplicated(queueKey,dedupKey,deviceImei, Duration.ofHours(24));
|
||||
//在线状态
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(62));
|
||||
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(120));
|
||||
}
|
||||
|
||||
String state = payloadDict.getStr("state");
|
||||
|
||||
@ -90,6 +90,8 @@ public class BjqAlarmRule implements MqttMessageRule {
|
||||
deviceAlarmBo.setDurationTime(durationBetween);
|
||||
// 0已处理,1未处理
|
||||
deviceAlarmBo.setTreatmentState(0);
|
||||
// 告警状态,0 解除告警, 1 告警中
|
||||
deviceAlarmBo.setAlarmState(0);
|
||||
deviceAlarmService.updateByBo(deviceAlarmBo);
|
||||
}
|
||||
}
|
||||
@ -107,6 +109,8 @@ public class BjqAlarmRule implements MqttMessageRule {
|
||||
deviceAlarmBo.setStartTime(new Date());
|
||||
// 0已处理,1未处理
|
||||
deviceAlarmBo.setTreatmentState(1);
|
||||
// 告警状态,0 解除告警, 1 告警中
|
||||
deviceAlarmBo.setAlarmState(1);
|
||||
|
||||
// LoginUser loginUser = LoginHelper.getLoginUser();
|
||||
// deviceAlarmBo.setCreateBy(loginUser.getUserId());
|
||||
|
||||
@ -5,6 +5,8 @@ import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.equipment.service.DeviceService;
|
||||
import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil;
|
||||
import com.fuyuanshen.equipment.utils.map.LngLonUtil;
|
||||
import com.fuyuanshen.global.mqtt.base.MqttMessageRule;
|
||||
@ -36,8 +38,9 @@ import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVIC
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class BjqLocationDataRule implements MqttMessageRule {
|
||||
|
||||
|
||||
private final MqttGateway mqttGateway;
|
||||
private final DeviceService deviceService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -56,6 +59,8 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
||||
|
||||
// 异步发送经纬度到Redis
|
||||
asyncSendLocationToRedisWithFuture(context.getDeviceImei(), latitude, longitude);
|
||||
// 异步保存数据
|
||||
asyncSaveLocationToMySQLWithFuture(context.getDeviceImei(), latitude, longitude);
|
||||
|
||||
Map<String, Object> map = buildLocationDataMap(latitude, longitude);
|
||||
mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), 1, JsonUtils.toJsonString(map));
|
||||
@ -114,13 +119,13 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
||||
public void asyncSendLocationToRedisWithFuture(String deviceImei, String latitude, String longitude) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
if(StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)){
|
||||
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
||||
return;
|
||||
}
|
||||
// String[] latArr = latitude.split("\\.");
|
||||
// String[] lonArr = longitude.split("\\.");
|
||||
// // 将位置信息存储到Redis中
|
||||
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DEVICE_LOCATION_KEY_PREFIX;
|
||||
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX;
|
||||
// String redisObj = RedisUtils.getCacheObject(redisKey);
|
||||
// JSONObject jsonOBj = JSONObject.parseObject(redisObj);
|
||||
// if(jsonOBj != null){
|
||||
@ -153,7 +158,6 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
||||
locationInfo.put("timestamp", System.currentTimeMillis());
|
||||
|
||||
|
||||
|
||||
String locationJson = JsonUtils.toJsonString(locationInfo);
|
||||
|
||||
// 存储到Redis
|
||||
@ -171,12 +175,38 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 异步保存位置信息到MySQL数据库
|
||||
*
|
||||
* @param deviceImei 设备IMEI
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
*/
|
||||
public void asyncSaveLocationToMySQLWithFuture(String deviceImei, String latitude, String longitude) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用服务层方法更新设备位置信息
|
||||
deviceService.updateDeviceLocationByImei(deviceImei, longitude, latitude);
|
||||
|
||||
log.info("位置信息已异步保存到MySQL: device={}, lat={}, lon={}", deviceImei, latitude, longitude);
|
||||
} catch (Exception e) {
|
||||
log.error("异步保存位置信息到MySQL时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 存储设备30天历史轨迹到Redis (使用Sorted Set)
|
||||
*/
|
||||
public void storeDeviceTrajectoryWithSortedSet(String deviceImei, String locationJson) {
|
||||
try {
|
||||
String trajectoryKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_LOCATION_HISTORY_KEY_PREFIX;
|
||||
String trajectoryKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_LOCATION_HISTORY_KEY_PREFIX;
|
||||
// String trajectoryKey = "device:trajectory:zset:" + deviceImei;
|
||||
// String locationJson = JsonUtils.toJsonString(locationInfo);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
@ -194,20 +224,20 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
||||
log.error("存储设备轨迹到Redis(ZSet)失败: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Map<String, Object> buildLocationDataMap(String latitude, String longitude) {
|
||||
String[] latArr = latitude.split("\\.");
|
||||
String[] lonArr = longitude.split("\\.");
|
||||
|
||||
|
||||
ArrayList<Integer> intData = new ArrayList<>();
|
||||
intData.add(11);
|
||||
intData.add(Integer.parseInt(latArr[0]));
|
||||
String str1 = latArr[1];
|
||||
intData.add(Integer.parseInt(str1.substring(0,4)));
|
||||
intData.add(Integer.parseInt(str1.substring(0, 4)));
|
||||
String str2 = lonArr[1];
|
||||
intData.add(Integer.parseInt(lonArr[0]));
|
||||
intData.add(Integer.parseInt(str2.substring(0,4)));
|
||||
|
||||
intData.add(Integer.parseInt(str2.substring(0, 4)));
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("instruct", intData);
|
||||
return map;
|
||||
|
||||
@ -98,21 +98,24 @@ public class MqttMessageConsumer {
|
||||
String threadName = Thread.currentThread().getName();
|
||||
try {
|
||||
log.info("业务处理线程 {} 开始处理消息: {}", threadName, message);
|
||||
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ message + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
String deviceOnlineStatusRedis = RedisUtils.getCacheObject(deviceOnlineStatusRedisKey);
|
||||
if(StringUtils.isBlank(deviceOnlineStatusRedis)){
|
||||
// String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ message + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||
// String deviceOnlineStatusRedis = RedisUtils.getCacheObject(deviceOnlineStatusRedisKey);
|
||||
// if(StringUtils.isBlank(deviceOnlineStatusRedis)){
|
||||
// UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||
// updateWrapper.eq("device_imei", message)
|
||||
// .set("online_status", 1);
|
||||
// deviceMapper.update(updateWrapper);
|
||||
// }
|
||||
QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("device_imei", message);
|
||||
queryWrapper.eq("online_status", 1);
|
||||
Long count = deviceMapper.selectCount(queryWrapper);
|
||||
if(count == 0){
|
||||
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("device_imei", message)
|
||||
.set("online_status", 1);
|
||||
deviceMapper.update(updateWrapper);
|
||||
}
|
||||
// QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
|
||||
// queryWrapper.eq("device_imei", message);
|
||||
// queryWrapper.eq("online_status", 1);
|
||||
// Long count = deviceMapper.selectCount(queryWrapper);
|
||||
// if(count == 0){
|
||||
//
|
||||
// }
|
||||
// 模拟业务处理耗时
|
||||
// Thread.sleep(200);
|
||||
|
||||
|
||||
@ -0,0 +1,142 @@
|
||||
package com.fuyuanshen.web.controller;
|
||||
|
||||
import com.fuyuanshen.common.core.domain.R;
|
||||
import com.fuyuanshen.equipment.domain.vo.*;
|
||||
import com.fuyuanshen.equipment.service.IDeviceAlarmService;
|
||||
import com.fuyuanshen.equipment.service.DeviceService;
|
||||
import com.fuyuanshen.equipment.service.IWeatherService;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 大屏数据
|
||||
*
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-27 08:42
|
||||
*/
|
||||
@Tag(name = "大屏数据", description = "大屏数据")
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/api/largeScreen")
|
||||
public class LargeScreenController {
|
||||
|
||||
private final IDeviceAlarmService deviceAlarmService;
|
||||
private final DeviceService deviceService;
|
||||
private final IWeatherService weatherService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取设备总览信息
|
||||
* 包含设备总数、在线设备数量、设备型号数量
|
||||
*/
|
||||
@GetMapping("/getDeviceOverview")
|
||||
public R<DeviceOverviewVo> getDeviceOverview() {
|
||||
return R.ok(deviceService.getDeviceOverview());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取 实时报警信息
|
||||
* RealtimeAlarm
|
||||
*/
|
||||
@GetMapping("/getRealtimeAlarm")
|
||||
public R<List<DeviceAlarmVo>> getRealtimeAlarm() {
|
||||
return R.ok(deviceAlarmService.getRealtimeAlarm());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取报警统计数据
|
||||
* 包括正在报警数量、报警总数、已处理报警数量
|
||||
*/
|
||||
@GetMapping("/getAlarmStatistics")
|
||||
public R<AlarmStatisticsVo> getAlarmStatistics() {
|
||||
return R.ok(deviceAlarmService.getAlarmStatistics());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取最近一年每月告警统计数据
|
||||
*/
|
||||
@GetMapping("/getMonthlyAlarmStatistics")
|
||||
public R<MonthlyAlarmStatisticsVo> getMonthlyAlarmStatistics() {
|
||||
return R.ok(deviceAlarmService.getMonthlyAlarmStatistics());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取设备通讯方式统计数据
|
||||
* 包含通讯方式名称、设备总数、异常设备数
|
||||
*/
|
||||
@GetMapping("/getDeviceCommunicationModeStatistics")
|
||||
public R<List<DeviceCommunicationModeStatisticsVo>> getDeviceCommunicationModeStatistics() {
|
||||
return R.ok(deviceService.getDeviceCommunicationModeStatistics());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取设备使用频次统计数据
|
||||
*
|
||||
* @param days 天数(近一个月传30,近半年传180)
|
||||
*/
|
||||
@GetMapping("/getDeviceUsageFrequency")
|
||||
public R<List<DeviceUsageFrequencyVo>> getDeviceUsageFrequency(@RequestParam int days) {
|
||||
return R.ok(deviceService.getDeviceUsageFrequency(days));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据条件查询设备位置信息
|
||||
*
|
||||
* @param groupId 设备分组ID
|
||||
* @param deviceType 设备类型
|
||||
* @param deviceImei 设备IMEI
|
||||
* @return 设备位置信息列表
|
||||
*/
|
||||
@GetMapping("/getDeviceLocationInfo")
|
||||
public R<List<DeviceLocationVo>> getDeviceLocationInfo(
|
||||
@RequestParam(required = false) Long groupId,
|
||||
@RequestParam(required = false) Long deviceType,
|
||||
@RequestParam(required = false) String deviceImei) {
|
||||
return R.ok(deviceService.getDeviceLocationInfo(groupId, deviceType, deviceImei));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据经纬度获取天气信息
|
||||
*
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
* @return 天气信息
|
||||
*/
|
||||
@GetMapping("/weather")
|
||||
public R<WeatherInfoVo> getWeatherInfo(
|
||||
@RequestParam Double latitude,
|
||||
@RequestParam Double longitude) {
|
||||
if (latitude == null || longitude == null) {
|
||||
return R.fail("经纬度参数不能为空");
|
||||
}
|
||||
|
||||
// 简单的经纬度范围校验
|
||||
if (latitude < -90 || latitude > 90 || longitude < -180 || longitude > 180) {
|
||||
return R.fail("经纬度参数范围不正确");
|
||||
}
|
||||
|
||||
WeatherInfoVo weatherInfo = weatherService.getWeatherByCoordinates(latitude, longitude);
|
||||
if (weatherInfo != null) {
|
||||
return R.ok(weatherInfo);
|
||||
} else {
|
||||
return R.fail("获取天气信息失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -49,7 +49,7 @@ public class APPDeviceType extends TenantEntity {
|
||||
@Schema(name = "联网方式", example = "0:无;1:4G;2:WIFI")
|
||||
private String networkWay;
|
||||
|
||||
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙")
|
||||
@Schema(name = "通讯方式", example = "通讯方式 0:4G;1:蓝牙,2 4G&蓝牙")
|
||||
private String communicationMode;
|
||||
|
||||
|
||||
|
||||
@ -50,6 +50,9 @@ public class AppDeviceBindRecord extends TenantEntity {
|
||||
*/
|
||||
private Date bindingTime;
|
||||
|
||||
/**
|
||||
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||
*/
|
||||
private Integer communicationMode;
|
||||
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ public class APPDeviceQueryCriteria {
|
||||
@Schema(name = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙")
|
||||
@Schema(name = "通讯方式", example = "通讯方式 0:4G;1:蓝牙,2 4G&蓝牙")
|
||||
private Integer communicationMode;
|
||||
|
||||
}
|
||||
|
||||
@ -10,6 +10,9 @@ public class APPDeviceTypeVo {
|
||||
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||
*/
|
||||
private String communicationMode;
|
||||
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ public class AppDeviceDetailVo {
|
||||
private String deviceMac;
|
||||
|
||||
/**
|
||||
* 通讯方式 0:4G;1:蓝牙
|
||||
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||
*/
|
||||
private Integer communicationMode;
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ public class AppDeviceShareDetailVo implements Serializable {
|
||||
private String deviceMac;
|
||||
|
||||
/**
|
||||
* 通讯方式 0:4G;1:蓝牙
|
||||
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||
*/
|
||||
private Integer communicationMode;
|
||||
|
||||
|
||||
@ -114,4 +114,9 @@ public class AppDeviceShareVo implements Serializable {
|
||||
* 创建时间
|
||||
*/
|
||||
private String createTime;
|
||||
|
||||
/**
|
||||
* 设备详情页面
|
||||
*/
|
||||
private String detailPageUrl;
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
@ -33,23 +34,62 @@ public class IgnoreFailedImageConverter implements Converter<URL> {
|
||||
@Override
|
||||
public WriteCellData<?> convertToExcelData(URL value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
logger.debug("图片URL为空");
|
||||
return new WriteCellData<>(new byte[0]);
|
||||
}
|
||||
|
||||
try {
|
||||
logger.debug("开始加载图片: {}", value);
|
||||
URLConnection conn = value.openConnection();
|
||||
conn.setConnectTimeout(2000); // 2秒超时
|
||||
conn.setReadTimeout(3000); // 3秒超时
|
||||
// 增加连接和读取超时时间
|
||||
conn.setConnectTimeout(10000); // 10秒连接超时
|
||||
conn.setReadTimeout(30000); // 30秒读取超时
|
||||
|
||||
// 添加User-Agent避免被服务器拦截
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ExcelExporter/1.0");
|
||||
|
||||
// 如果是HTTP连接,设置一些额外的属性
|
||||
if (conn instanceof HttpURLConnection) {
|
||||
HttpURLConnection httpConn = (HttpURLConnection) conn;
|
||||
httpConn.setRequestMethod("GET");
|
||||
// 不使用缓存
|
||||
httpConn.setUseCaches(false);
|
||||
// 跟随重定向
|
||||
httpConn.setInstanceFollowRedirects(true);
|
||||
}
|
||||
|
||||
long contentLength = conn.getContentLengthLong();
|
||||
logger.debug("连接建立成功,图片大小: {} 字节", contentLength);
|
||||
|
||||
// 检查内容长度是否有效
|
||||
if (contentLength == 0) {
|
||||
logger.warn("图片文件为空: {}", value);
|
||||
return new WriteCellData<>(new byte[0]);
|
||||
}
|
||||
|
||||
// 限制图片大小(防止过大文件导致内存问题)
|
||||
if (contentLength > 10 * 1024 * 1024) { // 10MB限制
|
||||
logger.warn("图片文件过大 ({} bytes),跳过加载: {}", contentLength, value);
|
||||
return new WriteCellData<>(new byte[0]);
|
||||
}
|
||||
|
||||
try (InputStream inputStream = conn.getInputStream()) {
|
||||
// byte[] bytes = FileUtils.readInputStream(inputStream, value.toString());
|
||||
// 替代 FileUtils.readInputStream 的自定义方法
|
||||
byte[] bytes = readInputStream(inputStream);
|
||||
|
||||
// 检查读取到的数据是否为空
|
||||
if (bytes == null || bytes.length == 0) {
|
||||
logger.warn("读取到空的图片数据: {}", value);
|
||||
return new WriteCellData<>(new byte[0]);
|
||||
}
|
||||
|
||||
logger.debug("成功读取图片数据,大小: {} 字节", bytes.length);
|
||||
return new WriteCellData<>(bytes);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 静默忽略错误,只记录日志
|
||||
logger.debug("忽略图片加载失败: {}, 原因: {}", value, e.getMessage());
|
||||
logger.warn("图片加载失败: {}, 原因: {}", value, e.getMessage(), e);
|
||||
// return null; // 返回null表示不写入图片
|
||||
return new WriteCellData<>(new byte[0]); // 返回空数组而不是 null
|
||||
}
|
||||
@ -66,9 +106,17 @@ public class IgnoreFailedImageConverter implements Converter<URL> {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
int totalBytes = 0;
|
||||
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
totalBytes += bytesRead;
|
||||
|
||||
// 如果读取的数据过大,提前终止
|
||||
if (totalBytes > 10 * 1024 * 1024) { // 10MB限制
|
||||
logger.warn("读取的图片数据超过10MB限制,提前终止");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return outputStream.toByteArray();
|
||||
|
||||
@ -69,4 +69,9 @@ public class DeviceFenceAccessRecord extends BaseEntity {
|
||||
*/
|
||||
private Date eventTime;
|
||||
|
||||
/**
|
||||
* 事件地址
|
||||
*/
|
||||
private String eventAddress;
|
||||
|
||||
}
|
||||
|
||||
@ -114,5 +114,9 @@ public class DeviceAlarmBo extends TenantEntity {
|
||||
*/
|
||||
private Integer treatmentState;
|
||||
|
||||
/**
|
||||
* 告警状态,0 解除告警, 1 告警中
|
||||
*/
|
||||
private Integer alarmState;
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.fuyuanshen.equipment.domain.bo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fuyuanshen.common.core.validate.AddGroup;
|
||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||
@ -8,7 +9,9 @@ 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;
|
||||
|
||||
/**
|
||||
@ -25,19 +28,24 @@ public class DeviceFenceAccessRecordBo extends BaseEntity {
|
||||
/**
|
||||
* 记录ID
|
||||
*/
|
||||
@NotNull(message = "记录ID不能为空", groups = { EditGroup.class })
|
||||
@NotNull(message = "记录ID不能为空", groups = {EditGroup.class})
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
@NotNull(message = "围栏ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@NotNull(message = "围栏ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long fenceId;
|
||||
|
||||
/**
|
||||
* 围栏名称
|
||||
*/
|
||||
private String fenceName;
|
||||
|
||||
/**
|
||||
* 设备标识
|
||||
*/
|
||||
@NotBlank(message = "设备标识不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@NotBlank(message = "设备标识不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
@ -48,19 +56,19 @@ public class DeviceFenceAccessRecordBo extends BaseEntity {
|
||||
/**
|
||||
* 事件类型
|
||||
*/
|
||||
@NotNull(message = "事件类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@NotNull(message = "事件类型不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long eventType;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
@NotNull(message = "纬度不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@NotNull(message = "纬度不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
@NotNull(message = "经度不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@NotNull(message = "经度不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
@ -71,9 +79,14 @@ public class DeviceFenceAccessRecordBo extends BaseEntity {
|
||||
/**
|
||||
* 事件时间
|
||||
*/
|
||||
@NotNull(message = "事件时间不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@NotNull(message = "事件时间不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Date eventTime;
|
||||
|
||||
/**
|
||||
* 事件地址
|
||||
*/
|
||||
private String eventAddress;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
|
||||
@ -19,24 +19,25 @@ import java.net.URL;
|
||||
@ContentRowHeight(100) // 内容行高
|
||||
public class DeviceExcelExportDTO {
|
||||
|
||||
@ExcelProperty("ID")
|
||||
private Long id;
|
||||
// @ExcelProperty("ID")
|
||||
// private Long id;
|
||||
|
||||
@ExcelProperty("设备类型")
|
||||
private Long deviceType;
|
||||
|
||||
// @ExcelProperty("设备类型")
|
||||
// private Long deviceType;
|
||||
|
||||
// @ExcelProperty("客户号")
|
||||
// private Long customerId;
|
||||
|
||||
@ExcelProperty("所属客户")
|
||||
private String customerName;
|
||||
// @ExcelProperty("所属客户")
|
||||
// private String customerName;
|
||||
|
||||
@ExcelProperty("设备名称")
|
||||
@ColumnWidth(20)
|
||||
private String deviceName;
|
||||
|
||||
@ExcelProperty(value = "设备图片", converter = IgnoreFailedImageConverter.class)
|
||||
@ColumnWidth(15) // 设置图片列宽度
|
||||
@ColumnWidth(30) // 设置图片列宽度
|
||||
private URL devicePic; // 使用URL类型
|
||||
|
||||
@ExcelProperty("设备MAC")
|
||||
@ -51,28 +52,37 @@ public class DeviceExcelExportDTO {
|
||||
@ColumnWidth(20)
|
||||
private String deviceImei;
|
||||
|
||||
@ExcelProperty("经度")
|
||||
private String longitude;
|
||||
@ExcelProperty("设备类型")
|
||||
@ColumnWidth(20)
|
||||
private String typeName;
|
||||
|
||||
@ExcelProperty("纬度")
|
||||
private String latitude;
|
||||
// @ExcelProperty("经度")
|
||||
// private String longitude;
|
||||
|
||||
// @ExcelProperty("纬度")
|
||||
// private String latitude;
|
||||
|
||||
/**
|
||||
* 绑定状态
|
||||
* 0 未绑定
|
||||
* 1 已绑定
|
||||
*/
|
||||
@ExcelProperty("绑定状态")
|
||||
@ColumnWidth(20)
|
||||
private String bindingStatus;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
@ColumnWidth(30)
|
||||
private String remark;
|
||||
|
||||
@ExcelProperty("设备类型名称")
|
||||
@ColumnWidth(20)
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
* 设备状态
|
||||
* 0 失效
|
||||
* 1 正常
|
||||
*/
|
||||
@ExcelProperty("设备状态")
|
||||
@ColumnWidth(20)
|
||||
private String deviceStatus;
|
||||
// @ExcelProperty("设备状态")
|
||||
// @ColumnWidth(20)
|
||||
// private String deviceStatus;
|
||||
|
||||
@ExcelProperty("创建时间")
|
||||
@ColumnWidth(20)
|
||||
|
||||
@ -16,24 +16,24 @@ import lombok.Data;
|
||||
@ContentRowHeight(100) // 内容行高
|
||||
public class DeviceExcelImportDTO {
|
||||
|
||||
@ExcelProperty("设备类型")
|
||||
private Long deviceType;
|
||||
|
||||
@ExcelProperty("客户号")
|
||||
private Long customerId;
|
||||
// @ExcelProperty("设备类型")
|
||||
// private Long deviceType;
|
||||
|
||||
@ExcelProperty("设备名称")
|
||||
@ColumnWidth(20)
|
||||
private String deviceName;
|
||||
|
||||
@ExcelProperty(value = "设备图片", converter = ByteArrayImageConverter.class)
|
||||
@ColumnWidth(15)
|
||||
private byte[] devicePic;
|
||||
@ExcelProperty("设备类型名称")
|
||||
private String typeName;
|
||||
|
||||
// 添加图片写入方法
|
||||
public void setDevicePicFromBytes(byte[] bytes) {
|
||||
this.devicePic = bytes;
|
||||
}
|
||||
// @ExcelProperty(value = "设备图片", converter = ByteArrayImageConverter.class)
|
||||
// @ColumnWidth(15)
|
||||
// private byte[] devicePic;
|
||||
//
|
||||
// // 添加图片写入方法
|
||||
// public void setDevicePicFromBytes(byte[] bytes) {
|
||||
// this.devicePic = bytes;
|
||||
// }
|
||||
|
||||
@ExcelProperty("设备MAC")
|
||||
@ColumnWidth(20)
|
||||
@ -43,24 +43,21 @@ public class DeviceExcelImportDTO {
|
||||
@ColumnWidth(20)
|
||||
private String deviceImei;
|
||||
|
||||
@ExcelProperty("设备SN")
|
||||
@ColumnWidth(20)
|
||||
private String deviceSn;
|
||||
@ExcelProperty("蓝牙名称")
|
||||
private String bluetoothName;
|
||||
|
||||
@ExcelProperty("经度")
|
||||
private String longitude;
|
||||
|
||||
@ExcelProperty("纬度")
|
||||
private String latitude;
|
||||
// @ExcelProperty("设备SN")
|
||||
// @ColumnWidth(20)
|
||||
// private String deviceSn;
|
||||
//
|
||||
// @ExcelProperty("经度")
|
||||
// private String longitude;
|
||||
//
|
||||
// @ExcelProperty("纬度")
|
||||
// private String latitude;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
@ColumnWidth(30)
|
||||
private String remark;
|
||||
|
||||
@ExcelProperty("设备类型名称")
|
||||
private String typeName;
|
||||
|
||||
@ExcelProperty("蓝牙名称")
|
||||
private String bluetoothName;
|
||||
|
||||
}
|
||||
@ -43,7 +43,6 @@ public class DeviceForm {
|
||||
@Schema(title = "蓝牙名称")
|
||||
private String bluetoothName;
|
||||
|
||||
|
||||
@Schema(title = "设备IMEI")
|
||||
private String deviceImei;
|
||||
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 报警统计信息
|
||||
*
|
||||
* @author: fuyuanshen
|
||||
* @date: 2025-09-27
|
||||
*/
|
||||
@Data
|
||||
public class AlarmStatisticsVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 正在报警数量(未处理的报警)
|
||||
*/
|
||||
private Integer activeAlarms = 0;
|
||||
|
||||
/**
|
||||
* 报警总数
|
||||
*/
|
||||
private Integer totalAlarms = 0;
|
||||
|
||||
/**
|
||||
* 已处理报警数量
|
||||
*/
|
||||
private Integer processedAlarms = 0;
|
||||
|
||||
/**
|
||||
* 强制报警数量
|
||||
* device_action = 0
|
||||
*/
|
||||
private Integer forcedAlarms = 0;
|
||||
|
||||
/**
|
||||
* 撞击闯入报警数量
|
||||
* device_action = 1
|
||||
*/
|
||||
private Integer intrusionImpactAlarms = 0;
|
||||
|
||||
/**
|
||||
* 手动报警数量
|
||||
* device_action = 2
|
||||
*/
|
||||
private Integer manualAlarms = 0;
|
||||
|
||||
/**
|
||||
* 电子围栏告警数量
|
||||
* device_action = 3
|
||||
*/
|
||||
private Integer geoFenceAlarms = 0;
|
||||
|
||||
}
|
||||
@ -90,13 +90,13 @@ public class DeviceAlarmVo implements Serializable {
|
||||
* 经度
|
||||
*/
|
||||
@ExcelProperty(value = "经度")
|
||||
private Long longitude;
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
@ExcelProperty(value = "纬度")
|
||||
private Long latitude;
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 报警位置
|
||||
@ -123,6 +123,7 @@ public class DeviceAlarmVo implements Serializable {
|
||||
private String durationTime;
|
||||
|
||||
/**
|
||||
* 处理状态
|
||||
* 0已处理,1未处理
|
||||
*/
|
||||
@ExcelProperty(value = "0已处理,1未处理")
|
||||
@ -135,5 +136,4 @@ public class DeviceAlarmVo implements Serializable {
|
||||
@Schema(name = "设备图片")
|
||||
private String devicePic;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 设备通讯方式统计Vo
|
||||
*
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-27
|
||||
*/
|
||||
@Data
|
||||
public class DeviceCommunicationModeStatisticsVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 通讯方式名称
|
||||
* 0:4G;1:蓝牙;2:4G&蓝牙
|
||||
*/
|
||||
private String communicationModeName;
|
||||
|
||||
/**
|
||||
* 通讯方式值
|
||||
* 0:4G;1:蓝牙;2:4G&蓝牙
|
||||
*/
|
||||
private Integer communicationModeValue;
|
||||
|
||||
/**
|
||||
* 设备总数
|
||||
*/
|
||||
private Integer totalDevices = 0;
|
||||
|
||||
/**
|
||||
* 异常设备数
|
||||
*/
|
||||
private Integer abnormalDevices = 0;
|
||||
}
|
||||
@ -77,13 +77,13 @@ public class DeviceFenceAccessRecordVo implements Serializable {
|
||||
* 纬度
|
||||
*/
|
||||
@ExcelProperty(value = "纬度")
|
||||
private Long latitude;
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
@ExcelProperty(value = "经度")
|
||||
private Long longitude;
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 定位精度
|
||||
@ -97,6 +97,12 @@ public class DeviceFenceAccessRecordVo implements Serializable {
|
||||
@ExcelProperty(value = "事件时间")
|
||||
private Date eventTime;
|
||||
|
||||
/**
|
||||
* 事件地址
|
||||
*/
|
||||
@ExcelProperty(value = "事件地址")
|
||||
private String eventAddress;
|
||||
|
||||
/**
|
||||
* 记录创建时间
|
||||
*/
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.DeviceGeoFence;
|
||||
import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 设备位置信息VO
|
||||
*
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-2714:33
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "设备位置信息VO")
|
||||
public class DeviceLocationVo {
|
||||
|
||||
@Schema(description = "设备ID")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
@Schema(description = "经度")
|
||||
private String longitude;
|
||||
|
||||
@Schema(description = "纬度")
|
||||
private String latitude;
|
||||
|
||||
@Schema(description = "设备是否在电子围栏内")
|
||||
private Boolean inFence;
|
||||
|
||||
@Schema(description = "进入的电子围栏信息")
|
||||
private DeviceGeoFence fenceInfo;
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 设备总览信息
|
||||
*
|
||||
* @author: fuyuanshen
|
||||
* @date: 2025-09-27
|
||||
*/
|
||||
@Data
|
||||
public class DeviceOverviewVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 设备总数
|
||||
*/
|
||||
private Integer totalDevices = 0;
|
||||
|
||||
/**
|
||||
* 在线设备数量
|
||||
*/
|
||||
private Integer onlineDevices = 0;
|
||||
|
||||
/**
|
||||
* 设备型号数量
|
||||
*/
|
||||
private Integer deviceTypes = 0;
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 设备使用频次统计Vo
|
||||
*
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-27
|
||||
*/
|
||||
@Data
|
||||
public class DeviceUsageFrequencyVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 使用频次
|
||||
*/
|
||||
private Integer frequency = 0;
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 每月告警统计信息
|
||||
*
|
||||
* @author: fuyuanshen
|
||||
* @date: 2025-09-27
|
||||
*/
|
||||
@Data
|
||||
public class MonthlyAlarmStatisticsVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 每月告警统计数据
|
||||
* key: 月份 (m1-m12)
|
||||
* value: 告警数量
|
||||
*/
|
||||
private Map<String, Integer> monthlyStatistics = new HashMap<>();
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
package com.fuyuanshen.equipment.domain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**天气信息视图对象
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-2715:25
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "天气信息视图对象")
|
||||
public class WeatherInfoVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 经度
|
||||
*/
|
||||
@Schema(description = "经度")
|
||||
private Double longitude;
|
||||
|
||||
/**
|
||||
* 纬度
|
||||
*/
|
||||
@Schema(description = "纬度")
|
||||
private Double latitude;
|
||||
|
||||
/**
|
||||
* 天气状况
|
||||
*/
|
||||
@Schema(description = "天气状况")
|
||||
private String weatherCondition;
|
||||
|
||||
/**
|
||||
* 天气描述
|
||||
*/
|
||||
@Schema(description = "天气描述")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 温度
|
||||
*/
|
||||
@Schema(description = "温度(摄氏度)")
|
||||
private Double temperature;
|
||||
|
||||
/**
|
||||
* 体感温度
|
||||
*/
|
||||
@Schema(description = "体感温度(摄氏度)")
|
||||
private Double feelsLike;
|
||||
|
||||
/**
|
||||
* 湿度
|
||||
*/
|
||||
@Schema(description = "湿度(%)")
|
||||
private Integer humidity;
|
||||
|
||||
/**
|
||||
* 气压
|
||||
*/
|
||||
@Schema(description = "气压(hPa)")
|
||||
private Double pressure;
|
||||
|
||||
/**
|
||||
* 能见度
|
||||
*/
|
||||
@Schema(description = "能见度(米)")
|
||||
private Integer visibility;
|
||||
|
||||
/**
|
||||
* 风速
|
||||
*/
|
||||
@Schema(description = "风速(m/s)")
|
||||
private Double windSpeed;
|
||||
|
||||
/**
|
||||
* 风向
|
||||
*/
|
||||
@Schema(description = "风向(度)")
|
||||
private Integer windDirection;
|
||||
|
||||
/**
|
||||
* 云量
|
||||
*/
|
||||
@Schema(description = "云量(%)")
|
||||
private Integer cloudiness;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@Schema(description = "数据更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@ -72,7 +72,7 @@ public class UploadDeviceDataListener implements ReadListener<DeviceExcelImportD
|
||||
// 设置图片数据
|
||||
byte[] imageData = rowImageMap.get(rowIndex);
|
||||
if (imageData != null) {
|
||||
recordWithImage.setDevicePicFromBytes(imageData);
|
||||
// recordWithImage.setDevicePicFromBytes(imageData);
|
||||
}
|
||||
|
||||
failedRecordsWithImages.add(recordWithImage);
|
||||
@ -125,7 +125,6 @@ public class UploadDeviceDataListener implements ReadListener<DeviceExcelImportD
|
||||
rowDeviceMap.put(rowIndex, device);
|
||||
rowDtoMap.put(rowIndex, data);
|
||||
rowIndexList.add(rowIndex);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -191,7 +190,8 @@ public class UploadDeviceDataListener implements ReadListener<DeviceExcelImportD
|
||||
if (device != null) {
|
||||
try {
|
||||
byte[] imageData = picture.getPictureData().getData();
|
||||
String extraValue = getCellValue(sheet, rowIndex, 4);
|
||||
// 表示Excel表格中的第3列(因为索引从0开始计算)
|
||||
String extraValue = getCellValue(sheet, rowIndex, 2);
|
||||
String imageUrl = uploadAndGenerateUrl(imageData, extraValue);
|
||||
device.setDevicePic(imageUrl);
|
||||
|
||||
|
||||
@ -4,10 +4,16 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.equipment.domain.DeviceAlarm;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceAlarmBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AlarmStatisticsVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.MonthlyAlarmStatisticsVo;
|
||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.MapKey;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 设备告警Mapper接口
|
||||
*
|
||||
@ -23,7 +29,7 @@ public interface DeviceAlarmMapper extends BaseMapperPlus<DeviceAlarm, DeviceAla
|
||||
* @param bo 设备告警
|
||||
* @return 设备告警
|
||||
*/
|
||||
Page<DeviceAlarmVo> selectVoPage( Page pageQuery,@Param("bo") DeviceAlarmBo bo);
|
||||
Page<DeviceAlarmVo> selectVoPage(Page pageQuery, @Param("bo") DeviceAlarmBo bo);
|
||||
|
||||
/**
|
||||
* 根据设备IMEI查询最新的一条告警数据
|
||||
@ -34,4 +40,25 @@ public interface DeviceAlarmMapper extends BaseMapperPlus<DeviceAlarm, DeviceAla
|
||||
DeviceAlarmVo selectLatestByDeviceImei(@Param("deviceImei") String deviceImei);
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
* 获取实时告警列表
|
||||
*
|
||||
* @return 设备告警列表
|
||||
*/
|
||||
List<DeviceAlarmVo> getRealtimeAlarm();
|
||||
|
||||
/**
|
||||
* 获取报警统计数据
|
||||
*
|
||||
* @return 报警统计数据
|
||||
*/
|
||||
AlarmStatisticsVo getAlarmStatistics();
|
||||
|
||||
/**
|
||||
* 获取最近一年每月告警统计数据
|
||||
*
|
||||
* @return 每月告警统计数据
|
||||
*/
|
||||
@MapKey("key")
|
||||
List<Map<String, Object>> getMonthlyAlarmStatistics();
|
||||
}
|
||||
@ -5,6 +5,7 @@ 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.bo.DeviceFenceAccessRecordBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@ -27,7 +28,25 @@ public interface DeviceFenceAccessRecordMapper extends BaseMapperPlus<DeviceFenc
|
||||
*/
|
||||
Page<DeviceFenceAccessRecordVo> selectVoPageWithFenceAndDeviceName(Page<DeviceFenceAccessRecord> page, @Param(Constants.WRAPPER) Wrapper<DeviceFenceAccessRecord> wrapper);
|
||||
|
||||
List<DeviceFenceAccessRecordVo> selectVoPageWithFenceAndDeviceName(@Param(Constants.WRAPPER) Wrapper<DeviceFenceAccessRecord> wrapper);
|
||||
List<DeviceFenceAccessRecordVo> selectVoPageWithFenceAndDeviceName(@Param(Constants.WRAPPER) Wrapper<DeviceFenceAccessRecord> wrapper,@Param("fenceName") String fenceName);
|
||||
|
||||
/**
|
||||
* 分页查询围栏进出记录列表(纯XML形式)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @return 围栏进出记录分页列表
|
||||
*/
|
||||
Page<DeviceFenceAccessRecordVo> selectVoPageByXml(Page<DeviceFenceAccessRecord> page, @Param("bo") DeviceFenceAccessRecordBo bo);
|
||||
|
||||
|
||||
/**
|
||||
* 查询设备最新的围栏记录
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 围栏记录
|
||||
*/
|
||||
DeviceFenceAccessRecordVo selectLatestRecordByDeviceId(String deviceId);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -105,6 +105,9 @@ public interface DeviceMapper extends BaseMapper<Device> {
|
||||
*/
|
||||
List<Map<String, Object>> getEquipmentUsageData(@Param("deviceTypeId") Long deviceTypeId, @Param("range") Integer range);
|
||||
|
||||
// 在DeviceMapper.java中添加方法
|
||||
DeviceOverviewVo getDeviceOverview();
|
||||
|
||||
// 在DeviceMapper.java中添加方法
|
||||
int getUsageDataForMonth(@Param("deviceId") Long deviceId,
|
||||
@Param("year") int year,
|
||||
@ -117,4 +120,19 @@ public interface DeviceMapper extends BaseMapper<Device> {
|
||||
* @return 设备信息
|
||||
*/
|
||||
Device selectDeviceByImei(@Param("deviceImei") String deviceImei);
|
||||
|
||||
/**
|
||||
* 获取设备通讯方式统计数据
|
||||
*
|
||||
* @return 通讯方式统计列表
|
||||
*/
|
||||
List<DeviceCommunicationModeStatisticsVo> getDeviceCommunicationModeStatistics();
|
||||
|
||||
/**
|
||||
* 获取设备使用频次统计
|
||||
*
|
||||
* @param days 天数
|
||||
* @return 设备使用频次统计列表
|
||||
*/
|
||||
List<DeviceUsageFrequencyVo> getDeviceUsageFrequency(@Param("days") int days);
|
||||
}
|
||||
@ -1,11 +1,13 @@
|
||||
package com.fuyuanshen.equipment.service;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.fuyuanshen.common.core.domain.PageResult;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.domain.DeviceType;
|
||||
import com.fuyuanshen.equipment.domain.dto.AppDeviceBo;
|
||||
import com.fuyuanshen.equipment.domain.form.DeviceForm;
|
||||
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
||||
@ -152,4 +154,49 @@ public interface DeviceService extends IService<Device> {
|
||||
* @return 设备信息
|
||||
*/
|
||||
Device selectDeviceByImei(String deviceImei);
|
||||
|
||||
/**
|
||||
* 获取设备总览数据
|
||||
*
|
||||
* @return 设备总览数据
|
||||
*/
|
||||
DeviceOverviewVo getDeviceOverview();
|
||||
|
||||
/**
|
||||
* 获取设备通讯方式统计数据
|
||||
*
|
||||
* @return 通讯方式统计数据列表
|
||||
*/
|
||||
List<DeviceCommunicationModeStatisticsVo> getDeviceCommunicationModeStatistics();
|
||||
|
||||
/**
|
||||
* 获取设备使用频次统计
|
||||
*
|
||||
* @param days 天数(近一个月: 30, 近半年: 180)
|
||||
* @return 设备使用频次统计列表
|
||||
*/
|
||||
List<DeviceUsageFrequencyVo> getDeviceUsageFrequency(int days);
|
||||
|
||||
/**
|
||||
* 根据设备IMEI更新设备的经纬度信息
|
||||
*
|
||||
* @param deviceImei 设备IMEI
|
||||
* @param longitude 经度
|
||||
* @param latitude 纬度
|
||||
* @return 是否更新成功
|
||||
*/
|
||||
boolean updateDeviceLocationByImei(String deviceImei, String longitude, String latitude);
|
||||
|
||||
|
||||
/**
|
||||
* 根据条件查询设备位置信息
|
||||
*
|
||||
* @param groupId 设备分组ID
|
||||
* @param deviceType 设备类型
|
||||
* @param deviceImei 设备IMEI
|
||||
* @return 设备位置信息列表
|
||||
*/
|
||||
List<DeviceLocationVo> getDeviceLocationInfo(Long groupId, Long deviceType, String deviceImei);
|
||||
|
||||
|
||||
}
|
||||
@ -1,12 +1,15 @@
|
||||
package com.fuyuanshen.equipment.service;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceAlarmBo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceAlarmBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AlarmStatisticsVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.MonthlyAlarmStatisticsVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 设备告警Service接口
|
||||
@ -75,4 +78,24 @@ public interface IDeviceAlarmService {
|
||||
DeviceAlarmVo queryLatestByDeviceImei(String deviceImei);
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
* 获取实时告警列表
|
||||
*
|
||||
* @return 设备告警列表
|
||||
*/
|
||||
List<DeviceAlarmVo> getRealtimeAlarm();
|
||||
|
||||
/**
|
||||
* 获取报警统计数据
|
||||
*
|
||||
* @return 报警统计数据
|
||||
*/
|
||||
AlarmStatisticsVo getAlarmStatistics();
|
||||
|
||||
/**
|
||||
* 获取最近一年每月告警统计数据
|
||||
*
|
||||
* @return 每月告警统计数据
|
||||
*/
|
||||
MonthlyAlarmStatisticsVo getMonthlyAlarmStatistics();
|
||||
}
|
||||
@ -1,7 +1,10 @@
|
||||
package com.fuyuanshen.equipment.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
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;
|
||||
@ -16,7 +19,7 @@ import java.util.List;
|
||||
* @author Lion Li
|
||||
* @date 2025-09-11
|
||||
*/
|
||||
public interface IDeviceGeoFenceService {
|
||||
public interface IDeviceGeoFenceService extends IService<DeviceGeoFence> {
|
||||
|
||||
/**
|
||||
* 查询电子围栏
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package com.fuyuanshen.equipment.service;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.vo.WeatherInfoVo;
|
||||
|
||||
/**天气信息服务接口
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-2715:26
|
||||
*/
|
||||
public interface IWeatherService {
|
||||
|
||||
/**
|
||||
* 根据经纬度获取天气信息
|
||||
*
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
* @return 天气信息
|
||||
*/
|
||||
WeatherInfoVo getWeatherByCoordinates(Double latitude, Double longitude);
|
||||
|
||||
}
|
||||
@ -12,7 +12,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceAlarmBo;
|
||||
import com.fuyuanshen.equipment.domain.vo.AlarmStatisticsVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.MonthlyAlarmStatisticsVo;
|
||||
import com.fuyuanshen.equipment.domain.DeviceAlarm;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceAlarmMapper;
|
||||
import com.fuyuanshen.equipment.service.IDeviceAlarmService;
|
||||
@ -20,6 +22,7 @@ import com.fuyuanshen.equipment.service.IDeviceAlarmService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* 设备告警Service业务层处理
|
||||
@ -161,4 +164,51 @@ public class DeviceAlarmServiceImpl implements IDeviceAlarmService {
|
||||
return baseMapper.selectLatestByDeviceImei(deviceImei);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实时告警列表
|
||||
*
|
||||
* @return 设备告警列表
|
||||
*/
|
||||
@Override
|
||||
public List<DeviceAlarmVo> getRealtimeAlarm() {
|
||||
return baseMapper.getRealtimeAlarm();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取报警统计数据
|
||||
*
|
||||
* @return 报警统计数据
|
||||
*/
|
||||
@Override
|
||||
public AlarmStatisticsVo getAlarmStatistics() {
|
||||
return baseMapper.getAlarmStatistics();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近一年每月告警统计数据
|
||||
*
|
||||
* @return 每月告警统计数据
|
||||
*/
|
||||
@Override
|
||||
public MonthlyAlarmStatisticsVo getMonthlyAlarmStatistics() {
|
||||
List<Map<String, Object>> result = baseMapper.getMonthlyAlarmStatistics();
|
||||
MonthlyAlarmStatisticsVo vo = new MonthlyAlarmStatisticsVo();
|
||||
|
||||
if (result != null && !result.isEmpty()) {
|
||||
Map<String, Object> data = result.get(0);
|
||||
Map<String, Integer> monthlyStats = vo.getMonthlyStatistics();
|
||||
|
||||
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
// 将数据库查询结果转换为Integer类型
|
||||
Integer count = (value != null) ? Integer.valueOf(value.toString()) : 0;
|
||||
monthlyStats.put(key, count);
|
||||
}
|
||||
}
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,6 +5,7 @@ import com.alibaba.excel.util.DateUtils;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.domain.dto.DeviceExcelExportDTO;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -20,6 +21,7 @@ import java.util.stream.Collectors;
|
||||
* @date: 2025-06-0618:22
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class DeviceExportService {
|
||||
|
||||
public void export(List<Device> devices, HttpServletResponse response) {
|
||||
@ -36,22 +38,24 @@ public class DeviceExportService {
|
||||
// 转换为DTO列表
|
||||
List<DeviceExcelExportDTO> dtoList = devices.stream().map(device -> {
|
||||
DeviceExcelExportDTO dto = new DeviceExcelExportDTO();
|
||||
dto.setId(device.getId());
|
||||
dto.setDeviceType(device.getDeviceType());
|
||||
dto.setCustomerName(device.getCustomerName());
|
||||
// dto.setId(device.getId());
|
||||
// dto.setDeviceType(device.getDeviceType());
|
||||
// dto.setCustomerName(device.getCustomerName());
|
||||
dto.setDeviceName(device.getDeviceName());
|
||||
dto.setDeviceMac(device.getDeviceMac());
|
||||
// 设备IMEI
|
||||
dto.setDeviceImei(device.getDeviceImei());
|
||||
// 蓝牙名称
|
||||
dto.setBluetoothName(device.getBluetoothName());
|
||||
dto.setLongitude(device.getLongitude());
|
||||
dto.setLatitude(device.getLatitude());
|
||||
// dto.setLongitude(device.getLongitude());
|
||||
// dto.setLatitude(device.getLatitude());
|
||||
dto.setRemark(device.getRemark());
|
||||
dto.setTypeName(device.getTypeName());
|
||||
dto.setCreateBy(device.getCreateByName());
|
||||
Integer deviceStatus = device.getDeviceStatus();
|
||||
dto.setDeviceStatus(deviceStatus == 1 ? "正常" : "失效");
|
||||
Integer bindingStatus = device.getBindingStatus();
|
||||
// dto.setDeviceStatus(deviceStatus == 1 ? "正常" : "失效");
|
||||
dto.setBindingStatus(bindingStatus == 1 ? "已绑定" : "未绑定");
|
||||
// 时间戳转换
|
||||
dto.setCreateTime(DateUtils.format(device.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
@ -72,17 +76,31 @@ public class DeviceExportService {
|
||||
|
||||
private void handleDevicePic(Device device, DeviceExcelExportDTO dto) {
|
||||
String picUrl = device.getDevicePic();
|
||||
log.info("处理设备图片,设备ID: {}, 图片URL: {}", device.getId(), picUrl);
|
||||
|
||||
if (picUrl != null && !picUrl.trim().isEmpty()) {
|
||||
try {
|
||||
// 自动将HTTP转换为HTTPS以避免重定向问题
|
||||
if (picUrl.startsWith("http://")) {
|
||||
picUrl = "https://" + picUrl.substring(7);
|
||||
log.info("自动将HTTP转换为HTTPS: {}", picUrl);
|
||||
}
|
||||
|
||||
// 尝试创建URL对象(会自动验证格式)
|
||||
dto.setDevicePic(new URL(picUrl));
|
||||
} catch (MalformedURLException e) {
|
||||
URL url = new URL(picUrl);
|
||||
|
||||
dto.setDevicePic(url);
|
||||
log.info("成功设置设备图片URL到DTO");
|
||||
} catch (Exception e) {
|
||||
// 不是有效URL时设置为null
|
||||
log.info("设置设备图片失败,设备ID: {}, URL: {}, 错误: {}", device.getId(), picUrl, e.getMessage());
|
||||
dto.setDevicePic(null);
|
||||
}
|
||||
} else {
|
||||
log.info("设备没有设置图片,设备ID: {}", device.getId());
|
||||
dto.setDevicePic(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -54,7 +54,8 @@ public class DeviceFenceAccessRecordServiceImpl implements IDeviceFenceAccessRec
|
||||
@Override
|
||||
public TableDataInfo<DeviceFenceAccessRecordVo> queryPageList(DeviceFenceAccessRecordBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<DeviceFenceAccessRecord> lqw = buildQueryWrapper(bo);
|
||||
Page<DeviceFenceAccessRecordVo> result = baseMapper.selectVoPageWithFenceAndDeviceName(pageQuery.build(), lqw);
|
||||
// Page<DeviceFenceAccessRecordVo> result = baseMapper.selectVoPageWithFenceAndDeviceName(pageQuery.build(), lqw);
|
||||
Page<DeviceFenceAccessRecordVo> result = baseMapper.selectVoPageByXml(pageQuery.build(), bo);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@ -68,7 +69,7 @@ public class DeviceFenceAccessRecordServiceImpl implements IDeviceFenceAccessRec
|
||||
@Override
|
||||
public List<DeviceFenceAccessRecordVo> queryList(DeviceFenceAccessRecordBo bo) {
|
||||
LambdaQueryWrapper<DeviceFenceAccessRecord> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoPageWithFenceAndDeviceName(lqw);
|
||||
return baseMapper.selectVoPageWithFenceAndDeviceName(lqw, bo.getFenceName());
|
||||
}
|
||||
|
||||
|
||||
@ -85,6 +86,7 @@ public class DeviceFenceAccessRecordServiceImpl implements IDeviceFenceAccessRec
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.fuyuanshen.equipment.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||
@ -8,6 +9,7 @@ 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.Device;
|
||||
import com.fuyuanshen.equipment.domain.DeviceGeoFence;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceStatusBo;
|
||||
@ -17,10 +19,12 @@ import com.fuyuanshen.equipment.domain.query.FenceCheckRequest;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceFenceStatusVo;
|
||||
import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceGeoFenceMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.equipment.service.IDeviceFenceAccessRecordService;
|
||||
import com.fuyuanshen.equipment.service.IDeviceFenceStatusService;
|
||||
import com.fuyuanshen.equipment.service.IDeviceGeoFenceService;
|
||||
import com.fuyuanshen.equipment.utils.map.GeoFenceChecker;
|
||||
import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -37,7 +41,7 @@ import java.util.*;
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService {
|
||||
public class DeviceGeoFenceServiceImpl extends ServiceImpl<DeviceGeoFenceMapper, DeviceGeoFence> implements IDeviceGeoFenceService {
|
||||
|
||||
private final DeviceGeoFenceMapper baseMapper;
|
||||
|
||||
@ -240,6 +244,9 @@ public class DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService {
|
||||
recordBo.setFenceId(fence.getId());
|
||||
recordBo.setLatitude(request.getLatitude());
|
||||
recordBo.setLongitude(request.getLongitude());
|
||||
String address = GetAddressFromLatUtil.getAdd(request.getLongitude().toString(), request.getLatitude().toString());
|
||||
recordBo.setEventAddress(address);
|
||||
|
||||
recordBo.setEventTime(new Date());
|
||||
// 1表示进入围栏,2表示离开围栏
|
||||
recordBo.setEventType(currentStatus);
|
||||
|
||||
@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.fuyuanshen.common.core.domain.model.LoginUser;
|
||||
import com.fuyuanshen.common.core.exception.BadRequestException;
|
||||
import com.fuyuanshen.common.core.utils.SpringUtils;
|
||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||
@ -19,11 +20,10 @@ import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||
import com.fuyuanshen.customer.domain.Customer;
|
||||
import com.fuyuanshen.customer.mapper.CustomerMapper;
|
||||
import com.fuyuanshen.equipment.constants.DeviceConstants;
|
||||
import com.fuyuanshen.equipment.domain.Device;
|
||||
import com.fuyuanshen.equipment.domain.DeviceAssignments;
|
||||
import com.fuyuanshen.equipment.domain.DeviceType;
|
||||
import com.fuyuanshen.equipment.domain.DeviceTypeGrants;
|
||||
import com.fuyuanshen.equipment.domain.*;
|
||||
import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo;
|
||||
import com.fuyuanshen.equipment.domain.dto.AppDeviceBo;
|
||||
import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse;
|
||||
import com.fuyuanshen.equipment.domain.form.DeviceForm;
|
||||
import com.fuyuanshen.equipment.domain.query.DeviceAssignmentQuery;
|
||||
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
||||
@ -32,13 +32,8 @@ import com.fuyuanshen.equipment.domain.vo.*;
|
||||
import com.fuyuanshen.equipment.enums.BindingStatusEnum;
|
||||
import com.fuyuanshen.equipment.enums.CommunicationModeEnum;
|
||||
import com.fuyuanshen.equipment.enums.DeviceActiveStatusEnum;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceAssignmentsMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceTypeGrantsMapper;
|
||||
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
|
||||
import com.fuyuanshen.equipment.service.DeviceAssignmentsService;
|
||||
import com.fuyuanshen.equipment.service.DeviceService;
|
||||
import com.fuyuanshen.equipment.service.DeviceTypeGrantsService;
|
||||
import com.fuyuanshen.equipment.mapper.*;
|
||||
import com.fuyuanshen.equipment.service.*;
|
||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||
import com.fuyuanshen.system.domain.vo.SysRoleVo;
|
||||
import com.fuyuanshen.system.service.ISysOssService;
|
||||
@ -88,6 +83,8 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
private final DeviceTypeGrantsService deviceTypeGrantsService;
|
||||
private final DeviceTypeGrantsMapper deviceTypeGrantsMapper;
|
||||
|
||||
private final DeviceFenceAccessRecordMapper deviceFenceAccessRecordMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询设备
|
||||
@ -139,8 +136,27 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
|
||||
@Override
|
||||
public List<Device> queryAll(DeviceQueryCriteria criteria) {
|
||||
criteria.setCurrentOwnerId(LoginHelper.getUserId());
|
||||
|
||||
// 角色管理员
|
||||
Long userId = LoginHelper.getUserId();
|
||||
List<SysRoleVo> roles = roleService.selectRolesAuthByUserId(userId);
|
||||
boolean isAdmin = false;
|
||||
if (CollectionUtil.isNotEmpty(roles)) {
|
||||
for (SysRoleVo role : roles) {
|
||||
if (role.getRoleKey().equals("admin")) {
|
||||
isAdmin = true;
|
||||
criteria.setIsAdmin(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 只有非admin用户才设置当前用户ID条件
|
||||
if (!isAdmin) {
|
||||
criteria.setCurrentOwnerId(LoginHelper.getUserId());
|
||||
}
|
||||
return deviceMapper.findAll(criteria);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -684,4 +700,120 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
|
||||
return baseMapper.selectDeviceByImei(deviceImei);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备总览
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public DeviceOverviewVo getDeviceOverview() {
|
||||
return deviceMapper.getDeviceOverview();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备通讯方式统计
|
||||
*
|
||||
* @return 设备通讯方式统计列表
|
||||
*/
|
||||
@Override
|
||||
public List<DeviceCommunicationModeStatisticsVo> getDeviceCommunicationModeStatistics() {
|
||||
return deviceMapper.getDeviceCommunicationModeStatistics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceUsageFrequencyVo> getDeviceUsageFrequency(int days) {
|
||||
return deviceMapper.getDeviceUsageFrequency(days);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备IMEI更新设备的经纬度信息
|
||||
*
|
||||
* @param deviceImei 设备IMEI
|
||||
* @param longitude 经度
|
||||
* @param latitude 纬度
|
||||
* @return 是否更新成功
|
||||
*/
|
||||
@Override
|
||||
public boolean updateDeviceLocationByImei(String deviceImei, String longitude, String latitude) {
|
||||
// 根据设备IMEI查询设备
|
||||
Device device = deviceMapper.selectDeviceByImei(deviceImei);
|
||||
if (device == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新设备的经纬度信息
|
||||
device.setLongitude(longitude);
|
||||
device.setLatitude(latitude);
|
||||
|
||||
// 更新数据库中的设备信息
|
||||
return deviceMapper.updateById(device) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据条件查询设备位置信息
|
||||
*
|
||||
* @param groupId 设备分组ID
|
||||
* @param deviceType 设备类型
|
||||
* @param deviceImei 设备IMEI
|
||||
* @return 设备位置信息列表
|
||||
*/
|
||||
@Override
|
||||
public List<DeviceLocationVo> getDeviceLocationInfo(Long groupId, Long deviceType, String deviceImei) {
|
||||
// 构建查询条件
|
||||
DeviceQueryCriteria criteria = new DeviceQueryCriteria();
|
||||
criteria.setGroupId(groupId);
|
||||
criteria.setDeviceType(deviceType);
|
||||
criteria.setDeviceImei(deviceImei);
|
||||
|
||||
// 查询符合条件的设备
|
||||
List<Device> devices = deviceMapper.findDevices(criteria);
|
||||
|
||||
// 构建返回结果
|
||||
List<DeviceLocationVo> result = new ArrayList<>();
|
||||
|
||||
// 注入电子围栏服务
|
||||
IDeviceGeoFenceService geoFenceService = SpringUtils.getBean(IDeviceGeoFenceService.class);
|
||||
|
||||
for (Device device : devices) {
|
||||
DeviceLocationVo vo = new DeviceLocationVo();
|
||||
vo.setDeviceId(device.getId());
|
||||
vo.setDeviceName(device.getDeviceName());
|
||||
vo.setLongitude(device.getLongitude());
|
||||
vo.setLatitude(device.getLatitude());
|
||||
|
||||
// 检查设备是否在电子围栏内
|
||||
if (StringUtils.isNotBlank(device.getLongitude()) && StringUtils.isNotBlank(device.getLatitude())) {
|
||||
// 查询设备最新的围栏进出记录
|
||||
DeviceFenceAccessRecordVo latestRecord = deviceFenceAccessRecordMapper.selectLatestRecordByDeviceId(String.valueOf(device.getId()));
|
||||
|
||||
// 判断是否在围栏内
|
||||
if (latestRecord != null) {
|
||||
// 如果最新的记录是进入围栏(事件类型为1),则设备在围栏内
|
||||
if (latestRecord.getEventType() != null && latestRecord.getEventType() == 1L) {
|
||||
vo.setInFence(true);
|
||||
|
||||
// 获取围栏完整信息
|
||||
DeviceGeoFence fenceInfo = geoFenceService.getById(latestRecord.getFenceId());
|
||||
if (fenceInfo != null) {
|
||||
vo.setFenceInfo(fenceInfo);
|
||||
}
|
||||
} else {
|
||||
vo.setInFence(false);
|
||||
}
|
||||
} else {
|
||||
vo.setInFence(false);
|
||||
}
|
||||
} else {
|
||||
vo.setInFence(false);
|
||||
}
|
||||
|
||||
result.add(vo);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -98,18 +98,35 @@ public class DeviceTypeServiceImpl extends ServiceImpl<DeviceTypeMapper, DeviceT
|
||||
public List<DeviceType> queryDeviceTypes() {
|
||||
DeviceTypeQueryCriteria criteria = new DeviceTypeQueryCriteria();
|
||||
|
||||
// 管理员
|
||||
String username = LoginHelper.getUsername();
|
||||
if (!username.equals("admin")) {
|
||||
criteria.setCustomerId(LoginHelper.getUserId());
|
||||
// // 管理员
|
||||
// String username = LoginHelper.getUsername();
|
||||
// if (!username.equals("admin")) {
|
||||
// criteria.setCustomerId(LoginHelper.getUserId());
|
||||
//
|
||||
// Long userId = LoginHelper.getUserId();
|
||||
// criteria.setCustomerId(userId);
|
||||
// }
|
||||
|
||||
Long userId = LoginHelper.getUserId();
|
||||
criteria.setCustomerId(userId);
|
||||
// 角色管理员
|
||||
Long userId = LoginHelper.getUserId();
|
||||
List<SysRoleVo> roles = roleService.selectRolesAuthByUserId(userId);
|
||||
boolean isAdmin = false;
|
||||
if (CollectionUtil.isNotEmpty(roles)) {
|
||||
for (SysRoleVo role : roles) {
|
||||
if (role.getRoleKey().contains("admin")) {
|
||||
isAdmin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isAdmin) {
|
||||
criteria.setCustomerId(LoginHelper.getUserId());
|
||||
}
|
||||
|
||||
return deviceTypeMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据设备类型名称查询设备类型
|
||||
*
|
||||
@ -119,7 +136,23 @@ public class DeviceTypeServiceImpl extends ServiceImpl<DeviceTypeMapper, DeviceT
|
||||
@Override
|
||||
public DeviceType queryByName(String typeName) {
|
||||
DeviceTypeQueryCriteria criteria = new DeviceTypeQueryCriteria();
|
||||
criteria.setCustomerId(LoginHelper.getUserId());
|
||||
|
||||
// 角色管理员
|
||||
Long userId = LoginHelper.getUserId();
|
||||
List<SysRoleVo> roles = roleService.selectRolesAuthByUserId(userId);
|
||||
boolean isAdmin = false;
|
||||
if (CollectionUtil.isNotEmpty(roles)) {
|
||||
for (SysRoleVo role : roles) {
|
||||
if (role.getRoleKey().contains("admin")) {
|
||||
isAdmin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isAdmin) {
|
||||
criteria.setCustomerId(LoginHelper.getUserId());
|
||||
}
|
||||
|
||||
criteria.setTypeName(typeName);
|
||||
DeviceType deviceType = deviceTypeMapper.queryByName(criteria);
|
||||
return deviceType;
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
package com.fuyuanshen.equipment.service.impl;
|
||||
|
||||
import com.fuyuanshen.equipment.domain.vo.WeatherInfoVo;
|
||||
import com.fuyuanshen.equipment.service.IWeatherService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**天气信息服务实现类
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-09-2715:26
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class WeatherServiceImpl implements IWeatherService {
|
||||
|
||||
// 这里使用OpenWeatherMap API作为示例
|
||||
private static final String WEATHER_API_URL = "http://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={appid}&units=metric&lang=zh_cn";
|
||||
|
||||
// 需要在配置文件中配置API密钥
|
||||
private final String apiKey = ""; // 从配置文件获取
|
||||
|
||||
@Override
|
||||
public WeatherInfoVo getWeatherByCoordinates(Double latitude, Double longitude) {
|
||||
try {
|
||||
// 注意:实际使用时需要配置API密钥并启用以下代码
|
||||
/*
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
String url = WEATHER_API_URL.replace("{lat}", latitude.toString())
|
||||
.replace("{lon}", longitude.toString())
|
||||
.replace("{appid}", apiKey);
|
||||
|
||||
// 调用第三方API获取天气数据
|
||||
// 这里需要根据实际API返回的数据结构进行解析
|
||||
// 以下为示例代码,实际实现需要根据API文档调整
|
||||
|
||||
WeatherInfoVo weatherInfo = new WeatherInfoVo();
|
||||
weatherInfo.setLatitude(latitude);
|
||||
weatherInfo.setLongitude(longitude);
|
||||
weatherInfo.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
// 模拟数据,实际应从API获取
|
||||
weatherInfo.setWeatherCondition("晴");
|
||||
weatherInfo.setDescription("晴朗");
|
||||
weatherInfo.setTemperature(25.0);
|
||||
weatherInfo.setFeelsLike(26.0);
|
||||
weatherInfo.setHumidity(60);
|
||||
weatherInfo.setPressure(1013.0);
|
||||
weatherInfo.setVisibility(10000);
|
||||
weatherInfo.setWindSpeed(2.5);
|
||||
weatherInfo.setWindDirection(180);
|
||||
weatherInfo.setCloudiness(0);
|
||||
|
||||
return weatherInfo;
|
||||
*/
|
||||
|
||||
// 临时返回模拟数据
|
||||
WeatherInfoVo weatherInfo = new WeatherInfoVo();
|
||||
weatherInfo.setLatitude(latitude);
|
||||
weatherInfo.setLongitude(longitude);
|
||||
weatherInfo.setWeatherCondition("晴");
|
||||
weatherInfo.setDescription("晴朗");
|
||||
weatherInfo.setTemperature(25.0);
|
||||
weatherInfo.setFeelsLike(26.0);
|
||||
weatherInfo.setHumidity(60);
|
||||
weatherInfo.setPressure(1013.0);
|
||||
weatherInfo.setVisibility(10000);
|
||||
weatherInfo.setWindSpeed(2.5);
|
||||
weatherInfo.setWindDirection(180);
|
||||
weatherInfo.setCloudiness(0);
|
||||
weatherInfo.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
return weatherInfo;
|
||||
} catch (Exception e) {
|
||||
log.error("获取天气信息失败,经纬度: {},{}", latitude, longitude, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,8 @@ import org.slf4j.LoggerFactory;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* 根据经纬度获取地址信息工具类
|
||||
*
|
||||
* @author: 默苍璃
|
||||
* @date: 2025-07-2615:59
|
||||
*/
|
||||
@ -74,5 +76,6 @@ public class GetAddressFromLatUtil {
|
||||
System.out.println("通过API获取到具体位置:" + res);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,8 @@
|
||||
left join device_type dt on dt.id = d.device_type
|
||||
<where>
|
||||
<if test="bo.content != null">
|
||||
and d.device_name like concat('%', #{bo.content}, '%') or dt.type_name like concat('%', #{bo.content}, '%')
|
||||
and d.device_name like concat('%', #{bo.content}, '%') or dt.type_name like concat('%', #{bo.content},
|
||||
'%')
|
||||
</if>
|
||||
<if test="bo.deviceName != null">
|
||||
and d.device_name like concat('%', #{bo.deviceName}, '%')
|
||||
@ -29,9 +30,10 @@
|
||||
and da.treatment_state = #{bo.treatmentState}
|
||||
</if>
|
||||
<if test="bo.queryTime1 != null and bo.queryTime2 != null ">
|
||||
and da.start_time between #{bo.queryTime1} and #{bo.queryTime2}
|
||||
and da.start_time BETWEEN #{bo.queryTime1} AND #{bo.queryTime2}
|
||||
</if>
|
||||
</where>
|
||||
order by da.create_time DESC
|
||||
</select>
|
||||
|
||||
|
||||
@ -50,4 +52,52 @@
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
<!-- 获取实时告警列表 -->
|
||||
<select id="getRealtimeAlarm" resultType="com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo">
|
||||
select da.*,
|
||||
d.device_mac as deviceMac,
|
||||
d.device_imei as deviceImei,
|
||||
d.device_name as deviceName,
|
||||
d.device_type as deviceType,
|
||||
d.type_name as deviceTypeName,
|
||||
d.device_pic as devicePic
|
||||
from device_alarm da
|
||||
left join device d on da.device_id = d.id
|
||||
left join device_type dt on dt.id = d.device_type
|
||||
WHERE da.treatment_state = 1
|
||||
order by da.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 获取报警统计数据 -->
|
||||
<select id="getAlarmStatistics" resultType="com.fuyuanshen.equipment.domain.vo.AlarmStatisticsVo">
|
||||
SELECT
|
||||
(SELECT COUNT(1) FROM device_alarm WHERE treatment_state = 1) AS activeAlarms,
|
||||
(SELECT COUNT(1) FROM device_alarm) AS totalAlarms,
|
||||
(SELECT COUNT(1) FROM device_alarm WHERE treatment_state = 0) AS processedAlarms,
|
||||
(SELECT COUNT(1) FROM device_alarm WHERE device_action = 0) AS forcedAlarms,
|
||||
(SELECT COUNT(1) FROM device_alarm WHERE device_action = 1) AS intrusionImpactAlarms,
|
||||
(SELECT COUNT(1) FROM device_alarm WHERE device_action = 2) AS manualAlarms,
|
||||
(SELECT COUNT(1) FROM device_alarm WHERE device_action = 3) AS geoFenceAlarms
|
||||
</select>
|
||||
|
||||
<!-- 获取最近一年每月告警统计数据 -->
|
||||
<select id="getMonthlyAlarmStatistics" resultType="map">
|
||||
SELECT
|
||||
COUNT(CASE WHEN MONTH(create_time) = 1 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m1,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 2 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m2,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 3 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m3,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 4 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m4,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 5 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m5,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 6 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m6,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 7 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m7,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 8 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m8,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 9 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m9,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 10 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m10,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 11 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m11,
|
||||
COUNT(CASE WHEN MONTH(create_time) = 12 AND create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) THEN 1 END) AS m12
|
||||
FROM device_alarm
|
||||
WHERE create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH)
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
@ -8,22 +8,99 @@
|
||||
<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
|
||||
r.fence_id,
|
||||
f.name AS fence_name,
|
||||
r.device_id,
|
||||
d.device_name,
|
||||
r.user_id,
|
||||
r.event_type,
|
||||
r.latitude,
|
||||
r.longitude,
|
||||
r.accuracy,
|
||||
r.event_time,
|
||||
r.create_time
|
||||
FROM device_fence_access_record r
|
||||
LEFT JOIN device_geo_fence f ON r.fence_id = f.id
|
||||
LEFT JOIN device d ON r.device_id = d.id
|
||||
${ew.customSqlSegment}
|
||||
LEFT JOIN device_geo_fence f ON r.fence_id = f.id
|
||||
LEFT JOIN device d ON r.device_id = d.id
|
||||
${ew.customSqlSegment}
|
||||
<where>
|
||||
<if test="fenceName != null and fenceName != ''">
|
||||
AND f.name LIKE CONCAT('%', #{fenceName}, '%')
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY r.id ASC
|
||||
</select>
|
||||
|
||||
|
||||
|
||||
<!-- 分页查询围栏进出记录列表(纯XML形式) -->
|
||||
<select id="selectVoPageByXml" 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.event_address,
|
||||
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>
|
||||
<if test="bo.fenceId != null">
|
||||
AND r.fence_id = #{bo.fenceId}
|
||||
</if>
|
||||
<if test="bo.deviceId != null and bo.deviceId != ''">
|
||||
AND r.device_id = #{bo.deviceId}
|
||||
</if>
|
||||
<if test="bo.userId != null">
|
||||
AND r.user_id = #{bo.userId}
|
||||
</if>
|
||||
<if test="bo.eventType != null">
|
||||
AND r.event_type = #{bo.eventType}
|
||||
</if>
|
||||
<if test="bo.latitude != null">
|
||||
AND r.latitude = #{bo.latitude}
|
||||
</if>
|
||||
<if test="bo.longitude != null">
|
||||
AND r.longitude = #{bo.longitude}
|
||||
</if>
|
||||
<if test="bo.accuracy != null">
|
||||
AND r.accuracy = #{bo.accuracy}
|
||||
</if>
|
||||
<if test="bo.eventTime != null">
|
||||
AND r.event_time = #{bo.eventTime}
|
||||
</if>
|
||||
<if test="bo.createTime != null">
|
||||
AND r.create_time = #{bo.createTime}
|
||||
</if>
|
||||
<if test="bo.fenceName != null and bo.fenceName != ''">
|
||||
AND f.name LIKE CONCAT('%', #{bo.fenceName}, '%')
|
||||
</if>
|
||||
<!-- 添加时间范围筛选条件 -->
|
||||
<if test="bo.beginTime != null and bo.beginTime != ''">
|
||||
AND r.event_time >= #{bo.beginTime}
|
||||
</if>
|
||||
<if test="bo.endTime != null and bo.endTime != ''">
|
||||
AND r.event_time <![CDATA[ <= ]]> #{bo.endTime}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY r.event_time DESC
|
||||
</select>
|
||||
|
||||
|
||||
<!-- 查询设备最新的围栏记录 -->
|
||||
<select id="selectLatestRecordByDeviceId" resultType="com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo">
|
||||
SELECT *
|
||||
FROM device_fence_access_record
|
||||
WHERE device_id = #{deviceId}
|
||||
ORDER BY event_time DESC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
@ -1,5 +1,5 @@
|
||||
<?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" >
|
||||
<?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.DeviceMapper">
|
||||
<resultMap id="BaseResultMap" type="com.fuyuanshen.equipment.domain.Device">
|
||||
<id column="id" property="id"/>
|
||||
@ -239,8 +239,7 @@
|
||||
where d.device_mac = #{deviceMac}
|
||||
</select>
|
||||
<select id="queryWebDeviceList" resultType="com.fuyuanshen.equipment.domain.vo.WebDeviceVo">
|
||||
select d.id, d.device_name, d.device_name,
|
||||
d.device_name,
|
||||
select * from (select d.id, d.device_name,
|
||||
d.device_mac,
|
||||
d.device_sn,
|
||||
d.device_imei,
|
||||
@ -252,40 +251,41 @@
|
||||
ap.name personnelBy,
|
||||
d.device_status,
|
||||
d.online_status,
|
||||
c.binding_time
|
||||
c.binding_time,
|
||||
ROW_NUMBER() OVER (PARTITION BY d.id ORDER BY c.binding_time) AS row_num
|
||||
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 and c.communication_mode = 0
|
||||
inner join app_device_bind_record c on d.id = c.device_id
|
||||
left join app_personnel_info ap on ap.device_id = d.id
|
||||
where dt.communication_mode in (0, 2)
|
||||
where dt.communication_mode in (0, 2) ) a where a.row_num = 1
|
||||
<if test="criteria.deviceType != null">
|
||||
and d.device_type = #{criteria.deviceType}
|
||||
and a.device_type = #{criteria.deviceType}
|
||||
</if>
|
||||
<if test="criteria.deviceName != null and criteria.deviceName != ''">
|
||||
and d.device_name like concat('%', #{criteria.deviceName}, '%')
|
||||
and a.device_name like concat('%', #{criteria.deviceName}, '%')
|
||||
</if>
|
||||
<if test="criteria.deviceImei != null and criteria.deviceImei != ''">
|
||||
and (d.device_imei = #{criteria.deviceImei}
|
||||
and a.device_imei = #{criteria.deviceImei}
|
||||
</if>
|
||||
<if test="criteria.content != null and criteria.content != ''">
|
||||
AND d.device_imei = #{criteria.content} or d.device_mac = #{criteria.content}
|
||||
AND (a.device_imei = #{criteria.content} or a.device_mac = #{criteria.content})
|
||||
</if>
|
||||
<if test="criteria.deviceStatus != null">
|
||||
and d.device_status = #{criteria.deviceStatus}
|
||||
and a.device_status = #{criteria.deviceStatus}
|
||||
</if>
|
||||
<if test="criteria.personnelBy != null and criteria.personnelBy != ''">
|
||||
and ap.name like concat('%', #{criteria.personnelBy}, '%')
|
||||
and a.personnelBy like concat('%', #{criteria.personnelBy}, '%')
|
||||
</if>
|
||||
<if test="criteria.communicationMode != null">
|
||||
and dt.communication_mode = #{criteria.communicationMode}
|
||||
and a.communication_mode = #{criteria.communicationMode}
|
||||
</if>
|
||||
<if test="criteria.groupId != null">
|
||||
and d.group_id = #{criteria.groupId}
|
||||
and a.group_id = #{criteria.groupId}
|
||||
</if>
|
||||
<if test="criteria.onlineStatus != null">
|
||||
and d.online_status = #{criteria.onlineStatus}
|
||||
and a.online_status = #{criteria.onlineStatus}
|
||||
</if>
|
||||
ORDER BY d.create_time DESC
|
||||
ORDER BY a.binding_time DESC
|
||||
</select>
|
||||
<select id="getLocationHistory" resultType="com.fuyuanshen.equipment.domain.vo.LocationHistoryVo">
|
||||
select a.id,a.device_name,a.device_type,b.type_name deviceTypeName,a.device_imei,a.device_mac from device a
|
||||
@ -319,6 +319,32 @@
|
||||
a.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 获取设备总览信息 -->
|
||||
<select id="getDeviceOverview" resultType="com.fuyuanshen.equipment.domain.vo.DeviceOverviewVo">
|
||||
SELECT (SELECT COUNT(1) FROM device) AS totalDevices,
|
||||
(SELECT COUNT(1) FROM device WHERE online_status = 1) AS onlineDevices,
|
||||
(SELECT COUNT(DISTINCT device_type) FROM device) AS deviceTypes
|
||||
</select>
|
||||
|
||||
<!-- 获取设备通讯方式统计数据 -->
|
||||
<select id="getDeviceCommunicationModeStatistics" resultType="com.fuyuanshen.equipment.domain.vo.DeviceCommunicationModeStatisticsVo">
|
||||
SELECT
|
||||
dt.communication_mode AS communicationModeValue,
|
||||
CASE
|
||||
WHEN dt.communication_mode = 0 THEN '4G'
|
||||
WHEN dt.communication_mode = 1 THEN '蓝牙'
|
||||
WHEN dt.communication_mode = 2 THEN '4G&蓝牙'
|
||||
ELSE '未知'
|
||||
END AS communicationModeName,
|
||||
COUNT(d.id) AS totalDevices,
|
||||
COUNT(CASE WHEN d.online_status = 2 THEN 1 END) AS abnormalDevices
|
||||
FROM device_type dt
|
||||
LEFT JOIN device d ON dt.id = d.device_type
|
||||
WHERE dt.communication_mode IN (0, 1, 2)
|
||||
GROUP BY dt.communication_mode
|
||||
ORDER BY dt.communication_mode
|
||||
</select>
|
||||
|
||||
<!-- 获取数据总览 -->
|
||||
<select id="getDataOverview" resultType="com.fuyuanshen.equipment.domain.vo.DataOverviewVo">
|
||||
SELECT (SELECT COUNT(1) FROM device) AS devicesNumber,
|
||||
@ -423,6 +449,17 @@
|
||||
AND MONTH (dl.create_time) = #{month}
|
||||
</select>
|
||||
|
||||
<!-- 获取设备使用频次统计 -->
|
||||
<select id="getDeviceUsageFrequency" resultType="com.fuyuanshen.equipment.domain.vo.DeviceUsageFrequencyVo">
|
||||
SELECT
|
||||
device_name AS deviceName,
|
||||
COUNT(*) AS frequency
|
||||
FROM device_log
|
||||
WHERE create_time >= DATE_SUB(NOW(), INTERVAL #{days} DAY)
|
||||
GROUP BY device_name
|
||||
ORDER BY frequency DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据设备IMEI查询设备 -->
|
||||
<select id="selectDeviceByImei" resultType="com.fuyuanshen.equipment.domain.Device">
|
||||
SELECT *
|
||||
|
||||
@ -49,8 +49,13 @@
|
||||
parameterType="com.fuyuanshen.equipment.domain.query.DeviceTypeQueryCriteria">
|
||||
SELECT dt.*, dg.id AS grant_id
|
||||
FROM device_type dt
|
||||
JOIN device_type_grants dg ON dt.id = dg.device_type_id
|
||||
WHERE dt.type_name = #{criteria.typeName}
|
||||
AND dg.customer_id = #{criteria.customerId}
|
||||
JOIN device_type_grants dg ON dt.id = dg.device_type_id
|
||||
<where>
|
||||
dt.type_name = #{criteria.typeName}
|
||||
<if test="criteria.customerId != null">
|
||||
and dg.customer_id = #{criteria.customerId}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user