From ebd86681781345b83d3c74f3daebc0c47a83080f Mon Sep 17 00:00:00 2001 From: daiyongfei <974332738@qq.com> Date: Tue, 9 Sep 2025 11:03:38 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E8=AE=BE=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/vo/EquipmentClassificationVo.java | 20 +++++++++++++++++++ .../service/impl/DeviceServiceImpl.java | 1 + .../mapper/equipment/DeviceMapper.xml | 4 ++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/EquipmentClassificationVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/EquipmentClassificationVo.java index d84f59ad..2ebecdc1 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/EquipmentClassificationVo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/EquipmentClassificationVo.java @@ -26,4 +26,24 @@ public class EquipmentClassificationVo { */ private Integer devices4GAndBluetooth = 0; + /** + * 设备总数 + */ + private Integer total; + + + /** + * 计算设备总数 + * + * @return 设备总数 + */ + public Integer getTotal() { + if (total == null) { + total = (equipment4G == null ? 0 : equipment4G) + + (deviceBluetooth == null ? 0 : deviceBluetooth) + + (devices4GAndBluetooth == null ? 0 : devices4GAndBluetooth); + } + return total; + } + } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceServiceImpl.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceServiceImpl.java index 967bc391..f356e414 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceServiceImpl.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceServiceImpl.java @@ -630,6 +630,7 @@ public class DeviceServiceImpl extends ServiceImpl impleme @Override public EquipmentClassificationVo getEquipmentClassification() { EquipmentClassificationVo equipmentClassification = deviceMapper.getEquipmentClassification(); + equipmentClassification.getTotal(); return equipmentClassification; } diff --git a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml index 81c66744..0ce9fc67 100644 --- a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml +++ b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml @@ -321,11 +321,11 @@ From 7e87971c0b5ed51a76ce47a4df06b4945e7f3702 Mon Sep 17 00:00:00 2001 From: daiyongfei <974332738@qq.com> Date: Tue, 9 Sep 2025 15:02:46 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=E8=AE=BE=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/mapper/equipment/DeviceMapper.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml index 0ce9fc67..d1ebc0ea 100644 --- a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml +++ b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml @@ -322,7 +322,7 @@ - SELECT COUNT(CASE WHEN MONTH (dl.create_time) = 1 THEN 1 END) AS m1, - COUNT(CASE WHEN MONTH (dl.create_time) = 2 THEN 1 END) AS m2, - COUNT(CASE WHEN MONTH (dl.create_time) = 3 THEN 1 END) AS m3, - COUNT(CASE WHEN MONTH (dl.create_time) = 4 THEN 1 END) AS m4, - COUNT(CASE WHEN MONTH (dl.create_time) = 5 THEN 1 END) AS m5, - COUNT(CASE WHEN MONTH (dl.create_time) = 6 THEN 1 END) AS m6, - COUNT(CASE WHEN MONTH (dl.create_time) = 7 THEN 1 END) AS m7, - COUNT(CASE WHEN MONTH (dl.create_time) = 8 THEN 1 END) AS m8, - COUNT(CASE WHEN MONTH (dl.create_time) = 9 THEN 1 END) AS m9, - COUNT(CASE WHEN MONTH (dl.create_time) = 10 THEN 1 END) AS m10, - COUNT(CASE WHEN MONTH (dl.create_time) = 11 THEN 1 END) AS m11, - COUNT(CASE WHEN MONTH (dl.create_time) = 12 THEN 1 END) AS m12 + SELECT COUNT(CASE WHEN MONTH (dl.create_time) = 1 THEN 1 END) AS m1, + COUNT(CASE WHEN MONTH (dl.create_time) = 2 THEN 1 END) AS m2, + COUNT(CASE WHEN MONTH (dl.create_time) = 3 THEN 1 END) AS m3, + COUNT(CASE WHEN MONTH (dl.create_time) = 4 THEN 1 END) AS m4, + COUNT(CASE WHEN MONTH (dl.create_time) = 5 THEN 1 END) AS m5, + COUNT(CASE WHEN MONTH (dl.create_time) = 6 THEN 1 END) AS m6, + COUNT(CASE WHEN MONTH (dl.create_time) = 7 THEN 1 END) AS m7, + COUNT(CASE WHEN MONTH (dl.create_time) = 8 THEN 1 END) AS m8, + COUNT(CASE WHEN MONTH (dl.create_time) = 9 THEN 1 END) AS m9, + COUNT(CASE WHEN MONTH (dl.create_time) = 10 THEN 1 END) AS m10, + COUNT(CASE WHEN MONTH (dl.create_time) = 11 THEN 1 END) AS m11, + COUNT(CASE WHEN MONTH (dl.create_time) = 12 THEN 1 END) AS m12 FROM device_log dl - LEFT JOIN device d ON dl.device_id = d.id - LEFT JOIN device_type dt ON d.device_type = dt.id - WHERE dt.id = #{deviceId} - AND ( + LEFT JOIN device d ON dl.device_id = d.id + LEFT JOIN device_type dt ON d.device_type = dt.id + + + dt.id = #{deviceTypeId} + + AND ( (#{range} = 1 AND dl.create_time >= DATE_SUB(NOW(), INTERVAL 6 MONTH)) OR (#{range} = 2 AND dl.create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH)) ) + - SELECT (SELECT COUNT(1) FROM device_alarm WHERE treatment_state = 0 AND DATE (create_time) = CURDATE()) AS alarmsTotal, ( + SELECT (SELECT COUNT(1) FROM device_alarm WHERE treatment_state = 0) AS alarmsTotal + , (SELECT COUNT(1) + FROM device_alarm + WHERE treatment_state = 0) AS processingAlarm + , (SELECT COUNT(1) + FROM device_alarm + WHERE treatment_state = 0 AND + DATE (create_time) = CURDATE()) AS alarmsTotalToday + , ( SELECT COUNT (1) FROM device_alarm WHERE treatment_state = 0 - AND DATE (create_time) = CURDATE()) AS processingAlarm + AND DATE (create_time) = CURDATE()) AS processingAlarmToday , ( SELECT COUNT (1) FROM device_alarm WHERE device_action = 0 - AND DATE (create_time) = CURDATE()) AS alarmForced + ) AS alarmForced , ( SELECT COUNT (1) FROM device_alarm WHERE device_action = 1 - AND DATE (create_time) = CURDATE()) AS intrusionImpact + ) AS intrusionImpact , ( SELECT COUNT (1) FROM device_alarm WHERE device_action = 2 - AND DATE (create_time) = CURDATE()) AS alarmManual + ) AS alarmManual , ( SELECT COUNT (1) FROM device_alarm - WHERE device_action = 3 AND DATE (create_time) = CURDATE()) AS fenceElectronic + WHERE device_action = 3) AS fenceElectronic From 6bc1d5b20bbecd5917289d6f0389483e7c22dfd3 Mon Sep 17 00:00:00 2001 From: daiyongfei <974332738@qq.com> Date: Wed, 10 Sep 2025 09:56:39 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E7=BB=91=E5=AE=9A=E8=AE=BE=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java | 7 +++++++ .../src/main/resources/mapper/equipment/DeviceMapper.xml | 3 +++ 2 files changed, 10 insertions(+) diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java index c8c016d7..10fbe2e7 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java @@ -26,6 +26,13 @@ public class DataOverviewVo { */ private Integer bindingNew = 0; + + /** + * 绑定设备 + */ + private Integer binding = 0; + + /** * 异常设备 */ diff --git a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml index f70aeca7..4d1a80fd 100644 --- a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml +++ b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml @@ -325,6 +325,9 @@ (SELECT COUNT(1) FROM device WHERE DATE (create_time) = CURDATE() AND binding_status = 1 ) AS bindingNew, ( SELECT COUNT (1) FROM device + WHERE binding_status = 1 ) AS binding, ( + SELECT COUNT (1) + FROM device WHERE online_status = 2) AS equipmentAbnormal From b8af6b511cbddb30bb894a937a78430d99f484e1 Mon Sep 17 00:00:00 2001 From: daiyongfei <974332738@qq.com> Date: Thu, 11 Sep 2025 10:54:56 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E7=94=B5=E5=AD=90=E5=9B=B4=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DeviceFenceAccessRecordController.java | 108 ++++++++++ .../fence/DeviceGeoFenceController.java | 124 +++++++++++ .../domain/DeviceFenceAccessRecord.java | 78 +++++++ .../equipment/domain/DeviceGeoFence.java | 78 +++++++ .../domain/bo/DeviceChargeDischargeBo.java | 13 ++ .../domain/bo/DeviceFenceAccessRecordBo.java | 83 ++++++++ .../equipment/domain/bo/DeviceGeoFenceBo.java | 80 +++++++ .../domain/dto/FenceCheckResponse.java | 63 ++++++ .../domain/query/FenceCheckRequest.java | 39 ++++ .../domain/vo/AlarmInformationVo.java | 2 +- .../equipment/domain/vo/DataOverviewVo.java | 4 +- .../domain/vo/DeviceFenceAccessRecordVo.java | 94 +++++++++ .../equipment/domain/vo/DeviceGeoFenceVo.java | 94 +++++++++ .../mapper/DeviceFenceAccessRecordMapper.java | 15 ++ .../mapper/DeviceGeoFenceMapper.java | 15 ++ .../IDeviceFenceAccessRecordService.java | 68 ++++++ .../service/IDeviceGeoFenceService.java | 78 +++++++ .../DeviceFenceAccessRecordServiceImpl.java | 140 ++++++++++++ .../impl/DeviceGeoFenceServiceImpl.java | 199 ++++++++++++++++++ .../equipment/utils/map/Coordinate.java | 24 +++ .../equipment/utils/map/GeoFenceChecker.java | 135 ++++++++++++ .../DeviceFenceAccessRecordMapper.xml | 7 + .../mapper/equipment/DeviceGeoFenceMapper.xml | 7 + 23 files changed, 1544 insertions(+), 4 deletions(-) create mode 100644 fys-admin/src/main/java/com/fuyuanshen/web/controller/device/fence/DeviceFenceAccessRecordController.java create mode 100644 fys-admin/src/main/java/com/fuyuanshen/web/controller/device/fence/DeviceGeoFenceController.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceFenceAccessRecord.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceGeoFence.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceFenceAccessRecordBo.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceGeoFenceBo.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/FenceCheckResponse.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/query/FenceCheckRequest.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceFenceAccessRecordVo.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceGeoFenceVo.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceFenceAccessRecordMapper.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceGeoFenceMapper.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceFenceAccessRecordService.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceGeoFenceService.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceFenceAccessRecordServiceImpl.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceGeoFenceServiceImpl.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/map/Coordinate.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/map/GeoFenceChecker.java create mode 100644 fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceFenceAccessRecordMapper.xml create mode 100644 fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceGeoFenceMapper.xml diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/fence/DeviceFenceAccessRecordController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/fence/DeviceFenceAccessRecordController.java new file mode 100644 index 00000000..97e7aa97 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/fence/DeviceFenceAccessRecordController.java @@ -0,0 +1,108 @@ +package com.fuyuanshen.web.controller.device.fence; + +import java.util.List; + +import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo; +import com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo; +import com.fuyuanshen.equipment.service.IDeviceFenceAccessRecordService; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit; +import com.fuyuanshen.common.log.annotation.Log; +import com.fuyuanshen.common.web.core.BaseController; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.fuyuanshen.common.core.domain.R; +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.core.validate.EditGroup; +import com.fuyuanshen.common.log.enums.BusinessType; +import com.fuyuanshen.common.excel.utils.ExcelUtil; + +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; + +/** + * 围栏进出记录 + * + * @author Lion Li + * @date 2025-09-11 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/fys-equipment/fenceAccessRecord") +public class DeviceFenceAccessRecordController extends BaseController { + + private final IDeviceFenceAccessRecordService deviceFenceAccessRecordService; + + /** + * 查询围栏进出记录列表 + */ + @SaCheckPermission("fys-equipment:fenceAccessRecord:list") + @GetMapping("/list") + public TableDataInfo list(DeviceFenceAccessRecordBo bo, PageQuery pageQuery) { + return deviceFenceAccessRecordService.queryPageList(bo, pageQuery); + } + + /** + * 围栏进出记录列表 + */ + @SaCheckPermission("fys-equipment:fenceAccessRecord:export") + @Log(title = "围栏进出记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(DeviceFenceAccessRecordBo bo, HttpServletResponse response) { + List list = deviceFenceAccessRecordService.queryList(bo); + ExcelUtil.exportExcel(list, "围栏进出记录", DeviceFenceAccessRecordVo.class, response); + } + + /** + * 获取围栏进出记录详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("fys-equipment:fenceAccessRecord:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(deviceFenceAccessRecordService.queryById(id)); + } + + /** + * 新增围栏进出记录 + */ + @SaCheckPermission("fys-equipment:fenceAccessRecord:add") + @Log(title = "围栏进出记录", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody DeviceFenceAccessRecordBo bo) { + return toAjax(deviceFenceAccessRecordService.insertByBo(bo)); + } + + /** + * 修改围栏进出记录 + */ + @SaCheckPermission("fys-equipment:fenceAccessRecord:edit") + @Log(title = "围栏进出记录", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody DeviceFenceAccessRecordBo bo) { + return toAjax(deviceFenceAccessRecordService.updateByBo(bo)); + } + + /** + * 删除围栏进出记录 + * + * @param ids 主键串 + */ + @SaCheckPermission("fys-equipment:fenceAccessRecord:remove") + @Log(title = "围栏进出记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(deviceFenceAccessRecordService.deleteWithValidByIds(List.of(ids), true)); + } + + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/fence/DeviceGeoFenceController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/fence/DeviceGeoFenceController.java new file mode 100644 index 00000000..cae25e3f --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/fence/DeviceGeoFenceController.java @@ -0,0 +1,124 @@ +package com.fuyuanshen.web.controller.device.fence; + +import java.util.List; + +import com.fuyuanshen.equipment.domain.bo.DeviceGeoFenceBo; +import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse; +import com.fuyuanshen.equipment.domain.query.FenceCheckRequest; +import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo; +import com.fuyuanshen.equipment.service.IDeviceGeoFenceService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit; +import com.fuyuanshen.common.log.annotation.Log; +import com.fuyuanshen.common.web.core.BaseController; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.fuyuanshen.common.core.domain.R; +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.core.validate.EditGroup; +import com.fuyuanshen.common.log.enums.BusinessType; +import com.fuyuanshen.common.excel.utils.ExcelUtil; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; + +/** + * 电子围栏 + * + * @author Lion Li + * @date 2025-09-11 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/fys-equipment/geoFence") +public class DeviceGeoFenceController extends BaseController { + + private final IDeviceGeoFenceService deviceGeoFenceService; + + /** + * 查询电子围栏列表 + */ + @SaCheckPermission("fys-equipment:geoFence:list") + @GetMapping("/list") + public TableDataInfo list(DeviceGeoFenceBo bo, PageQuery pageQuery) { + return deviceGeoFenceService.queryPageList(bo, pageQuery); + } + + /** + * 电子围栏列表 + */ + @SaCheckPermission("fys-equipment:geoFence:export") + @Log(title = "电子围栏", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(DeviceGeoFenceBo bo, HttpServletResponse response) { + List list = deviceGeoFenceService.queryList(bo); + ExcelUtil.exportExcel(list, "电子围栏", DeviceGeoFenceVo.class, response); + } + + /** + * 获取电子围栏详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("fys-equipment:geoFence:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(deviceGeoFenceService.queryById(id)); + } + + /** + * 新增电子围栏 + */ + @SaCheckPermission("fys-equipment:geoFence:add") + @Log(title = "电子围栏", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody DeviceGeoFenceBo bo) { + return toAjax(deviceGeoFenceService.insertByBo(bo)); + } + + /** + * 修改电子围栏 + */ + @SaCheckPermission("fys-equipment:geoFence:edit") + @Log(title = "电子围栏", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody DeviceGeoFenceBo bo) { + return toAjax(deviceGeoFenceService.updateByBo(bo)); + } + + /** + * 删除电子围栏 + * + * @param ids 主键串 + */ + @SaCheckPermission("fys-equipment:geoFence:remove") + @Log(title = "电子围栏", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(deviceGeoFenceService.deleteWithValidByIds(List.of(ids), true)); + } + + + /** + * 位置检查 + * + * @param request + * @return + */ + @PostMapping("/check") + public ResponseEntity checkPosition( + @Valid @RequestBody FenceCheckRequest request) { + FenceCheckResponse response = deviceGeoFenceService.checkPosition(request); + return ResponseEntity.ok(response); + } + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceFenceAccessRecord.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceFenceAccessRecord.java new file mode 100644 index 00000000..8b50674c --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceFenceAccessRecord.java @@ -0,0 +1,78 @@ +package com.fuyuanshen.equipment.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.fuyuanshen.common.mybatis.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 围栏进出记录对象 device_fence_access_record + * + * @author Lion Li + * @date 2025-09-11 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("device_fence_access_record") +public class DeviceFenceAccessRecord extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 记录ID + */ + @TableId(value = "id") + private Long id; + + /** + * 围栏ID + */ + private Long fenceId; + + /** + * 设备标识 + */ + private String deviceId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 事件类型 + */ + private Long eventType; + + /** + * 纬度 + */ + private Long latitude; + + /** + * 经度 + */ + private Long longitude; + + /** + * 定位精度 + */ + private Long accuracy; + + /** + * 事件时间 + */ + private Date eventTime; + + /** + * 记录创建时间 + */ + private Date createdTime; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceGeoFence.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceGeoFence.java new file mode 100644 index 00000000..37285038 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceGeoFence.java @@ -0,0 +1,78 @@ +package com.fuyuanshen.equipment.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.fuyuanshen.common.mybatis.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 电子围栏对象 device_geo_fence + * + * @author Lion Li + * @date 2025-09-11 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("device_geo_fence") +public class DeviceGeoFence extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 围栏唯一标识 + */ + @TableId(value = "id") + private Long id; + + /** + * 围栏名称 + */ + private String name; + + /** + * 围栏描述 + */ + private String description; + + /** + * 围栏区域类型, 0 POLYGON, 1 CIRCLE + */ + private Long areaType; + + /** + * 围栏坐标数据 + */ + private String coordinates; + + /** + * 圆形围栏半径(米) + */ + private Long radius; + + /** + * 是否激活 + */ + private Long isActive; + + /** + * 创建人 + */ + private Long createdBy; + + /** + * 创建时间 + */ + private Date createdTime; + + /** + * 更新时间 + */ + private Date updatedTime; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceChargeDischargeBo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceChargeDischargeBo.java index e953b0e8..cda7d679 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceChargeDischargeBo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceChargeDischargeBo.java @@ -6,6 +6,7 @@ import com.fuyuanshen.equipment.domain.DeviceChargeDischarge; import com.fuyuanshen.common.mybatis.core.domain.BaseEntity; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import cn.hutool.core.date.DateUtil; import lombok.EqualsAndHashCode; import jakarta.validation.constraints.*; import java.util.Date; @@ -44,13 +45,25 @@ public class DeviceChargeDischargeBo extends BaseEntity { * 开始时间 */ @NotNull(message = "开始时间不能为空", groups = { AddGroup.class, EditGroup.class }) + @JsonFormat(pattern = "yyyy-MM-dd") private Date startTime; + // 添加字符串类型的setter方法来处理前端传递的字符串日期 + public void setStartTime(String startTime) { + this.startTime = DateUtil.parseDate(startTime); + } + /** * 结束时间 */ + @JsonFormat(pattern = "yyyy-MM-dd") private Date endTime; + // 添加字符串类型的setter方法来处理前端传递的字符串日期 + public void setEndTime(String endTime) { + this.endTime = DateUtil.parseDate(endTime); + } + /** * 起始电量百分比(0-100) */ diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceFenceAccessRecordBo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceFenceAccessRecordBo.java new file mode 100644 index 00000000..60d00f4e --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceFenceAccessRecordBo.java @@ -0,0 +1,83 @@ +package com.fuyuanshen.equipment.domain.bo; + +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.core.validate.EditGroup; +import com.fuyuanshen.common.mybatis.core.domain.BaseEntity; +import com.fuyuanshen.equipment.domain.DeviceFenceAccessRecord; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 围栏进出记录业务对象 device_fence_access_record + * + * @author Lion Li + * @date 2025-09-11 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = DeviceFenceAccessRecord.class, reverseConvertGenerate = false) +public class DeviceFenceAccessRecordBo extends BaseEntity { + + /** + * 记录ID + */ + @NotNull(message = "记录ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 围栏ID + */ + @NotNull(message = "围栏ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long fenceId; + + /** + * 设备标识 + */ + @NotBlank(message = "设备标识不能为空", groups = { AddGroup.class, EditGroup.class }) + private String deviceId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 事件类型 + */ + @NotNull(message = "事件类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long eventType; + + /** + * 纬度 + */ + @NotNull(message = "纬度不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long latitude; + + /** + * 经度 + */ + @NotNull(message = "经度不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long longitude; + + /** + * 定位精度 + */ + private Long accuracy; + + /** + * 事件时间 + */ + @NotNull(message = "事件时间不能为空", groups = { AddGroup.class, EditGroup.class }) + private Date eventTime; + + /** + * 记录创建时间 + */ + private Date createdTime; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceGeoFenceBo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceGeoFenceBo.java new file mode 100644 index 00000000..d13217d9 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceGeoFenceBo.java @@ -0,0 +1,80 @@ +package com.fuyuanshen.equipment.domain.bo; + +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.core.validate.EditGroup; +import com.fuyuanshen.common.mybatis.core.domain.BaseEntity; +import com.fuyuanshen.equipment.domain.DeviceGeoFence; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 电子围栏业务对象 device_geo_fence + * + * @author Lion Li + * @date 2025-09-11 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = DeviceGeoFence.class, reverseConvertGenerate = false) +public class DeviceGeoFenceBo extends BaseEntity { + + /** + * 围栏唯一标识 + */ + @NotNull(message = "围栏唯一标识不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 围栏名称 + */ + @NotBlank(message = "围栏名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String name; + + /** + * 围栏描述 + */ + private String description; + + /** + * 围栏区域类型, 0 POLYGON, 1 CIRCLE + */ + @NotNull(message = "围栏区域类型, 0 POLYGON, 1 CIRCLE不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long areaType; + + /** + * 围栏坐标数据 + */ + @NotBlank(message = "围栏坐标数据不能为空", groups = { AddGroup.class, EditGroup.class }) + private String coordinates; + + /** + * 圆形围栏半径(米) + */ + private Long radius; + + /** + * 是否激活 + */ + private Long isActive; + + /** + * 创建人 + */ + private Long createdBy; + + /** + * 创建时间 + */ + private Date createdTime; + + /** + * 更新时间 + */ + private Date updatedTime; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/FenceCheckResponse.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/FenceCheckResponse.java new file mode 100644 index 00000000..5d47f15d --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/FenceCheckResponse.java @@ -0,0 +1,63 @@ +package com.fuyuanshen.equipment.domain.dto; + +import lombok.Data; + +import java.util.List; + + +/** + * 围栏位置检查响应结果 + * + * @author: 默苍璃 + * @date: 2025-09-1110:11 + */ + +@Data +public class FenceCheckResponse { + + /** + * 设备ID + */ + private String deviceId; + + /** + * 检查时间 + */ + private Long checkTime; + + /** + * 进入围栏列表 + */ + private List enteredFences; + + /** + * 离开围栏列表 + */ + private List exitedFences; + + /** + * 当前所在围栏列表 + */ + private List currentFences; + + /** + * 围栏信息 + */ + @Data + public static class FenceInfo { + /** + * 围栏ID + */ + private Long fenceId; + + /** + * 围栏名称 + */ + private String fenceName; + + /** + * 围栏类型 + */ + private Integer fenceType; + } +} \ No newline at end of file diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/query/FenceCheckRequest.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/query/FenceCheckRequest.java new file mode 100644 index 00000000..de556516 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/query/FenceCheckRequest.java @@ -0,0 +1,39 @@ +package com.fuyuanshen.equipment.domain.query; + +/** + * @author: 默苍璃 + * @date: 2025-09-1110:10 + */ + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 围栏位置检查请求参数 + */ +@Data +public class FenceCheckRequest { + + /** + * 设备ID + */ + @NotNull(message = "设备ID不能为空") + private String deviceId; + + /** + * 纬度 + */ + @NotNull(message = "纬度不能为空") + private Double latitude; + + /** + * 经度 + */ + @NotNull(message = "经度不能为空") + private Double longitude; + + /** + * 定位精度(米) + */ + private Double accuracy; +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/AlarmInformationVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/AlarmInformationVo.java index 58216893..1d2e2484 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/AlarmInformationVo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/AlarmInformationVo.java @@ -49,7 +49,7 @@ public class AlarmInformationVo { private Integer alarmManual = 0; /** - * 电子围栏 + * */ private Integer fenceElectronic = 0; diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java index 10fbe2e7..c4b6d39e 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java @@ -26,13 +26,11 @@ public class DataOverviewVo { */ private Integer bindingNew = 0; - /** - * 绑定设备 + * 已绑定设备 */ private Integer binding = 0; - /** * 异常设备 */ diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceFenceAccessRecordVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceFenceAccessRecordVo.java new file mode 100644 index 00000000..a91b3950 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceFenceAccessRecordVo.java @@ -0,0 +1,94 @@ +package com.fuyuanshen.equipment.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import com.fuyuanshen.common.excel.annotation.ExcelDictFormat; +import com.fuyuanshen.common.excel.convert.ExcelDictConvert; +import com.fuyuanshen.equipment.domain.DeviceFenceAccessRecord; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 围栏进出记录视图对象 device_fence_access_record + * + * @author Lion Li + * @date 2025-09-11 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = DeviceFenceAccessRecord.class) +public class DeviceFenceAccessRecordVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 记录ID + */ + @ExcelProperty(value = "记录ID") + private Long id; + + /** + * 围栏ID + */ + @ExcelProperty(value = "围栏ID") + private Long fenceId; + + /** + * 设备标识 + */ + @ExcelProperty(value = "设备标识") + private String deviceId; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户ID") + private Long userId; + + /** + * 事件类型 + */ + @ExcelProperty(value = "事件类型") + private Long eventType; + + /** + * 纬度 + */ + @ExcelProperty(value = "纬度") + private Long latitude; + + /** + * 经度 + */ + @ExcelProperty(value = "经度") + private Long longitude; + + /** + * 定位精度 + */ + @ExcelProperty(value = "定位精度") + private Long accuracy; + + /** + * 事件时间 + */ + @ExcelProperty(value = "事件时间") + private Date eventTime; + + /** + * 记录创建时间 + */ + @ExcelProperty(value = "记录创建时间") + private Date createdTime; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceGeoFenceVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceGeoFenceVo.java new file mode 100644 index 00000000..50fbc372 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceGeoFenceVo.java @@ -0,0 +1,94 @@ +package com.fuyuanshen.equipment.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import com.fuyuanshen.common.excel.annotation.ExcelDictFormat; +import com.fuyuanshen.common.excel.convert.ExcelDictConvert; +import com.fuyuanshen.equipment.domain.DeviceGeoFence; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 电子围栏视图对象 device_geo_fence + * + * @author Lion Li + * @date 2025-09-11 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = DeviceGeoFence.class) +public class DeviceGeoFenceVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 围栏唯一标识 + */ + @ExcelProperty(value = "围栏唯一标识") + private Long id; + + /** + * 围栏名称 + */ + @ExcelProperty(value = "围栏名称") + private String name; + + /** + * 围栏描述 + */ + @ExcelProperty(value = "围栏描述") + private String description; + + /** + * 围栏区域类型, 0 POLYGON, 1 CIRCLE + */ + @ExcelProperty(value = "围栏区域类型, 0 POLYGON, 1 CIRCLE") + private Integer areaType; + + /** + * 围栏坐标数据 + */ + @ExcelProperty(value = "围栏坐标数据") + private String coordinates; + + /** + * 圆形围栏半径(米) + */ + @ExcelProperty(value = "圆形围栏半径(米)") + private Long radius; + + /** + * 是否激活 + */ + @ExcelProperty(value = "是否激活") + private Long isActive; + + /** + * 创建人 + */ + @ExcelProperty(value = "创建人") + private Long createdBy; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createdTime; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Date updatedTime; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceFenceAccessRecordMapper.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceFenceAccessRecordMapper.java new file mode 100644 index 00000000..f6f03f6d --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceFenceAccessRecordMapper.java @@ -0,0 +1,15 @@ +package com.fuyuanshen.equipment.mapper; + +import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus; +import com.fuyuanshen.equipment.domain.DeviceFenceAccessRecord; +import com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo; + +/** + * 围栏进出记录Mapper接口 + * + * @author Lion Li + * @date 2025-09-11 + */ +public interface DeviceFenceAccessRecordMapper extends BaseMapperPlus { + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceGeoFenceMapper.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceGeoFenceMapper.java new file mode 100644 index 00000000..f6352b93 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceGeoFenceMapper.java @@ -0,0 +1,15 @@ +package com.fuyuanshen.equipment.mapper; + +import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus; +import com.fuyuanshen.equipment.domain.DeviceGeoFence; +import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo; + +/** + * 电子围栏Mapper接口 + * + * @author Lion Li + * @date 2025-09-11 + */ +public interface DeviceGeoFenceMapper extends BaseMapperPlus { + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceFenceAccessRecordService.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceFenceAccessRecordService.java new file mode 100644 index 00000000..0d596719 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceFenceAccessRecordService.java @@ -0,0 +1,68 @@ +package com.fuyuanshen.equipment.service; + +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo; +import com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo; + +import java.util.Collection; +import java.util.List; + +/** + * 围栏进出记录Service接口 + * + * @author Lion Li + * @date 2025-09-11 + */ +public interface IDeviceFenceAccessRecordService { + + /** + * 查询围栏进出记录 + * + * @param id 主键 + * @return 围栏进出记录 + */ + DeviceFenceAccessRecordVo queryById(Long id); + + /** + * 分页查询围栏进出记录列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 围栏进出记录分页列表 + */ + TableDataInfo queryPageList(DeviceFenceAccessRecordBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的围栏进出记录列表 + * + * @param bo 查询条件 + * @return 围栏进出记录列表 + */ + List queryList(DeviceFenceAccessRecordBo bo); + + /** + * 新增围栏进出记录 + * + * @param bo 围栏进出记录 + * @return 是否新增成功 + */ + Boolean insertByBo(DeviceFenceAccessRecordBo bo); + + /** + * 修改围栏进出记录 + * + * @param bo 围栏进出记录 + * @return 是否修改成功 + */ + Boolean updateByBo(DeviceFenceAccessRecordBo bo); + + /** + * 校验并批量删除围栏进出记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceGeoFenceService.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceGeoFenceService.java new file mode 100644 index 00000000..69a7d8f3 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceGeoFenceService.java @@ -0,0 +1,78 @@ +package com.fuyuanshen.equipment.service; + +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.fuyuanshen.equipment.domain.bo.DeviceGeoFenceBo; +import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse; +import com.fuyuanshen.equipment.domain.query.FenceCheckRequest; +import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo; + +import java.util.Collection; +import java.util.List; + +/** + * 电子围栏Service接口 + * + * @author Lion Li + * @date 2025-09-11 + */ +public interface IDeviceGeoFenceService { + + /** + * 查询电子围栏 + * + * @param id 主键 + * @return 电子围栏 + */ + DeviceGeoFenceVo queryById(Long id); + + /** + * 分页查询电子围栏列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 电子围栏分页列表 + */ + TableDataInfo queryPageList(DeviceGeoFenceBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的电子围栏列表 + * + * @param bo 查询条件 + * @return 电子围栏列表 + */ + List queryList(DeviceGeoFenceBo bo); + + /** + * 新增电子围栏 + * + * @param bo 电子围栏 + * @return 是否新增成功 + */ + Boolean insertByBo(DeviceGeoFenceBo bo); + + /** + * 修改电子围栏 + * + * @param bo 电子围栏 + * @return 是否修改成功 + */ + Boolean updateByBo(DeviceGeoFenceBo bo); + + /** + * 校验并批量删除电子围栏信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 检查设备位置与围栏的关系 + * + * @param request 位置检查请求 + * @return 位置检查结果 + */ + FenceCheckResponse checkPosition(FenceCheckRequest request); +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceFenceAccessRecordServiceImpl.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceFenceAccessRecordServiceImpl.java new file mode 100644 index 00000000..a09f8386 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceFenceAccessRecordServiceImpl.java @@ -0,0 +1,140 @@ +package com.fuyuanshen.equipment.service.impl; + +import com.fuyuanshen.common.core.utils.MapstructUtils; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.fuyuanshen.equipment.domain.DeviceFenceAccessRecord; +import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo; +import com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo; +import com.fuyuanshen.equipment.mapper.DeviceFenceAccessRecordMapper; +import com.fuyuanshen.equipment.service.IDeviceFenceAccessRecordService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 围栏进出记录Service业务层处理 + * + * @author Lion Li + * @date 2025-09-11 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class DeviceFenceAccessRecordServiceImpl implements IDeviceFenceAccessRecordService { + + private final DeviceFenceAccessRecordMapper baseMapper; + + /** + * 查询围栏进出记录 + * + * @param id 主键 + * @return 围栏进出记录 + */ + @Override + public DeviceFenceAccessRecordVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询围栏进出记录列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 围栏进出记录分页列表 + */ + @Override + public TableDataInfo queryPageList(DeviceFenceAccessRecordBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的围栏进出记录列表 + * + * @param bo 查询条件 + * @return 围栏进出记录列表 + */ + @Override + public List queryList(DeviceFenceAccessRecordBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(DeviceFenceAccessRecordBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(DeviceFenceAccessRecord::getId); + lqw.eq(bo.getFenceId() != null, DeviceFenceAccessRecord::getFenceId, bo.getFenceId()); + lqw.eq(StringUtils.isNotBlank(bo.getDeviceId()), DeviceFenceAccessRecord::getDeviceId, bo.getDeviceId()); + lqw.eq(bo.getUserId() != null, DeviceFenceAccessRecord::getUserId, bo.getUserId()); + lqw.eq(bo.getEventType() != null, DeviceFenceAccessRecord::getEventType, bo.getEventType()); + lqw.eq(bo.getLatitude() != null, DeviceFenceAccessRecord::getLatitude, bo.getLatitude()); + lqw.eq(bo.getLongitude() != null, DeviceFenceAccessRecord::getLongitude, bo.getLongitude()); + lqw.eq(bo.getAccuracy() != null, DeviceFenceAccessRecord::getAccuracy, bo.getAccuracy()); + lqw.eq(bo.getEventTime() != null, DeviceFenceAccessRecord::getEventTime, bo.getEventTime()); + lqw.eq(bo.getCreatedTime() != null, DeviceFenceAccessRecord::getCreatedTime, bo.getCreatedTime()); + return lqw; + } + + /** + * 新增围栏进出记录 + * + * @param bo 围栏进出记录 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(DeviceFenceAccessRecordBo bo) { + DeviceFenceAccessRecord add = MapstructUtils.convert(bo, DeviceFenceAccessRecord.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改围栏进出记录 + * + * @param bo 围栏进出记录 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(DeviceFenceAccessRecordBo bo) { + DeviceFenceAccessRecord update = MapstructUtils.convert(bo, DeviceFenceAccessRecord.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(DeviceFenceAccessRecord entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除围栏进出记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceGeoFenceServiceImpl.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceGeoFenceServiceImpl.java new file mode 100644 index 00000000..c5fbb2df --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceGeoFenceServiceImpl.java @@ -0,0 +1,199 @@ +package com.fuyuanshen.equipment.service.impl; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fuyuanshen.common.core.utils.MapstructUtils; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.fuyuanshen.equipment.domain.DeviceGeoFence; +import com.fuyuanshen.equipment.domain.bo.DeviceGeoFenceBo; +import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse; +import com.fuyuanshen.equipment.domain.query.FenceCheckRequest; +import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo; +import com.fuyuanshen.equipment.mapper.DeviceGeoFenceMapper; +import com.fuyuanshen.equipment.service.IDeviceGeoFenceService; +import com.fuyuanshen.equipment.utils.map.GeoFenceChecker; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 电子围栏Service业务层处理 + * + * @author Lion Li + * @date 2025-09-11 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService { + + private final DeviceGeoFenceMapper baseMapper; + + /** + * 查询电子围栏 + * + * @param id 主键 + * @return 电子围栏 + */ + @Override + public DeviceGeoFenceVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询电子围栏列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 电子围栏分页列表 + */ + @Override + public TableDataInfo queryPageList(DeviceGeoFenceBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的电子围栏列表 + * + * @param bo 查询条件 + * @return 电子围栏列表 + */ + @Override + public List queryList(DeviceGeoFenceBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(DeviceGeoFenceBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(DeviceGeoFence::getId); + lqw.like(StringUtils.isNotBlank(bo.getName()), DeviceGeoFence::getName, bo.getName()); + lqw.eq(StringUtils.isNotBlank(bo.getDescription()), DeviceGeoFence::getDescription, bo.getDescription()); + lqw.eq(bo.getAreaType() != null, DeviceGeoFence::getAreaType, bo.getAreaType()); + lqw.eq(StringUtils.isNotBlank(bo.getCoordinates()), DeviceGeoFence::getCoordinates, bo.getCoordinates()); + lqw.eq(bo.getRadius() != null, DeviceGeoFence::getRadius, bo.getRadius()); + lqw.eq(bo.getIsActive() != null, DeviceGeoFence::getIsActive, bo.getIsActive()); + lqw.eq(bo.getCreatedBy() != null, DeviceGeoFence::getCreatedBy, bo.getCreatedBy()); + lqw.eq(bo.getCreatedTime() != null, DeviceGeoFence::getCreatedTime, bo.getCreatedTime()); + lqw.eq(bo.getUpdatedTime() != null, DeviceGeoFence::getUpdatedTime, bo.getUpdatedTime()); + return lqw; + } + + /** + * 新增电子围栏 + * + * @param bo 电子围栏 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(DeviceGeoFenceBo bo) { + DeviceGeoFence add = MapstructUtils.convert(bo, DeviceGeoFence.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改电子围栏 + * + * @param bo 电子围栏 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(DeviceGeoFenceBo bo) { + DeviceGeoFence update = MapstructUtils.convert(bo, DeviceGeoFence.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(DeviceGeoFence entity) { + // TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除电子围栏信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + + /** + * 检查设备位置与围栏的关系 + * + * @param request 位置检查请求 + * @return 位置检查结果 + */ + @Override + public FenceCheckResponse checkPosition(FenceCheckRequest request) { + // 1. 获取所有激活的围栏 + DeviceGeoFenceBo bo = new DeviceGeoFenceBo(); + bo.setIsActive(1L); // 假设1表示激活状态 + List activeFences = queryList(bo); + + // 2. 判断设备位置与各围栏的关系 + FenceCheckResponse response = new FenceCheckResponse(); + response.setDeviceId(request.getDeviceId()); + response.setCheckTime(System.currentTimeMillis()); + + // 这里需要实现具体的围栏判断逻辑 + // 根据您之前提供的算法实现点在围栏内的判断 + + for (DeviceGeoFenceVo fence : activeFences) { + String coordinates = fence.getCoordinates(); + + // 在需要转换的地方 + ObjectMapper objectMapper = new ObjectMapper(); + List coordinateList = List.of(); + try { + coordinateList = objectMapper.readValue(coordinates, + new TypeReference>() { + }); + } catch (Exception e) { + // 处理解析异常 + log.error("坐标数据解析失败: {}", e.getMessage()); + } + + FenceCheckResponse.FenceInfo fenceInfo = new FenceCheckResponse.FenceInfo(); + boolean pointInFence = GeoFenceChecker.isPointInFence(request.getLatitude(), request.getLongitude(), fence.getAreaType(), coordinateList, fence.getRadius()); + if (pointInFence) { + fenceInfo.setFenceId(fence.getId()); + fenceInfo.setFenceName(fence.getName()); + fenceInfo.setFenceType(fence.getAreaType()); + response.getEnteredFences().add(fenceInfo); + } else { + response.getExitedFences().add(fenceInfo); + } + } + + return response; + } + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/map/Coordinate.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/map/Coordinate.java new file mode 100644 index 00000000..781c9a23 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/map/Coordinate.java @@ -0,0 +1,24 @@ +package com.fuyuanshen.equipment.utils.map; + +/** + * @author: 默苍璃 + * @date: 2025-09-1110:27 + */ +public class Coordinate { + private double lat; + private double lng; + + // 构造函数 + public Coordinate() {} + + public Coordinate(double lat, double lng) { + this.lat = lat; + this.lng = lng; + } + + // getter和setter方法 + public double getLat() { return lat; } + public void setLat(double lat) { this.lat = lat; } + public double getLng() { return lng; } + public void setLng(double lng) { this.lng = lng; } +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/map/GeoFenceChecker.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/map/GeoFenceChecker.java new file mode 100644 index 00000000..5f38139c --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/map/GeoFenceChecker.java @@ -0,0 +1,135 @@ +package com.fuyuanshen.equipment.utils.map; + +import java.util.List; + +/** + * @author: 默苍璃 + * @date: 2025-09-1110:13 + */ +public class GeoFenceChecker { + + /** + * 点是否在围栏内 + * + * @param pointLat 点的纬度 + * @param pointLng 点的经度 + * @param fenceType 围栏类型:0 POLYGON 或 1 CIRCLE + * @param coordinates 围栏坐标点列表 + * @param radius 圆形围栏半径(米),仅对CIRCLE类型有效 + * @return true表示在围栏内,false表示在围栏外 + */ + public static boolean isPointInFence(double pointLat, double pointLng, + Integer fenceType, + List coordinates, + Long radius) { + if (fenceType == 0) { + return isPointInPolygon(pointLat, pointLng, coordinates); + } else if (fenceType == 1) { + if (coordinates == null || coordinates.isEmpty() || radius == null) { + return false; + } + // 圆形围栏只有一个坐标点(圆心) + Coordinate center = coordinates.get(0); + return isPointInCircle(pointLat, pointLng, center.lat, center.lng, radius); + } + return false; + } + + /** + * 使用射线投射算法判断点是否在多边形内 + * + * @param pointLat 点的纬度 + * @param pointLng 点的经度 + * @param polygon 多边形顶点坐标列表 + * @return true表示在多边形内,false表示在多边形外 + */ + public static boolean isPointInPolygon(double pointLat, double pointLng, + List polygon) { + if (polygon == null || polygon.size() < 3) { + return false; + } + + int intersectCount = 0; + int vertexCount = polygon.size(); + + // 遍历多边形的每条边 + for (int i = 0; i < vertexCount; i++) { + Coordinate p1 = polygon.get(i); + Coordinate p2 = polygon.get((i + 1) % vertexCount); + + // 检查点是否在边的y范围内 + if (p1.lat != p2.lat && + (pointLat >= Math.min(p1.lat, p2.lat)) && + (pointLat < Math.max(p1.lat, p2.lat))) { + + // 计算边与从点发出的水平射线的交点经度 + double intersectLng = (pointLat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng; + + // 如果交点在点的右侧,则计数加1 + if (pointLng < intersectLng) { + intersectCount++; + } + } + } + + // 奇数个交点表示点在多边形内 + return intersectCount % 2 == 1; + } + + /** + * 判断点是否在圆形内 + * + * @param pointLat 点的纬度 + * @param pointLng 点的经度 + * @param centerLat 圆心纬度 + * @param centerLng 圆心经度 + * @param radius 半径(米) + * @return true表示在圆内,false表示在圆外 + */ + public static boolean isPointInCircle(double pointLat, double pointLng, + double centerLat, double centerLng, + Long radius) { + double distance = calculateDistance(pointLat, pointLng, centerLat, centerLng); + return distance <= radius; + } + + /** + * 计算两点间距离(使用Haversine公式) + * + * @param lat1 点1纬度 + * @param lng1 点1经度 + * @param lat2 点2纬度 + * @param lng2 点2经度 + * @return 距离(米) + */ + public static double calculateDistance(double lat1, double lng1, double lat2, double lng2) { + final double EARTH_RADIUS = 6371000; // 地球半径(米) + + double dLat = Math.toRadians(lat2 - lat1); + double dLng = Math.toRadians(lng2 - lng1); + + double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * + Math.sin(dLng / 2) * Math.sin(dLng / 2); + + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + + return EARTH_RADIUS * c; + } + + /** + * 坐标点类 + */ + public static class Coordinate { + public double lat; + public double lng; + + public Coordinate() { + } + + public Coordinate(double lat, double lng) { + this.lat = lat; + this.lng = lng; + } + } +} \ No newline at end of file diff --git a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceFenceAccessRecordMapper.xml b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceFenceAccessRecordMapper.xml new file mode 100644 index 00000000..2667e1b3 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceFenceAccessRecordMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceGeoFenceMapper.xml b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceGeoFenceMapper.xml new file mode 100644 index 00000000..1590ebe0 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceGeoFenceMapper.xml @@ -0,0 +1,7 @@ + + + + +