whyzxhnd 1 day ago
parent
commit
570097387d
  1. 2
      cc-admin-master/pom.xml
  2. 403
      cc-admin-master/tmp/.scr/auto_export.py
  3. 63
      cc-admin-master/yudao-module-hand-mqtt/pom.xml
  4. 52
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/config/BatchProcessorConfig.java
  5. 89
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/config/TdengineBatchConfig.java
  6. 34
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/kafka/KafkaConfig.java
  7. 58
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/kafka/KafkaMessageConsumer.java
  8. 44
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/kafka/KafkaTopicType.java
  9. 150
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/mqtt/Client.java
  10. 9
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/mqtt/MqttConnectedEvent.java
  11. 68
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/mqtt/OnMessageCallback.java
  12. 31
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/mqtt/ThreadPoolConfig.java
  13. 505
      cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/processor/DeviceMessageProcessor.java
  14. 8
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/AlarmRuleController.java
  15. 8
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/AlarmTypeController.java
  16. 107
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/FactoryController.java
  17. 8
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/FenceAlarmController.java
  18. 12
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/FenceController.java
  19. 8
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/GasTypeController.java
  20. 8
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/HandAlarmController.java
  21. 39
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/HandDetectorController.java
  22. 66
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/HandTdengineController.java
  23. 2
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/package-info.java
  24. 23
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/AlarmRuleDO.java
  25. 16
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/AlarmTypeDO.java
  26. 97
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/FactoryDO.java
  27. 37
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/FenceAlarmDO.java
  28. 19
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/FenceDO.java
  29. 20
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/GasTypeDO.java
  30. 31
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/HandAlarmDO.java
  31. 37
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/HandDetectorDO.java
  32. 48
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/AlarmLevelEnum.java
  33. 53
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/AlarmType.java
  34. 14
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/EnableStatus.java
  35. 6
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/ErrorCodeConstants.java
  36. 52
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/FenceStatusType.java
  37. 52
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/FenceType.java
  38. 52
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/HandAlarmType.java
  39. 14
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/MaxDirection.java
  40. 52
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/OnlineStatusType.java
  41. 3
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/AlarmRuleMapper.java
  42. 3
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/AlarmTypeMapper.java
  43. 41
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/FactoryMapper.java
  44. 3
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/FenceAlarmMapper.java
  45. 3
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/FenceMapper.java
  46. 3
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/GasTypeMapper.java
  47. 3
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/HandAlarmMapper.java
  48. 12
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/HandDetectorMapper.java
  49. 30
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/TdengineMapper.java
  50. 11
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/AlarmRuleService.java
  51. 8
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/AlarmTypeService.java
  52. 64
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/FactoryService.java
  53. 11
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/FenceAlarmService.java
  54. 16
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/FenceService.java
  55. 8
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/GasTypeService.java
  56. 10
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/HandAlarmService.java
  57. 16
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/HandDetectorService.java
  58. 20
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/TdengineService.java
  59. 68
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/AlarmRuleServiceImpl.java
  60. 10
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/AlarmTypeServiceImpl.java
  61. 88
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/FactoryServiceImpl.java
  62. 16
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/FenceAlarmServiceImpl.java
  63. 57
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/FenceServiceImpl.java
  64. 13
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/GasTypeServiceImpl.java
  65. 22
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/HandAlarmServiceImpl.java
  66. 184
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/HandDetectorServiceImpl.java
  67. 100
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/TdengineServiceImpl.java
  68. 76
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/BatteryConverterUtils.java
  69. 188
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/CoordinateTransferUtils.java
  70. 284
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/GeofenceUtils.java
  71. 56
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/RedisKeyUtil.java
  72. 742
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/RedisUtil.java
  73. 8
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmRulePageReqVO.java
  74. 14
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmRuleRespVO.java
  75. 16
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmRuleSaveReqVO.java
  76. 6
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmTypePageReqVO.java
  77. 11
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmTypeRespVO.java
  78. 17
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmTypeSaveReqVO.java
  79. 68
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FactoryPageReqVO.java
  80. 86
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FactoryRespVO.java
  81. 68
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FactorySaveReqVO.java
  82. 18
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceAlarmPageReqVO.java
  83. 19
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceAlarmRespVO.java
  84. 20
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceAlarmSaveReqVO.java
  85. 15
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FencePageReqVO.java
  86. 19
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FencePointVo.java
  87. 15
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceRespVO.java
  88. 12
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceSaveReqVO.java
  89. 14
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/GasTypePageReqVO.java
  90. 15
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/GasTypeRespVO.java
  91. 12
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/GasTypeSaveReqVO.java
  92. 47
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/Geofence.java
  93. 17
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandAlarmPageReqVO.java
  94. 17
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandAlarmRespVO.java
  95. 29
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandAlarmSaveReqVO.java
  96. 104
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandDataVo.java
  97. 18
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandDetectorPageReqVO.java
  98. 16
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandDetectorRespVO.java
  99. 18
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandDetectorSaveReqVO.java
  100. 17
      cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandOriginalLog.java

2
cc-admin-master/pom.xml

@ -18,7 +18,7 @@
<module>yudao-module-bpm</module>
<module>yudao-module-report</module>
<module>yudao-module-hand</module>
<!--<module>yudao-module-iot</module>-->
<module>yudao-module-hand-mqtt</module>
</modules>
<name>${project.artifactId}</name>

403
cc-admin-master/tmp/.scr/auto_export.py

@ -1,403 +0,0 @@
#!/usr/bin/env python
# -*-coding:utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.chrome.options import Options
import time
import sys
import getopt
import json
import os
import shutil
import platform
import re
# import traceback
import base64
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
# 默认文件下载目录 改成自己服务器的
DEFAULT_BASE_DOWNLOAD_PATH = os.path.dirname(os.path.realpath('__file__')) + os.sep + "downloads" + os.sep
# update-begin---author:chenrui ---date:20240130 for:[QQYUN-8127]通过接口导出功能要获取token和查询参数------------
# 临时下载目录
TEMP_DOWNLOAD_PATH = os.sep + "temp" + os.sep
# update-end---author:chenrui ---date:20240130 for:[QQYUN-8127]通过接口导出功能要获取token和查询参数------------
# 默认积木报表访问地址 改成自己的
DEFAULT_BASE_SHARE_VIEW_URL = "http://localhost:8085/jmreport/view/"
# 结束日志标识
LOG_END_MARK = "$JM$END$"
def append_common_params(payload: str, token: str) -> str:
"""
拼接报表的通用参数
:param payload:
:param token:
:return:
"""
if payload is None or len(payload) == 0:
return ""
if token is not None and len(token) > 0:
token = "token=" + token
if "?" in payload:
payload += "&" + token
else:
payload += "?" + token
if "?" in payload:
payload += "&directDld=1"
else:
payload += "?directDld=1"
return payload
def dict_2_str_payload(payload: dict) -> str:
"""
字典数据转换为查询payload
:param payload:
:return:
"""
if payload is not None and len(payload) > 0:
return str("&".join([key + "=" + val for key, val in payload.items() if key is not None and len(key) > 0]))
else:
return ""
def init_args(argv=None):
"""初始化参数"""
global opts
print('共有:', len(argv), '个参数。')
if len(argv) <= 0:
raise Exception('参数异常')
arg = argv[0]
if arg is not None and len(arg) > 0:
opts = json.loads(base64.b64decode(arg))
# 批次号
batch_no = None
# 导出类型
export_type = 'PDF'
# 报表ids
report_ids = None
# 报表参数,与report_ids二选一
report_params = list()
# 积木报表预览页面地址
base_share_view_url = DEFAULT_BASE_SHARE_VIEW_URL
# 报表下载基础目录
base_download_path = DEFAULT_BASE_DOWNLOAD_PATH
# token
token = ''
if 'batch_no' in opts:
batch_no = opts['batch_no']
if 'export_type' in opts:
export_type = opts['export_type']
if 'report_ids' in opts:
report_ids = opts['report_ids']
if 'report_params' in opts:
report_params = opts['report_params']
if 'jimu_view_url' in opts:
base_share_view_url = opts['jimu_view_url']
if 'base_download_path' in opts:
base_download_path = opts['base_download_path']
if 'token' in opts:
token = opts['token']
if export_type.upper() == "EXCEL":
export_type = "Excel"
elif export_type.upper() == "PDF":
export_type = "PDF"
else:
export_type = "PDF"
# 拼接报表查询参数
reports: list[dict] = list()
if report_params is not None and len(report_params) > 0:
for report_param in report_params:
report_query = report_param['id']
if 'params' in report_param:
params = report_param['params']
if params is not None and len(params) > 0:
payload = dict_2_str_payload(params)
if payload is not None and len(payload) > 0:
report_query += "?" + payload
custom_export_type = export_type
if 'export_type' in report_param:
custom_export_type = report_param['export_type']
custom_export_type = export_type if custom_export_type is None else custom_export_type
reports.append({"url": append_common_params(report_query, token), "export_type": custom_export_type})
elif report_ids is not None and len(report_ids) > 0:
reports = [{"url": append_common_params(report_id, token), "export_type": export_type} for report_id in
report_ids]
# 确保传入路径正确,统一修改所有的/ 和 \\为当前系统的盘符
base_download_path = base_download_path.replace("/", os.sep).replace("\\", os.sep)
if not os.path.isabs(base_download_path):
raise Exception("导出失败,下载目录必须是绝对路径")
if "windows" in platform.platform().lower() and base_download_path.startswith("\\"):
# windows 系统下 并且没有写盘符时,拼接盘符
run_path = os.path.dirname(os.path.realpath('__file__'))
base_download_path = os.path.splitdrive(run_path)[0] + base_download_path
options = {
'batch_no': batch_no,
'export_type': export_type,
'reports': reports,
"base_share_view_url": base_share_view_url,
"base_download_path": base_download_path
}
print("运行参数:" + json.dumps(options))
return options
def auto_export(options):
print(" >>> java进入Python 脚本方法,options = ", options)
"""
自动导出函数
:param options: {batch_no:批次号,export_type:导出类型,reports:[{url:报表url,export_type:导出类型}]}
"""
# 整理参数
batch_no = options['batch_no']
export_type = options['export_type']
reports = None
# 优先使用report
if "reports" in options:
reports = options['reports']
if not reports or reports is None:
if "report_ids" in options:
report_ids = options['report_ids']
if not report_ids:
raise Exception('报表id不能为空')
else:
# reports 为空,将report_ids转换为reports
reports = [{"url": report_id, "export_type": export_type} for report_id in report_ids]
else:
raise Exception('报表id不能为空')
if not batch_no or not reports:
raise Exception('批次编号或报表id不能为空')
# 下载目录
download_path = options["base_download_path"] + batch_no
# 获取域名
base_share_view_url = options["base_share_view_url"]
match = re.match(r'(http[s]?://[^/]+)', base_share_view_url)
if match:
base_url = match.group(1)
else:
base_url = ""
# 获取webDriver
driver = build_web_driver(download_path, base_url)
# 确保目录存在
if os.path.exists(download_path) is False:
os.makedirs(download_path)
# update-begin---author:chenrui ---date:20240129 for:[QQYUN-8127]通过接口导出功能要获取token和查询参数------------
else:
# 清空文件夹并重建
shutil.rmtree(download_path)
os.makedirs(download_path)
# 确保临时目录存在
if os.path.exists(download_path + TEMP_DOWNLOAD_PATH) is False:
os.makedirs(download_path + TEMP_DOWNLOAD_PATH)
# update-end---author:chenrui ---date:20240129 for:[QQYUN-8127]通过接口导出功能要获取token和查询参数------------
downloaded_count = 0
download_failure_rids = []
# 导出失败的报表标题
failure_report_title = ""
# 开始自动导出
for report in reports:
report_url = report['url']
custom_export_type = report['export_type']
if not custom_export_type:
custom_export_type = export_type
else:
if custom_export_type.upper() == "EXCEL":
custom_export_type = "Excel"
elif custom_export_type.upper() == "PDF":
custom_export_type = "PDF"
else:
custom_export_type = "PDF"
print("开始导出报表:" + report_url)
# 打开url网页
driver.get(options["base_share_view_url"] + report_url)
# 等待数据查询完成
export_el = WebDriverWait(driver, 10, 0.2).until_not(
EC.presence_of_element_located((By.CLASS_NAME, "ivu-spin-fullscreen"))
)
# 等待导出按钮加载完成
export_el = WebDriverWait(driver, 10, 0.2).until(
EC.presence_of_element_located((By.CLASS_NAME, "export"))
)
# 获取title
title = driver.title
if len(title) > 0 and "-" in title:
title = title[:title.rindex("-")].strip()
print("报表名称:" + title)
if not download_check(download_path, title, custom_export_type.lower(), 1):
# 报表不存在,开始下载
print("报表{}未下载,开始下载...".format(title))
# 等待0.5秒,防止页面未完成渲染
time.sleep(0.5)
# 鼠标移到导出按钮
ActionChains(driver).move_to_element(export_el).perform()
# 点击导出pdf按钮
driver.find_element(By.ID, custom_export_type).click()
# 检查是否下载完成
if not download_check(download_path, title, custom_export_type.lower(), 30, 1):
print("报表{}下载失败".format(title))
failure_report_title += title + " "
download_failure_rids.append(report_url)
else:
downloaded_count = downloaded_count + 1
print("报表:" + report_url + "导出完成")
else:
# 报表存在
downloaded_count = downloaded_count + 1
# update-begin---author:chenrui ---date:20240129 for:统一py脚本的返回结果格式------------
err_msg = ""
if len(reports) != downloaded_count:
err_msg = "报表[" + failure_report_title + "]导出失败"
result = {
"success": len(reports) == downloaded_count,
"message": err_msg,
"result": {
"report_count": len(reports),
"downloaded_count": downloaded_count,
"failure_rids": download_failure_rids,
"download_path": download_path,
**options
}
}
# update-end---author:chenrui ---date:20240129 for:统一py脚本的返回结果格式------------
# 退出浏览器
driver.quit()
return result
def build_web_driver(download_path, safe_domain=""):
"""
构建webDriver
:param safe_domain: 安全域名
:param download_path: 下载目录
:return: webDriver
"""
chrome_options = Options()
# 不使用沙箱
chrome_options.add_argument('--no-sandbox')
# 将浏览器静音
chrome_options.add_argument("--mute-audio")
# 当程序结束时,浏览器不会关闭
# chrome_options.add_experimental_option("detach", True)
# 开启无界面浏览器(minos必须开启无界面)
chrome_options.add_argument("--headless")
# 禁用gpu
chrome_options.add_argument("--disable-gpu")
# 添加安全域名
if safe_domain is not None and bool(safe_domain):
chrome_options.add_argument("--unsafely-treat-insecure-origin-as-secure=" + safe_domain)
if 'linux' in platform.platform().lower():
# fix:DevToolsActivePort file doesn't
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--remote-debugging-port=9222')
# 设置下载路径
prefs = {'profile.default_content_settings.popups': 0,
'download.prompt_for_download': False,
'safebrowsing.disable_download_protection': True,
'download.default_directory': download_path + TEMP_DOWNLOAD_PATH}
chrome_options.add_experimental_option('prefs', prefs)
# 忽略不安全的错误
chrome_options.add_argument('ignore-certificate-errors')
# Chrome浏览器
driver = webdriver.Chrome(options=chrome_options)
return driver
def download_check(check_path, check_file_name, check_ext, check_times=3, check_interval=5):
"""
检测函数
:param check_path:检测路径
:param check_file_name: 检查文件名称
:param check_ext:检测扩展名
:param check_times:检测次数默认值:3
:param check_interval:检测时间间隔默认值:5
:return:返回真假
"""
temp_check_path = check_path + TEMP_DOWNLOAD_PATH
if os.path.exists(temp_check_path) is False:
return False
else:
for number in range(0, int(check_times)):
print("验证文件{}是否存在;第{}次检测.".format(check_file_name, str(number + 1)))
# time.sleep(0.2)
# 读取目录下所有文件
# update-begin---author:chenrui ---date:20240129 for:[QQYUN-8127]通过接口导出功能要获取token和查询参数------------
files = os.listdir(temp_check_path)
file_number = len(files)
if file_number > 0:
# 存在多个文件,检查当前文件是否存在
for file in files:
if str(check_file_name.strip()) in str(file):
# 文件存在
dest_move_file_path = check_path
if os.path.exists(check_path + os.sep + str(file)):
print("文件{}存在;重命名该文件.".format(check_file_name, str(number + 1)))
filename, extension = os.path.splitext(file)
dest_move_file_path += (os.sep + filename
+ "({})".format(str(int(time.time())))
+ extension)
shutil.move(temp_check_path + str(file), dest_move_file_path)
# update-end---author:chenrui ---date:20240129 for:[QQYUN-8127]通过接口导出功能要获取token和查询参数------------
return True
# 文件不存在
if check_times != 1 or number < check_times - 1:
time.sleep(int(check_interval)) # 休眠一会
return False
if __name__ == '__main__':
"""
入口
"""
result = {}
try:
print(" >>> java进入Python ==> step.1 进入Main方法")
args = sys.argv[1:]
# #本地调试参数
# args = ['-b', '1713260060264cubcWF', '-r',
# '537516331017523200?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MTM1NTgxNDQsInVzZXJuYW1lIjoiMTg2MTE3ODg1MjUifQ.JXZLzqgkuZRcbEYFn0l-L0DXZzOw3hJZIzn0y2EmzQM',
# '-t', 'PDF', '-s', 'http://localhost:8087/jmreport/view/', '-d', 'E:\\opt\\jmpydownload\\']
print(" >>> java进入Python ==> step.2 初始化参数")
export_options = init_args(args)
print(" >>> java进入Python ==> step.3 开始执行py脚本")
result = auto_export(export_options)
print(" >>> java进入Python ==> step.4 返回执行结果")
except Exception as e:
print("异常日志:", e)
# traceback.print_exc()
msg = ""
if hasattr(e, "msg"):
msg = e.msg
else:
msg = str(e)
# update-begin---author:chenrui ---date:20240129 for:统一py脚本的返回结果格式------------
result = {
"success": False,
"message": msg,
"result": None
}
# update-end---author:chenrui ---date:20240129 for:统一py脚本的返回结果格式------------
print(LOG_END_MARK + json.dumps(result) + LOG_END_MARK)

63
cc-admin-master/yudao-module-hand-mqtt/pom.xml

@ -0,0 +1,63 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>cc-admin-master</artifactId>
<version>${revision}</version> <!-- 1. 修改 version 为 ${revision} -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-module-hand-mqtt</artifactId>
<packaging>jar</packaging> <!-- 2. 新增 packaging 为 jar -->
<name>${project.artifactId}</name>
<dependencies> <!-- 5. 新增依赖,这里引入的都是比较常用的业务组件、技术组件 -->
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
</dependency>-->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-acl</artifactId>
<version>4.9.4</version> <!-- 注意:这里的版本号建议和你的 rocketmq-client 版本保持一致 -->
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.9.4</version> <!-- 请根据需要选择合适的版本 -->
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-hand</artifactId>
<version>2.6.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

52
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/config/BatchProcessorConfig.java

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.mqtt.config;
import cn.iocoder.yudao.module.hand.service.TdengineService;
import cn.iocoder.yudao.module.hand.vo.TdengineDataVo;
import cn.iocoder.yudao.module.hand.vo.HandOriginalLog;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
@Configuration
@EnableScheduling // 确保定时任务被启用
public class BatchProcessorConfig {
@Resource
private TdengineService tdengineService;
// --- 为 handOriginalLog 创建一个专用的批量处理器 Bean ---
@Bean
public TdengineBatchConfig<HandOriginalLog> handLogBatchProcessor() {
return new TdengineBatchConfig<>(
"HandLogProcessor", // 处理器名字
list -> tdengineService.saveHandLogBatch(list), // 【核心】将具体的保存逻辑作为 Lambda 传入
50000, // 队列容量
1000, // 批次大小
5000 // 执行频率
);
}
@Bean
public TdengineBatchConfig<TdengineDataVo> handLogBatchDataProcessor() {
return new TdengineBatchConfig<>(
"handLogBatchDataProcessor", // 处理器名字
list -> tdengineService.saveDataLogBatch(list), // 【核心】将具体的保存逻辑作为 Lambda 传入
50000, // 队列容量
1000, // 批次大小
5000 // 执行频率
);
}
// --- 创建一个调度器来统一调用所有处理器的 flush 方法 ---
@Scheduled(fixedRateString = "${batch.processor.flush.rate:5000}") // 从配置读取频率,默认5秒
public void scheduleFlush() {
// 调用 handLogProcessor 的刷新方法
handLogBatchProcessor().flush();
handLogBatchDataProcessor().flush();
// 如果有其他处理器,也在这里调用
}
}

89
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/config/TdengineBatchConfig.java

@ -0,0 +1,89 @@
package cn.iocoder.yudao.module.mqtt.config;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@Slf4j
public class TdengineBatchConfig<T> {
// --- 这些参数可以在构造时传入,使其更灵活 ---
private final int queueCapacity;
private final int batchSize;
private final long fixedRateMs;
private final long offerTimeoutMs;
private final String processorName; // 用于日志,区分不同的处理器实例
private final BlockingQueue<T> dataQueue;
private final Consumer<List<T>> batchAction; // 【核心】用于处理一个批次的具体业务逻辑
/**
* 构造函数
* @param processorName 处理器名称用于日志区分
* @param batchAction 一个函数接收一个 List<T> 并执行相应的批量操作例如写入数据库
* @param queueCapacity 队列容量
* @param batchSize 批次大小
* @param fixedRateMs 执行频率
*/
public TdengineBatchConfig(String processorName, Consumer<List<T>> batchAction,
int queueCapacity, int batchSize, long fixedRateMs) {
this.processorName = processorName;
this.batchAction = batchAction;
this.queueCapacity = queueCapacity;
this.batchSize = batchSize;
this.fixedRateMs = fixedRateMs;
this.offerTimeoutMs = 100L;
this.dataQueue = new LinkedBlockingQueue<>(this.queueCapacity);
}
public void addToBatch(T data) {
if (data == null) {
return;
}
try {
if (!dataQueue.offer(data, offerTimeoutMs, TimeUnit.MILLISECONDS)) {
log.warn("[{}] 缓冲区已满且在 {} 毫秒内无法添加,数据可能被丢弃!当前队列大小: {}",
this.processorName, this.offerTimeoutMs, dataQueue.size());
}
} catch (InterruptedException e) {
log.error("[{}] 添加数据到缓冲区时线程被中断", this.processorName, e);
Thread.currentThread().interrupt();
}
}
// 注意:@Scheduled 注解不能用在非 Spring Bean 的普通类方法上。
// 我们将在下一步的配置类中解决这个问题。
public void flush() {
if (dataQueue.isEmpty()) {
return;
}
List<T> batchList = new ArrayList<>(batchSize);
try {
int drainedCount = dataQueue.drainTo(batchList, batchSize);
if (drainedCount > 0) {
log.debug("[{}] 定时任务触发,准备将 {} 条数据进行批量处理...", this.processorName, drainedCount);
// 调用构造时传入的业务逻辑
this.batchAction.accept(batchList);
log.debug("[{}] 成功批量处理 {} 条数据。", this.processorName, drainedCount);
}
} catch (Exception e) {
log.error("[{}] 批量处理数据时发生严重错误!数据量: {}", this.processorName, batchList.size(), e);
}
}
@PreDestroy
public void onShutdown() {
log.info("[{}] 应用即将关闭,开始执行最后的缓冲区数据刷新...", this.processorName);
while (!dataQueue.isEmpty()) {
log.debug("[{}] 停机处理中,剩余 {} 条数据待处理...", this.processorName, dataQueue.size());
flush();
}
log.debug("[{}] 缓冲区数据已全部处理完毕。", this.processorName);
}
}

