融合通信电子围栏
parent
d9396f33d1
commit
3456c73183
|
|
@ -0,0 +1,67 @@
|
|||
package org.dromara.system.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.system.domain.bo.MapDeviceFenceRecordBo;
|
||||
import org.dromara.system.domain.vo.MapDeviceFenceRecordVo;
|
||||
import org.dromara.system.service.IMapDeviceFenceRecordService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备进出记录控制器
|
||||
*
|
||||
* @author luya
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/mapDeviceFenceRecord")
|
||||
public class MapDeviceFenceRecordController extends BaseController {
|
||||
|
||||
private final IMapDeviceFenceRecordService mapDeviceFenceRecordService;
|
||||
|
||||
/**
|
||||
* 查询设备进出记录列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<MapDeviceFenceRecordVo> list(MapDeviceFenceRecordBo bo, PageQuery pageQuery) {
|
||||
return mapDeviceFenceRecordService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出设备进出记录列表
|
||||
*/
|
||||
@PostMapping("/export")
|
||||
public void export(MapDeviceFenceRecordBo bo, HttpServletResponse response) throws IOException {
|
||||
List<MapDeviceFenceRecordVo> list = mapDeviceFenceRecordService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "设备进出记录", MapDeviceFenceRecordVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备进出记录详细信息
|
||||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public R<MapDeviceFenceRecordVo> getInfo(@PathVariable Long id) {
|
||||
return R.ok(mapDeviceFenceRecordService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备进出记录
|
||||
*/
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@PathVariable Long[] ids) {
|
||||
return toAjax(mapDeviceFenceRecordService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
|
|
@ -10,13 +10,17 @@ import org.dromara.common.mybatis.core.page.PageQuery;
|
|||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.system.domain.bo.MapPolygonBo;
|
||||
import org.dromara.system.domain.bo.MapPolygonDeviceBo;
|
||||
import org.dromara.system.domain.vo.MapPolygonDeviceVo;
|
||||
import org.dromara.system.domain.vo.MapPolygonVo;
|
||||
import org.dromara.system.service.IMapPolygonDeviceService;
|
||||
import org.dromara.system.service.IMapPolygonService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 电子围栏控制器
|
||||
|
|
@ -30,11 +34,11 @@ import java.util.List;
|
|||
public class MapPolygonController extends BaseController {
|
||||
|
||||
private final IMapPolygonService mapPolygonService;
|
||||
private final IMapPolygonDeviceService mapPolygonDeviceService;
|
||||
|
||||
/**
|
||||
* 查询电子围栏列表
|
||||
*/
|
||||
@SaCheckPermission("system:mapPolygon:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<MapPolygonVo> list(MapPolygonBo mapPolygonBo, PageQuery pageQuery) {
|
||||
return mapPolygonService.queryPageList(mapPolygonBo, pageQuery);
|
||||
|
|
@ -45,7 +49,6 @@ public class MapPolygonController extends BaseController {
|
|||
/**
|
||||
* 获取电子围栏详细信息
|
||||
*/
|
||||
@SaCheckPermission("system:mapPolygon:query")
|
||||
@GetMapping(value = "/{id}")
|
||||
public R<MapPolygonVo> getInfo(@PathVariable Integer id) {
|
||||
return R.ok(mapPolygonService.queryById(id));
|
||||
|
|
@ -54,8 +57,6 @@ public class MapPolygonController extends BaseController {
|
|||
/**
|
||||
* 新增电子围栏
|
||||
*/
|
||||
@SaCheckPermission("system:mapPolygon:add")
|
||||
@Log(title = "电子围栏管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated @RequestBody MapPolygonBo mapPolygonBo) {
|
||||
return toAjax(mapPolygonService.insertByBo(mapPolygonBo));
|
||||
|
|
@ -64,8 +65,6 @@ public class MapPolygonController extends BaseController {
|
|||
/**
|
||||
* 修改电子围栏
|
||||
*/
|
||||
@SaCheckPermission("system:mapPolygon:edit")
|
||||
@Log(title = "电子围栏管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated @RequestBody MapPolygonBo mapPolygonBo) {
|
||||
return toAjax(mapPolygonService.updateByBo(mapPolygonBo));
|
||||
|
|
@ -74,8 +73,6 @@ public class MapPolygonController extends BaseController {
|
|||
/**
|
||||
* 删除电子围栏
|
||||
*/
|
||||
@SaCheckPermission("system:mapPolygon:remove")
|
||||
@Log(title = "电子围栏管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@PathVariable Integer[] ids) {
|
||||
return toAjax(mapPolygonService.deleteWithValidByIds(List.of(ids), true));
|
||||
|
|
@ -84,12 +81,56 @@ public class MapPolygonController extends BaseController {
|
|||
/**
|
||||
* 修改状态
|
||||
*/
|
||||
@SaCheckPermission("system:mapPolygon:edit")
|
||||
@Log(title = "电子围栏管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus")
|
||||
public R<Void> changeStatus(@RequestBody MapPolygonBo mapPolygonBo) {
|
||||
return toAjax(mapPolygonService.updateStatus(mapPolygonBo.getId(), mapPolygonBo.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询围栏绑定的设备列表
|
||||
*/
|
||||
@GetMapping("/deviceList/{polygonId}")
|
||||
public R<List<MapPolygonDeviceVo>> getDeviceList(@PathVariable Integer polygonId) {
|
||||
return R.ok(mapPolygonDeviceService.queryDeviceListByPolygonId(polygonId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加围栏设备绑定
|
||||
*/
|
||||
@PostMapping("/device")
|
||||
public R<Void> addDevice(@Validated @RequestBody MapPolygonDeviceBo mapPolygonDeviceBo) {
|
||||
return toAjax(mapPolygonDeviceService.insertByBo(mapPolygonDeviceBo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加围栏设备绑定
|
||||
*/
|
||||
@PostMapping("/device/batch")
|
||||
public R<Void> batchAddDevice(@RequestBody Map<String, Object> params) {
|
||||
Integer polygonId = (Integer) params.get("polygonId");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> deviceCodes = (List<String>) params.get("deviceCodes");
|
||||
return toAjax(mapPolygonDeviceService.batchInsert(polygonId, deviceCodes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除围栏设备绑定
|
||||
*/
|
||||
@DeleteMapping("/device/{ids}")
|
||||
public R<Void> removeDevice(@PathVariable Long[] ids) {
|
||||
return toAjax(mapPolygonDeviceService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据围栏ID和设备编码列表删除绑定
|
||||
*/
|
||||
@DeleteMapping("/device/batch")
|
||||
public R<Void> batchRemoveDevice(@RequestBody Map<String, Object> params) {
|
||||
Integer polygonId = (Integer) params.get("polygonId");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> deviceCodes = (List<String>) params.get("deviceCodes");
|
||||
return toAjax(mapPolygonDeviceService.deleteByPolygonIdAndDeviceCodes(polygonId, deviceCodes));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
package org.dromara.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 设备进出记录实体
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@TableName("map_device_fence_record")
|
||||
public class MapDeviceFenceRecord implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备编码
|
||||
*/
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
private Integer polygonId;
|
||||
|
||||
/**
|
||||
* 围栏名称
|
||||
*/
|
||||
private String polygonName;
|
||||
|
||||
/**
|
||||
* 进出类型 0进入 1离开
|
||||
*/
|
||||
private Short inOutType;
|
||||
|
||||
/**
|
||||
* 规则类型 0禁入 1禁出
|
||||
*/
|
||||
private Short ruleType;
|
||||
|
||||
/**
|
||||
* 是否违规 0否 1是
|
||||
*/
|
||||
private Short violation;
|
||||
|
||||
/**
|
||||
* 位置坐标
|
||||
*/
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* 记录时间
|
||||
*/
|
||||
private LocalDateTime recordTime;
|
||||
|
||||
/**
|
||||
* GPS时间戳(毫秒)
|
||||
*/
|
||||
private Long gpsTime;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private String deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -7,15 +7,16 @@ import lombok.EqualsAndHashCode;
|
|||
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 电子围栏实体
|
||||
*
|
||||
* @author luya
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("map_polygon")
|
||||
public class MapPolygon extends BaseEntity {
|
||||
public class MapPolygon implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
@ -105,4 +106,4 @@ public class MapPolygon extends BaseEntity {
|
|||
*/
|
||||
private Integer range;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
|
||||
package org.dromara.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 电子围栏设备绑定实体
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@TableName("map_polygon_device")
|
||||
public class MapPolygonDevice implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
private Integer polygonId;
|
||||
|
||||
/**
|
||||
* 设备编码
|
||||
*/
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package org.dromara.system.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.system.domain.MapDeviceFenceRecord;
|
||||
|
||||
/**
|
||||
* 设备进出记录业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = MapDeviceFenceRecord.class, reverseConvertGenerate = false)
|
||||
public class MapDeviceFenceRecordBo extends MapDeviceFenceRecord {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 设备编码
|
||||
*/
|
||||
@NotNull(message = "设备编码不能为空")
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
@NotNull(message = "设备类型不能为空")
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
@NotNull(message = "围栏ID不能为空")
|
||||
private Integer polygonId;
|
||||
|
||||
/**
|
||||
* 进出类型 0进入 1离开
|
||||
*/
|
||||
@NotNull(message = "进出类型不能为空")
|
||||
private Short inOutType;
|
||||
|
||||
/**
|
||||
* 规则类型 0禁入 1禁出
|
||||
*/
|
||||
@NotNull(message = "规则类型不能为空")
|
||||
private Short ruleType;
|
||||
|
||||
/**
|
||||
* 是否违规 0否 1是
|
||||
*/
|
||||
@NotNull(message = "是否违规不能为空")
|
||||
private Short violation;
|
||||
|
||||
private String startTime;
|
||||
|
||||
private String endTime;
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
package org.dromara.system.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.system.domain.MapPolygonDevice;
|
||||
|
||||
/**
|
||||
* 电子围栏设备绑定业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = MapPolygonDevice.class, reverseConvertGenerate = false)
|
||||
public class MapPolygonDeviceBo extends MapPolygonDevice {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
@NotNull(message = "围栏ID不能为空")
|
||||
private Integer polygonId;
|
||||
|
||||
/**
|
||||
* 设备编码
|
||||
*/
|
||||
@NotBlank(message = "设备编码不能为空")
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
@NotBlank(message = "设备类型不能为空")
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
package org.dromara.system.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.system.domain.MapDeviceFenceRecord;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 设备进出记录视图对象
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = MapDeviceFenceRecord.class)
|
||||
public class MapDeviceFenceRecordVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 设备编码
|
||||
*/
|
||||
@ExcelProperty(value = "设备编码")
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
@ExcelProperty(value = "设备类型")
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 设备类型名称
|
||||
*/
|
||||
@ExcelProperty(value = "设备类型名称")
|
||||
private String deviceTypeName;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@ExcelProperty(value = "设备名称")
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
@ExcelProperty(value = "围栏ID")
|
||||
private Integer polygonId;
|
||||
|
||||
/**
|
||||
* 围栏名称
|
||||
*/
|
||||
@ExcelProperty(value = "围栏名称")
|
||||
private String polygonName;
|
||||
|
||||
/**
|
||||
* 进出类型 0进入 1离开
|
||||
*/
|
||||
@ExcelProperty(value = "进出类型")
|
||||
private Short inOutType;
|
||||
|
||||
/**
|
||||
* 进出类型名称
|
||||
*/
|
||||
@ExcelProperty(value = "进出类型名称")
|
||||
private String inOutTypeName;
|
||||
|
||||
/**
|
||||
* 规则类型 0禁入 1禁出
|
||||
*/
|
||||
@ExcelProperty(value = "规则类型")
|
||||
private Short ruleType;
|
||||
|
||||
/**
|
||||
* 规则类型名称
|
||||
*/
|
||||
@ExcelProperty(value = "规则类型名称")
|
||||
private String ruleTypeName;
|
||||
|
||||
/**
|
||||
* 是否违规 0否 1是
|
||||
*/
|
||||
@ExcelProperty(value = "是否违规")
|
||||
private Short violation;
|
||||
|
||||
/**
|
||||
* 是否违规名称
|
||||
*/
|
||||
@ExcelProperty(value = "是否违规名称")
|
||||
private String violationName;
|
||||
|
||||
/**
|
||||
* 位置坐标
|
||||
*/
|
||||
@ExcelProperty(value = "位置坐标")
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* 记录时间
|
||||
*/
|
||||
@ExcelProperty(value = "记录时间")
|
||||
private LocalDateTime recordTime;
|
||||
|
||||
/**
|
||||
* GPS时间戳(毫秒)
|
||||
*/
|
||||
@ExcelProperty(value = "GPS时间")
|
||||
private Long gpsTime;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@ExcelProperty(value = "部门ID")
|
||||
private String deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@ExcelProperty(value = "部门名称")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
package org.dromara.system.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.system.domain.MapPolygonDevice;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 电子围栏设备绑定视图对象
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = MapPolygonDevice.class)
|
||||
public class MapPolygonDeviceVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 围栏ID
|
||||
*/
|
||||
@ExcelProperty(value = "围栏ID")
|
||||
private Integer polygonId;
|
||||
|
||||
/**
|
||||
* 围栏名称
|
||||
*/
|
||||
@ExcelProperty(value = "围栏名称")
|
||||
private String polygonName;
|
||||
|
||||
/**
|
||||
* 设备编码
|
||||
*/
|
||||
@ExcelProperty(value = "设备编码")
|
||||
private String deviceCode;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
@ExcelProperty(value = "设备类型")
|
||||
private String deviceType;
|
||||
|
||||
/**
|
||||
* 设备类型名称
|
||||
*/
|
||||
@ExcelProperty(value = "设备类型名称")
|
||||
private String deviceTypeName;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@ExcelProperty(value = "创建者")
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ExcelProperty(value = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@ExcelProperty(value = "更新者")
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.system.domain.MapDeviceFenceRecord;
|
||||
import org.dromara.system.domain.vo.MapDeviceFenceRecordVo;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备进出记录Mapper接口
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@DS("slave")
|
||||
public interface MapDeviceFenceRecordMapper extends BaseMapperPlus<MapDeviceFenceRecord, MapDeviceFenceRecordVo> {
|
||||
|
||||
/**
|
||||
* 查询设备进出记录分页列表
|
||||
*/
|
||||
Page<MapDeviceFenceRecordVo> selectPageList(@Param("page") Page<MapDeviceFenceRecord> page,
|
||||
@Param(Constants.WRAPPER) Wrapper<MapDeviceFenceRecord> queryWrapper);
|
||||
|
||||
/**
|
||||
* 查询设备进出记录列表
|
||||
*/
|
||||
List<MapDeviceFenceRecordVo> selectVoList(@Param(Constants.WRAPPER) Wrapper<MapDeviceFenceRecord> queryWrapper);
|
||||
|
||||
/**
|
||||
* 查询设备最近的进出记录
|
||||
*/
|
||||
MapDeviceFenceRecordVo selectLatestRecord(@Param("deviceCode") String deviceCode,
|
||||
@Param("polygonId") Integer polygonId);
|
||||
|
||||
/**
|
||||
* 查询指定时间范围内的设备进出记录
|
||||
*/
|
||||
List<MapDeviceFenceRecordVo> selectByTimeRange(@Param("deviceCode") String deviceCode,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime);
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.system.domain.MapPolygonDevice;
|
||||
import org.dromara.system.domain.vo.MapPolygonDeviceVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 电子围栏设备绑定Mapper接口
|
||||
*
|
||||
* @author luya
|
||||
*/
|
||||
@DS("slave")
|
||||
public interface MapPolygonDeviceMapper extends BaseMapperPlus<MapPolygonDevice, MapPolygonDeviceVo> {
|
||||
|
||||
/**
|
||||
* 查询围栏绑定的设备列表
|
||||
*/
|
||||
List<MapPolygonDeviceVo> selectDeviceListByPolygonId(@Param("polygonId") Integer polygonId);
|
||||
|
||||
/**
|
||||
* 查询设备绑定的围栏列表
|
||||
*/
|
||||
List<MapPolygonDeviceVo> selectPolygonListByDeviceCode(@Param("deviceCode") String deviceCode);
|
||||
|
||||
/**
|
||||
* 批量删除围栏设备绑定
|
||||
*/
|
||||
int deleteByPolygonIdAndDeviceCodes(@Param("polygonId") Integer polygonId, @Param("deviceCodes") List<String> deviceCodes);
|
||||
|
||||
int deleteByPolygonId(@Param("polygonId") Integer polygonId);
|
||||
|
||||
/**
|
||||
* 查询围栏设备绑定分页列表
|
||||
*/
|
||||
@DataPermission({
|
||||
@DataColumn(key = "deptName", value = "deptId")
|
||||
})
|
||||
Page<MapPolygonDeviceVo> selectPageList(@Param("page") Page<MapPolygonDevice> page, @Param(Constants.WRAPPER) Wrapper<MapPolygonDevice> queryWrapper);
|
||||
}
|
||||
|
|
@ -57,5 +57,17 @@ public interface MapPolygonMapper extends BaseMapperPlus<MapPolygon, MapPolygonV
|
|||
* @return 电子围栏视图对象
|
||||
*/
|
||||
MapPolygonVo selectByIdWithGeometry(@Param("id") Integer id);
|
||||
|
||||
/**
|
||||
* 判断设备是否在围栏内(考虑生效范围)
|
||||
*
|
||||
* @param polygonId 围栏ID
|
||||
* @param longitude 经度
|
||||
* @param latitude 纬度
|
||||
* @return 是否在围栏内(true=在范围内,false=在范围外)
|
||||
*/
|
||||
Boolean isDeviceInFence(@Param("polygonId") Integer polygonId,
|
||||
@Param("longitude") Double longitude,
|
||||
@Param("latitude") Double latitude);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
package org.dromara.system.service;
|
||||
|
||||
import org.dromara.system.domain.bo.MapDeviceFenceRecordBo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备进出检测服务
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface FenceDetectionService {
|
||||
|
||||
/**
|
||||
* 检测设备进出围栏情况
|
||||
*
|
||||
* @return 检测到的进出记录列表
|
||||
*/
|
||||
List<MapDeviceFenceRecordBo> detectDeviceInOut();
|
||||
|
||||
/**
|
||||
* 检测指定设备的进出围栏情况
|
||||
*
|
||||
* @param deviceCode 设备编码
|
||||
* @param deviceType 设备类型
|
||||
* @return 检测到的进出记录列表
|
||||
*/
|
||||
List<MapDeviceFenceRecordBo> detectDeviceInOut(String deviceCode, String deviceType);
|
||||
|
||||
/**
|
||||
* 检测指定围栏的设备进出情况
|
||||
*
|
||||
* @param polygonId 围栏ID
|
||||
* @return 检测到的进出记录列表
|
||||
*/
|
||||
List<MapDeviceFenceRecordBo> detectDeviceInOut(Integer polygonId);
|
||||
|
||||
/**
|
||||
* 判断点是否在多边形内
|
||||
*
|
||||
* @param point 点坐标,格式为"经度,纬度"
|
||||
* @param polygon 多边形坐标,格式为"经度,纬度;经度,纬度;..."
|
||||
* @return 是否在多边形内
|
||||
*/
|
||||
boolean isPointInPolygon(String point, String polygon);
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package org.dromara.system.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.bo.MapDeviceFenceRecordBo;
|
||||
import org.dromara.system.domain.vo.MapDeviceFenceRecordVo;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备进出记录Service接口
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface IMapDeviceFenceRecordService {
|
||||
|
||||
/**
|
||||
* 查询设备进出记录
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 设备进出记录
|
||||
*/
|
||||
MapDeviceFenceRecordVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询设备进出记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 设备进出记录列表
|
||||
*/
|
||||
List<MapDeviceFenceRecordVo> queryList(MapDeviceFenceRecordBo bo);
|
||||
|
||||
/**
|
||||
* 分页查询设备进出记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 设备进出记录分页列表
|
||||
*/
|
||||
TableDataInfo<MapDeviceFenceRecordVo> queryPageList(MapDeviceFenceRecordBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询设备最近的进出记录
|
||||
*
|
||||
* @param deviceCode 设备编码
|
||||
* @param polygonId 围栏ID
|
||||
* @return 设备进出记录
|
||||
*/
|
||||
MapDeviceFenceRecordVo queryLatestRecord(String deviceCode, Integer polygonId);
|
||||
|
||||
/**
|
||||
* 查询指定时间范围内的设备进出记录
|
||||
*
|
||||
* @param deviceCode 设备编码
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 设备进出记录列表
|
||||
*/
|
||||
List<MapDeviceFenceRecordVo> queryByTimeRange(String deviceCode, LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
/**
|
||||
* 新增设备进出记录
|
||||
*
|
||||
* @param bo 设备进出记录
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(MapDeviceFenceRecordBo bo);
|
||||
|
||||
/**
|
||||
* 批量新增设备进出记录
|
||||
*
|
||||
* @param list 设备进出记录列表
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean batchInsert(List<MapDeviceFenceRecordBo> list);
|
||||
|
||||
/**
|
||||
* 校验并批量删除设备进出记录信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
|
||||
package org.dromara.system.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.bo.MapPolygonDeviceBo;
|
||||
import org.dromara.system.domain.vo.MapPolygonDeviceVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 电子围栏设备绑定Service接口
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface IMapPolygonDeviceService {
|
||||
|
||||
/**
|
||||
* 查询电子围栏设备绑定
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 电子围栏设备绑定
|
||||
*/
|
||||
MapPolygonDeviceVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询电子围栏设备绑定列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 电子围栏设备绑定列表
|
||||
*/
|
||||
List<MapPolygonDeviceVo> queryList(MapPolygonDeviceBo bo);
|
||||
|
||||
/**
|
||||
* 分页查询电子围栏设备绑定列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 电子围栏设备绑定分页列表
|
||||
*/
|
||||
TableDataInfo<MapPolygonDeviceVo> queryPageList(MapPolygonDeviceBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询围栏绑定的设备列表
|
||||
*
|
||||
* @param polygonId 围栏ID
|
||||
* @return 设备列表
|
||||
*/
|
||||
List<MapPolygonDeviceVo> queryDeviceListByPolygonId(Integer polygonId);
|
||||
|
||||
/**
|
||||
* 查询设备绑定的围栏列表
|
||||
*
|
||||
* @param deviceCode 设备编码
|
||||
* @return 围栏列表
|
||||
*/
|
||||
List<MapPolygonDeviceVo> queryPolygonListByDeviceCode(String deviceCode);
|
||||
|
||||
/**
|
||||
* 新增电子围栏设备绑定
|
||||
*
|
||||
* @param bo 电子围栏设备绑定
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(MapPolygonDeviceBo bo);
|
||||
|
||||
/**
|
||||
* 批量新增电子围栏设备绑定
|
||||
*
|
||||
* @param polygonId 围栏ID
|
||||
* @param deviceCodes 设备编码列表
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean batchInsert(Integer polygonId, List<String> deviceCodes);
|
||||
|
||||
/**
|
||||
* 修改电子围栏设备绑定
|
||||
*
|
||||
* @param bo 电子围栏设备绑定
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(MapPolygonDeviceBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除电子围栏设备绑定信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 根据围栏ID和设备编码列表删除绑定
|
||||
*
|
||||
* @param polygonId 围栏ID
|
||||
* @param deviceCodes 设备编码列表
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteByPolygonIdAndDeviceCodes(Integer polygonId, List<String> deviceCodes);
|
||||
}
|
||||
|
|
@ -0,0 +1,695 @@
|
|||
package org.dromara.system.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.redis.utils.RedisUtils;
|
||||
import org.dromara.system.domain.MapDeviceFenceRecord;
|
||||
import org.dromara.system.domain.MapPolygon;
|
||||
import org.dromara.system.domain.MapPolygonDevice;
|
||||
import org.dromara.system.domain.TDevice;
|
||||
import org.dromara.system.domain.bo.MapDeviceFenceRecordBo;
|
||||
import org.dromara.system.domain.vo.MapDeviceFenceRecordVo;
|
||||
import org.dromara.system.domain.vo.MapPolygonDeviceVo;
|
||||
import org.dromara.system.mapper.MapPolygonDeviceMapper;
|
||||
import org.dromara.system.mapper.MapPolygonMapper;
|
||||
import org.dromara.system.mapper.TDeviceMapper;
|
||||
import org.dromara.system.service.FenceDetectionService;
|
||||
import org.dromara.system.service.IMapDeviceFenceRecordService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 设备进出检测服务实现
|
||||
*
|
||||
* @author luya
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class FenceDetectionServiceImpl implements FenceDetectionService {
|
||||
|
||||
private final MapPolygonDeviceMapper mapPolygonDeviceMapper;
|
||||
private final MapPolygonMapper mapPolygonMapper;
|
||||
private final TDeviceMapper tDeviceMapper;
|
||||
private final IMapDeviceFenceRecordService mapDeviceFenceRecordService;
|
||||
|
||||
/**
|
||||
* Redis中设备位置的key前缀
|
||||
*/
|
||||
private static final String DEVICE_LOCATION_KEY_PREFIX = "online_users:";
|
||||
|
||||
@Override
|
||||
public List<MapDeviceFenceRecordBo> detectDeviceInOut() {
|
||||
List<MapDeviceFenceRecordBo> result = new ArrayList<>();
|
||||
|
||||
// 获取所有围栏设备绑定关系
|
||||
List<MapPolygonDeviceVo> bindings = mapPolygonDeviceMapper.selectVoList(
|
||||
Wrappers.lambdaQuery(MapPolygonDevice.class)
|
||||
);
|
||||
|
||||
// 按设备分组
|
||||
Map<String, List<MapPolygonDeviceVo>> deviceBindings = new HashMap<>();
|
||||
for (MapPolygonDeviceVo binding : bindings) {
|
||||
String key = binding.getDeviceType() + ":" + binding.getDeviceCode();
|
||||
deviceBindings.computeIfAbsent(key, k -> new ArrayList<>()).add(binding);
|
||||
}
|
||||
|
||||
// 检测每个设备的进出情况
|
||||
for (Map.Entry<String, List<MapPolygonDeviceVo>> entry : deviceBindings.entrySet()) {
|
||||
String[] parts = entry.getKey().split(":");
|
||||
String deviceType = parts[0];
|
||||
String deviceCode = parts[1];
|
||||
|
||||
List<MapDeviceFenceRecordBo> records = detectDeviceInOut(deviceCode, deviceType);
|
||||
result.addAll(records);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
public List<MapDeviceFenceRecordBo> detectDeviceInOut(String deviceCode, String deviceType) {
|
||||
List<MapDeviceFenceRecordBo> result = new ArrayList<>();
|
||||
|
||||
// 从Redis获取设备当前位置信息
|
||||
Map<String, Object> locationInfo = getDeviceLocationInfo(deviceType, deviceCode);
|
||||
if (locationInfo == null) {
|
||||
log.debug("设备 {}:{} 未找到位置信息", deviceType, deviceCode);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取设备位置和GPS时间
|
||||
String location = locationInfo.get("lng") + "," + locationInfo.get("lat");
|
||||
Long gpsTime = extractGpsTime(locationInfo);
|
||||
|
||||
// 获取设备绑定的围栏列表
|
||||
List<MapPolygonDeviceVo> bindings = mapPolygonDeviceMapper.selectVoList(
|
||||
Wrappers.lambdaQuery(MapPolygonDevice.class)
|
||||
.eq(MapPolygonDevice::getDeviceCode, deviceCode)
|
||||
.eq(MapPolygonDevice::getDeviceType, deviceType)
|
||||
);
|
||||
|
||||
// 检测设备在每个围栏中的情况
|
||||
for (MapPolygonDeviceVo binding : bindings) {
|
||||
MapPolygon polygon = mapPolygonMapper.selectById(binding.getPolygonId());
|
||||
if (polygon == null || polygon.getStatus() == null || polygon.getStatus() != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 判断设备是否在围栏内
|
||||
double longitude = Double.parseDouble(locationInfo.get("lng").toString());
|
||||
double latitude = Double.parseDouble(locationInfo.get("lat").toString());
|
||||
boolean inside = mapPolygonMapper.isDeviceInFence(polygon.getId(), longitude, latitude);
|
||||
|
||||
// 根据围栏规则判断是否需要处理这个位置
|
||||
if (!shouldProcessByRule(polygon.getRuleType(), inside)) {
|
||||
// 设备处于正常状态,不需要记录
|
||||
log.debug("设备 {} 在围栏 {} 处于正常状态(规则:{}, 位置:{}),跳过处理",
|
||||
deviceCode, polygon.getName(),
|
||||
polygon.getRuleType() == 0 ? "禁入" : "禁出",
|
||||
inside ? "内" : "外");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取设备最近一次记录
|
||||
MapDeviceFenceRecordVo latestRecord = mapDeviceFenceRecordService.queryLatestRecord(deviceCode, polygon.getId());
|
||||
|
||||
// 判断是否需要创建新记录
|
||||
MapDeviceFenceRecordBo record = determineAndCreateRecord(
|
||||
deviceCode, deviceType, polygon, location, gpsTime,
|
||||
inside, latestRecord, locationInfo
|
||||
);
|
||||
|
||||
if (record != null) {
|
||||
result.add(record);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据围栏规则判断是否需要处理当前位置
|
||||
* @param ruleType 0禁入 1禁出
|
||||
* @param inside 是否在围栏内
|
||||
* @return true表示需要处理(违规状态),false表示不需要处理(正常状态)
|
||||
*/
|
||||
private boolean shouldProcessByRule(short ruleType, boolean inside) {
|
||||
|
||||
// 禁入围栏:只在围栏内时需要处理(违规)
|
||||
if (ruleType == 0) {
|
||||
return inside;
|
||||
}
|
||||
|
||||
// 禁出围栏:只在围栏外时需要处理(违规)
|
||||
if (ruleType == 1) {
|
||||
return !inside;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取GPS时间
|
||||
*/
|
||||
private Long extractGpsTime(Map<String, Object> locationInfo) {
|
||||
Object gpsTimeObj = locationInfo.get("gpsTime");
|
||||
if (gpsTimeObj instanceof Date) {
|
||||
return ((Date) gpsTimeObj).getTime();
|
||||
} else if (gpsTimeObj instanceof Long) {
|
||||
return (Long) gpsTimeObj;
|
||||
} else if (gpsTimeObj instanceof String) {
|
||||
try {
|
||||
return Long.parseLong((String) gpsTimeObj);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("GPS时间格式错误: {}", gpsTimeObj);
|
||||
}
|
||||
}
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断并创建记录
|
||||
*/
|
||||
private MapDeviceFenceRecordBo determineAndCreateRecord(
|
||||
String deviceCode, String deviceType, MapPolygon polygon,
|
||||
String location, Long gpsTime, boolean inside,
|
||||
MapDeviceFenceRecordVo latestRecord, Map<String, Object> locationInfo) {
|
||||
|
||||
// 计算违规类型(用于记录)
|
||||
boolean isViolation = true; // 能进入这个方法的一定是违规状态
|
||||
|
||||
// 如果没有历史记录
|
||||
if (latestRecord == null) {
|
||||
// 首次违规,记录进入状态
|
||||
log.info("设备 {} 首次违规进入围栏 {},规则:{}",
|
||||
deviceCode, polygon.getName(),
|
||||
polygon.getRuleType() == 0 ? "禁入" : "禁出");
|
||||
return createRecord(deviceCode, deviceType, polygon, location, gpsTime,
|
||||
(short)0, // 进入
|
||||
isViolation, locationInfo);
|
||||
}
|
||||
|
||||
// 解析上次记录的状态
|
||||
Short lastInOutType = latestRecord.getInOutType();
|
||||
Long lastGpsTime = latestRecord.getGpsTime();
|
||||
|
||||
// 检查GPS时间是否变化
|
||||
boolean gpsTimeChanged = lastGpsTime == null || !lastGpsTime.equals(gpsTime);
|
||||
|
||||
// 情况1:状态变化(上次是离开/持续,这次是进入)
|
||||
if (lastInOutType != null && lastInOutType == 1 || lastInOutType == 2) {
|
||||
// 上次是离开或持续违规,这次是新进入
|
||||
log.debug("设备 {} 重新进入违规状态", deviceCode);
|
||||
return createRecord(deviceCode, deviceType, polygon, location, gpsTime,
|
||||
(short)0, // 进入
|
||||
isViolation, locationInfo);
|
||||
}
|
||||
|
||||
// 情况2:持续违规,需要定时记录
|
||||
if (gpsTimeChanged) {
|
||||
if (shouldRecordPersistentViolation(latestRecord, gpsTime)) {
|
||||
log.debug("设备 {} 持续违规,时间间隔超过阈值", deviceCode);
|
||||
return createRecord(deviceCode, deviceType, polygon, location, gpsTime,
|
||||
(short)2, // 持续违规
|
||||
isViolation, locationInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// 情况3:不需要记录
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要记录持续违规
|
||||
*/
|
||||
private boolean shouldRecordPersistentViolation(MapDeviceFenceRecordVo latestRecord, Long currentGpsTime) {
|
||||
if (latestRecord == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Long lastGpsTime = latestRecord.getGpsTime();
|
||||
if (lastGpsTime == null || currentGpsTime == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取持续违规记录间隔(默认5分钟)
|
||||
long intervalMinutes = getPersistentViolationInterval();
|
||||
long intervalMillis = intervalMinutes * 60 * 1000;
|
||||
|
||||
// 如果上次记录时间距离现在超过间隔,需要再次记录
|
||||
return (currentGpsTime - lastGpsTime) >= intervalMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建进出记录
|
||||
*/
|
||||
private MapDeviceFenceRecordBo createRecord(
|
||||
String deviceCode, String deviceType, MapPolygon polygon,
|
||||
String location, Long gpsTime, Short inOutType,
|
||||
boolean isViolation, Map<String, Object> locationInfo) {
|
||||
|
||||
MapDeviceFenceRecordBo record = new MapDeviceFenceRecordBo();
|
||||
|
||||
// 设备信息
|
||||
record.setDeviceCode(deviceCode);
|
||||
record.setDeviceType(deviceType);
|
||||
record.setDeviceName(getDeviceName(deviceCode, deviceType, locationInfo));
|
||||
|
||||
// 围栏信息
|
||||
record.setPolygonId(polygon.getId());
|
||||
record.setPolygonName(polygon.getName());
|
||||
record.setRuleType(polygon.getRuleType());
|
||||
|
||||
// 记录类型
|
||||
record.setInOutType(inOutType); // 0进入 1离开 2持续违规
|
||||
record.setViolation(isViolation ? (short)1 : (short)0);
|
||||
|
||||
// 位置和时间
|
||||
record.setLocation(location);
|
||||
record.setGpsTime(gpsTime);
|
||||
record.setRecordTime(DateUtil.toLocalDateTime(new Date()));
|
||||
|
||||
// 部门信息
|
||||
if (locationInfo != null) {
|
||||
Object deptId = locationInfo.get("deptId");
|
||||
if (deptId != null) {
|
||||
record.setDeptId(deptId.toString());
|
||||
}
|
||||
|
||||
Object deptName = locationInfo.get("deptName");
|
||||
if (deptName != null) {
|
||||
record.setDeptName(deptName.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// 生成备注
|
||||
record.setRemark(generateRemark(polygon, inOutType, isViolation));
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成备注信息
|
||||
*/
|
||||
private String generateRemark(MapPolygon polygon, Short inOutType, boolean isViolation) {
|
||||
StringBuilder remark = new StringBuilder();
|
||||
|
||||
String ruleDesc = polygon.getRuleType() == 0 ? "禁入" : "禁出";
|
||||
String positionDesc = "";
|
||||
if (polygon.getRuleType() == 0) {
|
||||
positionDesc = "在围栏内";
|
||||
} else {
|
||||
positionDesc = "在围栏外";
|
||||
}
|
||||
|
||||
remark.append("【").append(ruleDesc).append("围栏】");
|
||||
|
||||
if (inOutType == 0) {
|
||||
remark.append("进入围栏,当前").append(positionDesc);
|
||||
} else if (inOutType == 1) {
|
||||
remark.append("离开围栏,当前").append(positionDesc);
|
||||
} else if (inOutType == 2) {
|
||||
remark.append("持续").append(positionDesc);
|
||||
}
|
||||
|
||||
if (isViolation) {
|
||||
remark.append(",触发告警");
|
||||
}
|
||||
|
||||
return remark.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备名称
|
||||
*/
|
||||
private String getDeviceName(String deviceCode, String deviceType, Map<String, Object> locationInfo) {
|
||||
if (locationInfo != null && locationInfo.get("deviceName") != null) {
|
||||
return locationInfo.get("deviceName").toString();
|
||||
}
|
||||
|
||||
try {
|
||||
TDevice device = tDeviceMapper.selectOne(
|
||||
Wrappers.lambdaQuery(TDevice.class)
|
||||
.eq(TDevice::getDeviceCode, deviceCode)
|
||||
.eq(TDevice::getDeviceType, deviceType)
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
if (device != null) {
|
||||
return device.getRemark1();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("查询设备名称失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取持续违规记录间隔
|
||||
*/
|
||||
private long getPersistentViolationInterval() {
|
||||
return 5L; // 5分钟
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<MapDeviceFenceRecordBo> detectDeviceInOut(Integer polygonId) {
|
||||
List<MapDeviceFenceRecordBo> result = new ArrayList<>();
|
||||
|
||||
// 获取围栏信息
|
||||
MapPolygon polygon = mapPolygonMapper.selectById(polygonId);
|
||||
if (polygon == null || polygon.getStatus() == null || polygon.getStatus() != 1) {
|
||||
// 围栏不存在或未启用
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取围栏绑定的设备列表
|
||||
List<MapPolygonDeviceVo> bindings = mapPolygonDeviceMapper.selectDeviceListByPolygonId(polygonId);
|
||||
|
||||
// 检测每个设备的进出情况
|
||||
for (MapPolygonDeviceVo binding : bindings) {
|
||||
String deviceCode = binding.getDeviceCode();
|
||||
String deviceType = binding.getDeviceType();
|
||||
|
||||
// 从Redis获取设备当前位置信息
|
||||
Map<String, Object> locationInfo = getDeviceLocationInfo(deviceType, deviceCode);
|
||||
if (locationInfo == null) {
|
||||
log.debug("设备 {}:{} 未找到位置信息", deviceType, deviceCode);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取设备位置字符串
|
||||
String location = locationInfo.get("lng") + "," + locationInfo.get("lat");
|
||||
|
||||
// 判断设备是否在围栏内(考虑生效范围)
|
||||
// 解析设备位置
|
||||
double longitude = Double.parseDouble(locationInfo.get("lng").toString());
|
||||
double latitude = Double.parseDouble(locationInfo.get("lat").toString());
|
||||
|
||||
// 使用PostGIS的ST_DWithin判断设备是否在围栏生效范围内
|
||||
boolean inside = mapPolygonMapper.isDeviceInFence(polygon.getId(), longitude, latitude);
|
||||
|
||||
// 获取设备最近一次进出记录
|
||||
MapDeviceFenceRecordVo latestRecord = mapDeviceFenceRecordService.queryLatestRecord(deviceCode, polygonId);
|
||||
|
||||
// 判断是否发生进出事件
|
||||
if (latestRecord == null) {
|
||||
// 没有历史记录,记录当前位置
|
||||
if (inside) {
|
||||
MapDeviceFenceRecordBo record = createRecord(deviceCode, deviceType, polygon, location, (short) 0, locationInfo);
|
||||
result.add(record);
|
||||
}
|
||||
} else {
|
||||
// 有历史记录,比较当前位置状态
|
||||
boolean wasInside = latestRecord.getInOutType() == 0;
|
||||
|
||||
// 检查位置和GPS时间是否未变化
|
||||
boolean locationUnchanged = isLocationAndTimeUnchanged(latestRecord, locationInfo);
|
||||
|
||||
if (inside && !wasInside) {
|
||||
// 进入围栏
|
||||
MapDeviceFenceRecordBo record = createRecord(deviceCode, deviceType, polygon, location, (short) 0, locationInfo);
|
||||
result.add(record);
|
||||
} else if (!inside && wasInside) {
|
||||
// 离开围栏
|
||||
MapDeviceFenceRecordBo record = createRecord(deviceCode, deviceType, polygon, location, (short) 1, locationInfo);
|
||||
result.add(record);
|
||||
} else if (locationUnchanged) {
|
||||
// 位置和GPS时间未变化,不创建新记录
|
||||
log.debug("设备 {}:{} 在围栏 {} 中位置和GPS时间未变化,跳过记录", deviceType, deviceCode, polygon.getName());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPointInPolygon(String point, String polygon) {
|
||||
if (StringUtils.isBlank(point) || StringUtils.isBlank(polygon)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 解析点坐标
|
||||
String[] pointParts = point.split(",");
|
||||
if (pointParts.length != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double px, py;
|
||||
try {
|
||||
px = Double.parseDouble(pointParts[0].trim());
|
||||
py = Double.parseDouble(pointParts[1].trim());
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("解析点坐标失败: {}", point, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 解析多边形坐标
|
||||
String[] polygonParts = polygon.split(";");
|
||||
if (polygonParts.length < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<double[]> vertices = new ArrayList<>();
|
||||
for (String part : polygonParts) {
|
||||
String[] coords = part.split(",");
|
||||
if (coords.length != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
double x = Double.parseDouble(coords[0].trim());
|
||||
double y = Double.parseDouble(coords[1].trim());
|
||||
vertices.add(new double[]{x, y});
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("解析多边形坐标失败: {}", part, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (vertices.size() < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 使用射线法判断点是否在多边形内
|
||||
return isPointInPolygon(px, py, vertices);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用射线法判断点是否在多边形内
|
||||
*
|
||||
* @param px 点的X坐标
|
||||
* @param py 点的Y坐标
|
||||
* @param vertices 多边形顶点列表
|
||||
* @return 是否在多边形内
|
||||
*/
|
||||
private boolean isPointInPolygon(double px, double py, List<double[]> vertices) {
|
||||
int n = vertices.size();
|
||||
boolean inside = false;
|
||||
|
||||
for (int i = 0, j = n - 1; i < n; j = i++) {
|
||||
double[] vi = vertices.get(i);
|
||||
double[] vj = vertices.get(j);
|
||||
|
||||
if (((vi[1] > py) != (vj[1] > py)) &&
|
||||
(px < (vj[0] - vi[0]) * (py - vi[1]) / (vj[1] - vi[1]) + vi[0])) {
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Redis获取设备位置
|
||||
*
|
||||
* @param deviceType 设备类型
|
||||
* @param deviceCode 设备编码
|
||||
* @return 设备位置,格式为"经度,纬度"
|
||||
*/
|
||||
private String getDeviceLocation(String deviceType, String deviceCode) {
|
||||
String key = DEVICE_LOCATION_KEY_PREFIX + deviceType + ":" + deviceCode;
|
||||
String location = RedisUtils.getCacheObject(key);
|
||||
if (StringUtils.isNotBlank(location)) {
|
||||
try {
|
||||
// 尝试解析JSON格式的位置数据
|
||||
Map<String, Object> locationMap = JSON.parseObject(location, Map.class);
|
||||
if (locationMap.containsKey("lng") && locationMap.containsKey("lat")) {
|
||||
return locationMap.get("lng") + "," + locationMap.get("lat");
|
||||
} else if (locationMap.containsKey("longitude") && locationMap.containsKey("latitude")) {
|
||||
return locationMap.get("longitude") + "," + locationMap.get("latitude");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析设备位置数据失败: {}", location, e);
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Redis获取设备位置信息
|
||||
*
|
||||
* @param deviceType 设备类型
|
||||
* @param deviceCode 设备编码
|
||||
* @return 设备位置信息Map,包含lng(经度)、lat(纬度)、gpsTime(GPS时间)
|
||||
*/
|
||||
private Map<String, Object> getDeviceLocationInfo(String deviceType, String deviceCode) {
|
||||
String key = DEVICE_LOCATION_KEY_PREFIX + deviceType + ":" + deviceCode;
|
||||
String location = RedisUtils.getCacheObject(key);
|
||||
if (StringUtils.isNotBlank(location)) {
|
||||
try {
|
||||
// 解析JSON格式的位置数据
|
||||
Map<String, Object> locationMap = JSON.parseObject(location, Map.class);
|
||||
// 提取经纬度信息
|
||||
if (locationMap.containsKey("lng") && locationMap.containsKey("lat")) {
|
||||
return locationMap;
|
||||
} else if (locationMap.containsKey("longitude") && locationMap.containsKey("latitude")) {
|
||||
// 统一使用lng和lat作为键名
|
||||
Map<String, Object> result = new HashMap<>(locationMap);
|
||||
result.put("lng", locationMap.get("longitude"));
|
||||
result.put("lat", locationMap.get("latitude"));
|
||||
return result;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析设备位置数据失败: {}", location, e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Redis获取设备GPS时间
|
||||
*
|
||||
* @param deviceType 设备类型
|
||||
* @param deviceCode 设备编码
|
||||
* @return GPS时间戳(毫秒)
|
||||
*/
|
||||
private Long getDeviceGpsTime(String deviceType, String deviceCode) {
|
||||
Map<String, Object> locationInfo = getDeviceLocationInfo(deviceType, deviceCode);
|
||||
if (locationInfo != null && locationInfo.containsKey("gpsTime")) {
|
||||
try {
|
||||
Object gpsTimeObj = locationInfo.get("gpsTime");
|
||||
if (gpsTimeObj instanceof Number) {
|
||||
return ((Number) gpsTimeObj).longValue();
|
||||
} else if (gpsTimeObj instanceof String) {
|
||||
return Long.parseLong((String) gpsTimeObj);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析设备GPS时间失败: {}", locationInfo.get("gpsTime"), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断设备位置和GPS时间是否与最近记录相同
|
||||
*
|
||||
* @param latestRecord 最近一次进出记录
|
||||
* @param locationInfo 当前位置信息
|
||||
* @return true表示相同,false表示不同
|
||||
*/
|
||||
private boolean isLocationAndTimeUnchanged(MapDeviceFenceRecordVo latestRecord, Map<String, Object> locationInfo) {
|
||||
if (latestRecord == null || locationInfo == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 比较位置
|
||||
String currentLocation = locationInfo.get("lng") + "," + locationInfo.get("lat");
|
||||
if (!currentLocation.equals(latestRecord.getLocation())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 比较GPS时间
|
||||
Long currentGpsTime = null;
|
||||
if (locationInfo.containsKey("gpsTime")) {
|
||||
try {
|
||||
Object gpsTimeObj = locationInfo.get("gpsTime");
|
||||
if (gpsTimeObj instanceof Number) {
|
||||
currentGpsTime = ((Number) gpsTimeObj).longValue();
|
||||
} else if (gpsTimeObj instanceof String) {
|
||||
currentGpsTime = Long.parseLong((String) gpsTimeObj);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析设备GPS时间失败: {}", locationInfo.get("gpsTime"), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果最新记录中有GPS时间,进行比较
|
||||
if (latestRecord.getGpsTime() != null && currentGpsTime != null) {
|
||||
return latestRecord.getGpsTime().equals(currentGpsTime);
|
||||
}
|
||||
|
||||
// 如果没有GPS时间信息,则认为位置相同
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建进出记录
|
||||
*
|
||||
* @param deviceCode 设备编码
|
||||
* @param deviceType 设备类型
|
||||
* @param polygon 围栏信息
|
||||
* @param location 位置坐标
|
||||
* @param inOutType 进出类型 0进入 1离开
|
||||
* @param locationInfo 设备位置信息Map,包含lng(经度)、lat(纬度)、gpsTime(GPS时间)
|
||||
* @return 进出记录
|
||||
*/
|
||||
private MapDeviceFenceRecordBo createRecord(String deviceCode, String deviceType, MapPolygon polygon,
|
||||
String location, short inOutType, Map<String, Object> locationInfo) {
|
||||
MapDeviceFenceRecordBo record = new MapDeviceFenceRecordBo();
|
||||
record.setDeviceCode(deviceCode);
|
||||
record.setDeviceType(deviceType);
|
||||
record.setPolygonId(polygon.getId());
|
||||
record.setPolygonName(polygon.getName());
|
||||
record.setInOutType(inOutType);
|
||||
record.setRuleType(polygon.getRuleType());
|
||||
|
||||
// 判断是否违规
|
||||
short violation = 0;
|
||||
if (inOutType == 0 && polygon.getRuleType() != null && polygon.getRuleType() == 0) {
|
||||
// 进入围栏且规则为禁入,则违规
|
||||
violation = 1;
|
||||
} else if (inOutType == 1 && polygon.getRuleType() != null && polygon.getRuleType() == 1) {
|
||||
// 离开围栏且规则为禁出,则违规
|
||||
violation = 1;
|
||||
}
|
||||
record.setViolation(violation);
|
||||
|
||||
record.setLocation(location);
|
||||
record.setRecordTime(LocalDateTime.now());
|
||||
record.setDeptId(polygon.getDeptId());
|
||||
record.setDeptName(polygon.getDeptName());
|
||||
|
||||
// 设置GPS时间
|
||||
if (locationInfo != null && locationInfo.containsKey("gpsTime")) {
|
||||
try {
|
||||
Object gpsTimeObj = locationInfo.get("gpsTime");
|
||||
if (gpsTimeObj instanceof Number) {
|
||||
record.setGpsTime(((Number) gpsTimeObj).longValue());
|
||||
} else if (gpsTimeObj instanceof String) {
|
||||
record.setGpsTime(Long.parseLong((String) gpsTimeObj));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析设备GPS时间失败: {}", locationInfo.get("gpsTime"), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取设备名称
|
||||
TDevice device = tDeviceMapper.selectOne(
|
||||
Wrappers.lambdaQuery(TDevice.class)
|
||||
.eq(TDevice::getDeviceCode, deviceCode)
|
||||
.eq(TDevice::getDeviceType, deviceType)
|
||||
);
|
||||
if (device != null) {
|
||||
record.setDeviceName(device.getPoliceName());
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
package org.dromara.system.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.MapDeviceFenceRecord;
|
||||
import org.dromara.system.domain.MapPolygon;
|
||||
import org.dromara.system.domain.TDevice;
|
||||
import org.dromara.system.domain.bo.MapDeviceFenceRecordBo;
|
||||
import org.dromara.system.domain.vo.MapDeviceFenceRecordVo;
|
||||
import org.dromara.system.mapper.MapDeviceFenceRecordMapper;
|
||||
import org.dromara.system.mapper.MapPolygonMapper;
|
||||
import org.dromara.system.mapper.TDeviceMapper;
|
||||
import org.dromara.system.service.IMapDeviceFenceRecordService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备进出记录Service业务层处理
|
||||
*
|
||||
* @author luya
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class MapDeviceFenceRecordServiceImpl implements IMapDeviceFenceRecordService {
|
||||
|
||||
private final MapDeviceFenceRecordMapper baseMapper;
|
||||
private final MapPolygonMapper mapPolygonMapper;
|
||||
private final TDeviceMapper tDeviceMapper;
|
||||
|
||||
@Override
|
||||
public MapDeviceFenceRecordVo queryById(Long id) {
|
||||
MapDeviceFenceRecordVo vo = baseMapper.selectVoById(id);
|
||||
if (vo != null) {
|
||||
fillDeviceTypeName(vo);
|
||||
fillInOutTypeName(vo);
|
||||
fillRuleTypeName(vo);
|
||||
fillViolationName(vo);
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MapDeviceFenceRecordVo> queryList(MapDeviceFenceRecordBo bo) {
|
||||
LambdaQueryWrapper<MapDeviceFenceRecord> lqw = buildQueryWrapper(bo);
|
||||
List<MapDeviceFenceRecordVo> list = baseMapper.selectVoList(lqw);
|
||||
list.forEach(this::fillDeviceTypeName);
|
||||
list.forEach(this::fillInOutTypeName);
|
||||
list.forEach(this::fillRuleTypeName);
|
||||
list.forEach(this::fillViolationName);
|
||||
return list;
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<MapDeviceFenceRecord> buildQueryWrapper(MapDeviceFenceRecordBo bo) {
|
||||
LambdaQueryWrapper<MapDeviceFenceRecord> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getDeviceCode()), MapDeviceFenceRecord::getDeviceCode, bo.getDeviceCode());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getDeviceType()), MapDeviceFenceRecord::getDeviceType, bo.getDeviceType());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getPolygonId()), MapDeviceFenceRecord::getPolygonId, bo.getPolygonId());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getInOutType()), MapDeviceFenceRecord::getInOutType, bo.getInOutType());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getRuleType()), MapDeviceFenceRecord::getRuleType, bo.getRuleType());
|
||||
lqw.like(ObjectUtil.isNotNull(bo.getDeviceName()),MapDeviceFenceRecord::getDeviceName,bo.getDeviceName());
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getViolation()), MapDeviceFenceRecord::getViolation, bo.getViolation());
|
||||
lqw.between(ObjectUtil.isNotNull(bo.getStartTime()) && ObjectUtil.isNotNull(bo.getEndTime()), MapDeviceFenceRecord::getRecordTime, bo.getStartTime(), bo.getEndTime());
|
||||
lqw.orderByDesc(MapDeviceFenceRecord::getRecordTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<MapDeviceFenceRecordVo> queryPageList(MapDeviceFenceRecordBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<MapDeviceFenceRecord> lqw = buildQueryWrapper(bo);
|
||||
Page<MapDeviceFenceRecordVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
result.getRecords().forEach(this::fillDeviceTypeName);
|
||||
result.getRecords().forEach(this::fillInOutTypeName);
|
||||
result.getRecords().forEach(this::fillRuleTypeName);
|
||||
result.getRecords().forEach(this::fillViolationName);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapDeviceFenceRecordVo queryLatestRecord(String deviceCode, Integer polygonId) {
|
||||
MapDeviceFenceRecordVo vo = baseMapper.selectLatestRecord(deviceCode, polygonId);
|
||||
if (vo != null) {
|
||||
fillDeviceTypeName(vo);
|
||||
fillInOutTypeName(vo);
|
||||
fillRuleTypeName(vo);
|
||||
fillViolationName(vo);
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MapDeviceFenceRecordVo> queryByTimeRange(String deviceCode, LocalDateTime startTime, LocalDateTime endTime) {
|
||||
List<MapDeviceFenceRecordVo> list = baseMapper.selectByTimeRange(deviceCode, startTime, endTime);
|
||||
list.forEach(this::fillDeviceTypeName);
|
||||
list.forEach(this::fillInOutTypeName);
|
||||
list.forEach(this::fillRuleTypeName);
|
||||
list.forEach(this::fillViolationName);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(MapDeviceFenceRecordBo bo) {
|
||||
MapDeviceFenceRecord add = MapstructUtils.convert(bo, MapDeviceFenceRecord.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean batchInsert(List<MapDeviceFenceRecordBo> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
List<MapDeviceFenceRecord> records = MapstructUtils.convert(list, MapDeviceFenceRecord.class);
|
||||
records.forEach(this::validEntityBeforeSave);
|
||||
return baseMapper.insertBatch(records);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(MapDeviceFenceRecord entity) {
|
||||
// 校验设备是否存在
|
||||
TDevice device = tDeviceMapper.selectOne(
|
||||
Wrappers.lambdaQuery(TDevice.class)
|
||||
.eq(TDevice::getDeviceCode, entity.getDeviceCode())
|
||||
.eq(TDevice::getDeviceType, entity.getDeviceType())
|
||||
);
|
||||
if (device == null) {
|
||||
throw new RuntimeException("设备不存在");
|
||||
}
|
||||
// 设置设备名称
|
||||
if (StringUtils.isBlank(entity.getDeviceName())) {
|
||||
entity.setDeviceName(device.getPoliceName());
|
||||
}
|
||||
|
||||
// 校验围栏是否存在
|
||||
MapPolygon polygon = mapPolygonMapper.selectById(entity.getPolygonId());
|
||||
if (polygon == null) {
|
||||
throw new RuntimeException("围栏不存在");
|
||||
}
|
||||
// 设置围栏名称
|
||||
if (StringUtils.isBlank(entity.getPolygonName())) {
|
||||
entity.setPolygonName(polygon.getName());
|
||||
}
|
||||
// 设置部门信息
|
||||
if (StringUtils.isBlank(entity.getDeptId())) {
|
||||
entity.setDeptId(polygon.getDeptId());
|
||||
}
|
||||
if (StringUtils.isBlank(entity.getDeptName())) {
|
||||
entity.setDeptName(polygon.getDeptName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// 进行有效性校验
|
||||
for (Long id : ids) {
|
||||
MapDeviceFenceRecordVo vo = queryById(id);
|
||||
if (vo == null) {
|
||||
throw new RuntimeException("记录不存在");
|
||||
}
|
||||
}
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充设备类型名称
|
||||
*/
|
||||
private void fillDeviceTypeName(MapDeviceFenceRecordVo vo) {
|
||||
if (vo == null || StringUtils.isBlank(vo.getDeviceType())) {
|
||||
return;
|
||||
}
|
||||
vo.setDeviceTypeName(getDeviceTypeName(vo.getDeviceType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充进出类型名称
|
||||
*/
|
||||
private void fillInOutTypeName(MapDeviceFenceRecordVo vo) {
|
||||
if (vo == null || vo.getInOutType() == null) {
|
||||
return;
|
||||
}
|
||||
vo.setInOutTypeName(vo.getInOutType() == 0 ? "进入" : "离开");
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充规则类型名称
|
||||
*/
|
||||
private void fillRuleTypeName(MapDeviceFenceRecordVo vo) {
|
||||
if (vo == null || vo.getRuleType() == null) {
|
||||
return;
|
||||
}
|
||||
vo.setRuleTypeName(vo.getRuleType() == 0 ? "禁入" : "禁出");
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充是否违规名称
|
||||
*/
|
||||
private void fillViolationName(MapDeviceFenceRecordVo vo) {
|
||||
if (vo == null || vo.getViolation() == null) {
|
||||
return;
|
||||
}
|
||||
vo.setViolationName(vo.getViolation() == 0 ? "否" : "是");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备类型名称
|
||||
*/
|
||||
private String getDeviceTypeName(String deviceType) {
|
||||
// 这里可以根据实际业务逻辑设置设备类型名称
|
||||
// 例如从字典表中获取
|
||||
switch (deviceType) {
|
||||
case "1":
|
||||
return "执法记录仪";
|
||||
case "2":
|
||||
return "车载终端";
|
||||
case "3":
|
||||
return "对讲机";
|
||||
case "4":
|
||||
return "单兵装备";
|
||||
case "5":
|
||||
return "无人机";
|
||||
default:
|
||||
return "未知设备";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
|
||||
package org.dromara.system.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.MapPolygon;
|
||||
import org.dromara.system.domain.MapPolygonDevice;
|
||||
import org.dromara.system.domain.TDevice;
|
||||
import org.dromara.system.domain.bo.MapPolygonDeviceBo;
|
||||
import org.dromara.system.domain.vo.MapPolygonDeviceVo;
|
||||
import org.dromara.system.mapper.MapPolygonDeviceMapper;
|
||||
import org.dromara.system.mapper.MapPolygonMapper;
|
||||
import org.dromara.system.mapper.TDeviceMapper;
|
||||
import org.dromara.system.service.IMapPolygonDeviceService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 电子围栏设备绑定Service业务层处理
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class MapPolygonDeviceServiceImpl implements IMapPolygonDeviceService {
|
||||
|
||||
private final MapPolygonDeviceMapper baseMapper;
|
||||
private final MapPolygonMapper mapPolygonMapper;
|
||||
private final TDeviceMapper tDeviceMapper;
|
||||
|
||||
@Override
|
||||
public MapPolygonDeviceVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MapPolygonDeviceVo> queryList(MapPolygonDeviceBo bo) {
|
||||
LambdaQueryWrapper<MapPolygonDevice> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<MapPolygonDevice> buildQueryWrapper(MapPolygonDeviceBo bo) {
|
||||
LambdaQueryWrapper<MapPolygonDevice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(ObjectUtil.isNotNull(bo.getPolygonId()), MapPolygonDevice::getPolygonId, bo.getPolygonId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDeviceCode()), MapPolygonDevice::getDeviceCode, bo.getDeviceCode());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDeviceType()), MapPolygonDevice::getDeviceType, bo.getDeviceType());
|
||||
lqw.orderByDesc(MapPolygonDevice::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<MapPolygonDeviceVo> queryPageList(MapPolygonDeviceBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<MapPolygonDevice> lqw = buildQueryWrapper(bo);
|
||||
Page<MapPolygonDeviceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MapPolygonDeviceVo> queryDeviceListByPolygonId(Integer polygonId) {
|
||||
List<MapPolygonDeviceVo> list = baseMapper.selectDeviceListByPolygonId(polygonId);
|
||||
// 填充设备类型名称
|
||||
fillDeviceTypeName(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MapPolygonDeviceVo> queryPolygonListByDeviceCode(String deviceCode) {
|
||||
List<MapPolygonDeviceVo> list = baseMapper.selectPolygonListByDeviceCode(deviceCode);
|
||||
// 填充围栏名称
|
||||
fillPolygonName(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(MapPolygonDeviceBo bo) {
|
||||
MapPolygonDevice add = MapstructUtils.convert(bo, MapPolygonDevice.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean batchInsert(Integer polygonId, List<String> deviceCodes) {
|
||||
if (deviceCodes == null || deviceCodes.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取围栏信息
|
||||
MapPolygon polygon = mapPolygonMapper.selectById(polygonId);
|
||||
if (polygon == null) {
|
||||
throw new RuntimeException("围栏不存在");
|
||||
}
|
||||
|
||||
// 查询设备信息
|
||||
List<TDevice> devices = tDeviceMapper.selectList(
|
||||
Wrappers.lambdaQuery(TDevice.class)
|
||||
.in(TDevice::getDeviceCode, deviceCodes)
|
||||
);
|
||||
|
||||
if (devices == null || devices.isEmpty()) {
|
||||
throw new RuntimeException("设备不存在");
|
||||
}
|
||||
|
||||
// 构建绑定关系列表
|
||||
List<MapPolygonDevice> list = new ArrayList<>();
|
||||
for (TDevice device : devices) {
|
||||
MapPolygonDevice binding = new MapPolygonDevice();
|
||||
binding.setPolygonId(polygonId);
|
||||
binding.setDeviceCode(device.getDeviceCode());
|
||||
binding.setDeviceType(device.getDeviceType());
|
||||
list.add(binding);
|
||||
}
|
||||
|
||||
baseMapper.deleteByPolygonId(polygonId);
|
||||
// 批量插入
|
||||
return baseMapper.insertBatch(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(MapPolygonDeviceBo bo) {
|
||||
MapPolygonDevice update = MapstructUtils.convert(bo, MapPolygonDevice.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(MapPolygonDevice entity) {
|
||||
// 校验围栏是否存在
|
||||
MapPolygon polygon = mapPolygonMapper.selectById(entity.getPolygonId());
|
||||
if (polygon == null) {
|
||||
throw new RuntimeException("围栏不存在");
|
||||
}
|
||||
|
||||
// 校验设备是否存在
|
||||
TDevice device = tDeviceMapper.selectOne(
|
||||
Wrappers.lambdaQuery(TDevice.class)
|
||||
.eq(TDevice::getDeviceCode, entity.getDeviceCode())
|
||||
.eq(TDevice::getDeviceType, entity.getDeviceType())
|
||||
);
|
||||
if (device == null) {
|
||||
throw new RuntimeException("设备不存在");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// 进行有效性校验
|
||||
for (Long id : ids) {
|
||||
MapPolygonDeviceVo vo = queryById(id);
|
||||
if (vo == null) {
|
||||
throw new RuntimeException("绑定关系不存在");
|
||||
}
|
||||
}
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteByPolygonIdAndDeviceCodes(Integer polygonId, List<String> deviceCodes) {
|
||||
if (deviceCodes == null || deviceCodes.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return baseMapper.deleteByPolygonIdAndDeviceCodes(polygonId, deviceCodes) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充设备类型名称
|
||||
*/
|
||||
private void fillDeviceTypeName(List<MapPolygonDeviceVo> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据设备类型获取类型名称
|
||||
for (MapPolygonDeviceVo vo : list) {
|
||||
if (StringUtils.isNotBlank(vo.getDeviceType())) {
|
||||
// 这里可以根据实际业务逻辑设置设备类型名称
|
||||
// 例如从字典表中获取
|
||||
vo.setDeviceTypeName(getDeviceTypeName(vo.getDeviceType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充围栏名称
|
||||
*/
|
||||
private void fillPolygonName(List<MapPolygonDeviceVo> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有围栏ID
|
||||
List<Integer> polygonIds = list.stream()
|
||||
.map(MapPolygonDeviceVo::getPolygonId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 查询围栏信息
|
||||
List<MapPolygon> polygons = mapPolygonMapper.selectBatchIds(polygonIds);
|
||||
|
||||
// 构建围栏ID到围栏名称的映射
|
||||
java.util.Map<Integer, String> polygonNameMap = polygons.stream()
|
||||
.collect(Collectors.toMap(MapPolygon::getId, MapPolygon::getName));
|
||||
|
||||
// 填充围栏名称
|
||||
for (MapPolygonDeviceVo vo : list) {
|
||||
vo.setPolygonName(polygonNameMap.get(vo.getPolygonId()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备类型名称
|
||||
*/
|
||||
private String getDeviceTypeName(String deviceType) {
|
||||
// 这里可以根据实际业务逻辑设置设备类型名称
|
||||
// 例如从字典表中获取
|
||||
switch (deviceType) {
|
||||
case "1":
|
||||
return "执法记录仪";
|
||||
case "2":
|
||||
return "车载终端";
|
||||
case "3":
|
||||
return "对讲机";
|
||||
case "4":
|
||||
return "单兵装备";
|
||||
case "5":
|
||||
return "无人机";
|
||||
default:
|
||||
return "未知设备";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -54,12 +54,12 @@ public class MapPolygonServiceImpl implements IMapPolygonService {
|
|||
query.setLayerId(bo.getLayerId());
|
||||
query.setStatus(bo.getStatus());
|
||||
query.setRuleType(bo.getRuleType());
|
||||
|
||||
|
||||
// 使用数据库分页查询
|
||||
Page<MapPolygonVo> page = pageQuery.build();
|
||||
List<MapPolygonVo> records = baseMapper.selectPageWithGeometry(page, query);
|
||||
page.setRecords(records);
|
||||
|
||||
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ public class MapPolygonServiceImpl implements IMapPolygonService {
|
|||
query.setLayerId(bo.getLayerId());
|
||||
query.setStatus(bo.getStatus());
|
||||
query.setRuleType(bo.getRuleType());
|
||||
|
||||
|
||||
return baseMapper.selectListWithGeometry(query);
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +101,7 @@ public class MapPolygonServiceImpl implements IMapPolygonService {
|
|||
public Boolean insertByBo(MapPolygonBo bo) {
|
||||
MapPolygon add = org.dromara.common.core.utils.MapstructUtils.convert(bo, MapPolygon.class);
|
||||
validEntityBeforeSave(add);
|
||||
add.setStatus((short) 1);
|
||||
boolean flag = baseMapper.insertWithGeometry(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
package org.dromara.system.task;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.system.domain.bo.MapDeviceFenceRecordBo;
|
||||
import org.dromara.system.service.FenceDetectionService;
|
||||
import org.dromara.system.service.IMapDeviceFenceRecordService;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备进出检测定时任务
|
||||
*
|
||||
* @author luya
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class FenceDetectionTask {
|
||||
|
||||
private final FenceDetectionService fenceDetectionService;
|
||||
private final IMapDeviceFenceRecordService mapDeviceFenceRecordService;
|
||||
|
||||
/**
|
||||
* 定时检测设备进出围栏情况
|
||||
* 每隔1分钟执行一次
|
||||
*/
|
||||
@Scheduled(cron = "0 */2 * * * ?")
|
||||
public void detectDeviceInOut() {
|
||||
log.debug("开始检测设备进出围栏情况");
|
||||
|
||||
try {
|
||||
// 检测设备进出围栏情况
|
||||
List<MapDeviceFenceRecordBo> records = fenceDetectionService.detectDeviceInOut();
|
||||
|
||||
if (!records.isEmpty()) {
|
||||
// 保存进出记录
|
||||
boolean success = mapDeviceFenceRecordService.batchInsert(records);
|
||||
|
||||
if (success) {
|
||||
log.debug("检测到 {} 条设备进出记录", records.size());
|
||||
|
||||
// 处理违规记录
|
||||
processViolationRecords(records);
|
||||
} else {
|
||||
log.error("保存设备进出记录失败");
|
||||
}
|
||||
} else {
|
||||
log.debug("未检测到设备进出记录");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("检测设备进出围栏情况失败", e);
|
||||
}
|
||||
|
||||
log.debug("结束检测设备进出围栏情况");
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理违规记录
|
||||
*
|
||||
* @param records 进出记录列表
|
||||
*/
|
||||
private void processViolationRecords(List<MapDeviceFenceRecordBo> records) {
|
||||
for (MapDeviceFenceRecordBo record : records) {
|
||||
if (record.getViolation() != null && record.getViolation() == 1) {
|
||||
// 发送违规提醒
|
||||
sendViolationAlert(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送违规提醒
|
||||
*
|
||||
* @param record 进出记录
|
||||
*/
|
||||
private void sendViolationAlert(MapDeviceFenceRecordBo record) {
|
||||
try {
|
||||
// TODO: 实现违规提醒逻辑
|
||||
// 可以使用WebSocket向客户端推送实时提醒
|
||||
// 或者使用消息队列异步处理提醒通知
|
||||
log.warn("设备 {}:{} {} 围栏 {},违规类型:{}",
|
||||
record.getDeviceType(),
|
||||
record.getDeviceCode(),
|
||||
record.getInOutType() == 0 ? "进入" : "离开",
|
||||
record.getPolygonName(),
|
||||
record.getRuleType() == 0 ? "禁入" : "禁出");
|
||||
} catch (Exception e) {
|
||||
log.error("发送违规提醒失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<?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="org.dromara.system.mapper.MapDeviceFenceRecordMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="org.dromara.system.domain.vo.MapDeviceFenceRecordVo">
|
||||
<id property="id" column="id"/>
|
||||
<result property="deviceCode" column="device_code"/>
|
||||
<result property="deviceType" column="device_type"/>
|
||||
<result property="deviceName" column="device_name"/>
|
||||
<result property="polygonId" column="polygon_id"/>
|
||||
<result property="polygonName" column="polygon_name"/>
|
||||
<result property="inOutType" column="in_out_type"/>
|
||||
<result property="ruleType" column="rule_type"/>
|
||||
<result property="violation" column="violation"/>
|
||||
<result property="location" column="location"/>
|
||||
<result property="recordTime" column="record_time"/>
|
||||
<result property="deptId" column="dept_id"/>
|
||||
<result property="deptName" column="dept_name"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectPageList" resultMap="BaseResultMap">
|
||||
SELECT id, device_code, device_type, device_name, polygon_id, polygon_name,
|
||||
in_out_type, rule_type, violation, location, record_time,
|
||||
dept_id, dept_name, remark
|
||||
FROM map_device_fence_record
|
||||
${ew.customSqlSegment}
|
||||
ORDER BY record_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectVoList" resultMap="BaseResultMap">
|
||||
SELECT id, device_code, device_type, device_name, polygon_id, polygon_name,
|
||||
in_out_type, rule_type, violation, location, record_time,
|
||||
dept_id, dept_name, remark
|
||||
FROM map_device_fence_record
|
||||
${ew.customSqlSegment}
|
||||
ORDER BY record_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectLatestRecord" resultMap="BaseResultMap">
|
||||
SELECT id, device_code, device_type, device_name, polygon_id, polygon_name,
|
||||
in_out_type, rule_type, violation, location, record_time,
|
||||
dept_id, dept_name, remark
|
||||
FROM map_device_fence_record
|
||||
WHERE device_code = #{deviceCode} AND polygon_id = #{polygonId}
|
||||
ORDER BY record_time DESC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectByTimeRange" resultMap="BaseResultMap">
|
||||
SELECT id, device_code, device_type, device_name, polygon_id, polygon_name,
|
||||
in_out_type, rule_type, violation, location, record_time,
|
||||
dept_id, dept_name, remark
|
||||
FROM map_device_fence_record
|
||||
WHERE device_code = #{deviceCode}
|
||||
AND record_time BETWEEN #{startTime} AND #{endTime}
|
||||
ORDER BY record_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<?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="org.dromara.system.mapper.MapPolygonDeviceMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="org.dromara.system.domain.vo.MapPolygonDeviceVo">
|
||||
<id property="id" column="id"/>
|
||||
<result property="polygonId" column="polygon_id"/>
|
||||
<result property="polygonName" column="polygon_name"/>
|
||||
<result property="deviceCode" column="device_code"/>
|
||||
<result property="deviceType" column="device_type"/>
|
||||
<result property="deviceTypeName" column="device_type_name"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 查询围栏绑定的设备列表 -->
|
||||
<select id="selectDeviceListByPolygonId" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
mpd.id,
|
||||
mpd.polygon_id,
|
||||
mp.name AS polygon_name,
|
||||
mpd.device_code,
|
||||
mpd.device_type,
|
||||
mpd.create_time,
|
||||
mpd.create_by,
|
||||
mpd.update_time,
|
||||
mpd.update_by,
|
||||
mpd.remark
|
||||
FROM map_polygon_device mpd
|
||||
LEFT JOIN map_polygon mp ON mpd.polygon_id = mp.id
|
||||
WHERE mpd.polygon_id = #{polygonId}
|
||||
ORDER BY mpd.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询设备绑定的围栏列表 -->
|
||||
<select id="selectPolygonListByDeviceCode" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
mpd.id,
|
||||
mpd.polygon_id,
|
||||
mp.name AS polygon_name,
|
||||
mpd.device_code,
|
||||
mpd.device_type,
|
||||
mpd.create_time,
|
||||
mpd.create_by,
|
||||
mpd.update_time,
|
||||
mpd.update_by,
|
||||
mpd.remark
|
||||
FROM map_polygon_device mpd
|
||||
LEFT JOIN map_polygon mp ON mpd.polygon_id = mp.id
|
||||
WHERE mpd.device_code = #{deviceCode}
|
||||
ORDER BY mpd.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 批量删除围栏设备绑定 -->
|
||||
<delete id="deleteByPolygonIdAndDeviceCodes">
|
||||
DELETE FROM map_polygon_device
|
||||
WHERE polygon_id = #{polygonId}
|
||||
AND device_code IN
|
||||
<foreach collection="deviceCodes" item="code" open="(" separator="," close=")">
|
||||
#{code}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByPolygonId">
|
||||
DELETE FROM map_polygon_device
|
||||
WHERE polygon_id = #{polygonId}
|
||||
</delete>
|
||||
|
||||
<!-- 查询围栏设备绑定分页列表 -->
|
||||
<select id="selectPageList" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
mpd.id,
|
||||
mpd.polygon_id,
|
||||
mp.name AS polygon_name,
|
||||
mpd.device_code,
|
||||
mpd.device_type,
|
||||
mpd.create_time,
|
||||
mpd.create_by,
|
||||
mpd.update_time,
|
||||
mpd.update_by,
|
||||
mpd.remark
|
||||
FROM map_polygon_device mpd
|
||||
LEFT JOIN map_polygon mp ON mpd.polygon_id = mp.id
|
||||
${ew.customSqlSegment}
|
||||
ORDER BY mpd.create_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
@ -120,5 +120,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
WHERE id = #{id}
|
||||
</select>
|
||||
|
||||
<!-- 判断设备是否在围栏内(考虑生效范围) -->
|
||||
<select id="isDeviceInFence" resultType="java.lang.Boolean">
|
||||
SELECT CASE
|
||||
WHEN ST_DWithin(
|
||||
ST_SetSRID(ST_MakePoint(#{longitude}, #{latitude}), 4326)::geography,
|
||||
geometry_location::geography,
|
||||
COALESCE(range, 0)
|
||||
) THEN true
|
||||
ELSE false
|
||||
END
|
||||
FROM map_polygon
|
||||
WHERE id = #{polygonId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
-- ----------------------------
|
||||
-- Table structure for map_device_fence_record
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS "public"."map_device_fence_record";
|
||||
CREATE TABLE "public"."map_device_fence_record" (
|
||||
"id" int4 NOT NULL DEFAULT nextval('map_elements_id_seq'::regclass),
|
||||
"device_code" varchar(100) COLLATE "pg_catalog"."default",
|
||||
"device_type" varchar(16) COLLATE "pg_catalog"."default",
|
||||
"device_name" varchar(50) COLLATE "pg_catalog"."default",
|
||||
"polygon_id" int4,
|
||||
"polygon_name" varchar(254) COLLATE "pg_catalog"."default",
|
||||
"in_out_type" int2,
|
||||
"rule_type" int2,
|
||||
"violation" int2,
|
||||
"location" varchar(200) COLLATE "pg_catalog"."default",
|
||||
"record_time" timestamp(0) DEFAULT CURRENT_TIMESTAMP,
|
||||
"dept_id" varchar(254) COLLATE "pg_catalog"."default",
|
||||
"dept_name" varchar(255) COLLATE "pg_catalog"."default",
|
||||
"remark" varchar(254) COLLATE "pg_catalog"."default"
|
||||
)
|
||||
;
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."id" IS 'ID';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."device_code" IS '设备编码';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."device_type" IS '设备类型';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."device_name" IS '设备名称';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."polygon_id" IS '围栏ID';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."polygon_name" IS '围栏名称';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."in_out_type" IS '进出类型 0进入 1离开';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."rule_type" IS '规则类型 0禁入 1禁出';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."violation" IS '是否违规 0否 1是';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."location" IS '位置坐标';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."record_time" IS '记录时间';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."dept_id" IS '部门ID';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."dept_name" IS '部门名称';
|
||||
COMMENT ON COLUMN "public"."map_device_fence_record"."remark" IS '备注';
|
||||
COMMENT ON TABLE "public"."map_device_fence_record" IS '设备进出记录';
|
||||
Loading…
Reference in New Issue