融合通信电子围栏

ds-hefei
luyya 2026-03-23 15:07:35 +08:00
parent d9396f33d1
commit 3456c73183
24 changed files with 2463 additions and 16 deletions

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
/**
* Rediskey
*/
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 truefalse
*/
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 Maplng()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;
}
/**
* RedisGPS
*
* @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 truefalse
*/
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 Maplng()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;
}
}

View File

@ -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 "未知设备";
}
}
}

View File

@ -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 "未知设备";
}
}
}

View File

@ -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());

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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 '设备进出记录';