34
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/kafka/KafkaConfig.java

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.mqtt.kafka;
import org.apache.kafka.common.TopicPartition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.KafkaOperations;
import org.springframework.kafka.listener.DeadLetterPublishingRecoverer;
import org.springframework.kafka.listener.DefaultErrorHandler;
import org.springframework.util.backoff.FixedBackOff;
@Configuration
public class KafkaConfig {
/**
* 配置一个通用的错误处理器.
* 它会在反序列化失败或监听器方法抛出异常时生效.
* @param operations KafkaTemplate 实例
* @return a DefaultErrorHandler
*/
@Bean
public DefaultErrorHandler errorHandler(KafkaOperations<Object, Object> operations) {
// 1. 创建 DeadLetterPublishingRecoverer,它负责将失败的消息推送到 DLT
// 这里我们为所有失败的消息都指定了一个通用的 DLT 主题
DeadLetterPublishingRecoverer recoverer = new DeadLetterPublishingRecoverer(operations,
(rec, ex) -> new TopicPartition(rec.topic() + ".DLT", rec.partition()));
// 根据业务需求选择合适的策略。
FixedBackOff backOff = new FixedBackOff(1000L, 2L);
// 3. 创建并返回 DefaultErrorHandler
// 当重试耗尽后,会调用 recoverer 将消息送入 DLT
return new DefaultErrorHandler(recoverer, backOff);
}
}

58
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/kafka/KafkaMessageConsumer.java

@ -0,0 +1,58 @@
package cn.iocoder.yudao.module.mqtt.kafka;
import cn.iocoder.yudao.module.mqtt.processor.DeviceMessageProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Service;
import static cn.iocoder.yudao.module.mqtt.kafka.KafkaTopicType.DEAD_LETTER_TOPIC;
@Slf4j
@Service // <--- 添加这个注解!
public class KafkaMessageConsumer {
private final TaskExecutor taskExecutor;
private final DeviceMessageProcessor deviceMessageProcessor;
private final KafkaTemplate<String, String> kafkaTemplate;
public KafkaMessageConsumer(DeviceMessageProcessor deviceMessageProcessor,
@Qualifier("mqttExecutor") TaskExecutor taskExecutor,
KafkaTemplate<String, String> kafkaTemplate) {
this.deviceMessageProcessor = deviceMessageProcessor;
this.taskExecutor = taskExecutor;
this.kafkaTemplate = kafkaTemplate;
}
@KafkaListener(topics = "zds_up")
public void handleMessage(@Payload String payload,
@Header(KafkaHeaders.RECEIVED_KEY) String key,
@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
log.debug("从 Kafka Topic 收到消息,准备处理: topic=[{}]", topic);
// 3. 异步执行,保证kafka不阻塞
taskExecutor.execute(() -> {
try {
// 核心业务逻辑调用
this.deviceMessageProcessor.process(key, payload);
} catch (Exception e) {
// 1. 捕获所有运行时异常
log.error("处理 Kafka 消息时发生严重错误!将消息发送到死信队列. Key: {}, Payload: {}", key, payload, e);
try {
// 2. 将失败的消息发送到 DLT
// 可以在消息头中添加额外信息,如原始主题、异常信息等,方便排查
kafkaTemplate.send(DEAD_LETTER_TOPIC.getValue(), key, payload);
} catch (Exception dltEx) {
log.error("无法将消息发送到死信队列!消息可能丢失. Key: {}, Payload: {}", key, payload, dltEx);
}
}
});
}
}

44
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/kafka/KafkaTopicType.java

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.mqtt.kafka;
import lombok.Getter;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Kafka 主题枚举类用于统一管理和引用 Topic 名称
*/
@Getter // Lombok 注解,自动为所有字段生成 public 的 getter 方法,例如 getValue()
public enum KafkaTopicType {
// 1. 常量名和值的含义保持一致,更清晰
DEVICE_STATUS_UP("zds_up"),
DEAD_LETTER_TOPIC("zds_up_dlt");
// 2. 添加了 final 字段
private final String value;
// 3. 【核心修复】添加了私有构造函数,用于初始化 final 字段
KafkaTopicType(String value) {
this.value = value;
}
// --- 以下是更高效和健壮的 from 方法实现 ---
// 4. 使用静态 Map 缓存,提高查找性能,避免每次调用都遍历
private static final Map<String, KafkaTopicType> LOOKUP_MAP = Arrays.stream(values())
.collect(Collectors.toMap(KafkaTopicType::getValue, Function.identity()));
/**
* 根据字符串值查找对应的枚举常量.
*
* @param value topic 字符串值
* @return 对应的枚举常量
* @throws IllegalArgumentException 如果找不到匹配的常量
*/
public static KafkaTopicType from(String value) {
return LOOKUP_MAP.get(value);
}
}

150
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/mqtt/Client.java

@ -0,0 +1,150 @@
package cn.iocoder.yudao.module.mqtt.mqtt;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
@Slf4j
@Component
public class Client {
private final OnMessageCallback onMessageCallback; // 1. 注入我们新的 Kafka 生产者回调
// --- 1. 配置注入 (保持不变) ---
@Value("${mqtt.enable:false}")
private Boolean enable;
@Value("${mqtt.url}")
private String hostUrl;
@Value("${mqtt.username:}")
private String username;
@Value("${mqtt.password:}")
private String password;
@Value("${mqtt.client.id}")
private String baseClientId;
@Value("${mqtt.connectionTimeout:10}")
private int connectionTimeout;
@Value("${mqtt.keepAliveInterval:60}")
private int keepAliveInterval;
@Value("${mqtt.cleanSession:true}")
private boolean cleanSession;
@Value("${mqtt.subscribe.topic}")
private String[] subscribeTopics;
@Value("${mqtt.subscribe.qos}")
private int[] subscribeQos;
@Value("${mqtt.default.publishQos:1}")
private int publishQos;
private IMqttClient mqttClient;
// 2. 构造函数注入 Spring Bean
public Client(OnMessageCallback onMessageCallback) {
this.onMessageCallback = onMessageCallback;
}
@PostConstruct
public void init() {
if (!enable) {
log.info("MQTT 功能已禁用。");
return;
}
connect();
}
private void connect() {
try {
String finalClientId = baseClientId + "-" + UUID.randomUUID().toString().substring(0, 8);
mqttClient = new MqttClient(hostUrl, finalClientId, new MemoryPersistence());
MqttConnectOptions options = createMqttConnectOptions();
// 3. 将注入的回调 Bean 设置给 Paho 客户端
mqttClient.setCallback(onMessageCallback);
log.info("正在连接到 MQTT Broker: {}", hostUrl);
mqttClient.connect(options);
subscribeToTopics();
} catch (MqttException e) {
log.error("连接到 MQTT Broker 时发生初始错误: {}", e.getMessage(), e);
}
}
private MqttConnectOptions createMqttConnectOptions() {
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(username);
options.setPassword(password.toCharArray());
options.setConnectionTimeout(connectionTimeout);
options.setKeepAliveInterval(keepAliveInterval);
options.setCleanSession(cleanSession);
options.setAutomaticReconnect(true); // 启用自动重连
return options;
}
/**
* 4. 创建一个事件监听器用于处理连接成功事件
* 这取代了之前传递 Runnable 的方式实现了更好的解耦
*/
/* @Async
@EventListener
public void handleMqttConnectionComplete(MqttConnectedEvent event) {
log.info("监听到 MQTT 连接成功事件,开始执行订阅操作...");
subscribeToTopics();
}*/
private void subscribeToTopics() {
if (mqttClient == null || !mqttClient.isConnected()) {
log.error("无法订阅主题,因为 MQTT 客户端尚未连接。");
return;
}
try {
log.info("执行 MQTT 主题订阅: {}", (Object) subscribeTopics);
mqttClient.subscribe(subscribeTopics, subscribeQos);
} catch (MqttException e) {
log.error("订阅 MQTT 主题时发生错误: {}", e.getMessage(), e);
}
}
// --- 4. 发布和清理方法 (保持不变) ---
public void publish(String topic, String payload) {
publish(topic, payload.getBytes(), this.publishQos, false);
}
public void publish(String topic, byte[] payload, int qos, boolean retained) {
if (mqttClient == null || !mqttClient.isConnected()) {
log.error("MQTT 客户端未连接,无法发布消息。");
return;
}
try {
MqttMessage message = new MqttMessage(payload);
message.setQos(qos);
message.setRetained(retained);
mqttClient.publish(topic, message);
} catch (MqttException e) {
log.error("发布 MQTT 消息到主题 [{}] 时发生错误: {}", topic, e.getMessage(), e);
}
}
@PreDestroy
public void cleanup() {
if (mqttClient != null) {
try {
if (mqttClient.isConnected()) {
mqttClient.disconnect();
}
mqttClient.close();
log.info("MQTT 客户端已成功关闭。");
} catch (MqttException e) {
log.error("关闭 MQTT 客户端时发生错误: {}", e.getMessage(), e);
}
}
}
}

9
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/mqtt/MqttConnectedEvent.java

@ -0,0 +1,9 @@
package cn.iocoder.yudao.module.mqtt.mqtt;
import org.springframework.context.ApplicationEvent;
public class MqttConnectedEvent extends ApplicationEvent {
public MqttConnectedEvent(Object source) {
super(source);
}
}

68
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/mqtt/OnMessageCallback.java

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.mqtt.mqtt;
import cn.hutool.core.util.ReUtil;
import cn.iocoder.yudao.module.mqtt.kafka.KafkaTopicType;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.regex.Pattern;
@Slf4j
@Component
public class OnMessageCallback implements MqttCallbackExtended {
private final Pattern topicPattern = Pattern.compile("([^/]+)/?(.+)?");
@Resource
private KafkaTemplate<String, String> kafkaTemplate;
@Resource
private ApplicationEventPublisher eventPublisher;
@Override
public void connectComplete(boolean reconnect, String serverURI) {
log.info("MQTT 连接成功。是否为重连: {}, 服务器 URI: {}", reconnect, serverURI);
// 3. 发布一个 Spring 事件,通知其他组件(如 Client)连接已成功
eventPublisher.publishEvent(new MqttConnectedEvent(this));
}
@Override
public void connectionLost(Throwable cause) {
log.error("MQTT 连接已断开,正在尝试自动重连...", cause);
}
@Override
public void messageArrived(String MqttTopic, MqttMessage message) {
String payload = new String(message.getPayload());
List<String> groups = ReUtil.getAllGroups(topicPattern, MqttTopic, false);
if (groups.get(1) == null) {
log.warn("无法从topic {} 中获取消息发送者ID", MqttTopic);
return;
}
String sn = groups.get(0);
String topic = groups.get(1);
KafkaTopicType from = KafkaTopicType.from(groups.get(1));
if (null == from) {
log.warn("发送的topic无效{}", topic);
return;
}
try {
kafkaTemplate.send(topic, sn, payload);
log.debug("成功将消息转发到 Kafka Topic [{}]: payload=[{}]", topic, payload);
} catch (Exception e) {
log.error("转发消息到 Kafka Topic [{}] 时发生错误!", topic, e);
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// no-op
}
}

31
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/mqtt/ThreadPoolConfig.java

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.mqtt.mqtt;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class ThreadPoolConfig {
@Bean("mqttExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数:CPU核心数
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
// 最大线程数:CPU核心数 * 2
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
// 队列大小
executor.setQueueCapacity(1000);
// 线程名称前缀
executor.setThreadNamePrefix("mqtt-executor-");
// 拒绝策略:由调用者线程处理
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}

505
cc-admin-master/yudao-module-hand-mqtt/src/main/java/cn/iocoder/yudao/module/mqtt/processor/DeviceMessageProcessor.java

@ -0,0 +1,505 @@
package cn.iocoder.yudao.module.mqtt.processor;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.hand.dal.*;
import cn.iocoder.yudao.module.hand.enums.*;
import cn.iocoder.yudao.module.hand.service.*;
import cn.iocoder.yudao.module.hand.util.*;
import cn.iocoder.yudao.module.hand.vo.*;
import cn.iocoder.yudao.module.mqtt.config.TdengineBatchConfig;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class DeviceMessageProcessor {
@Resource
private RedisUtil redisUtil;
@Resource
private TdengineBatchConfig<HandOriginalLog> tdengineBatchProcessor;
@Resource
private TdengineBatchConfig<TdengineDataVo> tdengineBatchConfig;
@Resource
private HandDetectorService handDetectorService;
@Resource
private HandAlarmService handAlarmService;
@Resource
private AlarmRuleService alarmRuleService;
@Resource
private RedissonClient redissonClient;
@Resource
private FenceService fenceService;
@Resource
private FenceAlarmService fenceAlarmService;
public void process(String topic, String payload) {
log.debug("[设备上报] 开始处理 -> 主题: {}, 内容: {}", topic, payload);
Object tenantIdObj = redisUtil.hget(RedisKeyUtil.getDeviceTenantMappingKey(), topic);
if (tenantIdObj == null || StringUtils.isBlank(tenantIdObj.toString())) {
log.warn("[设备上报] 无法找到 SN {} 对应的租户信息,设备可能未注册。消息丢弃。", topic);
return; // 结束处理
}
Long tenantId = Long.parseLong(tenantIdObj.toString());
// 保存原始日志,这个操作不涉及状态竞争,可以放在锁外
logSave(topic, payload, tenantId);
// topic 即为设备 sn,是锁的最佳 key
String deviceProcessLockKey = RedisKeyUtil.getDeviceProcessLockKey(tenantId, topic);
RLock lock = redissonClient.getLock(deviceProcessLockKey);
try {
// 尝试在 10 秒内获取锁,防止因锁等待导致 Kafka 消费者线程长时间阻塞
if (!lock.tryLock(10, TimeUnit.SECONDS)) {
log.warn("未能获取设备 {} 的处理锁,消息将被丢弃或重试。", topic);
// 抛出异常,外层逻辑可以捕获并发送到死信队列
throw new RuntimeException("获取设备锁超时: " + topic);
}
try {
// 从 Redis 中获取设备信息
Object meterObj = redisUtil.hget(RedisKeyUtil.getTenantDeviceHashKey(tenantId), topic);
HandDataVo detector;
if (meterObj == null) { // 缓存未命中
// 从数据库查询 DO 对象
HandDetectorDO one = handDetectorService.getBySn(topic);
if (one == null) {
log.warn("[数据不一致] 在租户 {} 的设备列表中未找到 SN {} 的详细信息。", tenantId, topic);
return; // 直接返回,无需再操作
}
detector = BeanUtils.toBean(one, HandDataVo.class);
} else { // 缓存命中
detector = BeanUtils.toBean(meterObj, HandDataVo.class);
}
if (EnableStatus.DISABLED.value().equals(detector.getEnableStatus())) {
log.info("未启用的手持探测器 sn: {}", topic);
return;
}
// 数据解析与转换
HandDataVo handVo = dataConvert(topic, payload, detector);
// 获取气种的报警规则
Map<Long, List<AlarmRuleDO>> ruleMap = alarmRuleService.selectCacheListMap(tenantId);
AlarmRuleDO alarmRule = getAlarmRule(handVo, ruleMap);
// 气体报警逻辑处理
HandDataVo vo = gasHandAlarm(alarmRule, handVo);
// 气体报警保存
saveGasAlarm(vo, alarmRule);
//围栏报警逻辑
fanceAlarm(handVo);
//电量报警逻辑
batteryAlarm(handVo);
// 无论是否发生告警,设备的状态(如电量、位置、最新值)都需要更新
handDetectorService.updateRedisData(tenantId, topic, handVo);
handLogSave(handVo);
} finally {
// 确保锁一定被释放
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("获取设备 {} 的锁时被中断", topic, e);
throw new RuntimeException("处理设备消息时线程被中断: " + topic, e);
}
}
private void handLogSave(HandDataVo handVo) {
TdengineDataVo bean = BeanUtils.toBean(handVo, TdengineDataVo.class);
bean.setTenantId(handVo.getTenantId());
bean.setTs(new Timestamp(System.currentTimeMillis())); // 直接创建Timestamp对象
tdengineBatchConfig.addToBatch(bean);
}
private void batteryAlarm(HandDataVo handVo) {
handVo.setBatteryStatus(EnableStatus.DISABLED.value()); // 默认状态为正常
if (null == handVo.getBatteryAlarmValue()) {
return;
}
if (null == handVo.getBatteryStatusAlarmId()) {
return;
}
// --- 步骤2: 计算当前电量 ---
// 只有在告警功能已配置的情况下,才继续执行后续的电量计算和判断逻辑。
int batteryPercentage;
try {
batteryPercentage = BatteryConverterUtils.getBatteryPercentage(Integer.parseInt(handVo.getBattery()));
} catch (NumberFormatException e) {
log.error("设备电池数据格式无效,设备SN: {},原始电池值: {},异常信息: {}",
handVo.getSn(), handVo.getBattery(), e.getMessage(), e);
return;
}
// --- 步骤3: 执行告警状态判断和转换逻辑 ---
int alarmThreshold = handVo.getBatteryAlarmValue().intValue(); // 此处调用是安全的,因为已在步骤1排除了null的可能
boolean isCurrentlyInAlarm = Objects.equals(handVo.getBatteryStatus(), EnableStatus.ENABLED.value());
boolean shouldBeInAlarm = batteryPercentage < alarmThreshold;
// 场景一:从“正常”变为“告警” -> 创建新告警
if (shouldBeInAlarm && !isCurrentlyInAlarm) {
HandAlarmSaveReqVO alarm = new HandAlarmSaveReqVO();
alarm.setAlarmType(AlarmType.BATTERY.getType());
alarm.setTAlarmStart(LocalDateTime.now());
alarm.setVAlarmFirst(handVo.getFirstValue());
alarm.setPicX(handVo.getLatitude());
alarm.setPicY(handVo.getLongitude());
handAlarmService.createHandAlarm(alarm);
// 场景二:从“告警”变为“正常” -> 结束告警
} else if (!shouldBeInAlarm && isCurrentlyInAlarm) {
HandAlarmSaveReqVO alarm = new HandAlarmSaveReqVO();
alarm.setTAlarmEnd(LocalDateTime.now());
// alarm.setId(handVo.getBatteryStatusAlarmId()); // 别忘了传递告警ID
handAlarmService.updateHandAlarm(alarm);
}
// 如果状态未变(持续告警或持续正常),不执行任何数据库操作。
// 根据当前是否应该告警来设置最终的正确状态。
if (shouldBeInAlarm) {
handVo.setBatteryStatus(EnableStatus.ENABLED.value());
} else {
handVo.setBatteryStatus(EnableStatus.DISABLED.value());
}
}
private void saveGasAlarm(HandDataVo vo, AlarmRuleDO alarmRule) {
if (null == alarmRule || null == alarmRule.getAlarmLevel()) {
log.error("报警规则不存在:sn: {}", vo.getSn());
return;
}
if (vo.getTAlarmStart() == null) {//没有开始时间不需要报警
return;
}
//报警恢复和添加报警
if (vo.getTAlarmEnd() != null) {
if (vo.getAlarmId() == null) {
log.error("报警恢复失败:一个已结束的报警事件在Redis中没有找到 alarmId。sn: {}", vo.getSn());
return;
}
HandAlarmDO alarm = new HandAlarmDO();
alarm.setTAlarmEnd(vo.getTAlarmEnd());
alarm.setId(vo.getAlarmId());
alarm.setVAlarmMaximum(vo.getMaxValue());
alarm.setAlarmLevel(vo.getMaxAlarmLevel());
alarm.setTenantId(vo.getTenantId());
int count = handAlarmService.updateById(alarm);
if (count > 0) {
log.info("报警事件(ID: {})已结束,成功更新数据库。", alarm.getId());
// 重置 Redis 数据
vo.setAlarmId(null);
vo.setFirstValue(null);
vo.setMaxValue(null);
vo.setTAlarmStart(null);
vo.setTAlarmEnd(null);
vo.setMaxAlarmLevel(null);
vo.setAlarmLevel(0); // 将当前级别设为正常
} else {
log.error("数据库更新失败:尝试结束报警事件(ID: {})时出错。", vo.getAlarmId());
}
} else {
if (vo.getAlarmId() == null) {
HandAlarmSaveReqVO alarmDO = BeanUtils.toBean(vo, HandAlarmSaveReqVO.class);
Long count = handAlarmService.createHandAlarm(alarmDO);
if (count > 0) {
vo.setAlarmId(count);
log.info("新报警事件已创建,数据库ID: {},并已回写至Redis。", count);
}
} else {
// -- 更新 --
HandAlarmDO alarmToUpdate = new HandAlarmDO();
alarmToUpdate.setId(vo.getAlarmId());
alarmToUpdate.setVAlarmMaximum(vo.getMaxValue());
handAlarmService.updateById(alarmToUpdate);
}
}
}
/**
* 围栏报警逻辑
*/
private void fanceAlarm(HandDataVo handVo) {
if (StringUtils.isBlank(handVo.getFenceIds())) {
log.info("当前设备未绑定围栏,sn{}", handVo.getSn());
return;
}
List<Long> list = Arrays.stream(handVo.getFenceIds().split(","))
.map(Long::parseLong)
.toList();
List<Geofence> fenceList = fenceService.getFenceList(list);
FenceType fenceType = FenceType.fromType(handVo.getFenceType());// 转换为枚举
// a. 判断点是否在任何一个围栏内
boolean isCurrentlyInside = GeofenceUtils.isInsideAnyFence(handVo.getLongitude(), handVo.getLatitude(), fenceList);
Boolean isViolating = switch (fenceType) {
case null -> {
log.error("围栏类型为 null,无法处理。");
yield null; // 使用 yield 从代码块中返回一个值
}
// "进入围栏报警" -> 违规条件是:车辆在围栏内部
case INSIDE -> isCurrentlyInside;
// "超出围栏报警" -> 违规条件是:车辆在围栏外部
case OUTSIDE -> !isCurrentlyInside;
// default 分支确保了所有未明确处理的枚举类型都能被覆盖
default -> {
log.error("逻辑中未处理的围拦类型: {}。", fenceType);
yield null;
}
};
// --- 3. 根据计算出的状态,执行统一的后续逻辑 ---
// 如果 isViolating 为 null (因为 fenceType 无效或为 null),则不执行任何操作。
if (isViolating != null) {
handleAlarmLifecycle(isViolating, handVo, fenceType, fenceList);
}
}
/**
* 统一处理报警的开始持续和结束
*
* @param isViolating 当前状态是否违规
* @param handVo 当前位置信息携带着报警状态 (fenceAlarmId)
* @param fenceType 围栏类型
* @param fenceList 围栏几何对象列表
*/
private void handleAlarmLifecycle(boolean isViolating, HandDataVo handVo, FenceType fenceType, List<Geofence> fenceList) {
// 关键状态判断:根据 handVo 中是否已有报警ID,判断之前是否有正在进行的报警
boolean hasOngoingAlarm = (handVo.getFenceAlarmId() != null);
if (isViolating) {
// --- 场景:当前处于违规状态 ---
// 计算当前的违规距离
double currentDistance = GeofenceUtils.fenceDistance(handVo, fenceType, fenceList);
if (!hasOngoingAlarm) {
// 1. 【触发新报警】: 之前不报警,现在开始违规
log.warn("触发 [{}] 类型围栏报警! sn: {}", fenceType, handVo.getSn());
FenceAlarmSaveReqVO newAlarm = new FenceAlarmSaveReqVO();
newAlarm.setDetectorId(handVo.getId());
/* newAlarm.setFenceId(fenceDO.getId());*/
newAlarm.setType(fenceType.getType());
newAlarm.setTAlarmStart(LocalDateTime.now()); // 记录报警开始时间
newAlarm.setPicX(handVo.getLongitude());
newAlarm.setPicY(handVo.getLatitude());
newAlarm.setTenantId(handVo.getTenantId());
// 初始化距离
newAlarm.setDistance(currentDistance);
newAlarm.setMaxDistance(currentDistance);
handVo.setDistance(currentDistance);
handVo.setMaxDistance(currentDistance);
// 保存新报警,并获取返回的ID,用于更新 handVo 的状态
Long fenceAlarm = fenceAlarmService.createFenceAlarm(newAlarm);
if (fenceAlarm != null) {
// *** 关键:更新内存/缓存中的 handVo 状态,以便下次判断 ***
handVo.setFenceAlarmId(fenceAlarm);
}
} else {
// 2. 【更新持续报警】: 之前在报警,现在仍然违规
log.info("持续 [{}] 类型围栏报警,更新距离... fenceAlarmId: {}", fenceType, handVo.getFenceAlarmId());
FenceAlarmDO existingAlarm = fenceAlarmService.getFenceAlarm(handVo.getFenceAlarmId());
if (existingAlarm == null) {
log.error("逻辑错误:handVo 中有报警ID,但数据库中找不到记录!ID: {}", handVo.getFenceAlarmId());
// 异常处理:可以选择重置 handVo 状态,或创建新报警
handVo.setFenceAlarmId(null); // 重置状态
return;
}
existingAlarm.setDistance(currentDistance);
if (existingAlarm.getMaxDistance() == null || currentDistance > existingAlarm.getMaxDistance()) {
existingAlarm.setMaxDistance(currentDistance);
handVo.setMaxDistance(currentDistance);
}
fenceAlarmService.update(existingAlarm);
}
handVo.setGasStatus(HandAlarmType.ALARM.getType());
} else {
// --- 场景:当前处于正常状态 ---
if (hasOngoingAlarm) {
// 3. 【结束报警】: 之前在报警,现在恢复正常
log.warn("结束 [{}] 类型围栏报警。 fenceAlarmId: {}", fenceType, handVo.getFenceAlarmId());
// 调用服务去结束报警(例如设置 endTime)
FenceAlarmDO fenceAlarmDO = new FenceAlarmDO();
fenceAlarmDO.setId(handVo.getFenceAlarmId());
fenceAlarmDO.setTAlarmEnd(LocalDateTime.now());
fenceAlarmService.update(fenceAlarmDO);
// *** 关键:重置内存/缓存中的 handVo 状态 ***
handVo.setFenceAlarmId(null);
handVo.setDistance(null);
handVo.setMaxDistance(null);
handVo.setGasStatus(HandAlarmType.NORMAL.getType());
} else {
log.debug("当前状态正常,且无进行中报警,无需操作。");
}
}
}
private AlarmRuleDO getAlarmRule(HandDataVo handVo, Map<Long, List<AlarmRuleDO>> ruleMap) {
double gasValue = handVo.getValue();
Long gasTypeId = handVo.getGasTypeId();
List<AlarmRuleDO> gasAlarmRuleList = ruleMap.get(gasTypeId);
if (gasAlarmRuleList == null || gasAlarmRuleList.isEmpty()) {
log.error("无报警规则:detector={} gas type={} value={}", handVo.getSn(), handVo.getGasChemical(), gasValue);
return null;
}
AlarmRuleDO alarmRule = null;
for (AlarmRuleDO rule : gasAlarmRuleList) {
// 最小值或最大值可为空
if ((rule.getMin() == null || rule.getMin() <= gasValue) && (rule.getMax() == null || gasValue <= rule.getMax())) {
// 范围重复高级别报警优先
if (alarmRule == null || alarmRule.getAlarmLevel() < rule.getAlarmLevel()) {
alarmRule = rule;
}
}
}
return alarmRule;
}
/**
* 气体报警逻辑处理
*/
private HandDataVo gasHandAlarm(AlarmRuleDO alarmRule, HandDataVo redisData) {
if (null == alarmRule) {
log.error("无报警规则:sn: {}", redisData.getSn());
return redisData;
}
LocalDateTime now = LocalDateTime.now();
//离线报警结束
if (OnlineStatusType.ONLINE.getType().equals(redisData.getOnlineStatus())
&& AlarmLevelEnum.OFFLINE.value().equals(redisData.getAlarmLevel())) {
HandAlarmDO handAlarmDO = new HandAlarmDO();
handAlarmDO.setId(redisData.getAlarmId());
handAlarmDO.setTAlarmEnd(now);
handAlarmService.updateById(handAlarmDO);
//删除离线报警
redisData.setAlarmId(null);
}
boolean isCurrentlyAlarming = redisData.getAlarmLevel() != null && redisData.getAlarmLevel() > 0;
boolean isRuleTriggeringAlarm = alarmRule.getAlarmLevel() > 0;
// 之前在报警,但现在报警恢复正常
if (isCurrentlyAlarming && !isRuleTriggeringAlarm) {
redisData.setAlarmLevel(0);
redisData.setTAlarmEnd(now);
redisData.setGasStatus(HandAlarmType.NORMAL.getType());
return redisData;
}
if (alarmRule.getAlarmLevel() == 0) {
redisData.setAlarmLevel(0);
return redisData;
}
if (isRuleTriggeringAlarm) {
Integer newAlarmLevel = alarmRule.getAlarmLevel();
// 如果是首次报警 (之前不处于报警状态)
if (!isCurrentlyAlarming) {
redisData.setFirstValue(redisData.getValue());
redisData.setTAlarmStart(now);
redisData.setMaxValue(redisData.getValue()); // 初始值
redisData.setMaxAlarmLevel(newAlarmLevel);
}
redisData.setAlarmLevel(newAlarmLevel);
// 报警升级
if (redisData.getMaxAlarmLevel() == null || newAlarmLevel > redisData.getMaxAlarmLevel()) {
redisData.setMaxAlarmLevel(newAlarmLevel);
}
// 更新最大值
if (MaxDirection.DOWN.value().equals(alarmRule.getDirection()) && redisData.getValue() < redisData.getMaxValue()
|| MaxDirection.UP.value().equals(alarmRule.getDirection()) && redisData.getValue() > redisData.getMaxValue()) {
// 更新最大值
redisData.setMaxValue(redisData.getValue());
}
}
redisData.setGasStatus(HandAlarmType.ALARM.getType());
return redisData;
}
/**
* 数据转换
*/
private HandDataVo dataConvert(String topic, String payload, HandDataVo detector) {
JSONObject obj = JSONUtil.parseObj(payload);
Double value = obj.getDouble("gas", null);//气体值
String loc = obj.getStr("loc");
String battery = obj.getStr("battery");
String numbersString = loc.substring(1, loc.length() - 1);
// 将字符串按逗号分割成数组
String[] split = numbersString.split(",");
Map<String, Double> wgs84ToGcj02 = CoordinateTransferUtils.wgs84ToGcj02(Double.parseDouble(split[0]), Double.parseDouble(split[1]));
Double lon = wgs84ToGcj02.get("lon");
Double lat = wgs84ToGcj02.get("lat");
detector.setBattery(battery);
detector.setLongitude(lon);
detector.setLatitude(lat);
detector.setValue(value);
detector.setSn(topic);
//添加最新时间
detector.setTime(new Date(System.currentTimeMillis()));
//添加默认状态
detector.setOnlineStatus(OnlineStatusType.ONLINE.getType());
return detector;
}
private void logSave(String topic, String payload, Long tenantId) {
HandOriginalLog handOriginalLog = new HandOriginalLog();
handOriginalLog.setSn(topic);
handOriginalLog.setPayload(payload);
handOriginalLog.setTenantId(tenantId);
handOriginalLog.setTs(new Timestamp(System.currentTimeMillis())); // 直接创建Timestamp对象
tdengineBatchProcessor.addToBatch(handOriginalLog);
}
}

8
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/AlarmRuleController.java

@ -44,7 +44,7 @@ public class AlarmRuleController {
@PostMapping("/create")
@Operation(summary = "创建GAS警报规则")
@PreAuthorize("@ss.hasPermission('gas:alarm-rule:create')")
public CommonResult<String> createAlarmRule(@Valid @RequestBody AlarmRuleSaveReqVO createReqVO) {
public CommonResult<Long> createAlarmRule(@Valid @RequestBody AlarmRuleSaveReqVO createReqVO) {
return success(alarmRuleService.createAlarmRule(createReqVO));
}
@ -60,7 +60,7 @@ public class AlarmRuleController {
@Operation(summary = "删除GAS警报规则")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('gas:alarm-rule:delete')")
public CommonResult<Boolean> deleteAlarmRule(@RequestParam("id") String id) {
public CommonResult<Boolean> deleteAlarmRule(@RequestParam("id") Long id) {
alarmRuleService.deleteAlarmRule(id);
return success(true);
}
@ -69,7 +69,7 @@ public class AlarmRuleController {
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除GAS警报规则")
@PreAuthorize("@ss.hasPermission('gas:alarm-rule:delete')")
public CommonResult<Boolean> deleteAlarmRuleList(@RequestParam("ids") List<String> ids) {
public CommonResult<Boolean> deleteAlarmRuleList(@RequestParam("ids") List<Long> ids) {
alarmRuleService.deleteAlarmRuleListByIds(ids);
return success(true);
}
@ -78,7 +78,7 @@ public class AlarmRuleController {
@Operation(summary = "获得GAS警报规则")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('gas:alarm-rule:query')")
public CommonResult<AlarmRuleRespVO> getAlarmRule(@RequestParam("id") String id) {
public CommonResult<AlarmRuleRespVO> getAlarmRule(@RequestParam("id") Long id) {
AlarmRuleDO alarmRule = alarmRuleService.getAlarmRule(id);
return success(BeanUtils.toBean(alarmRule, AlarmRuleRespVO.class));
}

8
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/AlarmTypeController.java

@ -44,7 +44,7 @@ public class AlarmTypeController {
@PostMapping("/create")
@Operation(summary = "创建GAS警报类型")
@PreAuthorize("@ss.hasPermission('gas:alarm-type:create')")
public CommonResult<String> createAlarmType(@Valid @RequestBody AlarmTypeSaveReqVO createReqVO) {
public CommonResult<Long> createAlarmType(@Valid @RequestBody AlarmTypeSaveReqVO createReqVO) {
return success(alarmTypeService.createAlarmType(createReqVO));
}
@ -60,7 +60,7 @@ public class AlarmTypeController {
@Operation(summary = "删除GAS警报类型")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('gas:alarm-type:delete')")
public CommonResult<Boolean> deleteAlarmType(@RequestParam("id") String id) {
public CommonResult<Boolean> deleteAlarmType(@RequestParam("id") Long id) {
alarmTypeService.deleteAlarmType(id);
return success(true);
}
@ -69,7 +69,7 @@ public class AlarmTypeController {
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除GAS警报类型")
@PreAuthorize("@ss.hasPermission('gas:alarm-type:delete')")
public CommonResult<Boolean> deleteAlarmTypeList(@RequestParam("ids") List<String> ids) {
public CommonResult<Boolean> deleteAlarmTypeList(@RequestParam("ids") List<Long> ids) {
alarmTypeService.deleteAlarmTypeListByIds(ids);
return success(true);
}
@ -78,7 +78,7 @@ public class AlarmTypeController {
@Operation(summary = "获得GAS警报类型")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('gas:alarm-type:query')")
public CommonResult<AlarmTypeRespVO> getAlarmType(@RequestParam("id") String id) {
public CommonResult<AlarmTypeRespVO> getAlarmType(@RequestParam("id") Long id) {
AlarmTypeDO alarmType = alarmTypeService.getAlarmType(id);
return success(BeanUtils.toBean(alarmType, AlarmTypeRespVO.class));
}

107
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/FactoryController.java

@ -0,0 +1,107 @@
package cn.iocoder.yudao.module.hand.controller.admin;
import cn.iocoder.yudao.module.hand.dal.FactoryDO;
import cn.iocoder.yudao.module.hand.service.FactoryService;
import cn.iocoder.yudao.module.hand.vo.FactoryPageReqVO;
import cn.iocoder.yudao.module.hand.vo.FactoryRespVO;
import cn.iocoder.yudao.module.hand.vo.FactorySaveReqVO;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.constraints.*;
import jakarta.validation.*;
import jakarta.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
@Tag(name = "管理后台 - GAS工厂")
@RestController
@RequestMapping("/gas/factory")
@Validated
public class FactoryController {
@Resource
private FactoryService factoryService;
@PostMapping("/create")
@Operation(summary = "创建GAS工厂")
@PreAuthorize("@ss.hasPermission('gas:factory:create')")
public CommonResult<Long> createFactory(@Valid @RequestBody FactorySaveReqVO createReqVO) {
return success(factoryService.createFactory(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新GAS工厂")
@PreAuthorize("@ss.hasPermission('gas:factory:update')")
public CommonResult<Boolean> updateFactory(@Valid @RequestBody FactorySaveReqVO updateReqVO) {
factoryService.updateFactory(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除GAS工厂")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('gas:factory:delete')")
public CommonResult<Boolean> deleteFactory(@RequestParam("id") Long id) {
factoryService.deleteFactory(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除GAS工厂")
@PreAuthorize("@ss.hasPermission('gas:factory:delete')")
public CommonResult<Boolean> deleteFactoryList(@RequestParam("ids") List<Long> ids) {
factoryService.deleteFactoryListByIds(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得GAS工厂")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('gas:factory:query')")
public CommonResult<FactoryRespVO> getFactory(@RequestParam("id") Long id) {
FactoryDO factory = factoryService.getFactory(id);
return success(BeanUtils.toBean(factory, FactoryRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得GAS工厂分页")
@PreAuthorize("@ss.hasPermission('gas:factory:query')")
public CommonResult<PageResult<FactoryRespVO>> getFactoryPage(@Valid FactoryPageReqVO pageReqVO) {
PageResult<FactoryDO> pageResult = factoryService.getFactoryPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, FactoryRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出GAS工厂 Excel")
@PreAuthorize("@ss.hasPermission('gas:factory:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportFactoryExcel(@Valid FactoryPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<FactoryDO> list = factoryService.getFactoryPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "GAS工厂.xls", "数据", FactoryRespVO.class,
BeanUtils.toBean(list, FactoryRespVO.class));
}
}

8
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/FenceAlarmController.java

@ -44,7 +44,7 @@ public class FenceAlarmController {
@PostMapping("/create")
@Operation(summary = "创建GAS手持探测器围栏报警")
@PreAuthorize("@ss.hasPermission('gas:fence-alarm:create')")
public CommonResult<String> createFenceAlarm(@Valid @RequestBody FenceAlarmSaveReqVO createReqVO) {
public CommonResult<Long> createFenceAlarm(@Valid @RequestBody FenceAlarmSaveReqVO createReqVO) {
return success(fenceAlarmService.createFenceAlarm(createReqVO));
}
@ -60,7 +60,7 @@ public class FenceAlarmController {
@Operation(summary = "删除GAS手持探测器围栏报警")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('gas:fence-alarm:delete')")
public CommonResult<Boolean> deleteFenceAlarm(@RequestParam("id") String id) {
public CommonResult<Boolean> deleteFenceAlarm(@RequestParam("id") Long id) {
fenceAlarmService.deleteFenceAlarm(id);
return success(true);
}
@ -69,7 +69,7 @@ public class FenceAlarmController {
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除GAS手持探测器围栏报警")
@PreAuthorize("@ss.hasPermission('gas:fence-alarm:delete')")
public CommonResult<Boolean> deleteFenceAlarmList(@RequestParam("ids") List<String> ids) {
public CommonResult<Boolean> deleteFenceAlarmList(@RequestParam("ids") List<Long> ids) {
fenceAlarmService.deleteFenceAlarmListByIds(ids);
return success(true);
}
@ -78,7 +78,7 @@ public class FenceAlarmController {
@Operation(summary = "获得GAS手持探测器围栏报警")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('gas:fence-alarm:query')")
public CommonResult<FenceAlarmRespVO> getFenceAlarm(@RequestParam("id") String id) {
public CommonResult<FenceAlarmRespVO> getFenceAlarm(@RequestParam("id") Long id) {
FenceAlarmDO fenceAlarm = fenceAlarmService.getFenceAlarm(id);
return success(BeanUtils.toBean(fenceAlarm, FenceAlarmRespVO.class));
}

12
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/FenceController.java

@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.hand.service.FenceService;
import cn.iocoder.yudao.module.hand.vo.FencePageReqVO;
import cn.iocoder.yudao.module.hand.vo.FenceRespVO;
import cn.iocoder.yudao.module.hand.vo.FenceSaveReqVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
@ -44,7 +46,7 @@ public class FenceController {
@PostMapping("/create")
@Operation(summary = "创建GAS电子围栏")
@PreAuthorize("@ss.hasPermission('gas:fence:create')")
public CommonResult<String> createFence(@Valid @RequestBody FenceSaveReqVO createReqVO) {
public CommonResult<Long> createFence(@Valid @RequestBody FenceSaveReqVO createReqVO) {
return success(fenceService.createFence(createReqVO));
}
@ -60,7 +62,9 @@ public class FenceController {
@Operation(summary = "删除GAS电子围栏")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('gas:fence:delete')")
public CommonResult<Boolean> deleteFence(@RequestParam("id") String id) {
public CommonResult<Boolean> deleteFence(@RequestParam("id") Long id) {
fenceService.deleteFence(id);
return success(true);
}
@ -69,7 +73,7 @@ public class FenceController {
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除GAS电子围栏")
@PreAuthorize("@ss.hasPermission('gas:fence:delete')")
public CommonResult<Boolean> deleteFenceList(@RequestParam("ids") List<String> ids) {
public CommonResult<Boolean> deleteFenceList(@RequestParam("ids") List<Long> ids) {
fenceService.deleteFenceListByIds(ids);
return success(true);
}
@ -78,7 +82,7 @@ public class FenceController {
@Operation(summary = "获得GAS电子围栏")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('gas:fence:query')")
public CommonResult<FenceRespVO> getFence(@RequestParam("id") String id) {
public CommonResult<FenceRespVO> getFence(@RequestParam("id") Long id) {
FenceDO fence = fenceService.getFence(id);
return success(BeanUtils.toBean(fence, FenceRespVO.class));
}

8
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/GasTypeController.java

@ -44,7 +44,7 @@ public class GasTypeController {
@PostMapping("/create")
@Operation(summary = "创建GAS气体")
@PreAuthorize("@ss.hasPermission('gas:type:create')")
public CommonResult<String> createType(@Valid @RequestBody GasTypeSaveReqVO createReqVO) {
public CommonResult<Long> createType(@Valid @RequestBody GasTypeSaveReqVO createReqVO) {
return success(typeService.createType(createReqVO));
}
@ -60,7 +60,7 @@ public class GasTypeController {
@Operation(summary = "删除GAS气体")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('gas:type:delete')")
public CommonResult<Boolean> deleteType(@RequestParam("id") String id) {
public CommonResult<Boolean> deleteType(@RequestParam("id") Long id) {
typeService.deleteType(id);
return success(true);
}
@ -69,7 +69,7 @@ public class GasTypeController {
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除GAS气体")
@PreAuthorize("@ss.hasPermission('gas:type:delete')")
public CommonResult<Boolean> deleteTypeList(@RequestParam("ids") List<String> ids) {
public CommonResult<Boolean> deleteTypeList(@RequestParam("ids") List<Long> ids) {
typeService.deleteTypeListByIds(ids);
return success(true);
}
@ -78,7 +78,7 @@ public class GasTypeController {
@Operation(summary = "获得GAS气体")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('gas:type:query')")
public CommonResult<GasTypeRespVO> getType(@RequestParam("id") String id) {
public CommonResult<GasTypeRespVO> getType(@RequestParam("id") Long id) {
GasTypeDO type = typeService.getType(id);
return success(BeanUtils.toBean(type, GasTypeRespVO.class));
}

8
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/HandAlarmController.java

@ -43,7 +43,7 @@ public class HandAlarmController {
@PostMapping("/create")
@Operation(summary = "创建GAS手持探测器警报")
@PreAuthorize("@ss.hasPermission('gas:hand-alarm:create')")
public CommonResult<String> createHandAlarm(@Valid @RequestBody HandAlarmSaveReqVO createReqVO) {
public CommonResult<Long> createHandAlarm(@Valid @RequestBody HandAlarmSaveReqVO createReqVO) {
return success(handAlarmService.createHandAlarm(createReqVO));
}
@ -59,7 +59,7 @@ public class HandAlarmController {
@Operation(summary = "删除GAS手持探测器警报")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('gas:hand-alarm:delete')")
public CommonResult<Boolean> deleteHandAlarm(@RequestParam("id") String id) {
public CommonResult<Boolean> deleteHandAlarm(@RequestParam("id") Long id) {
handAlarmService.deleteHandAlarm(id);
return success(true);
}
@ -68,7 +68,7 @@ public class HandAlarmController {
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除GAS手持探测器警报")
@PreAuthorize("@ss.hasPermission('gas:hand-alarm:delete')")
public CommonResult<Boolean> deleteHandAlarmList(@RequestParam("ids") List<String> ids) {
public CommonResult<Boolean> deleteHandAlarmList(@RequestParam("ids") List<Long> ids) {
handAlarmService.deleteHandAlarmListByIds(ids);
return success(true);
}
@ -77,7 +77,7 @@ public class HandAlarmController {
@Operation(summary = "获得GAS手持探测器警报")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('gas:hand-alarm:query')")
public CommonResult<HandAlarmRespVO> getHandAlarm(@RequestParam("id") String id) {
public CommonResult<HandAlarmRespVO> getHandAlarm(@RequestParam("id") Long id) {
HandAlarmDO handAlarm = handAlarmService.getHandAlarm(id);
return success(BeanUtils.toBean(handAlarm, HandAlarmRespVO.class));
}

39
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/HandDetectorController.java

@ -1,7 +1,11 @@
package cn.iocoder.yudao.module.hand.controller.admin;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.hand.dal.HandDetectorDO;
import cn.iocoder.yudao.module.hand.service.HandDetectorService;
import cn.iocoder.yudao.module.hand.util.RedisKeyUtil;
import cn.iocoder.yudao.module.hand.util.RedisUtil;
import cn.iocoder.yudao.module.hand.vo.HandDetectorPageReqVO;
import cn.iocoder.yudao.module.hand.vo.HandDetectorRespVO;
import cn.iocoder.yudao.module.hand.vo.HandDetectorSaveReqVO;
import org.springframework.web.bind.annotation.*;
@ -22,13 +26,17 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.HAND_DETECTOR_NOT_EXISTS;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.HAND_DETECTOR_REDIS_NOT_EXISTS;
@Tag(name = "管理后台 - GAS手持探测器")
@ -43,14 +51,14 @@ public class HandDetectorController {
@PostMapping("/create")
@Operation(summary = "创建GAS手持探测器")
@PreAuthorize("@ss.hasPermission('gas:hand-detector:create')")
public CommonResult<String> createHandDetector(@Valid @RequestBody HandDetectorSaveReqVO createReqVO) {
public CommonResult<Long> createHandDetector(@Valid @RequestBody HandDetectorSaveReqVO createReqVO) {
return success(handDetectorService.createHandDetector(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新GAS手持探测器")
@PreAuthorize("@ss.hasPermission('gas:hand-detector:update')")
public CommonResult<Boolean> updateHandDetector(@Valid @RequestBody cn.iocoder.yudao.module.hand.vo.HandDetectorSaveReqVO updateReqVO) {
public CommonResult<Boolean> updateHandDetector(@Valid @RequestBody HandDetectorSaveReqVO updateReqVO) {
handDetectorService.updateHandDetector(updateReqVO);
return success(true);
}
@ -59,7 +67,7 @@ public class HandDetectorController {
@Operation(summary = "删除GAS手持探测器")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('gas:hand-detector:delete')")
public CommonResult<Boolean> deleteHandDetector(@RequestParam("id") String id) {
public CommonResult<Boolean> deleteHandDetector(@RequestParam("id") Long id) {
handDetectorService.deleteHandDetector(id);
return success(true);
}
@ -68,7 +76,7 @@ public class HandDetectorController {
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除GAS手持探测器")
@PreAuthorize("@ss.hasPermission('gas:hand-detector:delete')")
public CommonResult<Boolean> deleteHandDetectorList(@RequestParam("ids") List<String> ids) {
public CommonResult<Boolean> deleteHandDetectorList(@RequestParam("ids") List<Long> ids) {
handDetectorService.deleteHandDetectorListByIds(ids);
return success(true);
}
@ -77,7 +85,7 @@ public class HandDetectorController {
@Operation(summary = "获得GAS手持探测器")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('gas:hand-detector:query')")
public CommonResult<cn.iocoder.yudao.module.hand.vo.HandDetectorRespVO> getHandDetector(@RequestParam("id") String id) {
public CommonResult<HandDetectorRespVO> getHandDetector(@RequestParam("id") Long id) {
HandDetectorDO handDetector = handDetectorService.getHandDetector(id);
return success(BeanUtils.toBean(handDetector, HandDetectorRespVO.class));
}
@ -85,7 +93,7 @@ public class HandDetectorController {
@GetMapping("/page")
@Operation(summary = "获得GAS手持探测器分页")
@PreAuthorize("@ss.hasPermission('gas:hand-detector:query')")
public CommonResult<PageResult<cn.iocoder.yudao.module.hand.vo.HandDetectorRespVO>> getHandDetectorPage(@Valid cn.iocoder.yudao.module.hand.vo.HandDetectorPageReqVO pageReqVO) {
public CommonResult<PageResult<HandDetectorRespVO>> getHandDetectorPage(@Valid HandDetectorPageReqVO pageReqVO) {
PageResult<HandDetectorDO> pageResult = handDetectorService.getHandDetectorPage(pageReqVO);
return success(BeanUtils.toBean(pageResult,HandDetectorRespVO.class));
}
@ -94,13 +102,24 @@ public class HandDetectorController {
@Operation(summary = "导出GAS手持探测器 Excel")
@PreAuthorize("@ss.hasPermission('gas:hand-detector:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportHandDetectorExcel(@Valid cn.iocoder.yudao.module.hand.vo.HandDetectorPageReqVO pageReqVO,
public void exportHandDetectorExcel(@Valid HandDetectorPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<HandDetectorDO> list = handDetectorService.getHandDetectorPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "GAS手持探测器.xls", "数据", cn.iocoder.yudao.module.hand.vo.HandDetectorRespVO.class,
BeanUtils.toBean(list, cn.iocoder.yudao.module.hand.vo.HandDetectorRespVO.class));
ExcelUtils.write(response, "GAS手持探测器.xls", "数据", HandDetectorRespVO.class,
BeanUtils.toBean(list, HandDetectorRespVO.class));
}
@GetMapping("/getByHandData")
@Operation(summary = "获得GAS手持探测器实时数据")
public CommonResult<Map<Object, Object>> getHandData(){
LoginUser loginUser = getLoginUser();
if (null == loginUser){
throw exception(HAND_DETECTOR_REDIS_NOT_EXISTS);
}
String tenantDeviceHashKey = RedisKeyUtil.getTenantDeviceHashKey(loginUser.getTenantId());
Map<Object, Object> handData = handDetectorService.getHandData(tenantDeviceHashKey);
return CommonResult.success(handData);
}
}

66
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/admin/HandTdengineController.java

@ -0,0 +1,66 @@
package cn.iocoder.yudao.module.hand.controller.admin;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.hand.dal.HandDetectorDO;
import cn.iocoder.yudao.module.hand.service.HandDetectorService;
import cn.iocoder.yudao.module.hand.service.TdengineService;
import cn.iocoder.yudao.module.hand.util.RedisKeyUtil;
import cn.iocoder.yudao.module.hand.util.RedisUtil;
import cn.iocoder.yudao.module.hand.vo.*;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.constraints.*;
import jakarta.validation.*;
import jakarta.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.HAND_DETECTOR_NOT_EXISTS;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.HAND_DETECTOR_REDIS_NOT_EXISTS;
@Tag(name = "管理后台 - 时序数据库查询")
@RestController
@RequestMapping("/gas/tdengine")
@Validated
public class HandTdengineController {
@Resource
private TdengineService tdengineService;
@GetMapping("/page")
@Operation(summary = "获取历史数据")
@PreAuthorize("@ss.hasPermission('gas:hand-td:query')")
public CommonResult<PageResult<TdengineDataVo>> getHandDetectorPage(@Valid HandTdenginePageVO pageReqVO) {
PageResult<TdengineDataVo> pageResult = tdengineService.getHandDataLog(pageReqVO);
return success(pageResult);
}
@GetMapping("/originalLogPage")
@Operation(summary = "获取原始数据")
@PreAuthorize("@ss.hasPermission('gas:hand-td:queryOriginal')")
public CommonResult<PageResult<HandOriginalLog>> originalLogPage(@Valid HandTdenginePageVO pageReqVO) {
PageResult<HandOriginalLog> pageResult = tdengineService.getOriginalLogPage(pageReqVO);
return success(pageResult);
}
}

2
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/controller/package-info.java

@ -1,4 +1,4 @@
/**
* infra 模块的 web 配置
*/
package cn.iocoder.yudao.module.lock.controller;
package cn.iocoder.yudao.module.hand.controller;

23
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/AlarmRuleDO.java

@ -25,16 +25,16 @@ public class AlarmRuleDO extends BaseDO {
/**
* 主键ID
*/
@TableId(type = IdType.INPUT)
private String id;
@TableId
private Long id;
/**
* 气体类型ID
*/
private String gasTypeId;
private Long gasTypeId;
/**
* 警报类型ID
*/
private String alarmTypeId;
private Long alarmTypeId;
/**
* 警报名称
*/
@ -71,18 +71,9 @@ public class AlarmRuleDO extends BaseDO {
* 备注
*/
private String remark;
/**
* 删除标志
*/
private Integer delFlag;
/**
* 创建者
*/
private String createBy;
/**
* 更新者
* 租户id
*/
private String updateBy;
private Integer tenantId;
}

16
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/AlarmTypeDO.java

@ -25,8 +25,8 @@ public class AlarmTypeDO extends BaseDO {
/**
* 主键ID
*/
@TableId(type = IdType.INPUT)
private String id;
@TableId
private Long id;
/**
* 名称
*/
@ -52,17 +52,9 @@ public class AlarmTypeDO extends BaseDO {
*/
private String remark;
/**
* 删除标志
* 租户id
*/
private Integer delFlag;
/**
* 创建者
*/
private String createBy;
/**
* 更新者
*/
private String updateBy;
private Integer tenantId;
}

97
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/FactoryDO.java

@ -0,0 +1,97 @@
package cn.iocoder.yudao.module.hand.dal;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* GAS工厂 DO
*
* @author 超级管理员
*/
@TableName("gas_factory")
@KeySequence("gas_factory_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FactoryDO extends BaseDO {
/**
* 主键ID
*/
@TableId
private Long id;
/**
* 父节点ID
*/
private Long parentId;
/**
* 层级1工厂2车间3班组
*/
private Integer type;
/**
* 名称
*/
private String name;
/**
* 城市
*/
private String city;
/**
* 总警报数
*/
private Integer alarmTotal;
/**
* 已处理警报数
*/
private Integer alarmDeal;
/**
* 区域图
*/
private String picUrl;
/**
* 区域图缩放比例
*/
private Integer picScale;
/**
* 在区域图X坐标值
*/
private Double picX;
/**
* 在区域图X坐标值
*/
private Double picY;
/**
* 经度
*/
private Double longitude;
/**
* 纬度
*/
private Double latitude;
/**
* 区域西南坐标
*/
private String rectSouthWest;
/**
* 区域东北坐标
*/
private String rectNorthEast;
/**
* 排序
*/
private Integer sortOrder;
/**
* 备注
*/
private String remark;
}

37
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/FenceAlarmDO.java

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.hand.dal;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
@ -27,16 +28,27 @@ public class FenceAlarmDO extends BaseDO {
/**
* 主键ID
*/
@TableId(type = IdType.INPUT)
private String id;
@TableId
private Long id;
/**
* 探头ID
* 手持表ID
*/
private String detectorId;
private Long detectorId;
/**
* 手持表ID
*/
private String name;
/**
* 手持表SN
*/
private String sn;
/**
* 围栏id
*/
private String fenceId;
private Long fenceId;
/**
* 报警类型
*/
@ -73,18 +85,9 @@ public class FenceAlarmDO extends BaseDO {
* 备注
*/
private String remark;
/**
* 删除标志
*/
private Integer delFlag;
/**
* 创建者
*/
private String createBy;
/**
* 更新者
* 租户id
*/
private String updateBy;
private Integer tenantId;
}

19
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/FenceDO.java

@ -25,8 +25,8 @@ public class FenceDO extends BaseDO {
/**
* 主键ID
*/
@TableId(type = IdType.INPUT)
private String id;
@TableId
private Long id;
/**
* 围栏名称
*/
@ -47,18 +47,9 @@ public class FenceDO extends BaseDO {
* 备注
*/
private String remark;
/**
* 删除标志
*/
private Integer delFlag;
/**
* 创建者
*/
private String createBy;
/**
* 更新者
* 租户id
*/
private String updateBy;
private Integer tenantId;
}

20
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/GasTypeDO.java

@ -25,8 +25,8 @@ public class GasTypeDO extends BaseDO {
/**
* 主键ID
*/
@TableId(type = IdType.INPUT)
private String id;
@TableId
private Long id;
/**
* 名称
*/
@ -47,18 +47,10 @@ public class GasTypeDO extends BaseDO {
* 备注
*/
private String remark;
/**
* 删除标志
*/
private Integer delFlag;
/**
* 创建者
*/
private String createBy;
/**
* 更新者
*/
private String updateBy;
/**
* 租户id
*/
private Integer tenantId;
}

31
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/HandAlarmDO.java

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.hand.dal;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
@ -27,8 +28,20 @@ public class HandAlarmDO extends BaseDO {
/**
* 主键ID
*/
@TableId(type = IdType.INPUT)
private String id;
@TableId
private Long id;
/**
* 名称
*/
private String name;
/**
* 报警类型
*/
private Integer alarmType;
/**
* 警报方式/级别0正常状态1一级警报2二级警报3弹窗警报
*/
@ -77,18 +90,10 @@ public class HandAlarmDO extends BaseDO {
* 备注
*/
private String remark;
/**
* 删除标志
*/
private Integer delFlag;
/**
* 创建者
*/
private String createBy;
/**
* 更新者
* 租户id
*/
private String updateBy;
private Long tenantId;
}

37
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/dal/HandDetectorDO.java

@ -4,6 +4,8 @@ import lombok.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import java.math.BigDecimal;
/**
* GAS手持探测器 DO
*
@ -22,8 +24,8 @@ public class HandDetectorDO extends BaseDO {
/**
* 主键ID
*/
@TableId(type = IdType.INPUT)
private String id;
@TableId
private Long id;
/**
* SN
*/
@ -35,11 +37,11 @@ public class HandDetectorDO extends BaseDO {
/**
* 围栏id
*/
private String fenceId;
private String fenceIds;
/**
* 气体类型ID
*/
private String gasTypeId;
private Long gasTypeId;
/**
* 气体化学式
*/
@ -52,10 +54,11 @@ public class HandDetectorDO extends BaseDO {
* 测量范围中的最大值
*/
private Double max;
/**
* 状态0未知1正常2故障3离线
* 低于多少电量报警
*/
private Integer status;
private BigDecimal batteryAlarmValue;
/**
* 单位
*/
@ -73,14 +76,6 @@ public class HandDetectorDO extends BaseDO {
*/
private Integer enableStatus;
/**
* 在区域图X坐标值
*/
private Double picX;
/**
* 在区域图Y坐标值
*/
private Double picY;
/**
* 经度
*/
private Double longitude;
@ -100,18 +95,10 @@ public class HandDetectorDO extends BaseDO {
* 备注
*/
private String remark;
/**
* 删除标志
*/
private Integer delFlag;
/**
* 创建者
*/
private String createBy;
/**
* 更新者
* 租户id
*/
private String updateBy;
private Integer tenantId;
}

48
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/AlarmLevelEnum.java

@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.hand.enums;
import lombok.Getter;
@Getter
public enum AlarmLevelEnum {
OFFLINE(-1,"离线报警"),
NORMAL(0,"正常状态"),
LEVEL_1(1,"一级报警"),
LEVEL_2(2,"二级报警"),
LEVEL_3(3,"弹窗警报");
private Integer value;
private String name;
AlarmLevelEnum(Integer val, String name) {
this.value = val;
this.name = name;
}
public Integer value() {
return value;
}
/**
* 根据value获取到枚举类名称
*
* @param value
* @return
*/
public static String getNameByValue(Integer value) {
AlarmLevelEnum type = getByValue(value);
return null == type ? "" : type.getName();
}
/**
* 根据value获取枚举类型
*
* @param value
* @return
*/
public static AlarmLevelEnum getByValue(Integer value) {
if (null != value) {
for (AlarmLevelEnum type : AlarmLevelEnum.values()) {
if (type.getValue() == value) {
return type;
}
}
}
return null;
}
}

53
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/AlarmType.java

@ -0,0 +1,53 @@
package cn.iocoder.yudao.module.hand.enums;
import lombok.Getter;
import java.util.Objects;
@Getter
public enum AlarmType {
GAS(1, "气体报警"),
BATTERY(2, "电量报警"),
OFFLINE(3, "离线报警");
private final Integer type;
private final String name;
AlarmType(Integer type, String name) {
this.type = type;
this.name = name;
}
// 通过 int 值获取枚举实例
public static AlarmType fromType(Integer type) {
for (AlarmType valveType : AlarmType.values()) {
if (Objects.equals(valveType.getType(), type)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门类型: " + type);
}
// 通过 int 值获取名称
public static String getNameByType(int type) {
AlarmType valveType = fromType(type);
return valveType.getName();
}
// 通过名称获取枚举实例
public static AlarmType fromName(String name) {
for (AlarmType valveType : AlarmType.values()) {
if (valveType.getName().equals(name)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门名称: " + name);
}
// 通过名称获取 int 值
public static Integer getTypeByName(String name) {
AlarmType valveType = fromName(name);
return valveType.getType();
}
}

14
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/EnableStatus.java

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.hand.enums;
public enum EnableStatus {
DISABLED(0), ENABLED(1),REPAIR(2);
private Integer value;
EnableStatus(Integer val) {
this.value = val;
}
public Integer value() {
return value;
}
}

6
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/ErrorCodeConstants.java

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
public interface ErrorCodeConstants {
ErrorCode HAND_DETECTOR_SN_EXISTS = new ErrorCode(100001, "GAS手持探测器SN已经存在");
ErrorCode HAND_DETECTOR_NOT_EXISTS = new ErrorCode(100001, "GAS手持探测器不存在");
@ -15,7 +16,12 @@ public interface ErrorCodeConstants {
ErrorCode FENCE_NOT_EXISTS = new ErrorCode(100005, "GAS电子围栏不存在");
ErrorCode FENCE_EXISTS_HAND_DETECTOR = new ErrorCode(100005, "围栏下仍有绑定的手持设备,请先解除关联后再进行删除操作");
ErrorCode ALARM_TYPE_NOT_EXISTS = new ErrorCode(100006, "GAS警报类型不存在");
ErrorCode ALARM_RULE_NOT_EXISTS = new ErrorCode(100007, "GAS警报规则不存在");
ErrorCode FACTORY_NOT_EXISTS = new ErrorCode(1000071, "GAS工厂不存在");
ErrorCode HAND_DETECTOR_REDIS_NOT_EXISTS = new ErrorCode(100001, "请先登录,再查看");
}

52
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/FenceStatusType.java

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.hand.enums;
import lombok.Getter;
import java.util.Objects;
@Getter
public enum FenceStatusType {
DISABLED(1,"启用"),
ENABLED(2,"禁用");
private final Integer type;
private final String name;
FenceStatusType(Integer type, String name) {
this.type = type;
this.name = name;
}
// 通过 int 值获取枚举实例
public static FenceStatusType fromType(Integer type) {
for (FenceStatusType valveType : FenceStatusType.values()) {
if (Objects.equals(valveType.getType(), type)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门类型: " + type);
}
// 通过 int 值获取名称
public static String getNameByType(int type) {
FenceStatusType valveType = fromType(type);
return valveType.getName();
}
// 通过名称获取枚举实例
public static FenceStatusType fromName(String name) {
for (FenceStatusType valveType : FenceStatusType.values()) {
if (valveType.getName().equals(name)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门名称: " + name);
}
// 通过名称获取 int 值
public static Integer getTypeByName(String name) {
FenceStatusType valveType = fromName(name);
return valveType.getType();
}
}

52
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/FenceType.java

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.hand.enums;
import lombok.Getter;
import java.util.Objects;
@Getter
public enum FenceType {
OUTSIDE(1,"超出围栏报警"),
INSIDE(2,"进入围栏报警");
private final Integer type;
private final String name;
FenceType(Integer type, String name) {
this.type = type;
this.name = name;
}
// 通过 int 值获取枚举实例
public static FenceType fromType(Integer type) {
for (FenceType valveType : FenceType.values()) {
if (Objects.equals(valveType.getType(), type)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门类型: " + type);
}
// 通过 int 值获取名称
public static String getNameByType(int type) {
FenceType valveType = fromType(type);
return valveType.getName();
}
// 通过名称获取枚举实例
public static FenceType fromName(String name) {
for (FenceType valveType : FenceType.values()) {
if (valveType.getName().equals(name)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门名称: " + name);
}
// 通过名称获取 int 值
public static Integer getTypeByName(String name) {
FenceType valveType = fromName(name);
return valveType.getType();
}
}

52
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/HandAlarmType.java

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.hand.enums;
import lombok.Getter;
import java.util.Objects;
@Getter
public enum HandAlarmType {
NORMAL(0, "正常"),
ALARM(1, "报警");
private final Integer type;
private final String name;
HandAlarmType(Integer type, String name) {
this.type = type;
this.name = name;
}
// 通过 int 值获取枚举实例
public static HandAlarmType fromType(Integer type) {
for (HandAlarmType valveType : HandAlarmType.values()) {
if (Objects.equals(valveType.getType(), type)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门类型: " + type);
}
// 通过 int 值获取名称
public static String getNameByType(int type) {
HandAlarmType valveType = fromType(type);
return valveType.getName();
}
// 通过名称获取枚举实例
public static HandAlarmType fromName(String name) {
for (HandAlarmType valveType : HandAlarmType.values()) {
if (valveType.getName().equals(name)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门名称: " + name);
}
// 通过名称获取 int 值
public static Integer getTypeByName(String name) {
HandAlarmType valveType = fromName(name);
return valveType.getType();
}
}

14
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/MaxDirection.java

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.hand.enums;
public enum MaxDirection {
DOWN(0), UP(1);
private Integer value;
MaxDirection(Integer val) {
this.value = val;
}
public Integer value() {
return value;
}
}

52
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/enums/OnlineStatusType.java

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.hand.enums;
import lombok.Getter;
import java.util.Objects;
@Getter
public enum OnlineStatusType {
OFFLINE(0, "离线"),
ONLINE(1, "正常");
private final Integer type;
private final String name;
OnlineStatusType(Integer type, String name) {
this.type = type;
this.name = name;
}
// 通过 int 值获取枚举实例
public static OnlineStatusType fromType(Integer type) {
for (OnlineStatusType valveType : OnlineStatusType.values()) {
if (Objects.equals(valveType.getType(), type)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门类型: " + type);
}
// 通过 int 值获取名称
public static String getNameByType(int type) {
OnlineStatusType valveType = fromType(type);
return valveType.getName();
}
// 通过名称获取枚举实例
public static OnlineStatusType fromName(String name) {
for (OnlineStatusType valveType : OnlineStatusType.values()) {
if (valveType.getName().equals(name)) {
return valveType;
}
}
throw new IllegalArgumentException("未知的阀门名称: " + name);
}
// 通过名称获取 int 值
public static Integer getTypeByName(String name) {
OnlineStatusType valveType = fromName(name);
return valveType.getType();
}
}

3
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/AlarmRuleMapper.java

@ -30,10 +30,7 @@ public interface AlarmRuleMapper extends BaseMapperX<AlarmRuleDO> {
.eqIfPresent(AlarmRuleDO::getDirection, reqVO.getDirection())
.eqIfPresent(AlarmRuleDO::getSortOrder, reqVO.getSortOrder())
.eqIfPresent(AlarmRuleDO::getRemark, reqVO.getRemark())
.eqIfPresent(AlarmRuleDO::getDelFlag, reqVO.getDelFlag())
.eqIfPresent(AlarmRuleDO::getCreateBy, reqVO.getCreateBy())
.betweenIfPresent(AlarmRuleDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(AlarmRuleDO::getUpdateBy, reqVO.getUpdateBy())
.orderByDesc(AlarmRuleDO::getId));
}

3
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/AlarmTypeMapper.java

@ -25,10 +25,7 @@ public interface AlarmTypeMapper extends BaseMapperX<AlarmTypeDO> {
.eqIfPresent(AlarmTypeDO::getLevel, reqVO.getLevel())
.eqIfPresent(AlarmTypeDO::getSortOrder, reqVO.getSortOrder())
.eqIfPresent(AlarmTypeDO::getRemark, reqVO.getRemark())
.eqIfPresent(AlarmTypeDO::getDelFlag, reqVO.getDelFlag())
.eqIfPresent(AlarmTypeDO::getCreateBy, reqVO.getCreateBy())
.betweenIfPresent(AlarmTypeDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(AlarmTypeDO::getUpdateBy, reqVO.getUpdateBy())
.orderByDesc(AlarmTypeDO::getId));
}

41
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/FactoryMapper.java

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.hand.mapper;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.hand.dal.FactoryDO;
import cn.iocoder.yudao.module.hand.vo.FactoryPageReqVO;
import org.apache.ibatis.annotations.Mapper;
/**
* GAS工厂 Mapper
*
* @author 超级管理员
*/
@Mapper
public interface FactoryMapper extends BaseMapperX<FactoryDO> {
default PageResult<FactoryDO> selectPage(FactoryPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<FactoryDO>()
.eqIfPresent(FactoryDO::getParentId, reqVO.getParentId())
.eqIfPresent(FactoryDO::getType, reqVO.getType())
.likeIfPresent(FactoryDO::getName, reqVO.getName())
.eqIfPresent(FactoryDO::getCity, reqVO.getCity())
.eqIfPresent(FactoryDO::getAlarmTotal, reqVO.getAlarmTotal())
.eqIfPresent(FactoryDO::getAlarmDeal, reqVO.getAlarmDeal())
.eqIfPresent(FactoryDO::getPicUrl, reqVO.getPicUrl())
.eqIfPresent(FactoryDO::getPicScale, reqVO.getPicScale())
.eqIfPresent(FactoryDO::getPicX, reqVO.getPicX())
.eqIfPresent(FactoryDO::getPicY, reqVO.getPicY())
.eqIfPresent(FactoryDO::getLongitude, reqVO.getLongitude())
.eqIfPresent(FactoryDO::getLatitude, reqVO.getLatitude())
.eqIfPresent(FactoryDO::getRectSouthWest, reqVO.getRectSouthWest())
.eqIfPresent(FactoryDO::getRectNorthEast, reqVO.getRectNorthEast())
.eqIfPresent(FactoryDO::getSortOrder, reqVO.getSortOrder())
.eqIfPresent(FactoryDO::getRemark, reqVO.getRemark())
.orderByDesc(FactoryDO::getId));
}
}

3
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/FenceAlarmMapper.java

@ -30,10 +30,7 @@ public interface FenceAlarmMapper extends BaseMapperX<FenceAlarmDO> {
.eqIfPresent(FenceAlarmDO::getTAlarmEnd, reqVO.getTAlarmEnd())
.eqIfPresent(FenceAlarmDO::getStatus, reqVO.getStatus())
.eqIfPresent(FenceAlarmDO::getRemark, reqVO.getRemark())
.eqIfPresent(FenceAlarmDO::getDelFlag, reqVO.getDelFlag())
.eqIfPresent(FenceAlarmDO::getCreateBy, reqVO.getCreateBy())
.betweenIfPresent(FenceAlarmDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(FenceAlarmDO::getUpdateBy, reqVO.getUpdateBy())
.orderByDesc(FenceAlarmDO::getId));
}

3
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/FenceMapper.java

@ -24,10 +24,7 @@ public interface FenceMapper extends BaseMapperX<FenceDO> {
.eqIfPresent(FenceDO::getStatus, reqVO.getStatus())
.eqIfPresent(FenceDO::getType, reqVO.getType())
.eqIfPresent(FenceDO::getRemark, reqVO.getRemark())
.eqIfPresent(FenceDO::getDelFlag, reqVO.getDelFlag())
.eqIfPresent(FenceDO::getCreateBy, reqVO.getCreateBy())
.betweenIfPresent(FenceDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(FenceDO::getUpdateBy, reqVO.getUpdateBy())
.orderByDesc(FenceDO::getId));
}

3
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/GasTypeMapper.java

@ -24,10 +24,7 @@ public interface GasTypeMapper extends BaseMapperX<GasTypeDO> {
.eqIfPresent(GasTypeDO::getUnit, reqVO.getUnit())
.eqIfPresent(GasTypeDO::getSortOrder, reqVO.getSortOrder())
.eqIfPresent(GasTypeDO::getRemark, reqVO.getRemark())
.eqIfPresent(GasTypeDO::getDelFlag, reqVO.getDelFlag())
.eqIfPresent(GasTypeDO::getCreateBy, reqVO.getCreateBy())
.betweenIfPresent(GasTypeDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(GasTypeDO::getUpdateBy, reqVO.getUpdateBy())
.orderByDesc(GasTypeDO::getId));
}

3
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/HandAlarmMapper.java

@ -31,10 +31,7 @@ public interface HandAlarmMapper extends BaseMapperX<HandAlarmDO> {
.eqIfPresent(HandAlarmDO::getTAlarmEnd, reqVO.getTAlarmEnd())
.eqIfPresent(HandAlarmDO::getStatus, reqVO.getStatus())
.eqIfPresent(HandAlarmDO::getRemark, reqVO.getRemark())
.eqIfPresent(HandAlarmDO::getDelFlag, reqVO.getDelFlag())
.eqIfPresent(HandAlarmDO::getCreateBy, reqVO.getCreateBy())
.betweenIfPresent(HandAlarmDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(HandAlarmDO::getUpdateBy, reqVO.getUpdateBy())
.orderByDesc(HandAlarmDO::getId));
}

12
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/HandDetectorMapper.java

@ -5,7 +5,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.hand.dal.HandDetectorDO;
import cn.iocoder.yudao.module.hand.vo.HandDetectorPageReqVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.cursor.Cursor;
/**
* GAS手持探测器 Mapper
@ -19,28 +21,24 @@ public interface HandDetectorMapper extends BaseMapperX<HandDetectorDO> {
return selectPage(reqVO, new LambdaQueryWrapperX<HandDetectorDO>()
.eqIfPresent(HandDetectorDO::getSn, reqVO.getSn())
.likeIfPresent(HandDetectorDO::getName, reqVO.getName())
.eqIfPresent(HandDetectorDO::getFenceId, reqVO.getFenceId())
.eqIfPresent(HandDetectorDO::getFenceIds, reqVO.getFenceId())
.eqIfPresent(HandDetectorDO::getGasTypeId, reqVO.getGasTypeId())
.eqIfPresent(HandDetectorDO::getGasChemical, reqVO.getGasChemical())
.eqIfPresent(HandDetectorDO::getMin, reqVO.getMin())
.eqIfPresent(HandDetectorDO::getMax, reqVO.getMax())
.eqIfPresent(HandDetectorDO::getStatus, reqVO.getStatus())
.eqIfPresent(HandDetectorDO::getUnit, reqVO.getUnit())
.eqIfPresent(HandDetectorDO::getModel, reqVO.getModel())
.eqIfPresent(HandDetectorDO::getManufacturer, reqVO.getManufacturer())
.eqIfPresent(HandDetectorDO::getEnableStatus, reqVO.getEnableStatus())
.eqIfPresent(HandDetectorDO::getPicX, reqVO.getPicX())
.eqIfPresent(HandDetectorDO::getPicY, reqVO.getPicY())
.eqIfPresent(HandDetectorDO::getLongitude, reqVO.getLongitude())
.eqIfPresent(HandDetectorDO::getLatitude, reqVO.getLatitude())
.eqIfPresent(HandDetectorDO::getAccuracy, reqVO.getAccuracy())
.eqIfPresent(HandDetectorDO::getSortOrder, reqVO.getSortOrder())
.eqIfPresent(HandDetectorDO::getRemark, reqVO.getRemark())
.eqIfPresent(HandDetectorDO::getDelFlag, reqVO.getDelFlag())
.eqIfPresent(HandDetectorDO::getCreateBy, reqVO.getCreateBy())
.betweenIfPresent(HandDetectorDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(HandDetectorDO::getUpdateBy, reqVO.getUpdateBy())
.orderByDesc(HandDetectorDO::getId));
}
Cursor<HandDetectorDO> selectCursor(QueryWrapper<Object> objectQueryWrapper);
}

30
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/mapper/TdengineMapper.java

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.hand.mapper;
import cn.iocoder.yudao.module.hand.vo.HandOriginalLog;
import cn.iocoder.yudao.module.hand.vo.HandTdenginePageVO;
import cn.iocoder.yudao.module.hand.vo.TdengineDataVo;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore; // 确保导入这个注解
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface TdengineMapper {
@InterceptorIgnore(tenantLine = "true")
void insertHandLogBatch(@Param("sn") String sn,@Param("tenantId")Long tenantId,
@Param("logList") List<HandOriginalLog> groupedLogs);
@InterceptorIgnore(tenantLine = "true")
void saveDataLogBatch(@Param("sn")String sn,@Param("tenantId")Long tenantId,
@Param("dataVoList")List<TdengineDataVo> dataVoList);
IPage<TdengineDataVo> selectPage(IPage<TdengineDataVo> page,@Param("vo") HandTdenginePageVO pageReqVO);
IPage<HandOriginalLog> selectOriginalPage(IPage<HandOriginalLog> page,@Param("vo") HandTdenginePageVO pageReqVO);
}

11
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/AlarmRuleService.java

@ -22,7 +22,7 @@ public interface AlarmRuleService {
* @param createReqVO 创建信息
* @return 编号
*/
String createAlarmRule(@Valid AlarmRuleSaveReqVO createReqVO);
Long createAlarmRule(@Valid AlarmRuleSaveReqVO createReqVO);
/**
* 更新GAS警报规则
@ -36,14 +36,14 @@ public interface AlarmRuleService {
*
* @param id 编号
*/
void deleteAlarmRule(String id);
void deleteAlarmRule(Long id);
/**
* 批量删除GAS警报规则
*
* @param ids 编号
*/
void deleteAlarmRuleListByIds(List<String> ids);
void deleteAlarmRuleListByIds(List<Long> ids);
/**
* 获得GAS警报规则
@ -51,7 +51,7 @@ public interface AlarmRuleService {
* @param id 编号
* @return GAS警报规则
*/
AlarmRuleDO getAlarmRule(String id);
AlarmRuleDO getAlarmRule(Long id);
/**
* 获得GAS警报规则分页
@ -61,4 +61,7 @@ public interface AlarmRuleService {
*/
PageResult<AlarmRuleDO> getAlarmRulePage(AlarmRulePageReqVO pageReqVO);
Map<Long, List<AlarmRuleDO>> selectCacheListMap(Long tenantId);
}

8
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/AlarmTypeService.java

@ -22,7 +22,7 @@ public interface AlarmTypeService {
* @param createReqVO 创建信息
* @return 编号
*/
String createAlarmType(@Valid AlarmTypeSaveReqVO createReqVO);
Long createAlarmType(@Valid AlarmTypeSaveReqVO createReqVO);
/**
* 更新GAS警报类型
@ -36,14 +36,14 @@ public interface AlarmTypeService {
*
* @param id 编号
*/
void deleteAlarmType(String id);
void deleteAlarmType(Long id);
/**
* 批量删除GAS警报类型
*
* @param ids 编号
*/
void deleteAlarmTypeListByIds(List<String> ids);
void deleteAlarmTypeListByIds(List<Long> ids);
/**
* 获得GAS警报类型
@ -51,7 +51,7 @@ public interface AlarmTypeService {
* @param id 编号
* @return GAS警报类型
*/
AlarmTypeDO getAlarmType(String id);
AlarmTypeDO getAlarmType(Long id);
/**
* 获得GAS警报类型分页

64
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/FactoryService.java

@ -0,0 +1,64 @@
package cn.iocoder.yudao.module.hand.service;
import java.util.*;
import cn.iocoder.yudao.module.hand.dal.FactoryDO;
import cn.iocoder.yudao.module.hand.vo.FactoryPageReqVO;
import cn.iocoder.yudao.module.hand.vo.FactorySaveReqVO;
import jakarta.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* GAS工厂 Service 接口
*
* @author 超级管理员
*/
public interface FactoryService {
/**
* 创建GAS工厂
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createFactory(@Valid FactorySaveReqVO createReqVO);
/**
* 更新GAS工厂
*
* @param updateReqVO 更新信息
*/
void updateFactory(@Valid FactorySaveReqVO updateReqVO);
/**
* 删除GAS工厂
*
* @param id 编号
*/
void deleteFactory(Long id);
/**
* 批量删除GAS工厂
*
* @param ids 编号
*/
void deleteFactoryListByIds(List<Long> ids);
/**
* 获得GAS工厂
*
* @param id 编号
* @return GAS工厂
*/
FactoryDO getFactory(Long id);
/**
* 获得GAS工厂分页
*
* @param pageReqVO 分页查询
* @return GAS工厂分页
*/
PageResult<FactoryDO> getFactoryPage(FactoryPageReqVO pageReqVO);
}

11
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/FenceAlarmService.java

@ -22,7 +22,7 @@ public interface FenceAlarmService {
* @param createReqVO 创建信息
* @return 编号
*/
String createFenceAlarm(@Valid FenceAlarmSaveReqVO createReqVO);
Long createFenceAlarm(@Valid FenceAlarmSaveReqVO createReqVO);
/**
* 更新GAS手持探测器围栏报警
@ -36,14 +36,14 @@ public interface FenceAlarmService {
*
* @param id 编号
*/
void deleteFenceAlarm(String id);
void deleteFenceAlarm(Long id);
/**
* 批量删除GAS手持探测器围栏报警
*
* @param ids 编号
*/
void deleteFenceAlarmListByIds(List<String> ids);
void deleteFenceAlarmListByIds(List<Long> ids);
/**
* 获得GAS手持探测器围栏报警
@ -51,7 +51,7 @@ public interface FenceAlarmService {
* @param id 编号
* @return GAS手持探测器围栏报警
*/
FenceAlarmDO getFenceAlarm(String id);
FenceAlarmDO getFenceAlarm(Long id);
/**
* 获得GAS手持探测器围栏报警分页
@ -61,4 +61,7 @@ public interface FenceAlarmService {
*/
PageResult<FenceAlarmDO> getFenceAlarmPage(FenceAlarmPageReqVO pageReqVO);
void update( FenceAlarmDO updateReqVO);
}

16
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/FenceService.java

@ -5,6 +5,7 @@ import java.util.*;
import cn.iocoder.yudao.module.hand.dal.FenceDO;
import cn.iocoder.yudao.module.hand.vo.FencePageReqVO;
import cn.iocoder.yudao.module.hand.vo.FenceSaveReqVO;
import cn.iocoder.yudao.module.hand.vo.Geofence;
import jakarta.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -22,7 +23,7 @@ public interface FenceService {
* @param createReqVO 创建信息
* @return 编号
*/
String createFence(@Valid FenceSaveReqVO createReqVO);
Long createFence(@Valid FenceSaveReqVO createReqVO);
/**
* 更新GAS电子围栏
@ -36,14 +37,14 @@ public interface FenceService {
*
* @param id 编号
*/
void deleteFence(String id);
void deleteFence(Long id);
/**
* 批量删除GAS电子围栏
*
* @param ids 编号
*/
void deleteFenceListByIds(List<String> ids);
void deleteFenceListByIds(List<Long> ids);
/**
* 获得GAS电子围栏
@ -51,7 +52,7 @@ public interface FenceService {
* @param id 编号
* @return GAS电子围栏
*/
FenceDO getFence(String id);
FenceDO getFence(Long id);
/**
* 获得GAS电子围栏分页
@ -61,4 +62,11 @@ public interface FenceService {
*/
PageResult<FenceDO> getFencePage(FencePageReqVO pageReqVO);
/**
* 获得GAS电子围栏列表, 用于 判断围栏是否在围栏内
*
* @param exportReqVO 查询条件
* @return GAS电子围栏列表
*/
List<Geofence> getFenceList(List<Long> idList);
}

8
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/GasTypeService.java

@ -22,7 +22,7 @@ public interface GasTypeService {
* @param createReqVO 创建信息
* @return 编号
*/
String createType(@Valid GasTypeSaveReqVO createReqVO);
Long createType(@Valid GasTypeSaveReqVO createReqVO);
/**
* 更新GAS气体
@ -36,14 +36,14 @@ public interface GasTypeService {
*
* @param id 编号
*/
void deleteType(String id);
void deleteType(Long id);
/**
* 批量删除GAS气体
*
* @param ids 编号
*/
void deleteTypeListByIds(List<String> ids);
void deleteTypeListByIds(List<Long> ids);
/**
* 获得GAS气体
@ -51,7 +51,7 @@ public interface GasTypeService {
* @param id 编号
* @return GAS气体
*/
GasTypeDO getType(String id);
GasTypeDO getType(Long id);
/**
* 获得GAS气体分页

10
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/HandAlarmService.java

@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.hand.vo.HandAlarmPageReqVO;
import cn.iocoder.yudao.module.hand.vo.HandAlarmSaveReqVO;
import jakarta.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* GAS手持探测器警报 Service 接口
@ -22,7 +21,7 @@ public interface HandAlarmService {
* @param createReqVO 创建信息
* @return 编号
*/
String createHandAlarm(@Valid HandAlarmSaveReqVO createReqVO);
Long createHandAlarm(@Valid HandAlarmSaveReqVO createReqVO);
/**
* 更新GAS手持探测器警报
@ -36,14 +35,14 @@ public interface HandAlarmService {
*
* @param id 编号
*/
void deleteHandAlarm(String id);
void deleteHandAlarm(Long id);
/**
* 批量删除GAS手持探测器警报
*
* @param ids 编号
*/
void deleteHandAlarmListByIds(List<String> ids);
void deleteHandAlarmListByIds(List<Long> ids);
/**
* 获得GAS手持探测器警报
@ -51,7 +50,7 @@ public interface HandAlarmService {
* @param id 编号
* @return GAS手持探测器警报
*/
HandAlarmDO getHandAlarm(String id);
HandAlarmDO getHandAlarm(Long id);
/**
* 获得GAS手持探测器警报分页
@ -61,4 +60,5 @@ public interface HandAlarmService {
*/
PageResult<HandAlarmDO> getHandAlarmPage(HandAlarmPageReqVO pageReqVO);
int updateById(HandAlarmDO alarm);
}

16
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/HandDetectorService.java

@ -3,8 +3,10 @@ package cn.iocoder.yudao.module.hand.service;
import java.util.*;
import cn.iocoder.yudao.module.hand.dal.HandDetectorDO;
import cn.iocoder.yudao.module.hand.vo.HandDataVo;
import cn.iocoder.yudao.module.hand.vo.HandDetectorPageReqVO;
import cn.iocoder.yudao.module.hand.vo.HandDetectorSaveReqVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -22,7 +24,7 @@ public interface HandDetectorService {
* @param createReqVO 创建信息
* @return 编号
*/
String createHandDetector(@Valid HandDetectorSaveReqVO createReqVO);
Long createHandDetector(@Valid HandDetectorSaveReqVO createReqVO);
/**
* 更新GAS手持探测器
@ -36,14 +38,14 @@ public interface HandDetectorService {
*
* @param id 编号
*/
void deleteHandDetector(String id);
void deleteHandDetector(Long id);
/**
* 批量删除GAS手持探测器
*
* @param ids 编号
*/
void deleteHandDetectorListByIds(List<String> ids);
void deleteHandDetectorListByIds(List<Long> ids);
/**
* 获得GAS手持探测器
@ -51,7 +53,7 @@ public interface HandDetectorService {
* @param id 编号
* @return GAS手持探测器
*/
HandDetectorDO getHandDetector(String id);
HandDetectorDO getHandDetector(Long id);
/**
* 获得GAS手持探测器分页
@ -61,4 +63,10 @@ public interface HandDetectorService {
*/
PageResult<HandDetectorDO> getHandDetectorPage(HandDetectorPageReqVO pageReqVO);
HandDetectorDO getBySn(String sn);
Map<Object, Object> getHandData(String tenantDeviceHashKey);
void updateRedisData(Long tenantId, String topic, HandDataVo handVo);
}

20
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/TdengineService.java

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.hand.service;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.hand.vo.HandOriginalLog;
import cn.iocoder.yudao.module.hand.vo.HandTdenginePageVO;
import cn.iocoder.yudao.module.hand.vo.TdengineDataVo;
import java.util.List;
public interface TdengineService {
void saveHandLogBatch(List<HandOriginalLog> batchList);
void saveDataLogBatch(List<TdengineDataVo> batchList);
PageResult<TdengineDataVo> getHandDataLog(HandTdenginePageVO pageReqVO);
PageResult<HandOriginalLog> getOriginalLogPage(HandTdenginePageVO pageReqVO);
}

68
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/AlarmRuleServiceImpl.java

@ -1,17 +1,27 @@
package cn.iocoder.yudao.module.hand.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.hand.dal.AlarmRuleDO;
import cn.iocoder.yudao.module.hand.mapper.AlarmRuleMapper;
import cn.iocoder.yudao.module.hand.service.AlarmRuleService;
import cn.iocoder.yudao.module.hand.util.RedisKeyUtil;
import cn.iocoder.yudao.module.hand.vo.AlarmRulePageReqVO;
import cn.iocoder.yudao.module.hand.vo.AlarmRuleSaveReqVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@ -20,6 +30,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.ALARM_RULE_NOT_EXISTS;
/**
@ -29,17 +40,21 @@ import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.ALARM_RULE_N
*/
@Service
@Validated
@Slf4j
public class AlarmRuleServiceImpl implements AlarmRuleService {
@Resource
private AlarmRuleMapper alarmRuleMapper;
@Override
public String createAlarmRule(AlarmRuleSaveReqVO createReqVO) {
public Long createAlarmRule(AlarmRuleSaveReqVO createReqVO) {
// 插入
AlarmRuleDO alarmRule = BeanUtils.toBean(createReqVO, AlarmRuleDO.class);
alarmRuleMapper.insert(alarmRule);
LoginUser loginUser = getLoginUser();
if (loginUser != null && loginUser.getTenantId() != null){
evictGasAlarmRuleCache(loginUser.getTenantId());
}
// 返回
return alarmRule.getId();
}
@ -51,37 +66,78 @@ public class AlarmRuleServiceImpl implements AlarmRuleService {
// 更新
AlarmRuleDO updateObj = BeanUtils.toBean(updateReqVO, AlarmRuleDO.class);
alarmRuleMapper.updateById(updateObj);
LoginUser loginUser = getLoginUser();
if (loginUser != null && loginUser.getTenantId() != null){
evictGasAlarmRuleCache(loginUser.getTenantId());
}
}
@Override
public void deleteAlarmRule(String id) {
public void deleteAlarmRule(Long id) {
// 校验存在
validateAlarmRuleExists(id);
// 删除
alarmRuleMapper.deleteById(id);
LoginUser loginUser = getLoginUser();
if (loginUser != null && loginUser.getTenantId() != null){
evictGasAlarmRuleCache(loginUser.getTenantId());
}
}
@Override
public void deleteAlarmRuleListByIds(List<String> ids) {
public void deleteAlarmRuleListByIds(List<Long> ids) {
// 删除
alarmRuleMapper.deleteByIds(ids);
LoginUser loginUser = getLoginUser();
if (loginUser != null && loginUser.getTenantId() != null){
evictGasAlarmRuleCache(loginUser.getTenantId());
}
}
private void validateAlarmRuleExists(String id) {
private void validateAlarmRuleExists(Long id) {
if (alarmRuleMapper.selectById(id) == null) {
throw exception(ALARM_RULE_NOT_EXISTS);
}
}
@Override
public AlarmRuleDO getAlarmRule(String id) {
public AlarmRuleDO getAlarmRule(Long id) {
return alarmRuleMapper.selectById(id);
}
@Override
@TenantIgnore
@Cacheable(cacheNames = RedisKeyUtil.ALARM_RULES_CACHE_NAME,
// 【关键修改】使用 #tenantId 来引用方法参数,确保缓存key与查询数据严格对应。
key = "'gas_rules_map:' + #tenantId")
public Map<Long, List<AlarmRuleDO>> selectCacheListMap(Long tenantId) {
// --- 这段代码只会在缓存未命中时执行 ---
log.info("气体报警规则缓存未命中,租户ID: {},执行数据库查询和分组...", tenantId);
QueryWrapper<AlarmRuleDO> ruleDOQueryWrapper = new QueryWrapper<>();
ruleDOQueryWrapper.lambda().eq(AlarmRuleDO::getTenantId, tenantId);
List<AlarmRuleDO> allRules = alarmRuleMapper.selectList(ruleDOQueryWrapper);
// 2. 按 GasTypeId 分组
return allRules.stream()
.collect(Collectors.groupingBy(AlarmRuleDO::getGasTypeId));
}
@Override
public PageResult<AlarmRuleDO> getAlarmRulePage(AlarmRulePageReqVO pageReqVO) {
return alarmRuleMapper.selectPage(pageReqVO);
}
/**
* 当规则发生变更时调用此方法来清空缓存
*/
@CacheEvict(cacheNames = RedisKeyUtil.ALARM_RULES_CACHE_NAME,
// 【关键修改】使用 #tenantId 来引用方法参数,确保缓存key与查询数据严格对应。
key = "'gas_rules_map:' + #tenantId")
@TenantIgnore
public void evictGasAlarmRuleCache(Long tenantId) {
log.info("成功清除气体报警规则缓存。");
}
}

10
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/AlarmTypeServiceImpl.java

@ -35,7 +35,7 @@ public class AlarmTypeServiceImpl implements AlarmTypeService {
private AlarmTypeMapper alarmTypeMapper;
@Override
public String createAlarmType(AlarmTypeSaveReqVO createReqVO) {
public Long createAlarmType(AlarmTypeSaveReqVO createReqVO) {
// 插入
AlarmTypeDO alarmType = BeanUtils.toBean(createReqVO, AlarmTypeDO.class);
alarmTypeMapper.insert(alarmType);
@ -54,7 +54,7 @@ public class AlarmTypeServiceImpl implements AlarmTypeService {
}
@Override
public void deleteAlarmType(String id) {
public void deleteAlarmType(Long id) {
// 校验存在
validateAlarmTypeExists(id);
// 删除
@ -62,20 +62,20 @@ public class AlarmTypeServiceImpl implements AlarmTypeService {
}
@Override
public void deleteAlarmTypeListByIds(List<String> ids) {
public void deleteAlarmTypeListByIds(List<Long> ids) {
// 删除
alarmTypeMapper.deleteByIds(ids);
}
private void validateAlarmTypeExists(String id) {
private void validateAlarmTypeExists(Long id) {
if (alarmTypeMapper.selectById(id) == null) {
throw exception(ALARM_TYPE_NOT_EXISTS);
}
}
@Override
public AlarmTypeDO getAlarmType(String id) {
public AlarmTypeDO getAlarmType(Long id) {
return alarmTypeMapper.selectById(id);
}

88
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/FactoryServiceImpl.java

@ -0,0 +1,88 @@
package cn.iocoder.yudao.module.hand.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.hand.dal.FactoryDO;
import cn.iocoder.yudao.module.hand.mapper.FactoryMapper;
import cn.iocoder.yudao.module.hand.service.FactoryService;
import cn.iocoder.yudao.module.hand.vo.FactoryPageReqVO;
import cn.iocoder.yudao.module.hand.vo.FactorySaveReqVO;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.FACTORY_NOT_EXISTS;
/**
* GAS工厂 Service 实现类
*
* @author 超级管理员
*/
@Service
@Validated
public class FactoryServiceImpl implements FactoryService {
@Resource
private FactoryMapper factoryMapper;
@Override
public Long createFactory(FactorySaveReqVO createReqVO) {
// 插入
FactoryDO factory = BeanUtils.toBean(createReqVO, FactoryDO.class);
factoryMapper.insert(factory);
// 返回
return factory.getId();
}
@Override
public void updateFactory(FactorySaveReqVO updateReqVO) {
// 校验存在
validateFactoryExists(updateReqVO.getId());
// 更新
FactoryDO updateObj = BeanUtils.toBean(updateReqVO, FactoryDO.class);
factoryMapper.updateById(updateObj);
}
@Override
public void deleteFactory(Long id) {
// 校验存在
validateFactoryExists(id);
// 删除
factoryMapper.deleteById(id);
}
@Override
public void deleteFactoryListByIds(List<Long> ids) {
// 删除
factoryMapper.deleteByIds(ids);
}
private void validateFactoryExists(Long id) {
if (factoryMapper.selectById(id) == null) {
throw exception(FACTORY_NOT_EXISTS);
}
}
@Override
public FactoryDO getFactory(Long id) {
return factoryMapper.selectById(id);
}
@Override
public PageResult<FactoryDO> getFactoryPage(FactoryPageReqVO pageReqVO) {
return factoryMapper.selectPage(pageReqVO);
}
}

16
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/FenceAlarmServiceImpl.java

@ -34,7 +34,7 @@ public class FenceAlarmServiceImpl implements FenceAlarmService {
private FenceAlarmMapper fenceAlarmMapper;
@Override
public String createFenceAlarm(FenceAlarmSaveReqVO createReqVO) {
public Long createFenceAlarm(FenceAlarmSaveReqVO createReqVO) {
// 插入
FenceAlarmDO fenceAlarm = BeanUtils.toBean(createReqVO, FenceAlarmDO.class);
fenceAlarmMapper.insert(fenceAlarm);
@ -53,7 +53,7 @@ public class FenceAlarmServiceImpl implements FenceAlarmService {
}
@Override
public void deleteFenceAlarm(String id) {
public void deleteFenceAlarm(Long id) {
// 校验存在
validateFenceAlarmExists(id);
// 删除
@ -61,20 +61,20 @@ public class FenceAlarmServiceImpl implements FenceAlarmService {
}
@Override
public void deleteFenceAlarmListByIds(List<String> ids) {
public void deleteFenceAlarmListByIds(List<Long> ids) {
// 删除
fenceAlarmMapper.deleteByIds(ids);
}
private void validateFenceAlarmExists(String id) {
private void validateFenceAlarmExists(Long id) {
if (fenceAlarmMapper.selectById(id) == null) {
throw exception(FENCE_ALARM_NOT_EXISTS);
}
}
@Override
public FenceAlarmDO getFenceAlarm(String id) {
public FenceAlarmDO getFenceAlarm(Long id) {
return fenceAlarmMapper.selectById(id);
}
@ -83,4 +83,10 @@ public class FenceAlarmServiceImpl implements FenceAlarmService {
return fenceAlarmMapper.selectPage(pageReqVO);
}
@Override
public void update(FenceAlarmDO updateReqVO) {
fenceAlarmMapper.updateById(updateReqVO);
}
}

57
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/FenceServiceImpl.java

@ -1,17 +1,28 @@
package cn.iocoder.yudao.module.hand.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.hand.dal.FenceDO;
import cn.iocoder.yudao.module.hand.dal.HandDetectorDO;
import cn.iocoder.yudao.module.hand.enums.FenceStatusType;
import cn.iocoder.yudao.module.hand.mapper.FenceMapper;
import cn.iocoder.yudao.module.hand.mapper.HandDetectorMapper;
import cn.iocoder.yudao.module.hand.service.FenceService;
import cn.iocoder.yudao.module.hand.util.GeofenceUtils;
import cn.iocoder.yudao.module.hand.util.RedisUtil;
import cn.iocoder.yudao.module.hand.vo.FencePageReqVO;
import cn.iocoder.yudao.module.hand.vo.FenceSaveReqVO;
import cn.iocoder.yudao.module.hand.vo.Geofence;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -21,6 +32,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.FENCE_EXISTS_HAND_DETECTOR;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.FENCE_NOT_EXISTS;
/**
@ -35,8 +47,13 @@ public class FenceServiceImpl implements FenceService {
@Resource
private FenceMapper fenceMapper;
@Resource
private HandDetectorMapper handDetectorMapper;
@Resource
private RedisUtil redisUtil;
@Override
public String createFence(FenceSaveReqVO createReqVO) {
public Long createFence(FenceSaveReqVO createReqVO) {
// 插入
FenceDO fence = BeanUtils.toBean(createReqVO, FenceDO.class);
fenceMapper.insert(fence);
@ -55,28 +72,36 @@ public class FenceServiceImpl implements FenceService {
}
@Override
public void deleteFence(String id) {
public void deleteFence(Long id) {
// 校验存在
validateFenceExists(id);
QueryWrapper<HandDetectorDO> objectQueryWrapper = new QueryWrapper<>();
objectQueryWrapper.eq("fence_id",id);
List<HandDetectorDO> list = handDetectorMapper.selectList(objectQueryWrapper);
if (CollectionUtils.isNotEmpty(list)){
throw exception(FENCE_EXISTS_HAND_DETECTOR);
}
// 删除
fenceMapper.deleteById(id);
}
@Override
public void deleteFenceListByIds(List<String> ids) {
public void deleteFenceListByIds(List<Long> ids) {
// 删除
fenceMapper.deleteByIds(ids);
}
private void validateFenceExists(String id) {
private void validateFenceExists(Long id) {
if (fenceMapper.selectById(id) == null) {
throw exception(FENCE_NOT_EXISTS);
}
}
@Override
public FenceDO getFence(String id) {
public FenceDO getFence(Long id) {
return fenceMapper.selectById(id);
}
@ -85,4 +110,26 @@ public class FenceServiceImpl implements FenceService {
return fenceMapper.selectPage(pageReqVO);
}
@Override
@TenantIgnore
public List<Geofence> getFenceList(List<Long> idList) {
QueryWrapper<FenceDO> queryWrapper = new QueryWrapper<>();
queryWrapper.in("id",idList);
queryWrapper.eq("status", FenceStatusType.DISABLED.getType());
List<FenceDO> fenceDOS = fenceMapper.selectList(queryWrapper);
List<Geofence> allGeofences = new ArrayList<>();
if (CollectionUtils.isNotEmpty(fenceDOS)){
for (FenceDO fenceDO : fenceDOS) {
// 关键:调用 parseFences 方法,它会处理JSON解析和Geofence对象的创建
// 它返回的是一个 List<Geofence>,因为一个 fenceDO 可能包含多个多边形
List<Geofence> fencesFromCurrentDO = GeofenceUtils.parseFences(fenceDO.getFenceRange());
// 将从当前 fenceDO 解析出的所有围栏,添加到总列表中
allGeofences.addAll(fencesFromCurrentDO);
}
}
return allGeofences;
}
}

13
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/GasTypeServiceImpl.java

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.hand.dal.GasTypeDO;
import cn.iocoder.yudao.module.hand.mapper.GasTypeMapper;
import cn.iocoder.yudao.module.hand.service.GasTypeService;
import cn.iocoder.yudao.module.hand.util.RedisKeyUtil;
import cn.iocoder.yudao.module.hand.vo.GasTypePageReqVO;
import cn.iocoder.yudao.module.hand.vo.GasTypeSaveReqVO;
import org.springframework.stereotype.Service;
@ -17,6 +18,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import javax.cache.annotation.CachePut;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
@ -35,7 +38,7 @@ public class GasTypeServiceImpl implements GasTypeService {
private GasTypeMapper typeMapper;
@Override
public String createType(GasTypeSaveReqVO createReqVO) {
public Long createType(GasTypeSaveReqVO createReqVO) {
// 插入
GasTypeDO type = BeanUtils.toBean(createReqVO, GasTypeDO.class);
typeMapper.insert(type);
@ -54,7 +57,7 @@ public class GasTypeServiceImpl implements GasTypeService {
}
@Override
public void deleteType(String id) {
public void deleteType(Long id) {
// 校验存在
validateTypeExists(id);
// 删除
@ -62,20 +65,20 @@ public class GasTypeServiceImpl implements GasTypeService {
}
@Override
public void deleteTypeListByIds(List<String> ids) {
public void deleteTypeListByIds(List<Long> ids) {
// 删除
typeMapper.deleteByIds(ids);
}
private void validateTypeExists(String id) {
private void validateTypeExists(Long id) {
if (typeMapper.selectById(id) == null) {
throw exception(TYPE_NOT_EXISTS);
}
}
@Override
public GasTypeDO getType(String id) {
public GasTypeDO getType(Long id) {
return typeMapper.selectById(id);
}

22
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/HandAlarmServiceImpl.java

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.hand.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.hand.dal.HandAlarmDO;
import cn.iocoder.yudao.module.hand.mapper.HandAlarmMapper;
import cn.iocoder.yudao.module.hand.service.HandAlarmService;
@ -12,14 +11,13 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.HAND_ALARM_NOT_EXISTS;
/**
@ -35,7 +33,7 @@ public class HandAlarmServiceImpl implements HandAlarmService {
private HandAlarmMapper handAlarmMapper;
@Override
public String createHandAlarm(HandAlarmSaveReqVO createReqVO) {
public Long createHandAlarm(HandAlarmSaveReqVO createReqVO) {
// 插入
HandAlarmDO handAlarm = BeanUtils.toBean(createReqVO, HandAlarmDO.class);
handAlarmMapper.insert(handAlarm);
@ -54,7 +52,7 @@ public class HandAlarmServiceImpl implements HandAlarmService {
}
@Override
public void deleteHandAlarm(String id) {
public void deleteHandAlarm(Long id) {
// 校验存在
validateHandAlarmExists(id);
// 删除
@ -62,20 +60,20 @@ public class HandAlarmServiceImpl implements HandAlarmService {
}
@Override
public void deleteHandAlarmListByIds(List<String> ids) {
public void deleteHandAlarmListByIds(List<Long> ids) {
// 删除
handAlarmMapper.deleteByIds(ids);
}
}
private void validateHandAlarmExists(String id) {
private void validateHandAlarmExists(Long id) {
if (handAlarmMapper.selectById(id) == null) {
throw exception(HAND_ALARM_NOT_EXISTS);
}
}
@Override
public HandAlarmDO getHandAlarm(String id) {
public HandAlarmDO getHandAlarm(Long id) {
return handAlarmMapper.selectById(id);
}
@ -84,4 +82,10 @@ public class HandAlarmServiceImpl implements HandAlarmService {
return handAlarmMapper.selectPage(pageReqVO);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int updateById(HandAlarmDO alarm) {
return handAlarmMapper.updateById(alarm);
}
}

184
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/HandDetectorServiceImpl.java

@ -1,22 +1,43 @@
package cn.iocoder.yudao.module.hand.service.impl;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.hand.dal.HandDetectorDO;
import cn.iocoder.yudao.module.hand.mapper.HandDetectorMapper;
import cn.iocoder.yudao.module.hand.service.HandDetectorService;
import cn.iocoder.yudao.module.hand.util.RedisKeyUtil;
import cn.iocoder.yudao.module.hand.util.RedisUtil;
import cn.iocoder.yudao.module.hand.vo.HandDataVo;
import cn.iocoder.yudao.module.hand.vo.HandDetectorPageReqVO;
import cn.iocoder.yudao.module.hand.vo.HandDetectorSaveReqVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.time.Duration;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.HAND_DETECTOR_NOT_EXISTS;
import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.HAND_DETECTOR_SN_EXISTS;
/**
* GAS手持探测器 Service 实现类
@ -25,53 +46,179 @@ import static cn.iocoder.yudao.module.hand.enums.ErrorCodeConstants.HAND_DETECTO
*/
@Service
@Validated
@Slf4j
public class HandDetectorServiceImpl implements HandDetectorService {
@Resource
private HandDetectorMapper handDetectorMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private RedisUtil redisUtil;
// 定义批量处理的大小,防止一次性加载过多数据到内存中
private static final int BATCH_SIZE = 1000;
@PostConstruct
@TenantIgnore
public void initDeviceTenantMappingCache() {
log.info("[缓存预热] 开始初始化 [设备SN -> 租户ID] 映射缓存 (流式查询模式)...");
long totalCount = 0;
try {
String redisKey = RedisKeyUtil.getDeviceTenantMappingKey();
redisUtil.del(redisKey);
log.info("[缓存预热] 已清空旧的映射缓存,Key: {}", redisKey);
// 【核心改造】使用 try-with-resources 确保 SqlSession 和 Cursor 被自动关闭
try (SqlSession sqlSession = sqlSessionFactory.openSession();
// 【关键修复】从手动创建的 sqlSession 中获取 Mapper 实例,而不是使用注入的那个
Cursor<HandDetectorDO> cursor = sqlSession.getMapper(HandDetectorMapper.class).selectCursor(new QueryWrapper<>())) {
Map<Object, Object> batchMap = new HashMap<>(BATCH_SIZE);
// 像迭代器一样遍历 Cursor,每次只从数据库连接中取少量数据
for (HandDetectorDO device : cursor) {
if (device.getSn() != null && device.getTenantId() != null) {
batchMap.put(device.getSn(), device.getTenantId().toString());
}
totalCount++;
// 达到批次大小,执行写入
if (batchMap.size() >= BATCH_SIZE) {
redisUtil.hmset(redisKey, batchMap);
log.info("[缓存预热] 成功写入 {} 条映射数据到 Redis...", batchMap.size());
batchMap.clear();
}
}
// 处理最后一个不足 BATCH_SIZE 的批次
if (!batchMap.isEmpty()) {
redisUtil.hmset(redisKey, batchMap);
log.info("[缓存预热] 成功写入最后 {} 条映射数据到 Redis...", batchMap.size());
}
} // try-with-resources 会在此处自动关闭 cursor 和 sqlSession
log.info("[缓存预热] [设备SN -> 租户ID] 映射缓存初始化完成,共处理 {} 条数据。", totalCount);
} catch (Exception e) {
log.error("[缓存预热] 初始化映射缓存时发生严重错误!", e);
}
}
@Override
public String createHandDetector(HandDetectorSaveReqVO createReqVO) {
@Transactional(rollbackFor = Exception.class)
public Long createHandDetector(HandDetectorSaveReqVO createReqVO) {
LoginUser loginUser = getLoginUser();
if (loginUser == null) {
return null;
}
// 校验SN是否已存在(排除自身)
validateSnUnique(createReqVO.getSn(), null);
// 插入
HandDetectorDO handDetector = BeanUtils.toBean(createReqVO, HandDetectorDO.class);
handDetectorMapper.insert(handDetector);
redisUtil.hset(
RedisKeyUtil.getDeviceTenantMappingKey(), // 获取全局映射的Key
createReqVO.getSn(), // 设备的SN作为field
loginUser.getTenantId() // 租户ID作为value
);
// 返回
return handDetector.getId();
}
private void validateSnUnique(String sn, Long excludeId) {
LambdaQueryWrapper<HandDetectorDO> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HandDetectorDO::getSn, sn);
if (excludeId != null) {
wrapper.ne(HandDetectorDO::getId, excludeId);
}
Long count = handDetectorMapper.selectCount(wrapper);
if (count > 0) {
throw exception(HAND_DETECTOR_SN_EXISTS);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateHandDetector(HandDetectorSaveReqVO updateReqVO) {
LoginUser loginUser = getLoginUser();
if (loginUser == null) {
return;
}
// 校验存在
validateHandDetectorExists(updateReqVO.getId());
HandDetectorDO handDetectorDO = validateHandDetectorExists(updateReqVO.getId());
// 获取旧的SN
String oldSn = handDetectorDO.getSn();
String newSn = updateReqVO.getSn();
// 如果SN有变化,需要校验唯一性并清理旧缓存
boolean snChanged = !oldSn.equals(newSn);
if (snChanged) {
// 校验SN是否已存在(排除自身)
validateSnUnique(newSn, updateReqVO.getId());
// 1. 从全局设备与租户的映射中删除旧的SN
redisUtil.hdel(RedisKeyUtil.getDeviceTenantMappingKey(), oldSn);
// 2. 从租户自己的设备信息缓存中删除旧的SN
String tenantDeviceKey = RedisKeyUtil.getTenantDeviceHashKey(loginUser.getTenantId());
redisUtil.hdel(tenantDeviceKey, oldSn);
}
// 更新
HandDetectorDO updateObj = BeanUtils.toBean(updateReqVO, HandDetectorDO.class);
handDetectorMapper.updateById(updateObj);
redisUtil.hset(
RedisKeyUtil.getDeviceTenantMappingKey(), // 获取全局映射的Key
updateReqVO.getSn(), // 设备的SN作为field
loginUser.getTenantId() // 租户ID作为value
);
// 2. 更新租户自己的设备信息缓存
String tenantDeviceKey = RedisKeyUtil.getTenantDeviceHashKey(loginUser.getTenantId());
redisUtil.hset(tenantDeviceKey, updateReqVO.getSn(), updateObj);
}
@Override
public void deleteHandDetector(String id) {
public void deleteHandDetector(Long id) {
LoginUser loginUser = getLoginUser();
if (null == loginUser) {
return;
}
// 校验存在
validateHandDetectorExists(id);
// 删除
handDetectorMapper.deleteById(id);
String deviceSn = handDetectorMapper.selectOne(HandDetectorDO::getId, id).getSn();
// 2. 从全局映射缓存中删除
redisUtil.hdel(RedisKeyUtil.getDeviceTenantMappingKey(), deviceSn);
// 3. 从租户自己的设备信息缓存中删除
String tenantDeviceKey = RedisKeyUtil.getTenantDeviceHashKey(loginUser.getTenantId());
redisUtil.hdel(tenantDeviceKey, deviceSn);
}
@Override
public void deleteHandDetectorListByIds(List<String> ids) {
public void deleteHandDetectorListByIds(List<Long> ids) {
// 删除
handDetectorMapper.deleteByIds(ids);
}
}
private HandDetectorDO validateHandDetectorExists(Long id) {
HandDetectorDO handDetectorDO = handDetectorMapper.selectById(id);
private void validateHandDetectorExists(String id) {
if (handDetectorMapper.selectById(id) == null) {
if (handDetectorDO == null) {
throw exception(HAND_DETECTOR_NOT_EXISTS);
}
return handDetectorDO;
}
@Override
public HandDetectorDO getHandDetector(String id) {
public HandDetectorDO getHandDetector(Long id) {
return handDetectorMapper.selectById(id);
}
@ -80,4 +227,25 @@ public class HandDetectorServiceImpl implements HandDetectorService {
return handDetectorMapper.selectPage(pageReqVO);
}
@Override
@TenantIgnore
public HandDetectorDO getBySn(String sn) {
return handDetectorMapper.selectOne(HandDetectorDO::getSn, sn);
}
@Override
@TenantIgnore
public Map<Object, Object> getHandData(String tenantDeviceHashKey) {
return redisUtil.hmget(tenantDeviceHashKey);
}
@Override
@TenantIgnore
public void updateRedisData(Long tenantId, String topic, HandDataVo handVo) {
redisUtil.hset(RedisKeyUtil.getTenantDeviceHashKey(tenantId), topic, handVo);
}
}

100
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/service/impl/TdengineServiceImpl.java

@ -0,0 +1,100 @@
package cn.iocoder.yudao.module.hand.service.impl;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.hand.mapper.TdengineMapper;
import cn.iocoder.yudao.module.hand.service.TdengineService;
import cn.iocoder.yudao.module.hand.vo.HandOriginalLog;
import cn.iocoder.yudao.module.hand.vo.HandTdenginePageVO;
import cn.iocoder.yudao.module.hand.vo.TdengineDataVo;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Validated
@DS("tdengine")
public class TdengineServiceImpl implements TdengineService {
private static final Logger log = LoggerFactory.getLogger(TdengineServiceImpl.class);
@Resource
private TdengineMapper tdengineMapper;
@Override
public void saveHandLogBatch(List<HandOriginalLog> batchList) {
if (batchList.isEmpty()) {
return;
}
// 1. 按设备SN分组
Map<String, List<HandOriginalLog>> groupedBySn = batchList.stream()
.collect(Collectors.groupingBy(HandOriginalLog::getSn));
// 遍历Map,每个Entry对应一个子表
for (Map.Entry<String, List<HandOriginalLog>> entry : groupedBySn.entrySet()) {
String sn = entry.getKey();
List<HandOriginalLog> logs = entry.getValue();
Long tenantId = logs.get(0).getTenantId();
tdengineMapper.insertHandLogBatch(sn, tenantId, logs);
}
}
@Override
public void saveDataLogBatch(List<TdengineDataVo> batchList) {
if (batchList.isEmpty()) {
return;
}
// 1. 按设备SN分组
Map<String, List<TdengineDataVo>> groupedBySn = batchList.stream()
.collect(Collectors.groupingBy(TdengineDataVo::getSn));
// 遍历Map,每个Entry对应一个子表
for (Map.Entry<String, List<TdengineDataVo>> entry : groupedBySn.entrySet()) {
String sn = entry.getKey();
List<TdengineDataVo> logs = entry.getValue();
Long tenantId = logs.get(0).getTenantId();
tdengineMapper.saveDataLogBatch(sn, tenantId, logs);
}
}
@Override
public PageResult<TdengineDataVo> getHandDataLog(HandTdenginePageVO pageReqVO) {
IPage<TdengineDataVo> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
IPage<TdengineDataVo> resultPage = tdengineMapper.selectPage(page, pageReqVO);
List<TdengineDataVo> doList = resultPage.getRecords();
if (doList == null || doList.isEmpty()) {
return PageResult.empty(resultPage.getTotal());
}
return new PageResult<>(doList, resultPage.getTotal());
}
@Override
public PageResult<HandOriginalLog> getOriginalLogPage(HandTdenginePageVO pageReqVO) {
IPage<HandOriginalLog> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
IPage<HandOriginalLog> resultPage = tdengineMapper.selectOriginalPage(page, pageReqVO);
List<HandOriginalLog> doList = resultPage.getRecords();
if (doList == null || doList.isEmpty()) {
return PageResult.empty(resultPage.getTotal());
}
return new PageResult<>(doList, resultPage.getTotal());
}
}

76
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/BatteryConverterUtils.java

@ -0,0 +1,76 @@
package cn.iocoder.yudao.module.hand.util;
public class BatteryConverterUtils {
// 定义电压-电量映射点 (电压单位: 毫伏 mV)
// 这些值是基于常见的单节锂电池放电曲线估算的
// [电压, 电量百分比]
private static final int[][] VOLTAGE_MAP = {
{4200, 100}, // 充满电
{4150, 95},
{4100, 90},
{4050, 85},
{4000, 80},
{3950, 75},
{3900, 70},
{3850, 65},
{3800, 60},
{3750, 50},
{3700, 40},
{3650, 30},
{3600, 20},
{3500, 10},
{3400, 5},
{3300, 0} // 电量耗尽
};
/**
* 将电池电压 (mV) 转换为电量百分比 (%)
*
* @param millivolts 当前电池电压单位为毫伏
* @return 估算的电量百分比 (0-100)
*/
public static int getBatteryPercentage(int millivolts) {
// 处理边界情况
if (millivolts >= VOLTAGE_MAP[0][0]) {
return 100;
}
if (millivolts <= VOLTAGE_MAP[VOLTAGE_MAP.length - 1][0]) {
return 0;
}
// 查找电压所在的区间
for (int i = 0; i < VOLTAGE_MAP.length - 1; i++) {
int upperVoltage = VOLTAGE_MAP[i][0];
int upperPercentage = VOLTAGE_MAP[i][1];
int lowerVoltage = VOLTAGE_MAP[i + 1][0];
int lowerPercentage = VOLTAGE_MAP[i + 1][1];
if (millivolts <= upperVoltage && millivolts > lowerVoltage) {
// 在找到的区间内进行线性插值计算
// 公式: y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)
// 这里: x=millivolts, x1=lowerVoltage, x2=upperVoltage
// y=percentage, y1=lowerPercentage, y2=upperPercentage
double percentage = lowerPercentage +
((double)(millivolts - lowerVoltage) * (upperPercentage - lowerPercentage)) /
(double)(upperVoltage - lowerVoltage);
return (int) Math.round(percentage);
}
}
// 如果出现意外情况,返回0
return 0;
}
public static void main(String[] args) {
int batteryVoltage = 4126; // 输入您设备的值
int percentage = getBatteryPercentage(batteryVoltage);
System.out.println("电压 " + batteryVoltage + "mV 约等于 " + percentage + "% 的电量。");
// 其他测试用例
System.out.println("电压 4200mV 约等于 " + getBatteryPercentage(4200) + "% 的电量。");
System.out.println("电压 3750mV 约等于 " + getBatteryPercentage(3750) + "% 的电量。");
System.out.println("电压 3300mV 约等于 " + getBatteryPercentage(3300) + "% 的电量。");
System.out.println("电压 3980mV 约等于 " + getBatteryPercentage(3980) + "% 的电量。");
}
}

188
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/CoordinateTransferUtils.java

@ -0,0 +1,188 @@
package cn.iocoder.yudao.module.hand.util;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class CoordinateTransferUtils {
/**
* 国内坐标边界
*/
private static final double MIN_LON = 72.004D;
private static final double MAX_LON = 137.8347D;
private static final double MIN_LAT = 0.8293D;
private static final double MAX_LAT = 55.8271D;
/**
* PI 圆周率
*/
private static final double PI = 3.14159265358979324D;
/**
* A WGS 长轴半径
*/
private static final double A = 6378245.0D;
/**
* EE WGS 偏心率的平方
*/
private static final double EE = 0.00669342162296594323D;
/**
* WGS84转换GCJ02核心方法
*
* @param fromLon 转换前的经度
* @param fromLat 转换前的纬度
* @return 转换后的经纬度map对象
*/
public static Map<String, Double> wgs84ToGcj02(double fromLon, double fromLat) {
HashMap<String, Double> transformRes = new HashMap<>(2);
// 国外坐标不用进行加密
if (outOfChina(fromLon, fromLat)) {
transformRes.put("lon", fromLon);
transformRes.put("lat", fromLat);
return transformRes;
}
// 计算转换后的经纬度坐标
double dLat = transformLat(fromLon - 105.0, fromLat - 35.0);
double dLon = transformLon(fromLon - 105.0, fromLat - 35.0);
double radLat = fromLat / 180.0 * PI;
double magic = Math.sin(radLat);
magic = 1 - EE * magic * magic;
double sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
double mgLat = fromLat + dLat;
double mgLon = fromLon + dLon;
transformRes.put("lon", new BigDecimal(mgLon + "", new MathContext(9, RoundingMode.HALF_UP)).doubleValue());
transformRes.put("lat", new BigDecimal(mgLat + "", new MathContext(9, RoundingMode.HALF_UP)).doubleValue());
return transformRes;
}
/**
* GCJ02转换WGS84
*
* @param lon 转换前的经度
* @param lat 转换后的纬度
* @return 转换后的经纬度map对象
*/
public static Map<String, Double> gcj02ToWgs84(double lon, double lat) {
Map<String, Double> transformRes = new HashMap<>(2);
double longitude = lon * 2 - wgs84ToGcj02(lon, lat).get("lon");
double latitude = lat * 2 - wgs84ToGcj02(lon, lat).get("lat");
transformRes.put("lon", longitude);
transformRes.put("lat", latitude);
return transformRes;
}
/**
* GCJ02转换BD09
*
* @param gcjLat GCL纬度坐标
* @param gcjLng GCL经度坐标
*/
public static Map<String, Double> Gcj02ToBd09(double gcjLat, double gcjLng) {
Map<String, Double> transformRes = new HashMap<>(2);
double z = Math.sqrt(gcjLng * gcjLng + gcjLat * gcjLat) + 0.00002 * Math.sin(gcjLat * PI);
double theta = Math.atan2(gcjLat, gcjLng) + 0.000003 * Math.cos(gcjLng * PI);
transformRes.put("lon", z * Math.cos(theta) + 0.0065);
transformRes.put("lat", z * Math.sin(theta) + 0.006);
return transformRes;
}
/**
* BD09转换GCJ02
*
* @param bdLat 百度纬度坐标
* @param bdLng 百度经度坐标
*/
public static Map<String, Double> bd09ToGcj02(double bdLat, double bdLng) {
Map<String, Double> transformRes = new HashMap<>(2);
double x = bdLng - 0.0065, y = bdLat - 0.006;
double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * PI);
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * PI);
transformRes.put("lon", z * Math.cos(theta));
transformRes.put("lat", z * Math.sin(theta));
return transformRes;
}
/**
* WGS84转换GCJ02优化处理转换前经纬度坐标为null问题
*
* @param fromLon 转换前的经度
* @param fromLat 转换前的纬度
* @param toLon 转换后的经度
* @param toLat 转换后的纬度
*/
private static void wgs84ToGcj02(Supplier<BigDecimal> fromLon, Supplier<BigDecimal> fromLat, Consumer<BigDecimal> toLon, Consumer<BigDecimal> toLat) {
wgs84ToGcj02(Optional.ofNullable(fromLon.get()).orElse(BigDecimal.ZERO), Optional.ofNullable(fromLat.get()).orElse(BigDecimal.ZERO), toLon, toLat);
}
/**
* WGS84转换GCJ02优化处理转换后经纬度坐标
*
* @param fromLon 转换前的经度
* @param fromLat 转换前的纬度
* @param toLon 转换后的经度
* @param toLat 转换后的纬度
*/
private static void wgs84ToGcj02(BigDecimal fromLon, BigDecimal fromLat, Consumer<BigDecimal> toLon, Consumer<BigDecimal> toLat) {
final Map<String, Double> transformRes = wgs84ToGcj02(fromLon.doubleValue(), fromLat.doubleValue());
toLon.accept(new BigDecimal(transformRes.get("lon") + ""));
toLat.accept(new BigDecimal(transformRes.get("lat") + ""));
}
/**
* 坐标是否在国外
*
* @param lon 经度
* @param lat 纬度
* @return true 国外坐标 false 国内坐标
*/
private static boolean outOfChina(double lon, double lat) {
if (lon < MIN_LON || lon > MAX_LON) {
return true;
}
return lat < MIN_LAT || lat > MAX_LAT;
}
/**
* 转换经度坐标
*
* @param x 偏移后的经度
* @param y 偏移后的纬度
* @return double 转换经度坐标
*/
private static double transformLat(double x, double y) {
double transform = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
transform += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
transform += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
transform += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
return transform;
}
/**
* 转换纬度坐标
*
* @param x 偏移后的经度
* @param y 偏移后的纬度
* @return double 转换纬度坐标
*/
private static double transformLon(double x, double y) {
double transform = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
transform += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
transform += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
transform += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
return transform;
}
}

284
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/GeofenceUtils.java

@ -0,0 +1,284 @@
package cn.iocoder.yudao.module.hand.util;
import cn.iocoder.yudao.module.hand.enums.FenceType;
import cn.iocoder.yudao.module.hand.vo.FencePointVo;
import cn.iocoder.yudao.module.hand.vo.Geofence;
import cn.iocoder.yudao.module.hand.vo.HandDataVo;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 高性能地理围栏计算工具类 (Optimized Geofence Calculation Utility)
*
* <p>核心优化:</p>
* <ol>
* <li><b>引入 Geofence 对象:</b> 封装了多边形顶点及其预计算的包围盒(Bounding Box)</li>
* <li><b>包围盒快速排斥:</b> 在进行昂贵的精确计算前先进行廉价的矩形范围判断能过滤掉绝大多数不相关的围栏</li>
* <li><b>距离计算剪枝 (Pruning):</b> 在计算最短距离时利用点到包围盒的距离提前跳过那些不可能存在最短距离的围栏</li>
* </ol>
*
* <p>使用流程:</p>
* <pre>{@code
* // 1. 从JSON或其他数据源创建Geofence列表(这个过程会自动计算包围盒)
* List<GeofenceUtils.Geofence> geofences = GeofenceUtils.parseFences(fenceDO.getFenceRange());
*
* // 2. 使用优化后的方法进行高效计算
* boolean isInside = GeofenceUtils.isInsideAnyFence(longitude, latitude, geofences);
* double distance = GeofenceUtils.calculateDistanceToFences(longitude, latitude, geofences);
* }</pre>
*/
@Slf4j
public final class GeofenceUtils {
private static final double METERS_PER_DEGREE_LATITUDE = 111132.954;
private static final Gson GSON_INSTANCE = new Gson();
// 私有构造函数,防止实例化工具类
private GeofenceUtils() {
}
/**
* 从JSON字符串解析并创建Geofence对象列表
* 这是推荐的初始化围栏数据的方式
*
* @param fenceRangeJson 符合`double[][][]`格式的JSON字符串
* @return Geofence对象列表如果解析失败或无有效多边形则返回空列表
*/
public static List<Geofence> parseFences(String fenceRangeJson) {
if (fenceRangeJson == null || fenceRangeJson.trim().isEmpty()) {
return Collections.emptyList();
}
try {
List<Geofence> geofences = new ArrayList<>();
double[][][] coordinates = GSON_INSTANCE.fromJson(fenceRangeJson, double[][][].class);
if (coordinates == null) return Collections.emptyList();
for (double[][] polygonCoordinates : coordinates) {
List<FencePointVo> polygon = new ArrayList<>();
for (double[] coordinate : polygonCoordinates) {
polygon.add(new FencePointVo(coordinate[0], coordinate[1]));
}
// 确保多边形有效才创建Geofence对象
if (polygon.size() >= 3) {
geofences.add(new Geofence(polygon));
}
}
return geofences;
} catch (JsonSyntaxException e) {
// 在实际项目中,这里应该记录日志
log.error("解析围栏JSON失败{} ", e.getMessage());
return Collections.emptyList();
}
}
/**
* 检查点是否在任何一个电子围栏内部高性能版
*
* @param x 点的经度
* @param y 点的纬度
* @param geofences Geofence对象列表
* @return 如果点在任何一个围栏内返回 true
*/
public static boolean isInsideAnyFence(double x, double y, List<Geofence> geofences) {
if (geofences == null || geofences.isEmpty()) {
return false;
}
for (Geofence fence : geofences) {
// 第一步:快速包围盒排斥。如果点不在包围盒内,则绝不可能在多边形内。
if (fence.isPointInBoundingBox(x, y)) {
// 第二步:通过包围盒测试后,再进行精确的多边形判断。
if (isPointInsidePolygon(x, y, fence.getVertices())) {
return true;
}
}
}
return false;
}
/**
* 计算点到一组围栏边界的最短距离高性能版
*
* @param x 点的经度
* @param y 点的纬度
* @param geofences Geofence对象列表
* @return 点到所有围栏边界的最短距离
*/
public static double calculateDistanceToFences(double x, double y, List<Geofence> geofences) {
if (geofences == null || geofences.isEmpty()) {
return Double.POSITIVE_INFINITY;
}
// 预先计算一次转换因子
double metersPerDegreeLongitude = METERS_PER_DEGREE_LATITUDE * Math.cos(Math.toRadians(y));
double minDistance = Double.MAX_VALUE;
// 优化:先检查是否在内部,如果在则直接返回0
if (isInsideAnyFence(x, y, geofences)) {
return 0.0;
}
for (Geofence fence : geofences) {
// *** 核心优化:剪枝 (Pruning) ***
// 计算点到该围栏包围盒的距离。
double distToBox = pointToBoundingBoxDistanceInMeters(x, y, fence, metersPerDegreeLongitude);
// 如果点到包围盒的距离已经比当前找到的最小距离还要大,
// 那么这个围栏内的任何一条边都不可能提供更短的距离,直接跳过。
if (distToBox >= minDistance) {
continue;
}
// 通过剪枝测试后,再对这个围栏的每条边进行精确计算
List<FencePointVo> polygon = fence.getVertices();
for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) {
FencePointVo p1 = polygon.get(i);
FencePointVo p2 = polygon.get(j);
double distance = pointToLineSegmentDistanceInMeters(x, y, p1, p2, metersPerDegreeLongitude);
minDistance = Math.min(minDistance, distance);
}
}
return minDistance;
}
/**
* 核心判断逻辑点是否在单个多边形内部射线法
*/
private static boolean isPointInsidePolygon(double x, double y, List<FencePointVo> polygon) {
if (isPointOnPolygonBoundary(x, y, polygon)) {
return true;
}
int intersectCount = 0;
for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) {
FencePointVo p1 = polygon.get(i);
FencePointVo p2 = polygon.get(j);
if ((p1.y > y) != (p2.y > y)) {
double xIntersection = (p2.x - p1.x) * (y - p1.y) / (p2.y - p1.y) + p1.x;
if (x < xIntersection) {
intersectCount++;
}
}
}
return (intersectCount % 2) == 1;
}
/**
* 判断点是否在多边形的边界上
*/
private static boolean isPointOnPolygonBoundary(double x, double y, List<FencePointVo> polygon) {
for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) {
FencePointVo p1 = polygon.get(i);
FencePointVo p2 = polygon.get(j);
double crossProduct = (y - p1.y) * (p2.x - p1.x) - (x - p1.x) * (p2.y - p1.y);
if (Math.abs(crossProduct) < 1E-9) { // 容忍浮点误差
if (Math.min(p1.x, p2.x) <= x && x <= Math.max(p1.x, p2.x) &&
Math.min(p1.y, p2.y) <= y && y <= Math.max(p1.y, p2.y)) {
return true;
}
}
}
return false;
}
/**
* 计算点到线段的最短距离
*/
private static double pointToLineSegmentDistanceInMeters(double px, double py, FencePointVo p1, FencePointVo p2, double metersPerDegreeLongitude) {
double p2_m_x = (p2.x - p1.x) * metersPerDegreeLongitude;
double p2_m_y = (p2.y - p1.y) * METERS_PER_DEGREE_LATITUDE;
double p_m_x = (px - p1.x) * metersPerDegreeLongitude;
double p_m_y = (py - p1.y) * METERS_PER_DEGREE_LATITUDE;
double lineLenSq = p2_m_x * p2_m_x + p2_m_y * p2_m_y;
if (lineLenSq == 0) {
return Math.sqrt(p_m_x * p_m_x + p_m_y * p_m_y);
}
double t = Math.max(0, Math.min(1, ((p_m_x * p2_m_x) + (p_m_y * p_m_y)) / lineLenSq));
double nearestX = t * p2_m_x;
double nearestY = t * p2_m_y;
double dx = p_m_x - nearestX;
double dy = p_m_y - nearestY;
return Math.sqrt(dx * dx + dy * dy);
}
/**
* 计算点到包围盒的最短距离用于剪枝
*/
private static double pointToBoundingBoxDistanceInMeters(double px, double py, Geofence fence, double metersPerDegreeLongitude) {
double dx = 0.0, dy = 0.0;
if (px < fence.getMaxX()) dx = fence.getMaxX() - px;
else if (px > fence.getMaxX()) dx = px - fence.getMaxX();
if (py < fence.getMinY()) dy = fence.getMinY() - py;
else if (py > fence.getMinY()) dy = py - fence.getMinY();
// 将经纬度差转换为米
double dx_meters = dx * metersPerDegreeLongitude;
double dy_meters = dy * METERS_PER_DEGREE_LATITUDE;
return Math.sqrt(dx_meters * dx_meters + dy_meters * dy_meters);
}
/**
* 计算一个点到一组围栏最近边界的物理距离单位
*
* <p><b> calculateDistanceToFences 的关键区别:</b></p>
* <p>此方法 <b>总是</b> 会计算并返回点到最近边界的实际最短距离
* <b>无论这个点是在围栏的内部还是外部</b></p>
*
* <p>例如如果点在围栏内部它会返回一个大于0的值表示该点距离逃出围栏的最近距离</p>
*
* @param x 点的经度
* @param y 点的纬度
* @param geofences Geofence对象列表
* @return 点到所有围栏边界的物理最短距离
*/
public static double calculateDistanceToNearestBoundary(double x, double y, List<Geofence> geofences) {
if (geofences == null || geofences.isEmpty()) {
return Double.POSITIVE_INFINITY;
}
double minDistance = Double.MAX_VALUE;
// 预先计算一次转换因子
double metersPerDegreeLongitude = METERS_PER_DEGREE_LATITUDE * Math.cos(Math.toRadians(y));
for (Geofence fence : geofences) {
// 剪枝优化对于外部点仍然有效,对于内部点虽然效果减弱,但无害且在多围栏场景下依然有用
double distToBox = pointToBoundingBoxDistanceInMeters(x, y, fence, metersPerDegreeLongitude);
if (distToBox >= minDistance) {
continue;
}
// 核心逻辑:直接遍历所有边并计算距离
List<FencePointVo> polygon = fence.getVertices();
for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) {
FencePointVo p1 = polygon.get(i);
FencePointVo p2 = polygon.get(j);
double distance = pointToLineSegmentDistanceInMeters(x, y, p1, p2, metersPerDegreeLongitude);
minDistance = Math.min(minDistance, distance);
}
}
return minDistance;
}
/**
* 计算违规距离
*
* @param handVo 手部数据对象
* @param fenceType 围栏类型
* @param fenceList 围栏列表
* @return 违规距离
*/
public static double fenceDistance(HandDataVo handVo, FenceType fenceType, List<Geofence> fenceList) {
if (fenceType == FenceType.INSIDE) {
// 规则是“必须在内”,违规意味着“在外面”,所以计算点到围栏的外部距离。
// 此方法专为外部点设计。calculateDistanceToNearestBoundary
return GeofenceUtils.calculateDistanceToNearestBoundary(handVo.getLongitude(), handVo.getLatitude(), fenceList);
} else { // 规则是OUTSIDE
// 违规意味着“在里面”,所以计算点到边界的内部深度。
// 此方法能处理内部点。
return GeofenceUtils.calculateDistanceToFences(handVo.getLongitude(), handVo.getLatitude(), fenceList);
}
}
}

56
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/RedisKeyUtil.java

@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.hand.util;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* redis 工具类
*
* @Author Scott
*/
@Data
public class RedisKeyUtil {
public static final String REDIS_KEY_PREFIX = "hand_detectorKey";
public static final String ALARM_RULES_CACHE_NAME = "alarm_rulesKey";
public static final String DEVICE_TENANT_MAPPING_KEY = "device:tenant:mapping";
// 基础前缀
public static final String DEVICE_INFO_PREFIX = "device:info";
public static final String LOCK_PREFIX = "lock:device";
/**
* 获取特定租户下的设备信息 Hash Key
* 结构示例: device:info:{tenantId} -> field为sn
*/
public static String getTenantDeviceHashKey(Long tenantId) {
return DEVICE_INFO_PREFIX + ":" + tenantId;
}
/**
* 获取处理锁 Key (加入租户维度更安全)
* 结构示例: lock:device:{tenantId}:{sn}
*/
public static String getDeviceProcessLockKey(Long tenantId, String sn) {
return LOCK_PREFIX + ":" + tenantId + ":" + sn;
}
public static String getDeviceTenantMappingKey() {
return DEVICE_TENANT_MAPPING_KEY;
}
}

742
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/util/RedisUtil.java

@ -0,0 +1,742 @@
package cn.iocoder.yudao.module.hand.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* redis 工具类
* @Author Scott
*
*/
@Component
@Slf4j
public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 指定缓存失效时间
*
* @param key
* @param time 时间()
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 不能为null
* @return 时间() 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}
// ============================String=============================
/**
* 普通缓存获取
*
* @param key
* @return
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key
* @param value
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key
* @param value
* @param time 时间() time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ================================Map=================================
/**
* HashGet
*
* @param key 不能为null
* @param item 不能为null
* @return
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 获取hashKey对应的所有键值
*
* @param key
* @return 对应的多个键值
*/
public Object hmget(String key,String item) {
Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
return entries.get(item);
}
/**
* HashSet
*
* @param key
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<Object, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key
* @param map 对应多个键值
* @param time 时间()
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key
* @param item
* @param value
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key
* @param item
* @param value
* @param time 时间() 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 不能为null
* @param item 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 不能为null
* @param item 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key
* @param item
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key
* @param item
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================set=============================
/**
* 根据key获取Set中的所有值
*
* @param key
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key
* @param value
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key
* @param values 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key
* @param time 时间()
* @param values 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key
* @param values 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ===============================list=================================
/**
* 获取list缓存的内容
*
* @param key
* @param start 开始
* @param end 结束 0 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key
* @param index 索引 index>=0时 0 表头1 第二个元素依次类推index<0时-1表尾-2倒数第二个元素依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @param time 时间()
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
//
// /**
// * list缓存全量更新,先删后存
// *
// * @param key 键
// * @param value 值
// * @return
// */
// public boolean lDelAndSet(String key, List<Object> value) {
// try {
// redisTemplate.execute(new SessionCallback<Object>() {
// @Override
// public Object execute(RedisOperations operations) throws DataAccessException {
// operations.multi();
//
// operations.delete(key);
// redisTemplate.opsForList().rightPushAll(key, value);
//
// operations.exec();
// return null;
// }
// });
// return true;
// } catch (Exception e) {
// e.printStackTrace();
// return false;
// }
// }
/**
* list缓存全量更新先删后存
*
* @param key
* @param value
* @return
*/
public boolean lDelAndSet(String key, List<Object> value) {
try {
String script = "redis.call('del', KEYS[1]) " +
"for i = 1, #ARGV do " +
" redis.call('rpush', KEYS[1], ARGV[i]) " +
"end ";
RedisScript<Void> redisScript = new DefaultRedisScript<>(script, Void.class);
redisTemplate.execute(redisScript, Collections.singletonList(key), value.toArray());
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @param time 时间()
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key
* @param index 索引
* @param value
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key
* @param count 移除多少个
* @param value
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* removing all values not within the slice between ``start`` and ``end``
*
* @param key
* @param start 开始
* @param end 结束 0 -1代表所有值
*/
public boolean lTrim(String key, long start, long end) {
try {
redisTemplate.opsForList().trim(key, start, end);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 查找匹配key
*
* @param pattern key
* @return /
*/
public List<String> scan(String pattern) {
ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
RedisConnection rc = Objects.requireNonNull(factory).getConnection();
Cursor<byte[]> cursor = rc.scan(options);
List<String> result = new ArrayList<>();
while (cursor.hasNext()) {
result.add(new String(cursor.next()));
}
try {
RedisConnectionUtils.releaseConnection(rc, factory);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return result;
}
// =============================== message queue =================================
/**
* 消息入队列
*
* @param queue
* @param message
* @return
*/
public Long queuePut(String queue, Object message) {
try {
return redisTemplate.opsForList().leftPush(queue, message);
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0L;
}
}
/**
* 消息出队列
*
* @param queue
* @return
*/
public Object queueGet(String queue) {
try {
return redisTemplate.opsForList().rightPop(queue, 1, TimeUnit.SECONDS);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
// =============================== lock =================================
/**
* 创建锁
*
* @param key 锁的Key
* @param releaseTime 锁过期时间防止死锁
* @return
*/
public boolean lock(String key, long releaseTime) {
// 尝试获取锁
Boolean success = redisTemplate.opsForValue().setIfAbsent(key, 1, releaseTime, TimeUnit.SECONDS);
// 判断结果
return success != null && success;
}
/**
* 根据key释放锁
*
* @param key
*/
public void deleteLock(String key) {
// 删除key即可释放锁
redisTemplate.delete(key);
}
public void flushDb() {
redisTemplate.execute((RedisCallback<Object>) connection -> {
connection.flushDb(); // 清空当前数据库
return null;
});
}
}

8
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmRulePageReqVO.java

@ -14,10 +14,10 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
public class AlarmRulePageReqVO extends PageParam {
@Schema(description = "气体类型ID", example = "2833")
private String gasTypeId;
private Long gasTypeId;
@Schema(description = "警报类型ID", example = "12917")
private String alarmTypeId;
private Long alarmTypeId;
@Schema(description = "警报名称", example = "赵六")
private String alarmName;
@ -50,13 +50,13 @@ public class AlarmRulePageReqVO extends PageParam {
private Integer delFlag;
@Schema(description = "创建者")
private String createBy;
private String creator;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "更新者")
private String updateBy;
private String updater;
}

14
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmRuleRespVO.java

@ -14,15 +14,15 @@ public class AlarmRuleRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4303")
@ExcelProperty("主键ID")
private String id;
private Long id;
@Schema(description = "气体类型ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2833")
@ExcelProperty("气体类型ID")
private String gasTypeId;
private Long gasTypeId;
@Schema(description = "警报类型ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12917")
@ExcelProperty("警报类型ID")
private String alarmTypeId;
private Long alarmTypeId;
@Schema(description = "警报名称", example = "赵六")
@ExcelProperty("警报名称")
@ -60,20 +60,14 @@ public class AlarmRuleRespVO {
@ExcelProperty("备注")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("删除标志")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建者")
private String createBy;
private String creator;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "更新者")
@ExcelProperty("更新者")
private String updateBy;
}

16
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmRuleSaveReqVO.java

@ -10,15 +10,15 @@ import jakarta.validation.constraints.*;
public class AlarmRuleSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "4303")
private String id;
private Long id;
@Schema(description = "气体类型ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2833")
@NotEmpty(message = "气体类型ID不能为空")
private String gasTypeId;
private Long gasTypeId;
@Schema(description = "警报类型ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12917")
@NotEmpty(message = "警报类型ID不能为空")
private String alarmTypeId;
private Long alarmTypeId;
@Schema(description = "警报名称", example = "赵六")
private String alarmName;
@ -49,15 +49,5 @@ public class AlarmRuleSaveReqVO {
@Schema(description = "备注", example = "你说的对")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "删除标志不能为空")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "创建者不能为空")
private String createBy;
@Schema(description = "更新者")
private String updateBy;
}

6
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmTypePageReqVO.java

@ -31,17 +31,13 @@ public class AlarmTypePageReqVO extends PageParam {
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "删除标志")
private Integer delFlag;
@Schema(description = "创建者")
private String createBy;
private String creator;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "更新者")
private String updateBy;
}

11
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmTypeRespVO.java

@ -14,7 +14,7 @@ public class AlarmTypeRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "18440")
@ExcelProperty("主键ID")
private String id;
private Long id;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@ExcelProperty("名称")
@ -40,20 +40,13 @@ public class AlarmTypeRespVO {
@ExcelProperty("备注")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("删除标志")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建者")
private String createBy;
private String creator;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "更新者")
@ExcelProperty("更新者")
private String updateBy;
}

17
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/AlarmTypeSaveReqVO.java

@ -10,7 +10,7 @@ import jakarta.validation.constraints.*;
public class AlarmTypeSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "18440")
private String id;
private Long id;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
@NotEmpty(message = "名称不能为空")
@ -27,22 +27,7 @@ public class AlarmTypeSaveReqVO {
@NotNull(message = "警报方式/级别(0:正常状态;1:一级警报;2:二级警报;3:弹窗警报)不能为空")
private Integer level;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "排序不能为空")
private Integer sortOrder;
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "删除标志不能为空")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "创建者不能为空")
private String createBy;
@Schema(description = "更新者")
private String updateBy;
}

68
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FactoryPageReqVO.java

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.hand.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - GAS工厂分页 Request VO")
@Data
public class FactoryPageReqVO extends PageParam {
@Schema(description = "父节点ID", example = "997")
private Long parentId;
@Schema(description = "层级(1:工厂;2:车间;3:班组)", example = "1")
private Integer type;
@Schema(description = "名称", example = "王五")
private String name;
@Schema(description = "城市")
private String city;
@Schema(description = "总警报数")
private Integer alarmTotal;
@Schema(description = "已处理警报数")
private Integer alarmDeal;
@Schema(description = "区域图", example = "https://www.iocoder.cn")
private String picUrl;
@Schema(description = "区域图缩放比例")
private Integer picScale;
@Schema(description = "在区域图X坐标值")
private Double picX;
@Schema(description = "在区域图X坐标值")
private Double picY;
@Schema(description = "经度")
private Double longitude;
@Schema(description = "纬度")
private Double latitude;
@Schema(description = "区域西南坐标")
private String rectSouthWest;
@Schema(description = "区域东北坐标")
private String rectNorthEast;
@Schema(description = "排序")
private Integer sortOrder;
@Schema(description = "备注", example = "你猜")
private String remark;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

86
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FactoryRespVO.java

@ -0,0 +1,86 @@
package cn.iocoder.yudao.module.hand.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - GAS工厂 Response VO")
@Data
@ExcelIgnoreUnannotated
public class FactoryRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "19786")
@ExcelProperty("主键ID")
private Long id;
@Schema(description = "父节点ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "997")
@ExcelProperty("父节点ID")
private Long parentId;
@Schema(description = "层级(1:工厂;2:车间;3:班组)", example = "1")
@ExcelProperty("层级(1:工厂;2:车间;3:班组)")
private Integer type;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
@ExcelProperty("名称")
private String name;
@Schema(description = "城市")
@ExcelProperty("城市")
private String city;
@Schema(description = "总警报数", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("总警报数")
private Integer alarmTotal;
@Schema(description = "已处理警报数", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("已处理警报数")
private Integer alarmDeal;
@Schema(description = "区域图", example = "https://www.iocoder.cn")
@ExcelProperty("区域图")
private String picUrl;
@Schema(description = "区域图缩放比例")
@ExcelProperty("区域图缩放比例")
private Integer picScale;
@Schema(description = "在区域图X坐标值")
@ExcelProperty("在区域图X坐标值")
private Double picX;
@Schema(description = "在区域图X坐标值")
@ExcelProperty("在区域图X坐标值")
private Double picY;
@Schema(description = "经度")
@ExcelProperty("经度")
private Double longitude;
@Schema(description = "纬度")
@ExcelProperty("纬度")
private Double latitude;
@Schema(description = "区域西南坐标")
@ExcelProperty("区域西南坐标")
private String rectSouthWest;
@Schema(description = "区域东北坐标")
@ExcelProperty("区域东北坐标")
private String rectNorthEast;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("排序")
private Integer sortOrder;
@Schema(description = "备注", example = "你猜")
@ExcelProperty("备注")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

68
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FactorySaveReqVO.java

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.hand.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
@Schema(description = "管理后台 - GAS工厂新增/修改 Request VO")
@Data
public class FactorySaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "19786")
private Long id;
@Schema(description = "父节点ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "997")
@NotNull(message = "父节点ID不能为空")
private Long parentId;
@Schema(description = "层级(1:工厂;2:车间;3:班组)", example = "1")
private Integer type;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
@NotEmpty(message = "名称不能为空")
private String name;
@Schema(description = "城市")
private String city;
@Schema(description = "总警报数", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "总警报数不能为空")
private Integer alarmTotal;
@Schema(description = "已处理警报数", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "已处理警报数不能为空")
private Integer alarmDeal;
@Schema(description = "区域图", example = "https://www.iocoder.cn")
private String picUrl;
@Schema(description = "区域图缩放比例")
private Integer picScale;
@Schema(description = "在区域图X坐标值")
private Double picX;
@Schema(description = "在区域图X坐标值")
private Double picY;
@Schema(description = "经度")
private Double longitude;
@Schema(description = "纬度")
private Double latitude;
@Schema(description = "区域西南坐标")
private String rectSouthWest;
@Schema(description = "区域东北坐标")
private String rectNorthEast;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "排序不能为空")
private Integer sortOrder;
@Schema(description = "备注", example = "你猜")
private String remark;
}

18
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceAlarmPageReqVO.java

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.hand.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
@ -14,10 +15,10 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
public class FenceAlarmPageReqVO extends PageParam {
@Schema(description = "探头ID", example = "32133")
private String detectorId;
private Long detectorId;
@Schema(description = "围栏id", example = "31072")
private String fenceId;
private Long fenceId;
@Schema(description = "报警类型", example = "2")
private Integer type;
@ -46,17 +47,8 @@ public class FenceAlarmPageReqVO extends PageParam {
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "删除标志")
private Integer delFlag;
@Schema(description = "创建者")
private String createBy;
@Schema(description = "创建时间")
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "更新者")
private String updateBy;
}

19
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceAlarmRespVO.java

@ -14,15 +14,15 @@ public class FenceAlarmRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12756")
@ExcelProperty("主键ID")
private String id;
private Long id;
@Schema(description = "探头ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "32133")
@ExcelProperty("探头ID")
private String detectorId;
private Long detectorId;
@Schema(description = "围栏id", requiredMode = Schema.RequiredMode.REQUIRED, example = "31072")
@ExcelProperty("围栏id")
private String fenceId;
private Long fenceId;
@Schema(description = "报警类型", example = "2")
@ExcelProperty("报警类型")
@ -60,20 +60,7 @@ public class FenceAlarmRespVO {
@ExcelProperty("备注")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("删除标志")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建者")
private String createBy;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "更新者")
@ExcelProperty("更新者")
private String updateBy;
}

20
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceAlarmSaveReqVO.java

@ -2,9 +2,12 @@ package cn.iocoder.yudao.module.hand.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - GAS手持探测器围栏报警新增/修改 Request VO")
@ -12,11 +15,11 @@ import java.time.LocalDateTime;
public class FenceAlarmSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12756")
private String id;
private Long id;
@Schema(description = "探头ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "32133")
@NotEmpty(message = "探头ID不能为空")
private String detectorId;
private Long detectorId;
@Schema(description = "围栏id", requiredMode = Schema.RequiredMode.REQUIRED, example = "31072")
@NotEmpty(message = "围栏id不能为空")
@ -51,15 +54,6 @@ public class FenceAlarmSaveReqVO {
@NotEmpty(message = "备注不能为空")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "删除标志不能为空")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "创建者不能为空")
private String createBy;
@Schema(description = "更新者")
private String updateBy;
@Schema(description = "租户id")
private Long tenantId;
}

15
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FencePageReqVO.java

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.hand.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
@ -28,17 +29,7 @@ public class FencePageReqVO extends PageParam {
@Schema(description = "备注", example = "你说的对")
private String remark;
@Schema(description = "删除标志")
private Integer delFlag;
@Schema(description = "创建者")
private String createBy;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime[] createTime;
@Schema(description = "更新者")
private String updateBy;
}

19
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FencePointVo.java

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.hand.vo;
import lombok.Data;
@Data
public class FencePointVo {
public double x;//经度
public double y;//纬度
//public Long fenceId;
public FencePointVo() {
}
public FencePointVo(double x, double y) {
this.x = x;
this.y = y;
}
}

15
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceRespVO.java

@ -14,7 +14,7 @@ public class FenceRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12448")
@ExcelProperty("主键ID")
private String id;
private Long id;
@Schema(description = "围栏名称", example = "王五")
@ExcelProperty("围栏名称")
@ -36,20 +36,7 @@ public class FenceRespVO {
@ExcelProperty("备注")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("删除标志")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建者")
private String createBy;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "更新者")
@ExcelProperty("更新者")
private String updateBy;
}

12
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/FenceSaveReqVO.java

@ -10,7 +10,7 @@ import jakarta.validation.constraints.*;
public class FenceSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "12448")
private String id;
private Long id;
@Schema(description = "围栏名称", example = "王五")
private String name;
@ -27,15 +27,5 @@ public class FenceSaveReqVO {
@Schema(description = "备注", example = "你说的对")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "删除标志不能为空")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "创建者不能为空")
private String createBy;
@Schema(description = "更新者")
private String updateBy;
}

14
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/GasTypePageReqVO.java

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.hand.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
@ -28,17 +29,8 @@ public class GasTypePageReqVO extends PageParam {
@Schema(description = "备注", example = "你说的对")
private String remark;
@Schema(description = "删除标志")
private Integer delFlag;
@Schema(description = "创建者")
private String createBy;
@Schema(description = "创建时间")
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "更新者")
private String updateBy;
}

15
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/GasTypeRespVO.java

@ -14,7 +14,7 @@ public class GasTypeRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25168")
@ExcelProperty("主键ID")
private String id;
private Long id;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
@ExcelProperty("名称")
@ -36,20 +36,7 @@ public class GasTypeRespVO {
@ExcelProperty("备注")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("删除标志")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建者")
private String createBy;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "更新者")
@ExcelProperty("更新者")
private String updateBy;
}

12
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/GasTypeSaveReqVO.java

@ -10,7 +10,7 @@ import jakarta.validation.constraints.*;
public class GasTypeSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "25168")
private String id;
private Long id;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
@NotEmpty(message = "名称不能为空")
@ -30,15 +30,5 @@ public class GasTypeSaveReqVO {
@Schema(description = "备注", example = "你说的对")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "删除标志不能为空")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "创建者不能为空")
private String createBy;
@Schema(description = "更新者")
private String updateBy;
}

47
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/Geofence.java

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.hand.vo;
import lombok.Data;
import java.util.Collections;
import java.util.List;
@Data
public class Geofence {
private final List<FencePointVo> vertices;
private final double minX, minY, maxX, maxY; // 包围盒
public Geofence(List<FencePointVo> vertices) {
if (vertices == null || vertices.size() < 3) {
throw new IllegalArgumentException("一个多边形至少需要3个顶点。");
}
this.vertices = Collections.unmodifiableList(vertices);
// 在构造时一次性计算包围盒
double tempMinX = Double.MAX_VALUE;
double tempMinY = Double.MAX_VALUE;
double tempMaxX = -Double.MAX_VALUE;
double tempMaxY = -Double.MAX_VALUE;
for (FencePointVo point : vertices) {
tempMinX = Math.min(tempMinX, point.x);
tempMinY = Math.min(tempMinY, point.y);
tempMaxX = Math.max(tempMaxX, point.x);
tempMaxY = Math.max(tempMaxY, point.y);
}
this.minX = tempMinX;
this.minY = tempMinY;
this.maxX = tempMaxX;
this.maxY = tempMaxY;
}
/**
* 判断一个点是否在当前围栏的包围盒内
* 这是一个快速的初步检查
*/
public boolean isPointInBoundingBox(double x, double y) {
return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY;
}
public List<FencePointVo> getVertices() {
return vertices;
}
}

17
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandAlarmPageReqVO.java

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.hand.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
@ -13,6 +14,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@Data
public class HandAlarmPageReqVO extends PageParam {
@Schema(description = "持有人姓名", example = "赵六")
private String name;
@Schema(description = "警报方式/级别(0:正常状态;1:一级警报;2:二级警报;3:弹窗警报)")
private Integer alarmLevel;
@ -49,17 +53,8 @@ public class HandAlarmPageReqVO extends PageParam {
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "删除标志")
private Integer delFlag;
@Schema(description = "创建者")
private String createBy;
@Schema(description = "创建时间")
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "更新者")
private String updateBy;
}

17
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandAlarmRespVO.java

@ -12,9 +12,12 @@ import com.alibaba.excel.annotation.*;
@ExcelIgnoreUnannotated
public class HandAlarmRespVO {
@Schema(description = "持有人姓名", example = "赵六")
private String name;
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "17955")
@ExcelProperty("主键ID")
private String id;
private Long id;
@Schema(description = "警报方式/级别(0:正常状态;1:一级警报;2:二级警报;3:弹窗警报)", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("警报方式/级别(0:正常状态;1:一级警报;2:二级警报;3:弹窗警报)")
@ -64,20 +67,8 @@ public class HandAlarmRespVO {
@ExcelProperty("备注")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("删除标志")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建者")
private String createBy;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "更新者")
@ExcelProperty("更新者")
private String updateBy;
}

29
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandAlarmSaveReqVO.java

@ -2,9 +2,12 @@ package cn.iocoder.yudao.module.hand.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - GAS手持探测器警报新增/修改 Request VO")
@ -12,12 +15,19 @@ import java.time.LocalDateTime;
public class HandAlarmSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "17955")
private String id;
private Long id;
@Schema(description = "持有人姓名", example = "赵六")
private String name;
@Schema(description = "警报方式/级别(0:正常状态;1:一级警报;2:二级警报;3:弹窗警报)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "警报方式/级别(0:正常状态;1:一级警报;2:二级警报;3:弹窗警报)不能为空")
private Integer alarmLevel;
@Schema(description = "报警类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "报警类型不能为空")
private Integer alarmType;
@Schema(description = "气体类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotEmpty(message = "气体类型不能为空")
private String gasType;
@ -48,22 +58,13 @@ public class HandAlarmSaveReqVO {
@Schema(description = "结束时间")
private LocalDateTime tAlarmEnd;
@Schema(description = "状态(0:待处理;1:处理中;1:已处理)", example = "1")
private Integer status;
@Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "随便")
@NotEmpty(message = "备注不能为空")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "删除标志不能为空")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "创建者不能为空")
private String createBy;
@Schema(description = "更新者")
private String updateBy;
/**
* 租户id
*/
private Integer tenantId;
}

104
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandDataVo.java

@ -0,0 +1,104 @@
package cn.iocoder.yudao.module.hand.vo;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class HandDataVo {
@Schema(description = "id")
private Long id;
@Schema(description = "设备sn")
private String sn;
@Schema(description = "电量")
private String battery;
@Schema(description = "数据")
private Double value;
@Schema(description = "经度")
private Double longitude;
@Schema(description = "纬度")
private Double latitude;
@Schema(description = "更新时间")
private Date time;
@Schema(description = "持有人姓名")
private String name;
@Schema(description = "围栏id")
private String fenceIds;
@Schema(description = "围栏类型(1:超出报警,2:进入报警)")
private Integer fenceType;
@Schema(description = "气体类型ID")
private Long gasTypeId;
@Schema(description = "气体化学式")
private String gasChemical;
@Schema(description = "低于多少电量报警")
private BigDecimal batteryAlarmValue;
@Schema(description = "数值除数")
private Integer accuracy;
@Schema(description = "报警等级")
private Integer alarmLevel;
@Schema(description = "最大报警等级")
private Integer maxAlarmLevel;
@Schema(description = "首次报警")
private Double firstValue;
@Schema(description = "最大报警值")
private Double maxValue;
@Schema(description = "报警开始时间")
private LocalDateTime tAlarmStart;
@Schema(description = "报警结束时间")
private LocalDateTime tAlarmEnd;
@Schema(description = "气体报警状态(0:正常;1:报警)")
private Integer gasStatus;
@Schema(description = "气体报警Id")
private Long alarmId;
@Schema(description = "电池报警状态(0:正常;1:报警)")
private Integer batteryStatus;
private Integer batteryStatusAlarmId;
@Schema(description = "电子围栏报警状态(0:正常;1:报警)")
private Integer fenceStatus;
@Schema(description = "电子围栏报警Id")
private Long fenceAlarmId;
@Schema(description = "在线状态(0:离线;1:在线)")
private Integer onlineStatus;
@Schema(description = "启用状态(0:备用;1:启用)")
private Integer enableStatus;
@Schema(description = "超出围栏米数")
private Double distance;
@Schema(description = "最远超出米数")
private Double maxDistance;
@Schema(description = "租户id")
private Long tenantId;
}

18
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandDetectorPageReqVO.java

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.hand.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -19,10 +20,10 @@ public class HandDetectorPageReqVO extends PageParam {
private String name;
@Schema(description = "围栏id", example = "15853")
private String fenceId;
private Long fenceId;
@Schema(description = "气体类型ID", example = "31358")
private String gasTypeId;
private Long gasTypeId;
@Schema(description = "气体化学式")
private String gasChemical;
@ -69,17 +70,8 @@ public class HandDetectorPageReqVO extends PageParam {
@Schema(description = "备注", example = "你猜")
private String remark;
@Schema(description = "删除标志")
private Integer delFlag;
@Schema(description = "创建者")
private String createBy;
@Schema(description = "创建时间")
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "更新者")
private String updateBy;
}

16
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandDetectorRespVO.java

@ -13,7 +13,7 @@ public class HandDetectorRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "24178")
@ExcelProperty("主键ID")
private String id;
private Long id;
@Schema(description = "SN")
@ExcelProperty("SN")
@ -25,11 +25,11 @@ public class HandDetectorRespVO {
@Schema(description = "围栏id", example = "15853")
@ExcelProperty("围栏id")
private String fenceId;
private Long fenceId;
@Schema(description = "气体类型ID", example = "31358")
@ExcelProperty("气体类型ID")
private String gasTypeId;
private Long gasTypeId;
@Schema(description = "气体化学式")
@ExcelProperty("气体化学式")
@ -91,20 +91,10 @@ public class HandDetectorRespVO {
@ExcelProperty("备注")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("删除标志")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建者")
private String createBy;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "更新者")
@ExcelProperty("更新者")
private String updateBy;
}

18
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandDetectorSaveReqVO.java

@ -9,7 +9,7 @@ import jakarta.validation.constraints.*;
public class HandDetectorSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "24178")
private String id;
private Long id;
@Schema(description = "SN")
private String sn;
@ -18,10 +18,10 @@ public class HandDetectorSaveReqVO {
private String name;
@Schema(description = "围栏id", example = "15853")
private String fenceId;
private Long fenceId;
@Schema(description = "气体类型ID", example = "31358")
private String gasTypeId;
private Long gasTypeId;
@Schema(description = "气体化学式")
private String gasChemical;
@ -32,9 +32,6 @@ public class HandDetectorSaveReqVO {
@Schema(description = "测量范围中的最大值")
private Double max;
@Schema(description = "状态(0:未知;1:正常;2:故障;3:离线)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态(0:未知;1:正常;2:故障;3:离线)不能为空")
private Integer status;
@Schema(description = "单位")
private String unit;
@ -46,7 +43,6 @@ public class HandDetectorSaveReqVO {
private String manufacturer;
@Schema(description = "启用状态(0:备用;1:启用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "启用状态(0:备用;1:启用)不能为空")
private Integer enableStatus;
@Schema(description = "在区域图X坐标值")
@ -70,15 +66,7 @@ public class HandDetectorSaveReqVO {
@Schema(description = "备注", example = "你猜")
private String remark;
@Schema(description = "删除标志", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "删除标志不能为空")
private Integer delFlag;
@Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "创建者不能为空")
private String createBy;
@Schema(description = "更新者")
private String updateBy;
}

17
cc-admin-master/yudao-module-hand/src/main/java/cn/iocoder/yudao/module/hand/vo/HandOriginalLog.java

@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.hand.vo;
import lombok.Data;
import java.sql.Timestamp; // 确保导入的是 java.sql.Timestamp
@Data
public class HandOriginalLog {
private String sn;
private String payload;
private Timestamp ts;
private Long tenantId;
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save