yuanzhongqiao 2 недель назад
Родитель
Сommit
455567c638
100 измененных файлов с 6631 добавлено и 57 удалено
  1. 9 0
      .dockerignore
  2. 162 0
      .gitignore
  3. 277 57
      README.md
  4. BIN
      images/10ae418a-8e41-4dc6-a999-cc950fe8da5d.png
  5. BIN
      images/2b5a0446-ed88-461d-b43d-973c5cb40ee9.png
  6. BIN
      images/402941a0-dba9-4411-943f-f95d5878f092.png
  7. BIN
      images/66e3542a-25da-4ad2-b9ef-a389eb0abcf2.png
  8. BIN
      images/6b06baf9-0968-4191-a53f-284856f5db1d.png
  9. BIN
      images/ac1e2edf-a67c-46a9-8e5b-ba8981ce9365.png
  10. BIN
      images/c09b4911-1cfe-4b73-a2d2-aabf16a70b0d.png
  11. BIN
      images/c4282592-c1c0-49f3-afd8-6d27a2ded4db.png
  12. BIN
      images/d63233d6-863e-452a-802c-29a7d7775e4c.png
  13. BIN
      images/e201c0b9-bf05-414b-b866-cdeb9eb73f9c.png
  14. BIN
      images/f761759c-0199-4cb5-9800-1d92b45cc24b.png
  15. BIN
      images/image.png
  16. 46 0
      ruoyi-qs-nvr-master/.gitignore
  17. 14 0
      ruoyi-qs-nvr-master/docker/.env.example
  18. 96 0
      ruoyi-qs-nvr-master/docker/copy.ps1
  19. 29 0
      ruoyi-qs-nvr-master/docker/copy.sh
  20. 75 0
      ruoyi-qs-nvr-master/docker/deploy.sh
  21. 421 0
      ruoyi-qs-nvr-master/docker/docker-compose.yml
  22. 2 0
      ruoyi-qs-nvr-master/docker/mysql/db/00-init-databases.sql
  23. 51 0
      ruoyi-qs-nvr-master/docker/mysql/db/01-ry-config.sql
  24. 1357 0
      ruoyi-qs-nvr-master/docker/mysql/db/02-ry-cloud.sql
  25. 7 0
      ruoyi-qs-nvr-master/docker/mysql/db/03-docker-nacos-override.sql
  26. 3 0
      ruoyi-qs-nvr-master/docker/mysql/db/04-rebrand-notice.sql
  27. 1 0
      ruoyi-qs-nvr-master/docker/mysql/db/readme.txt
  28. 7 0
      ruoyi-qs-nvr-master/docker/mysql/dockerfile
  29. 33 0
      ruoyi-qs-nvr-master/docker/nacos/conf/application.properties
  30. 2 0
      ruoyi-qs-nvr-master/docker/nacos/dockerfile
  31. 72 0
      ruoyi-qs-nvr-master/docker/nginx/conf/nginx.conf
  32. 24 0
      ruoyi-qs-nvr-master/docker/nginx/dockerfile
  33. 5 0
      ruoyi-qs-nvr-master/docker/redis/conf/redis.conf
  34. 12 0
      ruoyi-qs-nvr-master/docker/redis/dockerfile
  35. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/auth/dockerfile
  36. 1 0
      ruoyi-qs-nvr-master/docker/ruoyi/auth/jar/readme.txt
  37. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/gateway/dockerfile
  38. 1 0
      ruoyi-qs-nvr-master/docker/ruoyi/gateway/jar/readme.txt
  39. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/dahua/dockerfile
  40. 2 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/dahua/jar/readme.txt
  41. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/file/dockerfile
  42. 1 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/file/jar/readme.txt
  43. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/gb28181/dockerfile
  44. 2 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/gb28181/jar/readme.txt
  45. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/gen/dockerfile
  46. 1 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/gen/jar/readme.txt
  47. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/haikang-isup/dockerfile
  48. 2 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/haikang-isup/jar/readme.txt
  49. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/haikang/dockerfile
  50. 2 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/haikang/jar/readme.txt
  51. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/job/dockerfile
  52. 1 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/job/jar/readme.txt
  53. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/jt1078/dockerfile
  54. 2 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/jt1078/jar/readme.txt
  55. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/onvif/dockerfile
  56. 2 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/onvif/jar/readme.txt
  57. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/qs/dockerfile
  58. 2 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/qs/jar/readme.txt
  59. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/system/dockerfile
  60. 1 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/system/jar/readme.txt
  61. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/zlm/dockerfile
  62. 2 0
      ruoyi-qs-nvr-master/docker/ruoyi/modules/zlm/jar/readme.txt
  63. 5 0
      ruoyi-qs-nvr-master/docker/ruoyi/visual/monitor/dockerfile
  64. 1 0
      ruoyi-qs-nvr-master/docker/ruoyi/visual/monitor/jar/readme.txt
  65. 10 0
      ruoyi-qs-nvr-master/docker/start.bat
  66. 122 0
      ruoyi-qs-nvr-master/docker/start.ps1
  67. 4 0
      ruoyi-qs-nvr-master/docker/stop.bat
  68. 8 0
      ruoyi-qs-nvr-master/docker/stop.ps1
  69. 348 0
      ruoyi-qs-nvr-master/pom.xml
  70. 30 0
      ruoyi-qs-nvr-master/ruoyi-api/pom.xml
  71. 28 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/pom.xml
  72. 330 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/RemoteDaHuaService.java
  73. 73 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaAlarmArmInfo.java
  74. 92 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaBitrateInfo.java
  75. 101 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaCameraInfo.java
  76. 34 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaDevice.java
  77. 66 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaDeviceInfo.java
  78. 118 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaDeviceVideoParam.java
  79. 100 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaNetworkStatusInfo.java
  80. 73 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaPowerStateInfo.java
  81. 76 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaRecordDownloadRequest.java
  82. 89 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaRecordDownloadResponse.java
  83. 81 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaRecordStateInfo.java
  84. 69 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaRtspUrlInfo.java
  85. 165 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaSDCardInfo.java
  86. 172 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaSoftwareVersionInfo.java
  87. 315 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaStorageInfo.java
  88. 41 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaSystemParam.java
  89. 148 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaSystemResourceInfo.java
  90. 67 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaVideoParam.java
  91. 55 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/LoginDevice.java
  92. 172 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/factory/RemoteDaHuaFallbackFactory.java
  93. 1 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  94. 53 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/pom.xml
  95. 667 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/RemoteGb28181Service.java
  96. 13 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/DeviceNotFoundEvent.java
  97. 6 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/ErrorCallback.java
  98. 46 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/Gb28181Sdp.java
  99. 43 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/MessageResponseTask.java
  100. 12 0
      ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/Preset.java

+ 9 - 0
.dockerignore

@@ -0,0 +1,9 @@
+**/node_modules
+**/.git
+**/target
+**/mysql/data
+**/redis/data
+**/nacos/logs
+**/nginx/logs
+**/.idea
+**/.vscode

+ 162 - 0
.gitignore

@@ -0,0 +1,162 @@
+# =============================================================================
+# 云眼视频监控平台 — 仓库根目录 .gitignore
+# 用于推送远程仓库,排除构建产物、运行数据、本地密钥与 IDE 垃圾文件
+# =============================================================================
+
+# -----------------------------------------------------------------------------
+# 操作系统
+# -----------------------------------------------------------------------------
+.DS_Store
+.DS_Store?
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+$RECYCLE.BIN/
+
+# -----------------------------------------------------------------------------
+# IDE / 编辑器
+# -----------------------------------------------------------------------------
+.idea/
+*.iml
+*.ipr
+*.iws
+.vscode/
+!.vscode/extensions.json
+!.vscode/settings.json.example
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+*.swp
+*~
+.project
+.classpath
+.settings/
+.factorypath
+.apt_generated
+.springBeans
+nbproject/private/
+nbbuild/
+nbdist/
+.nb-gradle/
+
+# -----------------------------------------------------------------------------
+# 日志与临时文件
+# -----------------------------------------------------------------------------
+*.log
+*.log.*
+logs/
+**/logs/
+*.tmp
+*.temp
+*.bak
+*.orig
+hs_err_pid*
+replay_pid*
+
+# -----------------------------------------------------------------------------
+# Java / Maven(后端)
+# -----------------------------------------------------------------------------
+target/
+**/target/
+*.class
+*.jar
+*.war
+*.ear
+*.nar
+# Maven 复制到 Docker 目录的 JAR(由 copy.ps1 / mvn package 生成;保留 jar/readme.txt)
+ruoyi-qs-nvr-master/docker/ruoyi/**/jar/*.jar
+
+# 保留 Maven Wrapper(若存在)
+!**/mvnw
+!**/mvnw.cmd
+!**/.mvn/wrapper/maven-wrapper.jar
+
+# -----------------------------------------------------------------------------
+# Node / 前端构建
+# -----------------------------------------------------------------------------
+node_modules/
+**/node_modules/
+dist/
+**/dist/
+.npm
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+.eslintcache
+*.tsbuildinfo
+
+# 子项目原忽略 lock 文件;根仓库建议保留 lock 便于复现依赖(若需忽略可取消下行注释)
+# package-lock.json
+# yarn.lock
+# pnpm-lock.yaml
+
+# -----------------------------------------------------------------------------
+# Docker 运行数据(本地容器产生,勿提交)
+# -----------------------------------------------------------------------------
+ruoyi-qs-nvr-master/docker/mysql/data/
+ruoyi-qs-nvr-master/docker/redis/data/
+ruoyi-qs-nvr-master/docker/nacos/logs/
+ruoyi-qs-nvr-master/docker/nginx/logs/
+ruoyi-qs-nvr-master/docker/ruoyi/uploadPath/
+
+# -----------------------------------------------------------------------------
+# 环境变量与密钥(含数据库密码、Nacos Token 等)
+# -----------------------------------------------------------------------------
+ruoyi-qs-nvr-master/docker/.env
+.env
+.env.local
+.env.*.local
+!.env.example
+# 前端环境配置通常无敏感信息,可继续提交:
+# ruoyi-qs-nvr-ui-master/.env.development
+# ruoyi-qs-nvr-ui-master/.env.production
+# ruoyi-qs-nvr-ui-master/.env.staging
+
+# -----------------------------------------------------------------------------
+# 厂商 SDK 原生库(体积大、有版权,需自行放置)
+# -----------------------------------------------------------------------------
+**/lib/*.so
+**/lib/*.dll
+**/lib/*.dylib
+**/lib/*.lib
+!**/lib/.gitkeep
+!**/lib/README*
+
+# -----------------------------------------------------------------------------
+# 上传文件 / 录像 / 静态资源缓存
+# -----------------------------------------------------------------------------
+uploadPath/
+**/uploadPath/
+
+# -----------------------------------------------------------------------------
+# 测试与覆盖率
+# -----------------------------------------------------------------------------
+coverage/
+**/coverage/
+.nyc_output/
+test-results/
+playwright-report/
+tests/e2e/reports/
+
+# -----------------------------------------------------------------------------
+# 打包与压缩产物
+# -----------------------------------------------------------------------------
+*.zip
+*.tar
+*.tar.gz
+*.rar
+*.7z
+
+# -----------------------------------------------------------------------------
+# Cursor / 本地工具(若出现在项目目录内)
+# -----------------------------------------------------------------------------
+.cursor/
+*.cursor/

+ 277 - 57
README.md

@@ -1,92 +1,312 @@
-# 视频监控平台cloudeye-video-sur
+# 云眼视频监控平台
 
+<p align="center">
+  <img src="https://www.gitcc.com/uploads/-/system/appearance/header_logo/1/gitpp.png" width="120" alt="云眼 Logo" />
+</p>
 
+<p align="center">
+  <strong>企业级开源视频监控与流媒体管理平台</strong><br/>
+  多协议接入 · 国标级联 · 云端录像 · 地图可视化 · 一键 Docker 部署
+</p>
 
-## Getting started
+<p align="center">
+  <a href="https://www.gitcc.com" target="_blank">开源社区</a>
+</p>
 
-To make it easy for you to get started with GitLab, here's a list of recommended next steps.
+---
 
-Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
+![大屏展示](images/image.png)
 
-## Add your files
+## 这个项目是做什么的?
 
-- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
-- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
+**云眼视频监控平台**(原泉视 NVR 视频监控系统)是一套面向**企业、园区、门店、车队、政府项目**的视频监控一体化解决方案。你可以把它理解为一个「自建版萤石/海康平台」:
+
+- 把摄像头、NVR、车载终端、国标平台等**统一接入**到一个 Web 后台;
+- 在浏览器里完成**实时预览、录像回放、告警处理、地图定位**;
+- 通过 **ZLMediaKit** 做流媒体转发,通过 **GB28181 / JT808·1078** 对接行业平台与车载设备;
+- 基于 **RuoYi-Cloud 微服务** 架构,支持扩展用户权限、日志审计、定时任务等企业管理能力。
+
+**适合谁用?**
+
+| 场景 | 能做什么 |
+|------|----------|
+| 中小企业园区 | 多路监控、分屏查看、录像计划、云端存储 |
+| 集成商 / 二次开发 | 开源可改、多协议适配、国标上下级级联 |
+| 运维团队 | 设备在线状态、媒体节点、告警列表、服务监控 |
+| 学习研究 | Spring Cloud + 流媒体 + 国标协议完整示例 |
+
+---
+
+## 核心能力一览
+
+- **实时监看**:1 / 4 / 6 / 9 / 16 / 25 分屏,布局保存,云台控制,语音对讲(视协议而定)
+- **设备接入**:RTSP、RTMP、FLV、HLS、ONVIF、GB28181、JT808/JT1078、海康 SDK、海康 ISUP、大华 SDK、推流等
+- **录像能力**:设备录像 / 云端录像检索、回放、下载;录像计划按周时段配置
+- **国标级联**:向上级平台注册、目录推送、远程点播 / 回放 / 云台
+- **地图应用**:电子地图落点、设备树联动(天地图)
+- **告警中心**:移动侦测等告警记录、批量处理、导出
+- **系统管理**:用户 / 角色 / 菜单 / 部门、操作日志、Redis / 服务监控(RuoYi 体系)
+
+---
+
+## 技术架构(简要)
+
+| 层级 | 技术 |
+|------|------|
+| 前端 | Vue 3 + Element Plus + Vite |
+| 后端 | Spring Boot 3、Spring Cloud & Alibaba |
+| 注册 / 配置 | Nacos |
+| 缓存 / 会话 | Redis |
+| 数据库 | MySQL 5.7 |
+| 流媒体 | ZLMediaKit |
+| 播放器 | EasyPlayer |
+| 部署 | Docker Compose 一键拉起(推荐) |
+
+---
+
+## 快速开始(推荐:Docker 一键部署)
+
+### 环境要求
+
+- Windows 10/11 或 Linux
+- [Docker Desktop](https://www.docker.com/products/docker-desktop/)(已启动)
+- 首次完整构建需:**JDK 17**、**Maven 3.6+**(用于编译后端 JAR)
+- 前端在 Docker 构建阶段自动 `npm build`,**本机无需安装 Node**
+
+### 启动步骤
+
+```powershell
+# 1. 进入 Docker 目录
+cd ruoyi-qs-nvr-master\docker
+
+# 2. 一键:Maven 编译 → 复制 JAR/SQL → 启动全部容器(含前端 Nginx)
+.\start.ps1
+
+# 日常仅重启(跳过编译)
+.\start.ps1 -SkipBuild -NoImageBuild
+```
+
+也可双击同目录下的 `start.bat`。
+
+### 访问地址
+
+| 服务 | 地址 |
+|------|------|
+| **Web 管理端(主入口)** | http://localhost |
+| API 网关 | http://localhost:8080 |
+| Nacos 控制台 | http://localhost:8848/nacos |
+
+### 默认账号
+
+- 用户名:`admin`
+- 密码:`admin123`
+
+首次启动 MySQL 初始化约 **2~5 分钟**,请等待 Nacos、网关变为健康后再登录。若验证码失败,可执行 `docker compose restart ruoyi-redis ruoyi-gateway`。
+
+### 常用参数
+
+| 参数 | 说明 |
+|------|------|
+| `-SkipBuild` | 跳过 Maven,使用已有 JAR |
+| `-NoImageBuild` | 不重建镜像,仅重启容器 |
+| `-ResetDb` | 清空 `mysql/data` 后重新初始化库 |
+| `-WithVendorSdk` | 额外启动海康 / 大华 SDK 容器(需自备厂商原生库,见下文) |
+
+### 海康 / 大华 SDK 说明
+
+默认 **不启动** 海康、大华 SDK 微服务(镜像内无厂商 `.so` / `.dll`)。Windows 本机若已放置 SDK 到 `ruoyi-modules/*/lib`,可使用:
+
+```powershell
+.\start.ps1 -WithVendorSdk
+```
+
+---
+
+## 本地开发(前后端分离)
+
+### 后端
+
+```powershell
+cd ruoyi-qs-nvr-master
+mvn clean package -DskipTests
+# 按 RuoYi 文档分别启动 Nacos、Redis、MySQL 及各 ruoyi-* 模块
+```
+
+### 前端
+
+```powershell
+cd ruoyi-qs-nvr-ui-master
+npm install
+npm run dev
+```
+
+浏览器访问开发地址(一般为 `http://localhost:80` 或终端提示端口),接口代理指向网关 `/dev-api`。
+
+### 环境变量(前端)
+
+在 `ruoyi-qs-nvr-ui-master/.env.development` 中可配置:
+
+- `VITE_APP_TITLE`:系统名称(默认「云眼视频监控平台」)
+- `VITE_APP_LOGO`:Logo 图片 URL
+
+---
+
+## 目录结构
 
 ```
-cd existing_repo
-git remote add origin https://www.gitcc.com/ai1/cloudeye-video-sur.git
-git branch -M main
-git push -uf origin main
+视频监控系统/
+├── README.md                 # 本说明
+├── images/                   # 界面截图(文档用)
+├── ruoyi-qs-nvr-ui-master/    # 前端 Vue 工程
+└── ruoyi-qs-nvr-master/      # 后端微服务 + docker 一键部署
+    ├── ruoyi-gateway/        # 网关 [8080]
+    ├── ruoyi-auth/           # 认证中心
+    ├── ruoyi-modules/        # 业务模块(设备、国标、ZLM、车载等)
+    └── docker/               # Docker Compose、start.ps1
 ```
 
-## Integrate with your tools
+后端模块主要包括:`ruoyi-qs`(核心业务)、`ruoyi-zlm`(流媒体)、`ruoyi-gb28181`、`ruoyi-jt1078`、`ruoyi-onvif`、`ruoyi-haikang`、`ruoyi-dahua` 等,详见 `ruoyi-qs-nvr-master` 内 `pom.xml`。
+
+---
+
+## 协议支持
+
+### 流媒体协议
+
+| 协议 | 说明 |
+|------|------|
+| RTSP / RTMP / HTTP-FLV / HLS / WebSocket-FLV | 通用拉流 / 播放 |
+
+### 设备与行业标准
+
+| 类型 | 说明 |
+|------|------|
+| ONVIF | 发现、云台、事件 |
+| GB28181 | 国标设备接入、上下级级联 |
+| JT808 / JT1078 | 部标车载终端与视频 |
+| 海康 SDK / ISUP、大华 SDK | 厂商私有协议(需 SDK 文件) |
+
+---
+
+## 界面预览
+
+以下为 **云眼视频监控平台** 实际运行界面(深色侧栏 + 青绿主题)。
+
+### 分屏监控
+
+多路实时预览,支持 1~25 分屏、设备树、布局保存。
+
+![分屏监控](images/f761759c-0199-4cb5-9800-1d92b45cc24b.png)
+
+### 设备管理
+
+卡片式展示设备在线状态,支持国标、RTMP 等多协议,一键播放与配置。
+
+![设备管理](images/c4282592-c1c0-49f3-afd8-6d27a2ded4db.png)
 
-- [ ] [Set up project integrations](https://www.gitcc.com/ai1/cloudeye-video-sur/-/settings/integrations)
+### 录像回放
 
-## Collaborate with your team
+按设备、日期检索录像,支持设备录像与云端录像,时间轴播放控制。
 
-- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
-- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
-- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
-- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
-- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
+![录像回放](images/ac1e2edf-a67c-46a9-8e5b-ba8981ce9365.png)
 
-## Test and Deploy
+### 云端录像
 
-Use the built-in continuous integration in GitLab.
+检索 ZLM 云端 MP4 片段,在线播放、下载、批量删除。
 
-- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
-- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
-- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
-- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
-- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
+![云端录像](images/c09b4911-1cfe-4b73-a2d2-aabf16a70b0d.png)
 
-***
+### 电子地图
 
-# Editing this README
+天地图底图,设备落点与资源树联动,支持卫星视图。
 
-When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
+![电子地图](images/66e3542a-25da-4ad2-b9ef-a389eb0abcf2.png)
 
-## Suggestions for a good README
-Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
+### 录像计划
 
-## Name
-Choose a self-explaining name for your project.
+按周时段配置 7×24 录像计划,关联设备批量生效。
 
-## Description
-Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
+![录像计划](images/6b06baf9-0968-4191-a53f-284856f5db1d.png)
+
+### 国标 GB28181 级联
+
+上级平台注册、目录推送、通道关联与级联状态管理。
+
+![国标级联](images/e201c0b9-bf05-414b-b866-cdeb9eb73f9c.png)
+
+### 媒体节点
+
+管理 ZLMediaKit 流媒体节点,负载与推拉流能力集中配置。
+
+![媒体节点](images/2b5a0446-ed88-461d-b43d-973c5cb40ee9.png)
+
+### 设备报警
+
+告警列表、级别、处理状态,支持海康等 SDK 告警接入。
+
+![设备报警](images/d63233d6-863e-452a-802c-29a7d7775e4c.png)
+
+### 设备抓图
+
+手动 / 定时抓图记录,预览与导出。
+
+![设备抓图](images/10ae418a-8e41-4dc6-a999-cc950fe8da5d.png)
+
+### 组织结构(行政区划)
+
+按行政区域、业务分组管理设备,树形资源组 + 列表。
+
+![组织结构](images/402941a0-dba9-4411-943f-f95d5878f092.png)
+
+---
+
+## 典型使用流程
+
+```mermaid
+flowchart LR
+  A[部署 start.ps1] --> B[登录 admin]
+  B --> C[媒体节点配置 ZLM]
+  C --> D[设备管理添加摄像头]
+  D --> E[分屏监控预览]
+  D --> F[录像计划 / 云端录像]
+  D --> G[国标级联可选]
+  E --> H[告警 / 地图 / 回放]
+```
 
-## Badges
-On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
+1. **部署**:Docker 一键启动全部服务。  
+2. **配置流媒体**:在「媒体节点」添加 ZLMediaKit 地址(安装包需自行部署 ZLM,或使用已有节点)。  
+3. **接入设备**:在「设备管理」按协议添加 RTSP / 国标 / 车载等。  
+4. **日常监看**:「分屏监控」选设备播放;「电子地图」查看位置。  
+5. **录像与合规**:配置「录像计划」、在「云端录像 / 录像回放」检索历史。  
+6. **级联上级**:在「国标级联」配置上级平台参数(项目需要时)。
 
-## Visuals
-Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
+---
 
-## Installation
-Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
+## 常见问题
 
-## Usage
-Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
+| 问题 | 处理建议 |
+|------|----------|
+| 验证码无法显示 | `docker compose restart ruoyi-redis ruoyi-gateway` |
+| Nacos 启动失败 | 检查 `docker/.env` 中 `NACOS_AUTH_TOKEN` 是否配置 |
+| 网关日志连 127.0.0.1:8848 | 使用最新 `docker-compose` 与 `start.ps1` 重建网关 |
+| 海康 / 大华容器反复重启 | 默认未启用;需 `-WithVendorSdk` 且自备 SDK 库文件 |
+| 界面仍显示旧名称 / 蓝色主题 | 浏览器执行 `localStorage.removeItem('layout-setting'); location.reload()` |
+| 重新初始化数据库 | `.\start.ps1 -ResetDb`(会清空业务数据) |
 
-## Support
-Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
+---
 
-## Roadmap
-If you have ideas for releases in the future, it is a good idea to list them in the README.
+## 开源与社区
 
-## Contributing
-State if you are open to contributions and what your requirements are for accepting them.
+- 顶部导航 **「开源社区」** 跳转:[https://www.gitcc.com](https://www.gitcc.com)
+- 后端基于 [RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud) 微服务框架扩展
+- 本项目开源免费用于学习与企业内部部署;生产环境请自行评估安全、备份与网络隔离
 
-For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
+---
 
-You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
+## 许可证
 
-## Authors and acknowledgment
-Show your appreciation to those who have contributed to the project.
+请遵循各子项目及依赖组件的开源协议(RuoYi、ZLMediaKit、厂商 SDK 等)。厂商 SDK 版权归海康、大华等公司所有,部署时需遵守其授权条款。
 
-## License
-For open source projects, say how it is licensed.
+---
 
-## Project status
-If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
+<p align="center">云眼视频监控平台 · 让多源视频接入更简单</p>

BIN
images/10ae418a-8e41-4dc6-a999-cc950fe8da5d.png


BIN
images/2b5a0446-ed88-461d-b43d-973c5cb40ee9.png


BIN
images/402941a0-dba9-4411-943f-f95d5878f092.png


BIN
images/66e3542a-25da-4ad2-b9ef-a389eb0abcf2.png


BIN
images/6b06baf9-0968-4191-a53f-284856f5db1d.png


BIN
images/ac1e2edf-a67c-46a9-8e5b-ba8981ce9365.png


BIN
images/c09b4911-1cfe-4b73-a2d2-aabf16a70b0d.png


BIN
images/c4282592-c1c0-49f3-afd8-6d27a2ded4db.png


BIN
images/d63233d6-863e-452a-802c-29a7d7775e4c.png


BIN
images/e201c0b9-bf05-414b-b866-cdeb9eb73f9c.png


BIN
images/f761759c-0199-4cb5-9800-1d92b45cc24b.png


BIN
images/image.png


+ 46 - 0
ruoyi-qs-nvr-master/.gitignore

@@ -0,0 +1,46 @@
+######################################################################
+# Build Tools
+
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+######################################################################
+# IDE
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### JRebel ###
+rebel.xml
+### NetBeans ###
+nbproject/private/
+build/*
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+######################################################################
+# Others
+*.log
+*.xml.versionsBackup
+*.swp
+
+!*/build/*.java
+!*/build/*.html
+!*/build/*.xml

+ 14 - 0
ruoyi-qs-nvr-master/docker/.env.example

@@ -0,0 +1,14 @@
+# 复制为 .env 后使用:  copy .env.example .env
+# 切勿将含真实密码/Token 的 .env 提交到 Git
+
+COMPOSE_PROJECT_NAME=ruoyi-qs-nvr
+TZ=Asia/Shanghai
+MYSQL_ROOT_PASSWORD=password
+MYSQL_DATABASE=ry-cloud
+REDIS_PASSWORD=123456
+JAVA_OPTS=-Xms128m -Xmx384m -XX:+UseG1GC
+NACOS_SERVER_ADDR=ruoyi-nacos:8848
+# Nacos 3.x 必填:任意 32 字节以上的 Base64 字符串
+NACOS_AUTH_TOKEN=请替换为Base64编码的密钥
+NACOS_AUTH_IDENTITY_KEY=serverIdentity
+NACOS_AUTH_IDENTITY_VALUE=security

+ 96 - 0
ruoyi-qs-nvr-master/docker/copy.ps1

@@ -0,0 +1,96 @@
+# Copy backend JARs and SQL (frontend is built in nginx Dockerfile)
+param([switch]$SkipBuild)
+
+$ErrorActionPreference = "Stop"
+$DockerDir = $PSScriptRoot
+$BackendRoot = Join-Path $DockerDir ".."
+
+function Ensure-Dir([string]$Path) {
+    if (-not (Test-Path $Path)) { New-Item -ItemType Directory -Path $Path -Force | Out-Null }
+}
+
+Write-Host "=== SQL ===" -ForegroundColor Cyan
+$DbDir = Join-Path $DockerDir "mysql\db"
+Ensure-Dir $DbDir
+@(
+    @{ Out = "01-ry-config.sql"; Db = "ry-config"; Src = "sql\ry-config.sql" }
+    @{ Out = "02-ry-cloud.sql"; Db = "ry-cloud"; Src = "sql\ry-cloud.sql" }
+) | ForEach-Object {
+    $srcPath = Join-Path $BackendRoot $_.Src
+    if (-not (Test-Path $srcPath)) { throw "Missing: $srcPath" }
+    $lines = @("USE ``$($_.Db)``;"; "") + (Get-Content $srcPath -Encoding UTF8)
+    $lines | Set-Content (Join-Path $DbDir $_.Out) -Encoding UTF8
+    Write-Host ("OK: " + $_.Out)
+}
+
+if (-not $SkipBuild) {
+    Write-Host "=== Maven build ===" -ForegroundColor Cyan
+    if (-not (Get-Command mvn -ErrorAction SilentlyContinue)) {
+        throw "mvn not found. Install JDK 17 and Maven."
+    }
+    Push-Location $BackendRoot
+    try {
+        mvn clean package -DskipTests -T 1C
+        if ($LASTEXITCODE -ne 0) { throw "Maven build failed" }
+    } finally {
+        Pop-Location
+    }
+}
+
+Write-Host "=== JARs ===" -ForegroundColor Cyan
+$jars = @(
+    @{ Src = "ruoyi-gateway\target\ruoyi-gateway.jar"; Dest = "ruoyi\gateway\jar" }
+    @{ Src = "ruoyi-auth\target\ruoyi-auth.jar"; Dest = "ruoyi\auth\jar" }
+    @{ Src = "ruoyi-visual\ruoyi-monitor\target\ruoyi-visual-monitor.jar"; Dest = "ruoyi\visual\monitor\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-system\target\ruoyi-modules-system.jar"; Dest = "ruoyi\modules\system\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-file\target\ruoyi-modules-file.jar"; Dest = "ruoyi\modules\file\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-job\target\ruoyi-modules-job.jar"; Dest = "ruoyi\modules\job\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-gen\target\ruoyi-modules-gen.jar"; Dest = "ruoyi\modules\gen\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-haikang\target\ruoyi-modules-haikang.jar"; Dest = "ruoyi\modules\haikang\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-qs\target\ruoyi-modules-qs.jar"; Dest = "ruoyi\modules\qs\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-haikang-isup\target\ruoyi-modules-haikang-isup.jar"; Dest = "ruoyi\modules\haikang-isup\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-dahua\target\ruoyi-modules-dahua.jar"; Dest = "ruoyi\modules\dahua\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-onvif\target\ruoyi-modules-onvif.jar"; Dest = "ruoyi\modules\onvif\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-gb28181\target\ruoyi-modules-gb28181.jar"; Dest = "ruoyi\modules\gb28181\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-jt1078\target\ruoyi-modules-jt1078.jar"; Dest = "ruoyi\modules\jt1078\jar" }
+    @{ Src = "ruoyi-modules\ruoyi-zlm\target\ruoyi-modules-zlm.jar"; Dest = "ruoyi\modules\zlm\jar" }
+)
+
+$missing = [System.Collections.Generic.List[string]]::new()
+$copied = 0
+foreach ($item in $jars) {
+    $src = Join-Path $BackendRoot $item.Src
+    $destDir = Join-Path $DockerDir $item.Dest
+    if (-not (Test-Path $src)) {
+        $missing.Add($item.Src)
+        continue
+    }
+    Ensure-Dir $destDir
+    $jarName = Split-Path $src -Leaf
+    Copy-Item $src (Join-Path $destDir $jarName) -Force
+    Write-Host ("OK: " + $jarName)
+    $copied++
+}
+
+if ($copied -eq 0) {
+    Write-Host ""
+    Write-Host "No JAR files found. Run full build first:" -ForegroundColor Red
+    Write-Host "  .\start.ps1" -ForegroundColor Yellow
+    Write-Host "or:" -ForegroundColor Yellow
+    Write-Host "  cd .." -ForegroundColor Yellow
+    Write-Host "  mvn clean package -DskipTests" -ForegroundColor Yellow
+    if ($missing.Count -gt 0) {
+        Write-Host ""
+        Write-Host "Missing:" -ForegroundColor Red
+        $missing | ForEach-Object { Write-Host ("  - " + $_) }
+    }
+    throw "No JAR copied."
+}
+
+if ($missing.Count -gt 0) {
+    Write-Host ""
+    Write-Host ("Warning: " + $missing.Count + " JAR(s) missing (optional modules may be skipped):") -ForegroundColor Yellow
+    $missing | ForEach-Object { Write-Host ("  - " + $_) }
+}
+
+Write-Host ("Done. Copied " + $copied + " JAR(s).") -ForegroundColor Green

+ 29 - 0
ruoyi-qs-nvr-master/docker/copy.sh

@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# 复制构建产物到 docker 目录(后端 JAR + SQL)
+# 前端已在 docker/nginx/Dockerfile 多阶段构建,无需手动复制 dist
+
+echo "begin copy sql"
+echo "USE \`ry-config\`;" > ./mysql/db/01-ry-config.sql
+cat ../sql/ry-config.sql >> ./mysql/db/01-ry-config.sql
+echo "USE \`ry-cloud\`;" > ./mysql/db/02-ry-cloud.sql
+cat ../sql/ry-cloud.sql >> ./mysql/db/02-ry-cloud.sql
+
+echo "begin copy jars"
+cp ../ruoyi-gateway/target/ruoyi-gateway.jar ./ruoyi/gateway/jar
+cp ../ruoyi-auth/target/ruoyi-auth.jar ./ruoyi/auth/jar
+cp ../ruoyi-visual/ruoyi-monitor/target/ruoyi-visual-monitor.jar ./ruoyi/visual/monitor/jar
+cp ../ruoyi-modules/ruoyi-system/target/ruoyi-modules-system.jar ./ruoyi/modules/system/jar
+cp ../ruoyi-modules/ruoyi-file/target/ruoyi-modules-file.jar ./ruoyi/modules/file/jar
+cp ../ruoyi-modules/ruoyi-job/target/ruoyi-modules-job.jar ./ruoyi/modules/job/jar
+cp ../ruoyi-modules/ruoyi-gen/target/ruoyi-modules-gen.jar ./ruoyi/modules/gen/jar
+cp ../ruoyi-modules/ruoyi-haikang/target/ruoyi-modules-haikang.jar ./ruoyi/modules/haikang/jar
+cp ../ruoyi-modules/ruoyi-qs/target/ruoyi-modules-qs.jar ./ruoyi/modules/qs/jar
+cp ../ruoyi-modules/ruoyi-haikang-isup/target/ruoyi-modules-haikang-isup.jar ./ruoyi/modules/haikang-isup/jar
+cp ../ruoyi-modules/ruoyi-dahua/target/ruoyi-modules-dahua.jar ./ruoyi/modules/dahua/jar
+cp ../ruoyi-modules/ruoyi-onvif/target/ruoyi-modules-onvif.jar ./ruoyi/modules/onvif/jar
+cp ../ruoyi-modules/ruoyi-gb28181/target/ruoyi-modules-gb28181.jar ./ruoyi/modules/gb28181/jar
+cp ../ruoyi-modules/ruoyi-jt1078/target/ruoyi-modules-jt1078.jar ./ruoyi/modules/jt1078/jar
+cp ../ruoyi-modules/ruoyi-zlm/target/ruoyi-modules-zlm.jar ./ruoyi/modules/zlm/jar
+
+echo "done"

+ 75 - 0
ruoyi-qs-nvr-master/docker/deploy.sh

@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# 使用说明,用来提示输入参数
+usage() {
+	echo "Usage: sh 执行脚本.sh [port|base|modules|stop|rm]"
+	exit 1
+}
+
+# 开启所需端口
+port(){
+	firewall-cmd --add-port=80/tcp --permanent
+	firewall-cmd --add-port=8080/tcp --permanent
+	firewall-cmd --add-port=8848/tcp --permanent
+	firewall-cmd --add-port=9848/tcp --permanent
+	firewall-cmd --add-port=9849/tcp --permanent
+	firewall-cmd --add-port=6379/tcp --permanent
+	firewall-cmd --add-port=3306/tcp --permanent
+	firewall-cmd --add-port=8090/tcp --permanent
+	firewall-cmd --add-port=9100/tcp --permanent
+	firewall-cmd --add-port=9200/tcp --permanent
+	firewall-cmd --add-port=9201/tcp --permanent
+	firewall-cmd --add-port=9202/tcp --permanent
+	firewall-cmd --add-port=9203/tcp --permanent
+	firewall-cmd --add-port=9204/tcp --permanent
+	firewall-cmd --add-port=9205/tcp --permanent
+	firewall-cmd --add-port=9206/tcp --permanent
+	firewall-cmd --add-port=9207/tcp --permanent
+	firewall-cmd --add-port=9208/tcp --permanent
+	firewall-cmd --add-port=9209/tcp --permanent
+	firewall-cmd --add-port=9210/tcp --permanent
+	firewall-cmd --add-port=9300/tcp --permanent
+	service firewalld restart
+}
+
+# 启动基础环境(必须)
+base(){
+	docker-compose up -d ruoyi-mysql ruoyi-redis ruoyi-nacos
+}
+
+# 启动程序模块(必须)
+modules(){
+	docker-compose up -d ruoyi-nginx ruoyi-gateway ruoyi-auth ruoyi-modules-system ruoyi-modules-gen ruoyi-modules-job ruoyi-modules-file ruoyi-visual-monitor ruoyi-modules-haikang ruoyi-modules-qs ruoyi-modules-haikang-isup ruoyi-modules-dahua ruoyi-modules-onvif ruoyi-modules-gb28181 ruoyi-modules-jt1078 ruoyi-modules-zlm
+}
+
+# 关闭所有环境/模块
+stop(){
+	docker-compose stop
+}
+
+# 删除所有环境/模块
+rm(){
+	docker-compose rm
+}
+
+# 根据输入参数,选择执行对应方法,不输入则执行使用说明
+case "$1" in
+"port")
+	port
+;;
+"base")
+	base
+;;
+"modules")
+	modules
+;;
+"stop")
+	stop
+;;
+"rm")
+	rm
+;;
+*)
+	usage
+;;
+esac

+ 421 - 0
ruoyi-qs-nvr-master/docker/docker-compose.yml

@@ -0,0 +1,421 @@
+# 云眼视频监控平台 一键部署:MySQL + Redis + Nacos + 全部后端微服务 + 前端(Nginx)
+# 启动:在 docker 目录执行  .\start.ps1  或  .\start.bat
+
+name: ruoyi-qs-nvr
+
+x-java-env: &java-env
+  TZ: ${TZ:-Asia/Shanghai}
+  JAVA_OPTS: ${JAVA_OPTS:--Xms128m -Xmx384m -XX:+UseG1GC}
+  NACOS_SERVER_ADDR: ${NACOS_SERVER_ADDR:-ruoyi-nacos:8848}
+  # bootstrap.yml 写死 127.0.0.1 时,SPRING_CLOUD_NACOS_* 无法生效;用 JVM -D 强制覆盖
+  NACOS_JAVA_OPTS: >-
+    -Dspring.cloud.nacos.discovery.server-addr=${NACOS_SERVER_ADDR:-ruoyi-nacos:8848}
+    -Dspring.cloud.nacos.config.server-addr=${NACOS_SERVER_ADDR:-ruoyi-nacos:8848}
+  # Docker 未部署 Sentinel 控制台,关闭 eager 避免连 127.0.0.1:8718 刷错
+  SPRING_CLOUD_SENTINEL_EAGER: "false"
+  SENTINEL_EAGER: "false"
+  # 未部署 Sentinel 控制台时,避免 actuator 周期性 WARN
+  MANAGEMENT_HEALTH_SENTINEL_ENABLED: "false"
+  SPRING_PROFILES_ACTIVE: dev
+
+services:
+  ruoyi-mysql:
+    container_name: ruoyi-mysql
+    image: mysql:5.7
+    build:
+      context: ./mysql
+    restart: unless-stopped
+    ports:
+      - "3306:3306"
+    environment:
+      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-password}
+      MYSQL_DATABASE: ${MYSQL_DATABASE:-ry-cloud}
+      TZ: ${TZ:-Asia/Shanghai}
+    volumes:
+      - ./mysql/conf:/etc/mysql/conf.d
+      - ./mysql/logs:/logs
+      - ./mysql/data:/var/lib/mysql
+    command:
+      - mysqld
+      - --innodb-buffer-pool-size=128M
+      - --character-set-server=utf8mb4
+      - --collation-server=utf8mb4_unicode_ci
+      - --default-time-zone=+8:00
+      - --lower-case-table-names=1
+    networks:
+      - ruoyi-net
+    healthcheck:
+      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p${MYSQL_ROOT_PASSWORD:-password}"]
+      interval: 10s
+      timeout: 5s
+      retries: 15
+      start_period: 40s
+
+  ruoyi-redis:
+    container_name: ruoyi-redis
+    image: redis:7-alpine
+    build:
+      context: ./redis
+    restart: unless-stopped
+    ports:
+      - "6379:6379"
+    volumes:
+      - ./redis/conf/redis.conf:/home/ruoyi/redis/redis.conf
+      - ./redis/data:/data
+    command: redis-server /home/ruoyi/redis/redis.conf --dir /data
+    networks:
+      - ruoyi-net
+    healthcheck:
+      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-123456}", "ping"]
+      interval: 10s
+      timeout: 5s
+      retries: 8
+
+  ruoyi-nacos:
+    container_name: ruoyi-nacos
+    image: nacos/nacos-server:v3.0.2
+    build:
+      context: ./nacos
+    restart: unless-stopped
+    environment:
+      MODE: standalone
+      TZ: ${TZ:-Asia/Shanghai}
+      # Nacos 3.x 启动必填(即使关闭鉴权也需 Base64 Token)
+      NACOS_AUTH_ENABLE: "false"
+      NACOS_AUTH_TOKEN: ${NACOS_AUTH_TOKEN:-U2VjcmV0S2V5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OQ==}
+      NACOS_AUTH_IDENTITY_KEY: ${NACOS_AUTH_IDENTITY_KEY:-serverIdentity}
+      NACOS_AUTH_IDENTITY_VALUE: ${NACOS_AUTH_IDENTITY_VALUE:-security}
+      JVM_XMS: 256m
+      JVM_XMX: 512m
+      JVM_XMN: 128m
+    volumes:
+      - ./nacos/logs:/home/nacos/logs
+      - ./nacos/conf/application.properties:/home/nacos/conf/application.properties
+    ports:
+      - "8848:8848"
+      - "9848:9848"
+      - "9849:9849"
+    depends_on:
+      ruoyi-mysql:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+    healthcheck:
+      test: ["CMD-SHELL", "curl -sf http://127.0.0.1:8848/nacos/actuator/health | grep -q UP"]
+      interval: 15s
+      timeout: 10s
+      retries: 25
+      start_period: 120s
+
+  ruoyi-gateway:
+    container_name: ruoyi-gateway
+    build:
+      context: ./ruoyi/gateway
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "8080:8080"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-auth:
+    container_name: ruoyi-auth
+    build:
+      context: ./ruoyi/auth
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9200:9200"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-system:
+    container_name: ruoyi-modules-system
+    build:
+      context: ./ruoyi/modules/system
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9201:9201"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-gen:
+    container_name: ruoyi-modules-gen
+    build:
+      context: ./ruoyi/modules/gen
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9202:9202"
+    depends_on:
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-job:
+    container_name: ruoyi-modules-job
+    build:
+      context: ./ruoyi/modules/job
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9203:9203"
+    depends_on:
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-file:
+    container_name: ruoyi-modules-file
+    build:
+      context: ./ruoyi/modules/file
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9300:9300"
+    volumes:
+      - ./ruoyi/uploadPath:/home/ruoyi/uploadPath
+    depends_on:
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-visual-monitor:
+    container_name: ruoyi-visual-monitor
+    build:
+      context: ./ruoyi/visual/monitor
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9100:9100"
+    depends_on:
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-qs:
+    container_name: ruoyi-modules-qs
+    build:
+      context: ./ruoyi/modules/qs
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9205:9205"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-zlm:
+    container_name: ruoyi-modules-zlm
+    build:
+      context: ./ruoyi/modules/zlm
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "8090:8090"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-gb28181:
+    container_name: ruoyi-modules-gb28181
+    build:
+      context: ./ruoyi/modules/gb28181
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9209:9209"
+      - "8116:8116/tcp"
+      - "8116:8116/udp"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-onvif:
+    container_name: ruoyi-modules-onvif
+    build:
+      context: ./ruoyi/modules/onvif
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9208:9208"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-jt1078:
+    container_name: ruoyi-modules-jt1078
+    build:
+      context: ./ruoyi/modules/jt1078
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9210:9210"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-haikang:
+    profiles: ["vendor-sdk"]
+    container_name: ruoyi-modules-haikang
+    build:
+      context: ./ruoyi/modules/haikang
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9204:9204"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-haikang-isup:
+    profiles: ["vendor-sdk"]
+    container_name: ruoyi-modules-haikang-isup
+    build:
+      context: ./ruoyi/modules/haikang-isup
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9206:9206"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  ruoyi-modules-dahua:
+    profiles: ["vendor-sdk"]
+    container_name: ruoyi-modules-dahua
+    build:
+      context: ./ruoyi/modules/dahua
+      dockerfile: dockerfile
+    restart: unless-stopped
+    environment:
+      <<: *java-env
+    ports:
+      - "9207:9207"
+    depends_on:
+      ruoyi-redis:
+        condition: service_healthy
+      ruoyi-mysql:
+        condition: service_healthy
+      ruoyi-nacos:
+        condition: service_healthy
+    networks:
+      - ruoyi-net
+
+  # 前端 + 反向代理(容器内 npm build,无需本机 Node)
+  ruoyi-nginx:
+    container_name: ruoyi-nginx
+    build:
+      context: ../..
+      dockerfile: ruoyi-qs-nvr-master/docker/nginx/Dockerfile
+    restart: unless-stopped
+    ports:
+      - "80:80"
+    volumes:
+      - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
+      - ./nginx/logs:/var/log/nginx
+    depends_on:
+      - ruoyi-gateway
+      - ruoyi-modules-file
+    networks:
+      - ruoyi-net
+
+networks:
+  ruoyi-net:
+    driver: bridge

+ 2 - 0
ruoyi-qs-nvr-master/docker/mysql/db/00-init-databases.sql

@@ -0,0 +1,2 @@
+CREATE DATABASE IF NOT EXISTS `ry-config` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+CREATE DATABASE IF NOT EXISTS `ry-cloud` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Разница между файлами не показана из-за своего большого размера
+ 51 - 0
ruoyi-qs-nvr-master/docker/mysql/db/01-ry-config.sql


Разница между файлами не показана из-за своего большого размера
+ 1357 - 0
ruoyi-qs-nvr-master/docker/mysql/db/02-ry-cloud.sql


+ 7 - 0
ruoyi-qs-nvr-master/docker/mysql/db/03-docker-nacos-override.sql

@@ -0,0 +1,7 @@
+USE `ry-config`;
+
+UPDATE `config_info` SET `content` = REPLACE(`content`, 'host: localhost', 'host: ruoyi-redis') WHERE `content` LIKE '%host: localhost%';
+UPDATE `config_info` SET `content` = REPLACE(`content`, 'jdbc:mysql://localhost:3306', 'jdbc:mysql://ruoyi-mysql:3306') WHERE `content` LIKE '%jdbc:mysql://localhost:3306%';
+UPDATE `config_info` SET `content` = REPLACE(`content`, 'password: haoxin', 'password: password') WHERE `content` LIKE '%password: haoxin%';
+UPDATE `config_info` SET `content` = REPLACE(`content`, 'path: D:/ruoyi/uploadPath', 'path: /home/ruoyi/uploadPath') WHERE `content` LIKE '%path: D:/ruoyi/uploadPath%';
+UPDATE `config_info` SET `content` = REPLACE(`content`, 'domain: http://127.0.0.1:9300', 'domain: http://localhost:9300') WHERE `content` LIKE '%domain: http://127.0.0.1:9300%';

+ 3 - 0
ruoyi-qs-nvr-master/docker/mysql/db/04-rebrand-notice.sql

@@ -0,0 +1,3 @@
+-- 已有数据库升级:同步系统公告标题为新品牌名
+USE `ry-cloud`;
+UPDATE `sys_notice` SET `notice_title` = '云眼视频监控平台' WHERE `notice_id` = 1;

+ 1 - 0
ruoyi-qs-nvr-master/docker/mysql/db/readme.txt

@@ -0,0 +1 @@
+存放sql目录下的所有脚本,用于docker自动执行。

+ 7 - 0
ruoyi-qs-nvr-master/docker/mysql/dockerfile

@@ -0,0 +1,7 @@
+# 基础镜像
+FROM mysql:5.7
+# author
+MAINTAINER ruoyi
+
+# 执行sql脚本
+ADD ./db/*.sql /docker-entrypoint-initdb.d/

+ 33 - 0
ruoyi-qs-nvr-master/docker/nacos/conf/application.properties

@@ -0,0 +1,33 @@
+spring.datasource.platform=mysql
+db.num=1
+db.url.0=jdbc:mysql://ruoyi-mysql:3306/ry-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
+db.user=root
+db.password=password
+
+nacos.naming.empty-service.auto-clean=true
+nacos.naming.empty-service.clean.initial-delay-ms=50000
+nacos.naming.empty-service.clean.period-time-ms=30000
+
+management.endpoints.web.exposure.include=*
+
+management.metrics.export.elastic.enabled=false
+management.metrics.export.influx.enabled=false
+
+server.tomcat.accesslog.enabled=true
+server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
+
+server.tomcat.basedir=/home/ruoyi/nacos/tomcat/logs
+
+nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
+
+nacos.core.auth.system.type=nacos
+nacos.core.auth.enabled=false
+nacos.core.auth.default.token.expire.seconds=18000
+nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
+nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
+nacos.core.auth.caching.enabled=true
+nacos.core.auth.enable.userAgentAuthWhite=false
+nacos.core.auth.server.identity.key=serverIdentity
+nacos.core.auth.server.identity.value=security
+
+nacos.istio.mcp.server.enabled=false

+ 2 - 0
ruoyi-qs-nvr-master/docker/nacos/dockerfile

@@ -0,0 +1,2 @@
+FROM nacos/nacos-server:v3.0.2
+COPY ./conf/application.properties /home/nacos/conf/application.properties

+ 72 - 0
ruoyi-qs-nvr-master/docker/nginx/conf/nginx.conf

@@ -0,0 +1,72 @@
+worker_processes  auto;
+
+events {
+    worker_connections  2048;
+}
+
+http {
+    include       mime.types;
+    default_type  application/octet-stream;
+    sendfile        on;
+    keepalive_timeout  65;
+    client_max_body_size 1024m;
+    gzip on;
+    gzip_min_length 1k;
+    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss;
+
+    upstream ruoyi_gateway {
+        server ruoyi-gateway:8080;
+    }
+
+    upstream ruoyi_file {
+        server ruoyi-modules-file:9300;
+    }
+
+    server {
+        listen       80;
+        server_name  localhost;
+
+        root /home/ruoyi/projects/ruoyi-ui;
+        index index.html index.htm;
+
+        location / {
+            try_files $uri $uri/ /index.html;
+        }
+
+        # 前端 API(VITE_APP_BASE_API=/prod-api)
+        location /prod-api/ {
+            proxy_http_version 1.1;
+            proxy_set_header Host $http_host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_set_header X-Forwarded-Proto $scheme;
+            proxy_set_header Upgrade $http_upgrade;
+            proxy_set_header Connection "upgrade";
+            proxy_read_timeout 3600s;
+            proxy_send_timeout 3600s;
+            proxy_pass http://ruoyi_gateway/;
+        }
+
+        # 文件服务静态资源(截图、告警图等)
+        location /statics/ {
+            proxy_set_header Host $http_host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_pass http://ruoyi_file/statics/;
+        }
+
+        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|map)$ {
+            expires 7d;
+            add_header Cache-Control "public, immutable";
+            try_files $uri =404;
+        }
+
+        if ($uri ~ "/actuator") {
+            return 403;
+        }
+
+        error_page   500 502 503 504  /50x.html;
+        location = /50x.html {
+            root   /usr/share/nginx/html;
+        }
+    }
+}

+ 24 - 0
ruoyi-qs-nvr-master/docker/nginx/dockerfile

@@ -0,0 +1,24 @@
+# ??1??????????ruoyi-qs-nvr-ui?
+FROM node:20-alpine AS ui-builder
+
+WORKDIR /ui
+
+COPY ruoyi-qs-nvr-ui-master/package.json ./
+RUN npm install --registry=https://registry.npmmirror.com
+
+COPY ruoyi-qs-nvr-ui-master/ .
+
+# ???? API ?? /prod-api?? Nginx ??? gateway
+RUN npm run build:prod
+
+# ??2?Nginx ??????
+FROM nginx:1.27-alpine
+
+RUN mkdir -p /home/ruoyi/projects/ruoyi-ui /var/log/nginx
+
+COPY ruoyi-qs-nvr-master/docker/nginx/conf/nginx.conf /etc/nginx/nginx.conf
+COPY --from=ui-builder /ui/dist /home/ruoyi/projects/ruoyi-ui
+
+EXPOSE 80
+
+CMD ["nginx", "-g", "daemon off;"]

+ 5 - 0
ruoyi-qs-nvr-master/docker/redis/conf/redis.conf

@@ -0,0 +1,5 @@
+# Docker 环境:数据目录使用可写卷 /data(勿与只读挂载的 conf 目录混用)
+dir /data
+requirepass 123456
+# Windows 卷权限异常时避免阻塞写入(验证码、会话等依赖 Redis 写)
+stop-writes-on-bgsave-error no

+ 12 - 0
ruoyi-qs-nvr-master/docker/redis/dockerfile

@@ -0,0 +1,12 @@
+# 基础镜�
+FROM redis
+# author
+MAINTAINER ruoyi
+
+# 挂载目录
+VOLUME /home/ruoyi/redis
+# 创建目录
+RUN mkdir -p /home/ruoyi/redis
+# 指定路径
+WORKDIR /home/ruoyi/redis
+# �制conf文件到路�COPY ./conf/redis.conf /home/ruoyi/redis/redis.conf

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/auth/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-auth.jar /home/ruoyi/ruoyi-auth.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-auth.jar"]

+ 1 - 0
ruoyi-qs-nvr-master/docker/ruoyi/auth/jar/readme.txt

@@ -0,0 +1 @@
+存放认证中心打包好的jar文件,用于docker启动应用。

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/gateway/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-gateway.jar /home/ruoyi/ruoyi-gateway.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -Dspring.cloud.sentinel.datasource.ds1.nacos.server-addr=${NACOS_SERVER_ADDR:-ruoyi-nacos:8848} -jar /home/ruoyi/ruoyi-gateway.jar"]

+ 1 - 0
ruoyi-qs-nvr-master/docker/ruoyi/gateway/jar/readme.txt

@@ -0,0 +1 @@
+存放网关模块打包好的jar文件,用于docker启动应用。

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/dahua/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-dahua.jar /home/ruoyi/ruoyi-modules-dahua.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-dahua.jar"]

+ 2 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/dahua/jar/readme.txt

@@ -0,0 +1,2 @@
+
+大华sdk服务jar包存放目录

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/file/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-file.jar /home/ruoyi/ruoyi-modules-file.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-file.jar"]

+ 1 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/file/jar/readme.txt

@@ -0,0 +1 @@
+存放文件服务打包好的jar文件,用于docker启动应用。

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/gb28181/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-gb28181.jar /home/ruoyi/ruoyi-modules-gb28181.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-gb28181.jar"]

+ 2 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/gb28181/jar/readme.txt

@@ -0,0 +1,2 @@
+
+国标服务jar包存放目录

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/gen/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-gen.jar /home/ruoyi/ruoyi-modules-gen.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-gen.jar"]

+ 1 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/gen/jar/readme.txt

@@ -0,0 +1 @@
+存放代码生成打包好的jar文件,用于docker启动应用。

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/haikang-isup/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-haikang-isup.jar /home/ruoyi/ruoyi-modules-haikang-isup.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-haikang-isup.jar"]

+ 2 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/haikang-isup/jar/readme.txt

@@ -0,0 +1,2 @@
+
+海康isup服务jar包存放目录

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/haikang/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-haikang.jar /home/ruoyi/ruoyi-modules-haikang.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-haikang.jar"]

+ 2 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/haikang/jar/readme.txt

@@ -0,0 +1,2 @@
+
+海康服务jar包存放目录

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/job/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-job.jar /home/ruoyi/ruoyi-modules-job.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-job.jar"]

+ 1 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/job/jar/readme.txt

@@ -0,0 +1 @@
+存放定时任务打包好的jar文件,用于docker启动应用。

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/jt1078/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-jt1078.jar /home/ruoyi/ruoyi-modules-jt1078.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-jt1078.jar"]

+ 2 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/jt1078/jar/readme.txt

@@ -0,0 +1,2 @@
+
+jt1078服务jar包存放目录

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/onvif/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-onvif.jar /home/ruoyi/ruoyi-modules-onvif.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-onvif.jar"]

+ 2 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/onvif/jar/readme.txt

@@ -0,0 +1,2 @@
+
+onvif服务jar包存放目录

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/qs/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-qs.jar /home/ruoyi/ruoyi-modules-qs.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-qs.jar"]

+ 2 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/qs/jar/readme.txt

@@ -0,0 +1,2 @@
+
+泉视服务jar包存放目录

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/system/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-system.jar /home/ruoyi/ruoyi-modules-system.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-system.jar"]

+ 1 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/system/jar/readme.txt

@@ -0,0 +1 @@
+存放系统模块打包好的jar文件,用于docker启动应用。

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/zlm/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-modules-zlm.jar /home/ruoyi/ruoyi-modules-zlm.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-modules-zlm.jar"]

+ 2 - 0
ruoyi-qs-nvr-master/docker/ruoyi/modules/zlm/jar/readme.txt

@@ -0,0 +1,2 @@
+
+zlm服务jar包存放目录

+ 5 - 0
ruoyi-qs-nvr-master/docker/ruoyi/visual/monitor/dockerfile

@@ -0,0 +1,5 @@
+FROM eclipse-temurin:17-jre
+WORKDIR /home/ruoyi
+RUN mkdir -p /home/ruoyi
+COPY ./jar/ruoyi-visual-monitor.jar /home/ruoyi/ruoyi-visual-monitor.jar
+ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS $NACOS_JAVA_OPTS -jar /home/ruoyi/ruoyi-visual-monitor.jar"]

+ 1 - 0
ruoyi-qs-nvr-master/docker/ruoyi/visual/monitor/jar/readme.txt

@@ -0,0 +1 @@
+存放监控中心打包好的jar文件,用于docker启动应用。

+ 10 - 0
ruoyi-qs-nvr-master/docker/start.bat

@@ -0,0 +1,10 @@
+@echo off
+chcp 65001 >nul
+cd /d "%~dp0"
+powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0start.ps1" %*
+if errorlevel 1 (
+    echo.
+    echo Start failed. See errors above.
+    pause
+    exit /b 1
+)

+ 122 - 0
ruoyi-qs-nvr-master/docker/start.ps1

@@ -0,0 +1,122 @@
+# One-click: Maven build -> copy JARs/SQL -> docker compose up (frontend + all backend)
+param(
+    [switch]$SkipBuild,
+    [switch]$NoImageBuild,
+    [switch]$ResetDb,
+    [switch]$Rebuild,
+    [switch]$WithVendorSdk
+)
+if ($Rebuild) { $NoImageBuild = $false }
+
+$ErrorActionPreference = "Stop"
+$DockerDir = $PSScriptRoot
+$BackendRoot = Join-Path $DockerDir ".."
+
+function Test-DockerRunning {
+    if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
+        throw "Docker not found. Install Docker Desktop."
+    }
+    docker info 2>&1 | Out-Null
+    if ($LASTEXITCODE -ne 0) {
+        throw "Docker is not running. Start Docker Desktop first."
+    }
+}
+
+Write-Host ""
+Write-Host "========================================" -ForegroundColor Cyan
+Write-Host " YunYan Video Monitor - One Click Start" -ForegroundColor Cyan
+Write-Host " Frontend (Nginx) + All Backend Services" -ForegroundColor Cyan
+Write-Host "========================================" -ForegroundColor Cyan
+Write-Host ""
+
+Test-DockerRunning
+
+if ($ResetDb) {
+    Write-Host "[1/4] Reset MySQL data volume..." -ForegroundColor Yellow
+    $mysqlData = Join-Path $DockerDir "mysql\data"
+    if (Test-Path $mysqlData) {
+        Remove-Item $mysqlData -Recurse -Force
+        Write-Host "      Removed mysql\data" -ForegroundColor Yellow
+    }
+} else {
+    Write-Host "[1/4] Skip DB reset (use -ResetDb to re-init)" -ForegroundColor DarkGray
+}
+
+if (-not $SkipBuild) {
+    Write-Host "[2/4] Maven build all backend modules..." -ForegroundColor Green
+    if (-not (Get-Command mvn -ErrorAction SilentlyContinue)) {
+        throw "mvn not found. Install JDK 17 and Maven."
+    }
+    Push-Location $BackendRoot
+    try {
+        mvn clean package -DskipTests -T 1C
+        if ($LASTEXITCODE -ne 0) { throw "Maven build failed" }
+    } finally {
+        Pop-Location
+    }
+} else {
+    Write-Host "[2/4] Skip Maven (-SkipBuild)" -ForegroundColor DarkGray
+}
+
+Write-Host "[3/4] Copy JARs and SQL..." -ForegroundColor Green
+& (Join-Path $DockerDir "copy.ps1") -SkipBuild
+if ($LASTEXITCODE -ne 0) { throw "copy.ps1 failed" }
+
+Write-Host "[4/4] Docker compose up (build images)..." -ForegroundColor Green
+Push-Location $DockerDir
+try {
+    New-Item -ItemType Directory -Force -Path (Join-Path $DockerDir "ruoyi\uploadPath") | Out-Null
+
+    $composeArgs = @("compose", "--env-file", ".env", "up", "-d")
+    if (-not $NoImageBuild) {
+        $composeArgs += "--build"
+    }
+    if ($WithVendorSdk) {
+        $composeArgs += "--profile"
+        $composeArgs += "vendor-sdk"
+        Write-Host "      vendor-sdk: Hikvision/Dahua (requires vendor .so/.dll under ruoyi-modules/*/lib)" -ForegroundColor Yellow
+    } else {
+        Write-Host "      Default: skip Hikvision/Dahua SDK containers (no native libs in image)." -ForegroundColor DarkGray
+    }
+
+    & docker @composeArgs
+    if ($LASTEXITCODE -ne 0) { throw "docker compose failed" }
+
+    Write-Host ""
+    Write-Host "Waiting for core services (60-120s)..." -ForegroundColor Yellow
+    $deadline = (Get-Date).AddMinutes(8)
+    $ready = $false
+    while ((Get-Date) -lt $deadline) {
+        $nacos = docker inspect --format='{{.State.Health.Status}}' ruoyi-nacos 2>$null
+        $gw = docker inspect --format='{{.State.Status}}' ruoyi-gateway 2>$null
+        $ngx = docker inspect --format='{{.State.Status}}' ruoyi-nginx 2>$null
+        if ($nacos -eq "healthy" -and $gw -eq "running" -and $ngx -eq "running") {
+            $ready = $true
+            break
+        }
+        Start-Sleep -Seconds 5
+        Write-Host "  ... nacos=$nacos gateway=$gw nginx=$ngx" -ForegroundColor DarkGray
+    }
+} finally {
+    Pop-Location
+}
+
+Write-Host ""
+Write-Host "========================================" -ForegroundColor Green
+if ($ready) {
+    Write-Host " Ready" -ForegroundColor Green
+} else {
+    Write-Host " Containers started; some may still be booting" -ForegroundColor Yellow
+    Write-Host " Check: docker compose ps" -ForegroundColor Yellow
+}
+Write-Host "========================================" -ForegroundColor Green
+Write-Host " Web UI   : http://localhost"
+Write-Host " Gateway  : http://localhost:8080"
+Write-Host " Nacos    : http://localhost:8848/nacos"
+Write-Host " Login    : admin / admin123"
+Write-Host ""
+Write-Host " Stop     : .\stop.ps1"
+Write-Host " Restart  : .\start.ps1 -SkipBuild -NoImageBuild"
+Write-Host " Hik/Dahua: .\start.ps1 -WithVendorSdk (Windows native SDK only)"
+Write-Host "========================================"
+Write-Host ""

+ 4 - 0
ruoyi-qs-nvr-master/docker/stop.bat

@@ -0,0 +1,4 @@
+@echo off
+chcp 65001 >nul
+cd /d "%~dp0"
+powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0stop.ps1"

+ 8 - 0
ruoyi-qs-nvr-master/docker/stop.ps1

@@ -0,0 +1,8 @@
+$ErrorActionPreference = "Stop"
+Push-Location $PSScriptRoot
+try {
+    docker compose --env-file .env down
+    Write-Host "All services stopped (frontend + backend)." -ForegroundColor Green
+} finally {
+    Pop-Location
+}

+ 348 - 0
ruoyi-qs-nvr-master/pom.xml

@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.ruoyi</groupId>
+    <artifactId>ruoyi</artifactId>
+    <version>3.6.7</version>
+
+    <name>ruoyi</name>
+    <url>http://www.ruoyi.vip</url>
+    <description>若依微服务系统</description>
+
+    <properties>
+        <ruoyi.version>3.6.7</ruoyi.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>17</java.version>
+        <spring-boot.version>3.5.11</spring-boot.version>
+        <spring-cloud.version>2025.0.1</spring-cloud.version>
+        <spring-cloud-alibaba.version>2025.0.0.0</spring-cloud-alibaba.version>
+        <spring-boot-admin.version>3.5.8</spring-boot-admin.version>
+        <mybatis-spring.version>3.0.5</mybatis-spring.version>
+        <kaptcha.version>2.3.3</kaptcha.version>
+        <pagehelper.boot.version>2.1.0</pagehelper.boot.version>
+        <druid.version>1.2.27</druid.version>
+        <dynamic-ds.version>4.5.0</dynamic-ds.version>
+        <commons.io.version>2.21.0</commons.io.version>
+        <velocity.version>2.3</velocity.version>
+        <fastjson.version>2.0.61</fastjson.version>
+        <jjwt.version>0.9.1</jjwt.version>
+        <minio.version>8.2.2</minio.version>
+        <poi.version>4.1.2</poi.version>
+        <springdoc.version>2.8.16</springdoc.version>
+        <transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
+    </properties>
+
+    <!-- 依赖声明 -->
+    <dependencyManagement>
+        <dependencies>
+
+            <!-- SpringCloud 微服务 -->
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring-cloud.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- SpringCloud Alibaba 微服务 -->
+            <dependency>
+                <groupId>com.alibaba.cloud</groupId>
+                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
+                <version>${spring-cloud-alibaba.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- SpringBoot 依赖配置 -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- Springdoc webmvc 依赖配置 -->
+            <dependency>
+                <groupId>org.springdoc</groupId>
+                <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+                <version>${springdoc.version}</version>
+            </dependency>
+
+            <!-- 验证码 -->
+            <dependency>
+                <groupId>pro.fessional</groupId>
+                <artifactId>kaptcha</artifactId>
+                <version>${kaptcha.version}</version>
+            </dependency>
+
+            <!-- pagehelper 分页插件 -->
+            <dependency>
+                <groupId>com.github.pagehelper</groupId>
+                <artifactId>pagehelper-spring-boot-starter</artifactId>
+                <version>${pagehelper.boot.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <artifactId>mybatis-spring</artifactId>
+                        <groupId>org.mybatis</groupId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <dependency>
+                <groupId>org.mybatis</groupId>
+                <artifactId>mybatis-spring</artifactId>
+                <version>${mybatis-spring.version}</version>
+            </dependency>
+
+            <!-- io常用工具类 -->
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>${commons.io.version}</version>
+            </dependency>
+
+            <!-- excel工具 -->
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi-ooxml</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+
+            <!-- 代码生成使用模板 -->
+            <dependency>
+                <groupId>org.apache.velocity</groupId>
+                <artifactId>velocity-engine-core</artifactId>
+                <version>${velocity.version}</version>
+            </dependency>
+
+            <!-- JSON 解析器和生成器 -->
+            <dependency>
+                <groupId>com.alibaba.fastjson2</groupId>
+                <artifactId>fastjson2</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+
+            <!-- JWT -->
+            <dependency>
+                <groupId>io.jsonwebtoken</groupId>
+                <artifactId>jjwt</artifactId>
+                <version>${jjwt.version}</version>
+            </dependency>
+
+            <!-- 线程传递值 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>transmittable-thread-local</artifactId>
+                <version>${transmittable-thread-local.version}</version>
+            </dependency>
+
+            <!-- 核心模块 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common-core</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 接口模块 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common-swagger</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 安全模块 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common-security</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 数据脱敏 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common-sensitive</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 权限范围 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common-datascope</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 多数据源 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common-datasource</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 分布式事务 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common-seata</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 日志记录 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common-log</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 缓存服务 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common-redis</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 系统接口 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-api-system</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 海康sdk接口 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-api-haikang</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 泉视接口 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-api-qs</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 海康isup接口 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-api-haikang-isup</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 大华接口 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-api-dahua</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- zlm接口 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-api-zlm</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- onvif 接口 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-api-onvif</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- gb28181 接口 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-api-gb28181</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- jt1078 接口 -->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-api-jt1078</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <modules>
+        <module>ruoyi-auth</module>
+        <module>ruoyi-gateway</module>
+        <module>ruoyi-visual</module>
+        <module>ruoyi-modules</module>
+        <module>ruoyi-api</module>
+        <module>ruoyi-common</module>
+    </modules>
+    <packaging>pom</packaging>
+
+    <dependencies>
+        <!-- bootstrap 启动器 -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.11.0</version>
+                <configuration>
+                    <parameters>true</parameters>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-maven-plugin</artifactId>
+                    <version>${spring-boot.version}</version>
+                    <executions>
+                        <execution>
+                            <goals>
+                                <goal>repackage</goal>
+                            </goals>
+                        </execution>
+                    </executions>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+        </repository>
+    </repositories>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </pluginRepository>
+    </pluginRepositories>
+
+</project>

+ 30 - 0
ruoyi-qs-nvr-master/ruoyi-api/pom.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.ruoyi</groupId>
+        <artifactId>ruoyi</artifactId>
+        <version>3.6.7</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <modules>
+        <module>ruoyi-api-system</module>
+        <module>ruoyi-api-haikang</module>
+        <module>ruoyi-api-qs</module>
+        <module>ruoyi-api-haikang-isup</module>
+        <module>ruoyi-api-dahua</module>
+        <module>ruoyi-api-zlm</module>
+        <module>ruoyi-api-onvif</module>
+        <module>ruoyi-api-gb28181</module>
+        <module>ruoyi-api-jt1078</module>
+    </modules>
+
+    <artifactId>ruoyi-api</artifactId>
+    <packaging>pom</packaging>
+
+    <description>
+        ruoyi-api系统接口
+    </description>
+
+</project>

+ 28 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/pom.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.ruoyi</groupId>
+        <artifactId>ruoyi-api</artifactId>
+        <version>3.6.7</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-api-dahua</artifactId>
+
+    <description>
+        ruoyi-api-dahua 大华sdk接口模块
+    </description>
+
+    <dependencies>
+
+        <!-- RuoYi Common Core-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 330 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/RemoteDaHuaService.java

@@ -0,0 +1,330 @@
+package com.ruoyi.dahua.api;
+
+
+import com.ruoyi.common.core.constant.SecurityConstants;
+import com.ruoyi.common.core.constant.ServiceNameConstants;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.domain.RtpServerParam;
+import com.ruoyi.dahua.api.domain.DahuaDevice;
+import com.ruoyi.dahua.api.domain.LoginDevice;
+import com.ruoyi.dahua.api.domain.DahuaRecordDownloadRequest;
+import com.ruoyi.dahua.api.domain.DahuaRecordDownloadResponse;
+import com.ruoyi.dahua.api.factory.RemoteDaHuaFallbackFactory;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * 大华sdk 服务
+ *
+ * @FileName RemoteDaHuaService
+ * @Description
+ * @Author fengcheng
+ * @date 2026-03-30
+ **/
+@FeignClient(contextId = "remoteDaHuaService", value = ServiceNameConstants.DAHUA_SERVICE, fallbackFactory = RemoteDaHuaFallbackFactory.class)
+public interface RemoteDaHuaService {
+
+    /**
+     * 登录设备
+     *
+     * @param loginDevice 大华设备登录信息
+     * @param source      请求来源
+     */
+    @PostMapping(value = "/api/dahua/loginDevice")
+    public R<Void> loginDevice(@RequestBody LoginDevice loginDevice, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 查询是否登录
+     *
+     * @param ip     设备ip
+     * @param source 请求来源
+     * @return
+     */
+    @PostMapping(value = "/api/dahua/isUserId/{ip}")
+    R<Boolean> isUserId(@PathVariable String ip, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备获取时间
+     *
+     * @param ip     设备ip
+     * @param source 请求来源
+     * @return
+     */
+    @PostMapping(value = "/api/dahua/getTime/{ip}")
+    R<String> getTime(@PathVariable String ip, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备设置时间
+     *
+     * @param id     设备id
+     * @param date   日期时间
+     * @param type   类型
+     * @param source 请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/setTime/{id}")
+    R<Boolean> setTime(@PathVariable Long id, @RequestParam String date, @RequestParam boolean type, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备重启
+     *
+     * @param id     设备id
+     * @param source 请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/reboot/{id}")
+    R<Boolean> reboot(@PathVariable Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 获取大华主动上线设备
+     *
+     * @param ip     设备ip
+     * @param source 请求来源
+     * @return
+     */
+    @PostMapping(value = "/api/dahua/getDahuaDevice/{ip}")
+    R<DahuaDevice> getDahuaDevice(@PathVariable String ip, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 退出登录
+     *
+     * @param ip     设备ip
+     * @param source 请求来源
+     * @return
+     */
+    @PostMapping(value = "/api/dahua/logoutDevice/{ip}")
+    R<Boolean> logoutDevice(@PathVariable String ip, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 开始播放
+     *
+     * @param rtpServerParam 播放参数
+     * @param source         请求来源
+     */
+    @PostMapping(value = "/api/dahua/startPlay")
+    R<Void> startPlay(@RequestBody RtpServerParam rtpServerParam, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 停止播放
+     *
+     * @param id     设备id
+     * @param source 请求来源
+     */
+    @GetMapping(value = "/api/dahua/stopPlay/{id}")
+    R<Void> stopPlay(@PathVariable Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备云台控制(开始)
+     *
+     * @param id        设备id
+     * @param channelId 通道id
+     * @param direction 方向
+     * @param speed     速度
+     * @param source    请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/ptzControlUpStart/{id}/{channelId}")
+    R<Boolean> ptzControlUpStart(@PathVariable Long id, @PathVariable int channelId, @RequestParam String direction, @RequestParam Integer speed, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备云台控制(停止)
+     *
+     * @param id        设备id
+     * @param channelId 通道id
+     * @param direction 方向
+     * @param source    请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/ptzControlUpEnd/{id}/{channelId}")
+    R<Boolean> ptzControlUpEnd(@PathVariable Long id, @PathVariable int channelId, @RequestParam String direction, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备获取预置点列表
+     *
+     * @param id        设备id
+     * @param channelId 通道id
+     * @param source    请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/getPresetList/{id}/{channelId}")
+    R<ArrayList<HashMap<String, Object>>> getPresetList(@PathVariable Long id, @PathVariable int channelId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备设置预置点
+     *
+     * @param id          设备id
+     * @param channelId   通道id
+     * @param presetIndex 预置点号
+     * @param source      请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/setPreset/{id}/{channelId}")
+    R<Void> setPreset(@PathVariable Long id, @PathVariable int channelId, @RequestParam int presetIndex, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华删除设置预置点
+     *
+     * @param id          设备id
+     * @param channelId   通道id
+     * @param presetIndex 预置点号
+     * @param source      请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/delPreset/{id}/{channelId}")
+    R<Void> delPreset(@PathVariable Long id, @PathVariable int channelId, @RequestParam int presetIndex, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华调用设置预置点
+     *
+     * @param id          设备id
+     * @param channelId   通道id
+     * @param presetIndex 预置点号
+     * @param source      请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/invokePreset/{id}/{channelId}")
+    R<Void> invokePreset(@PathVariable Long id, @PathVariable int channelId, @RequestParam int presetIndex, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 灯光控制
+     *
+     * @param id        设备id
+     * @param channelId 通道id
+     * @param action    0-关,1-开
+     * @param source    请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/controlLight/{id}/{channelId}")
+    R<Void> controlLight(@PathVariable Long id, @PathVariable int channelId, @RequestParam int action, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 雨刷控制
+     *
+     * @param id        设备id
+     * @param channelId 通道id
+     * @param action    0-关,1-开
+     * @param source    请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/controlWiper/{id}/{channelId}")
+    R<Void> controlWiper(@PathVariable Long id, @PathVariable int channelId, @RequestParam int action, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 开始点间巡航
+     *
+     * @param id         设备id
+     * @param channelId 通道id
+     * @param tourIndex 巡航线路号
+     * @param source     请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/startTour/{id}/{channelId}")
+    R<Void> startTour(@PathVariable Long id, @PathVariable int channelId, @RequestParam int tourIndex, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 停止点间巡航
+     *
+     * @param id        设备id
+     * @param channelId 通道id
+     * @param source    请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/stopTour/{id}/{channelId}")
+    R<Void> stopTour(@PathVariable Long id, @PathVariable int channelId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 添加预置点到巡航线路
+     *
+     * @param id          设备id
+     * @param channelId   通道id
+     * @param tourIndex   巡航线路号
+     * @param presetIndex 预置点号
+     * @param source      请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/addPresetToTour/{id}/{channelId}")
+    R<Void> addPresetToTour(@PathVariable Long id, @PathVariable int channelId, @RequestParam int tourIndex, @RequestParam int presetIndex, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 从巡航线路删除预置点
+     *
+     * @param id          设备id
+     * @param channelId   通道id
+     * @param tourIndex   巡航线路号
+     * @param presetIndex 预置点号
+     * @param source      请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/removePresetFromTour/{id}/{channelId}")
+    R<Void> removePresetFromTour(@PathVariable Long id, @PathVariable int channelId, @RequestParam int tourIndex, @RequestParam int presetIndex, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 清除巡航线路
+     *
+     * @param id         设备id
+     * @param channelId 通道id
+     * @param tourIndex 巡航线路号
+     * @param source     请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/clearTour/{id}/{channelId}")
+    R<Void> clearTour(@PathVariable Long id, @PathVariable int channelId, @RequestParam int tourIndex, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备查询录像
+     *
+     * @param id         设备id
+     * @param channelId  通道id
+     * @param startTime  开始时间
+     * @param endTime    结束时间
+     * @param source     请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/queryRecord/{id}/{channelId}")
+    R<ArrayList<HashMap<String, Object>>> queryRecord(@PathVariable Long id, @PathVariable int channelId, @RequestParam String startTime, @RequestParam String endTime, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备开始录像回放
+     *
+     * @param rtpServerParam 回放参数
+     * @param source         请求来源
+     * @return
+     */
+    @PostMapping(value = "/api/dahua/startPlayback")
+    R<Void> startPlayback(@RequestBody RtpServerParam rtpServerParam, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备停止录像回放
+     *
+     * @param id     设备id
+     * @param source 请求来源
+     * @return
+     */
+    @GetMapping(value = "/api/dahua/stopPlayback/{id}")
+    R<Void> stopPlayback(@PathVariable Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备抓图并保存
+     *
+     * @param id           设备id
+     * @param channelId    通道id
+     * @param snapshotType 抓图类型
+     * @param source       请求来源
+     * @return 抓图记录id
+     */
+    @PostMapping(value = "/api/dahua/captureAndSave/{id}/{channelId}")
+    R<Long> captureAndSave(@PathVariable Long id, @PathVariable int channelId, @RequestParam String snapshotType, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 大华设备录像下载
+     *
+     * @param request 下载请求
+     * @param source 请求来源
+     * @return 下载响应
+     */
+    @PostMapping(value = "/api/dahua/downloadRecord")
+    R<DahuaRecordDownloadResponse> downloadRecord(@RequestBody DahuaRecordDownloadRequest request, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+}

+ 73 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaAlarmArmInfo.java

@@ -0,0 +1,73 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 大华设备报警布撤防信息
+ */
+public class DahuaAlarmArmInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 报警通道状态
+     */
+    public static class AlarmChannelState implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private Integer channelId;
+        private String channelName;
+        private Boolean armed;
+        private Integer armType;
+        private String armTypeDesc;
+
+        public Integer getChannelId() { return channelId; }
+        public void setChannelId(Integer channelId) { this.channelId = channelId; }
+
+        public String getChannelName() { return channelName; }
+        public void setChannelName(String channelName) { this.channelName = channelName; }
+
+        public Boolean getArmed() { return armed; }
+        public void setArmed(Boolean armed) { this.armed = armed; }
+
+        public Integer getArmType() { return armType; }
+        public void setArmType(Integer armType) { this.armType = armType; }
+
+        public String getArmTypeDesc() { return armTypeDesc; }
+        public void setArmTypeDesc(String armTypeDesc) { this.armTypeDesc = armTypeDesc; }
+    }
+
+    /**
+     * 报警通道数量
+     */
+    private Integer channelCount;
+
+    /**
+     * 报警通道状态列表
+     */
+    private List<AlarmChannelState> channelStates = new ArrayList<>();
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    public Integer getChannelCount() { return channelCount; }
+    public void setChannelCount(Integer channelCount) { this.channelCount = channelCount; }
+
+    public List<AlarmChannelState> getChannelStates() { return channelStates; }
+    public void setChannelStates(List<AlarmChannelState> channelStates) { this.channelStates = channelStates; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+}

+ 92 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaBitrateInfo.java

@@ -0,0 +1,92 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 大华设备通道码流信息
+ */
+public class DahuaBitrateInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 通道码流列表
+     */
+    private List<ChannelBitrate> channelBitrates;
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    public List<ChannelBitrate> getChannelBitrates() { return channelBitrates; }
+    public void setChannelBitrates(List<ChannelBitrate> channelBitrates) { this.channelBitrates = channelBitrates; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+
+    /**
+     * 单个通道码流信息
+     */
+    public static class ChannelBitrate implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 通道号
+         */
+        private Integer channelId;
+
+        /**
+         * 通道名称
+         */
+        private String channelName;
+
+        /**
+         * 码流类型: 0-主码流, 1-辅码流1, 2-辅码流2
+         */
+        private Integer streamType;
+
+        /**
+         * 码流类型描述
+         */
+        private String streamTypeDesc;
+
+        /**
+         * 实时码流(kbps)
+         */
+        private Integer bitrate;
+
+        /**
+         * 是否正在录像
+         */
+        private Boolean recording;
+
+        public Integer getChannelId() { return channelId; }
+        public void setChannelId(Integer channelId) { this.channelId = channelId; }
+
+        public String getChannelName() { return channelName; }
+        public void setChannelName(String channelName) { this.channelName = channelName; }
+
+        public Integer getStreamType() { return streamType; }
+        public void setStreamType(Integer streamType) { this.streamType = streamType; }
+
+        public String getStreamTypeDesc() { return streamTypeDesc; }
+        public void setStreamTypeDesc(String streamTypeDesc) { this.streamTypeDesc = streamTypeDesc; }
+
+        public Integer getBitrate() { return bitrate; }
+        public void setBitrate(Integer bitrate) { this.bitrate = bitrate; }
+
+        public Boolean getRecording() { return recording; }
+        public void setRecording(Boolean recording) { this.recording = recording; }
+    }
+}

+ 101 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaCameraInfo.java

@@ -0,0 +1,101 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 大华设备摄像头属性信息
+ */
+public class DahuaCameraInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 摄像头信息
+     */
+    public static class CameraInfo implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private Integer channelId;
+        private String cameraName;
+        private String cameraType;
+        private Boolean online;
+        private Integer status;
+        private String statusDesc;
+        private String manufacturer;
+        private String model;
+        private String serialNumber;
+        private String firmwareVersion;
+        private String ipAddress;
+        private Integer port;
+
+        public Integer getChannelId() { return channelId; }
+        public void setChannelId(Integer channelId) { this.channelId = channelId; }
+
+        public String getCameraName() { return cameraName; }
+        public void setCameraName(String cameraName) { this.cameraName = cameraName; }
+
+        public String getCameraType() { return cameraType; }
+        public void setCameraType(String cameraType) { this.cameraType = cameraType; }
+
+        public Boolean getOnline() { return online; }
+        public void setOnline(Boolean online) { this.online = online; }
+
+        public Integer getStatus() { return status; }
+        public void setStatus(Integer status) { this.status = status; }
+
+        public String getStatusDesc() { return statusDesc; }
+        public void setStatusDesc(String statusDesc) { this.statusDesc = statusDesc; }
+
+        public String getManufacturer() { return manufacturer; }
+        public void setManufacturer(String manufacturer) { this.manufacturer = manufacturer; }
+
+        public String getModel() { return model; }
+        public void setModel(String model) { this.model = model; }
+
+        public String getSerialNumber() { return serialNumber; }
+        public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; }
+
+        public String getFirmwareVersion() { return firmwareVersion; }
+        public void setFirmwareVersion(String firmwareVersion) { this.firmwareVersion = firmwareVersion; }
+
+        public String getIpAddress() { return ipAddress; }
+        public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
+
+        public Integer getPort() { return port; }
+        public void setPort(Integer port) { this.port = port; }
+    }
+
+    /**
+     * 摄像头数量
+     */
+    private Integer cameraCount;
+
+    /**
+     * 摄像头信息列表
+     */
+    private List<CameraInfo> cameraList = new ArrayList<>();
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    public Integer getCameraCount() { return cameraCount; }
+    public void setCameraCount(Integer cameraCount) { this.cameraCount = cameraCount; }
+
+    public List<CameraInfo> getCameraList() { return cameraList; }
+    public void setCameraList(List<CameraInfo> cameraList) { this.cameraList = cameraList; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+}

+ 34 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaDevice.java

@@ -0,0 +1,34 @@
+package com.ruoyi.dahua.api.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备对象 dahua_device
+ *
+ * @author fengcheng
+ * @date 2025-06-06
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DahuaDevice implements Serializable {
+
+    /**
+     * ip
+     */
+    private String ip;
+
+    /**
+     * 设备id
+     */
+    private String deviceId;
+
+    /**
+     * 端口
+     */
+    private String port;
+}

+ 66 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaDeviceInfo.java

@@ -0,0 +1,66 @@
+package com.ruoyi.dahua.api.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备详细信息
+ *
+ * @author ruoyi
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DahuaDeviceInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 序列号
+     */
+    private String serialNumber;
+
+    /**
+     * 报警输入个数
+     */
+    private Integer alarmInPortNum;
+
+    /**
+     * 报警输出个数
+     */
+    private Integer alarmOutPortNum;
+
+    /**
+     * 硬盘个数
+     */
+    private Integer diskNum;
+
+    /**
+     * DVR类型
+     */
+    private Integer dvrType;
+
+    /**
+     * 通道个数
+     */
+    private Integer channelNum;
+
+    /**
+     * 在线超时时间(分钟),0表示不限制
+     */
+    private Integer limitLoginTime;
+
+    /**
+     * 剩余登陆次数
+     */
+    private Integer leftLogTimes;
+
+    /**
+     * 解锁剩余时间(秒),-1表示设备未设置
+     */
+    private Integer lockLeftTime;
+
+}

+ 118 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaDeviceVideoParam.java

@@ -0,0 +1,118 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备视频输入参数
+ *
+ * @author ruoyi
+ */
+public class DahuaDeviceVideoParam implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 亮度
+     */
+    private Integer brightness;
+
+    /**
+     * 对比度
+     */
+    private Integer contrast;
+
+    /**
+     * 饱和度
+     */
+    private Integer saturation;
+
+    /**
+     * 色度
+     */
+    private Integer chroma;
+
+    /**
+     * 锐度
+     */
+    private Integer sharpness;
+
+    /**
+     * 色调
+     */
+    private Integer hue;
+
+    /**
+     * 增益
+     */
+    private Integer gain;
+
+    /**
+     * 黑白模式
+     * 0-彩色
+     * 1-黑白
+     */
+    private Integer blackWhiteMode;
+
+    public Integer getBrightness() {
+        return brightness;
+    }
+
+    public void setBrightness(Integer brightness) {
+        this.brightness = brightness;
+    }
+
+    public Integer getContrast() {
+        return contrast;
+    }
+
+    public void setContrast(Integer contrast) {
+        this.contrast = contrast;
+    }
+
+    public Integer getSaturation() {
+        return saturation;
+    }
+
+    public void setSaturation(Integer saturation) {
+        this.saturation = saturation;
+    }
+
+    public Integer getChroma() {
+        return chroma;
+    }
+
+    public void setChroma(Integer chroma) {
+        this.chroma = chroma;
+    }
+
+    public Integer getSharpness() {
+        return sharpness;
+    }
+
+    public void setSharpness(Integer sharpness) {
+        this.sharpness = sharpness;
+    }
+
+    public Integer getHue() {
+        return hue;
+    }
+
+    public void setHue(Integer hue) {
+        this.hue = hue;
+    }
+
+    public Integer getGain() {
+        return gain;
+    }
+
+    public void setGain(Integer gain) {
+        this.gain = gain;
+    }
+
+    public Integer getBlackWhiteMode() {
+        return blackWhiteMode;
+    }
+
+    public void setBlackWhiteMode(Integer blackWhiteMode) {
+        this.blackWhiteMode = blackWhiteMode;
+    }
+}

+ 100 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaNetworkStatusInfo.java

@@ -0,0 +1,100 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备网络状态信息
+ */
+public class DahuaNetworkStatusInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 设备IP地址
+     */
+    private String ipAddress;
+
+    /**
+     * 子网掩码
+     */
+    private String subnetMask;
+
+    /**
+     * 网关
+     */
+    private String gateway;
+
+    /**
+     * 主DNS
+     */
+    private String dns1;
+
+    /**
+     * 备DNS
+     */
+    private String dns2;
+
+    /**
+     * 网卡状态: 0-断开, 1-连接
+     */
+    private Integer linkStatus;
+
+    /**
+     * 网卡状态描述
+     */
+    private String linkStatusDesc;
+
+    /**
+     * 网络是否可用
+     */
+    private Boolean networkAvailable;
+
+    /**
+     * 是否有无线功能
+     */
+    private Boolean hasWireless;
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    // Getters and Setters
+    public String getIpAddress() { return ipAddress; }
+    public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
+
+    public String getSubnetMask() { return subnetMask; }
+    public void setSubnetMask(String subnetMask) { this.subnetMask = subnetMask; }
+
+    public String getGateway() { return gateway; }
+    public void setGateway(String gateway) { this.gateway = gateway; }
+
+    public String getDns1() { return dns1; }
+    public void setDns1(String dns1) { this.dns1 = dns1; }
+
+    public String getDns2() { return dns2; }
+    public void setDns2(String dns2) { this.dns2 = dns2; }
+
+    public Integer getLinkStatus() { return linkStatus; }
+    public void setLinkStatus(Integer linkStatus) { this.linkStatus = linkStatus; }
+
+    public String getLinkStatusDesc() { return linkStatusDesc; }
+    public void setLinkStatusDesc(String linkStatusDesc) { this.linkStatusDesc = linkStatusDesc; }
+
+    public Boolean getNetworkAvailable() { return networkAvailable; }
+    public void setNetworkAvailable(Boolean networkAvailable) { this.networkAvailable = networkAvailable; }
+
+    public Boolean getHasWireless() { return hasWireless; }
+    public void setHasWireless(Boolean hasWireless) { this.hasWireless = hasWireless; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+}

+ 73 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaPowerStateInfo.java

@@ -0,0 +1,73 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 大华设备电源状态信息
+ */
+public class DahuaPowerStateInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 电源状态
+     */
+    public static class PowerState implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private Integer powerId;
+        private String powerName;
+        private Integer status;
+        private String statusDesc;
+        private Boolean online;
+
+        public Integer getPowerId() { return powerId; }
+        public void setPowerId(Integer powerId) { this.powerId = powerId; }
+
+        public String getPowerName() { return powerName; }
+        public void setPowerName(String powerName) { this.powerName = powerName; }
+
+        public Integer getStatus() { return status; }
+        public void setStatus(Integer status) { this.status = status; }
+
+        public String getStatusDesc() { return statusDesc; }
+        public void setStatusDesc(String statusDesc) { this.statusDesc = statusDesc; }
+
+        public Boolean getOnline() { return online; }
+        public void setOnline(Boolean online) { this.online = online; }
+    }
+
+    /**
+     * 电源数量
+     */
+    private Integer powerCount;
+
+    /**
+     * 电源状态列表
+     */
+    private List<PowerState> powerStates = new ArrayList<>();
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    public Integer getPowerCount() { return powerCount; }
+    public void setPowerCount(Integer powerCount) { this.powerCount = powerCount; }
+
+    public List<PowerState> getPowerStates() { return powerStates; }
+    public void setPowerStates(List<PowerState> powerStates) { this.powerStates = powerStates; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+}

+ 76 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaRecordDownloadRequest.java

@@ -0,0 +1,76 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备录像下载请求
+ */
+public class DahuaRecordDownloadRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 设备ID
+     */
+    private Long id;
+
+    /**
+     * 通道ID
+     */
+    private int channelId;
+
+    /**
+     * 开始时间(格式:yyyy-MM-dd HH:mm:ss)
+     */
+    private String startTime;
+
+    /**
+     * 结束时间(格式:yyyy-MM-dd HH:mm:ss)
+     */
+    private String endTime;
+
+    /**
+     * 录像文件类型(0-主码流,1-子码流1,2-子码流2,参考SDK文档)
+     */
+    private Integer recordFileType;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public int getChannelId() {
+        return channelId;
+    }
+
+    public void setChannelId(int channelId) {
+        this.channelId = channelId;
+    }
+
+    public String getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(String startTime) {
+        this.startTime = startTime;
+    }
+
+    public String getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(String endTime) {
+        this.endTime = endTime;
+    }
+
+    public Integer getRecordFileType() {
+        return recordFileType;
+    }
+
+    public void setRecordFileType(Integer recordFileType) {
+        this.recordFileType = recordFileType;
+    }
+}

+ 89 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaRecordDownloadResponse.java

@@ -0,0 +1,89 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备录像下载响应
+ */
+public class DahuaRecordDownloadResponse implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 是否成功
+     */
+    private Boolean success;
+
+    /**
+     * 下载文件路径
+     */
+    private String filePath;
+
+    /**
+     * 下载文件URL
+     */
+    private String fileUrl;
+
+    /**
+     * 文件大小(字节)
+     */
+    private Long fileSize;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    /**
+     * 下载进度(0-100)
+     */
+    private Integer progress;
+
+    public Boolean getSuccess() {
+        return success;
+    }
+
+    public void setSuccess(Boolean success) {
+        this.success = success;
+    }
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
+
+    public String getFileUrl() {
+        return fileUrl;
+    }
+
+    public void setFileUrl(String fileUrl) {
+        this.fileUrl = fileUrl;
+    }
+
+    public Long getFileSize() {
+        return fileSize;
+    }
+
+    public void setFileSize(Long fileSize) {
+        this.fileSize = fileSize;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+
+    public Integer getProgress() {
+        return progress;
+    }
+
+    public void setProgress(Integer progress) {
+        this.progress = progress;
+    }
+}

+ 81 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaRecordStateInfo.java

@@ -0,0 +1,81 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 大华设备录像状态信息
+ */
+public class DahuaRecordStateInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 通道录像状态
+     */
+    public static class ChannelRecordState implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private Integer channelId;
+        private Boolean mainStreamRecording;
+        private Boolean extraStream1Recording;
+        private Boolean extraStream2Recording;
+        private Boolean extraStream3Recording;
+
+        public Integer getChannelId() { return channelId; }
+        public void setChannelId(Integer channelId) { this.channelId = channelId; }
+
+        public Boolean getMainStreamRecording() { return mainStreamRecording; }
+        public void setMainStreamRecording(Boolean mainStreamRecording) { this.mainStreamRecording = mainStreamRecording; }
+
+        public Boolean getExtraStream1Recording() { return extraStream1Recording; }
+        public void setExtraStream1Recording(Boolean extraStream1Recording) { this.extraStream1Recording = extraStream1Recording; }
+
+        public Boolean getExtraStream2Recording() { return extraStream2Recording; }
+        public void setExtraStream2Recording(Boolean extraStream2Recording) { this.extraStream2Recording = extraStream2Recording; }
+
+        public Boolean getExtraStream3Recording() { return extraStream3Recording; }
+        public void setExtraStream3Recording(Boolean extraStream3Recording) { this.extraStream3Recording = extraStream3Recording; }
+    }
+
+    /**
+     * 整体录像状态
+     */
+    private Boolean wholeRecording;
+
+    /**
+     * 整体编码状态
+     */
+    private Boolean wholeEncoding;
+
+    /**
+     * 通道录像状态列表
+     */
+    private List<ChannelRecordState> channelStates = new ArrayList<>();
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    public Boolean getWholeRecording() { return wholeRecording; }
+    public void setWholeRecording(Boolean wholeRecording) { this.wholeRecording = wholeRecording; }
+
+    public Boolean getWholeEncoding() { return wholeEncoding; }
+    public void setWholeEncoding(Boolean wholeEncoding) { this.wholeEncoding = wholeEncoding; }
+
+    public List<ChannelRecordState> getChannelStates() { return channelStates; }
+    public void setChannelStates(List<ChannelRecordState> channelStates) { this.channelStates = channelStates; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+}

+ 69 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaRtspUrlInfo.java

@@ -0,0 +1,69 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 大华设备RTSP URL信息
+ */
+public class DahuaRtspUrlInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * RTSP URL信息
+     */
+    public static class RtspUrl implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private Integer channelId;
+        private String streamType;
+        private String url;
+        private String description;
+
+        public Integer getChannelId() { return channelId; }
+        public void setChannelId(Integer channelId) { this.channelId = channelId; }
+
+        public String getStreamType() { return streamType; }
+        public void setStreamType(String streamType) { this.streamType = streamType; }
+
+        public String getUrl() { return url; }
+        public void setUrl(String url) { this.url = url; }
+
+        public String getDescription() { return description; }
+        public void setDescription(String description) { this.description = description; }
+    }
+
+    /**
+     * URL数量
+     */
+    private Integer urlCount;
+
+    /**
+     * RTSP URL列表
+     */
+    private List<RtspUrl> urlList = new ArrayList<>();
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    public Integer getUrlCount() { return urlCount; }
+    public void setUrlCount(Integer urlCount) { this.urlCount = urlCount; }
+
+    public List<RtspUrl> getUrlList() { return urlList; }
+    public void setUrlList(List<RtspUrl> urlList) { this.urlList = urlList; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+}

+ 165 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaSDCardInfo.java

@@ -0,0 +1,165 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 大华设备SD卡信息
+ */
+public class DahuaSDCardInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 磁盘信息
+     */
+    public static class DiskInfo implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private Integer diskNumber;
+        private Integer partitionNumber;
+        private Integer volume;
+        private Integer freeSpace;
+        private Integer status;
+        private Integer signal;
+        private Integer diskType;
+        private Integer diskStatus;
+
+        public Integer getDiskNumber() { return diskNumber; }
+        public void setDiskNumber(Integer diskNumber) { this.diskNumber = diskNumber; }
+
+        public Integer getPartitionNumber() { return partitionNumber; }
+        public void setPartitionNumber(Integer partitionNumber) { this.partitionNumber = partitionNumber; }
+
+        public Integer getVolume() { return volume; }
+        public void setVolume(Integer volume) { this.volume = volume; }
+
+        public Integer getFreeSpace() { return freeSpace; }
+        public void setFreeSpace(Integer freeSpace) { this.freeSpace = freeSpace; }
+
+        public Integer getStatus() { return status; }
+        public void setStatus(Integer status) { this.status = status; }
+
+        public Integer getSignal() { return signal; }
+        public void setSignal(Integer signal) { this.signal = signal; }
+
+        public Integer getDiskType() { return diskType; }
+        public void setDiskType(Integer diskType) { this.diskType = diskType; }
+
+        public Integer getDiskStatus() { return diskStatus; }
+        public void setDiskStatus(Integer diskStatus) { this.diskStatus = diskStatus; }
+    }
+
+    /**
+     * SD卡是否存在
+     */
+    private Boolean exists;
+
+    /**
+     * 磁盘数量
+     */
+    private Integer diskCount;
+
+    /**
+     * 磁盘列表
+     */
+    private List<DiskInfo> diskList;
+
+    /**
+     * SD卡总容量(字节)
+     */
+    private Long totalSpace;
+
+    /**
+     * SD卡已用容量(字节)
+     */
+    private Long usedSpace;
+
+    /**
+     * SD卡剩余容量(字节)
+     */
+    private Long freeSpace;
+
+    /**
+     * 总容量(GB)
+     */
+    private Double totalSpaceGB;
+
+    /**
+     * 已用容量(GB)
+     */
+    private Double usedSpaceGB;
+
+    /**
+     * 剩余容量(GB)
+     */
+    private Double freeSpaceGB;
+
+    /**
+     * 使用率(%)
+     */
+    private Double usagePercent;
+
+    /**
+     * SD卡状态
+     */
+    private Integer state;
+
+    /**
+     * 状态描述
+     */
+    private String stateDesc;
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    // Getters and Setters
+    public Boolean getExists() { return exists; }
+    public void setExists(Boolean exists) { this.exists = exists; }
+
+    public Integer getDiskCount() { return diskCount; }
+    public void setDiskCount(Integer diskCount) { this.diskCount = diskCount; }
+
+    public List<DiskInfo> getDiskList() { return diskList; }
+    public void setDiskList(List<DiskInfo> diskList) { this.diskList = diskList; }
+
+    public Long getTotalSpace() { return totalSpace; }
+    public void setTotalSpace(Long totalSpace) { this.totalSpace = totalSpace; }
+
+    public Long getUsedSpace() { return usedSpace; }
+    public void setUsedSpace(Long usedSpace) { this.usedSpace = usedSpace; }
+
+    public Long getFreeSpace() { return freeSpace; }
+    public void setFreeSpace(Long freeSpace) { this.freeSpace = freeSpace; }
+
+    public Double getTotalSpaceGB() { return totalSpaceGB; }
+    public void setTotalSpaceGB(Double totalSpaceGB) { this.totalSpaceGB = totalSpaceGB; }
+
+    public Double getUsedSpaceGB() { return usedSpaceGB; }
+    public void setUsedSpaceGB(Double usedSpaceGB) { this.usedSpaceGB = usedSpaceGB; }
+
+    public Double getFreeSpaceGB() { return freeSpaceGB; }
+    public void setFreeSpaceGB(Double freeSpaceGB) { this.freeSpaceGB = freeSpaceGB; }
+
+    public Double getUsagePercent() { return usagePercent; }
+    public void setUsagePercent(Double usagePercent) { this.usagePercent = usagePercent; }
+
+    public Integer getState() { return state; }
+    public void setState(Integer state) { this.state = state; }
+
+    public String getStateDesc() { return stateDesc; }
+    public void setStateDesc(String stateDesc) { this.stateDesc = stateDesc; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+}

+ 172 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaSoftwareVersionInfo.java

@@ -0,0 +1,172 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备软件版本信息
+ */
+public class DahuaSoftwareVersionInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主版本号
+     */
+    private String majorVersion;
+
+    /**
+     * 次版本号
+     */
+    private String minorVersion;
+
+    /**
+     * 修订版本号
+     */
+    private String revisionVersion;
+
+    /**
+     * 完整版本号
+     */
+    private String fullVersion;
+
+    /**
+     * 构建日期
+     */
+    private String buildDate;
+
+    /**
+     * 设备型号
+     */
+    private String deviceModel;
+
+    /**
+     * 序列号
+     */
+    private String serialNumber;
+
+    /**
+     * 硬件版本
+     */
+    private String hardwareVersion;
+
+    /**
+     * 软件版本
+     */
+    private String softwareVersion;
+
+    /**
+     * Web版本
+     */
+    private String webVersion;
+
+    /**
+     * 从片版本
+     */
+    private String peripheralVersion;
+
+    /**
+     * 地理信息定位芯片版本
+     */
+    private String geographyVersion;
+
+    /**
+     * 协议版本号
+     */
+    private Integer protocolVersion;
+
+    /**
+     * 软件构建日期
+     */
+    private Integer softwareBuildDate;
+
+    /**
+     * 从片构建日期
+     */
+    private Integer peripheralBuildDate;
+
+    /**
+     * 地理信息构建日期
+     */
+    private Integer geographyBuildDate;
+
+    /**
+     * 硬件日期
+     */
+    private Integer hardwareDate;
+
+    /**
+     * Web构建日期
+     */
+    private Integer webBuildDate;
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    // Getters and Setters
+    public String getMajorVersion() { return majorVersion; }
+    public void setMajorVersion(String majorVersion) { this.majorVersion = majorVersion; }
+
+    public String getMinorVersion() { return minorVersion; }
+    public void setMinorVersion(String minorVersion) { this.minorVersion = minorVersion; }
+
+    public String getRevisionVersion() { return revisionVersion; }
+    public void setRevisionVersion(String revisionVersion) { this.revisionVersion = revisionVersion; }
+
+    public String getFullVersion() { return fullVersion; }
+    public void setFullVersion(String fullVersion) { this.fullVersion = fullVersion; }
+
+    public String getBuildDate() { return buildDate; }
+    public void setBuildDate(String buildDate) { this.buildDate = buildDate; }
+
+    public String getDeviceModel() { return deviceModel; }
+    public void setDeviceModel(String deviceModel) { this.deviceModel = deviceModel; }
+
+    public String getSerialNumber() { return serialNumber; }
+    public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; }
+
+    public String getHardwareVersion() { return hardwareVersion; }
+    public void setHardwareVersion(String hardwareVersion) { this.hardwareVersion = hardwareVersion; }
+
+    public String getSoftwareVersion() { return softwareVersion; }
+    public void setSoftwareVersion(String softwareVersion) { this.softwareVersion = softwareVersion; }
+
+    public String getWebVersion() { return webVersion; }
+    public void setWebVersion(String webVersion) { this.webVersion = webVersion; }
+
+    public String getPeripheralVersion() { return peripheralVersion; }
+    public void setPeripheralVersion(String peripheralVersion) { this.peripheralVersion = peripheralVersion; }
+
+    public String getGeographyVersion() { return geographyVersion; }
+    public void setGeographyVersion(String geographyVersion) { this.geographyVersion = geographyVersion; }
+
+    public Integer getProtocolVersion() { return protocolVersion; }
+    public void setProtocolVersion(Integer protocolVersion) { this.protocolVersion = protocolVersion; }
+
+    public Integer getSoftwareBuildDate() { return softwareBuildDate; }
+    public void setSoftwareBuildDate(Integer softwareBuildDate) { this.softwareBuildDate = softwareBuildDate; }
+
+    public Integer getPeripheralBuildDate() { return peripheralBuildDate; }
+    public void setPeripheralBuildDate(Integer peripheralBuildDate) { this.peripheralBuildDate = peripheralBuildDate; }
+
+    public Integer getGeographyBuildDate() { return geographyBuildDate; }
+    public void setGeographyBuildDate(Integer geographyBuildDate) { this.geographyBuildDate = geographyBuildDate; }
+
+    public Integer getHardwareDate() { return hardwareDate; }
+    public void setHardwareDate(Integer hardwareDate) { this.hardwareDate = hardwareDate; }
+
+    public Integer getWebBuildDate() { return webBuildDate; }
+    public void setWebBuildDate(Integer webBuildDate) { this.webBuildDate = webBuildDate; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+}

+ 315 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaStorageInfo.java

@@ -0,0 +1,315 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 大华设备存储/硬盘信息
+ */
+public class DahuaStorageInfo implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+    
+    /**
+     * 存储设备列表
+     */
+    private List<StorageDevice> storageDevices;
+
+    public List<StorageDevice> getStorageDevices() {
+        return storageDevices;
+    }
+
+    public void setStorageDevices(List<StorageDevice> storageDevices) {
+        this.storageDevices = storageDevices;
+    }
+
+    /**
+     * 存储设备信息
+     */
+    public static class StorageDevice implements Serializable {
+        
+        private static final long serialVersionUID = 1L;
+        
+        /**
+         * 设备名称
+         */
+        private String name;
+        
+        /**
+         * 总空间(字节)
+         */
+        private Long totalSpace;
+        
+        /**
+         * 总空间(GB)
+         */
+        private Double totalSpaceGB;
+        
+        /**
+         * 剩余空间(字节)
+         */
+        private Long freeSpace;
+        
+        /**
+         * 剩余空间(GB)
+         */
+        private Double freeSpaceGB;
+        
+        /**
+         * 已用空间(字节)
+         */
+        private Long usedSpace;
+        
+        /**
+         * 已用空间(GB)
+         */
+        private Double usedSpaceGB;
+        
+        /**
+         * 使用率(%)
+         */
+        private Double usagePercent;
+        
+        /**
+         * 介质类型: 0-DISK, 1-CDROM, 2-FLASH
+         */
+        private Integer mediaType;
+        
+        /**
+         * 介质类型描述
+         */
+        private String mediaTypeDesc;
+        
+        /**
+         * 总线类型: 0-ATA, 1-SATA, 2-USB, 3-SDIO, 4-SCSI
+         */
+        private Integer busType;
+        
+        /**
+         * 总线类型描述
+         */
+        private String busTypeDesc;
+        
+        /**
+         * 卷类型: 0-物理卷, 1-Raid卷, 2-VG虚拟卷, 3-ISCSI, 4-独立物理卷, 5-全局热备卷, 6-NAS卷
+         */
+        private Integer volumeType;
+        
+        /**
+         * 卷类型描述
+         */
+        private String volumeTypeDesc;
+        
+        /**
+         * 物理硬盘状态
+         */
+        private Integer state;
+        
+        /**
+         * 物理硬盘状态描述
+         */
+        private String stateDesc;
+        
+        /**
+         * 物理编号
+         */
+        private Integer physicNo;
+        
+        /**
+         * 逻辑编号
+         */
+        private Integer logicNo;
+        
+        /**
+         * 上级存储组名称
+         */
+        private String parent;
+        
+        /**
+         * 设备模块
+         */
+        private String module;
+        
+        /**
+         * 序列号
+         */
+        private String serial;
+        
+        /**
+         * 固件版本
+         */
+        private String firmware;
+        
+        /**
+         * 分区数
+         */
+        private Integer partitionNum;
+        
+        /**
+         * 设备操作状态
+         */
+        private Integer opState;
+        
+        /**
+         * 设备操作状态描述
+         */
+        private String opStateDesc;
+        
+        /**
+         * 分区列表
+         */
+        private List<StoragePartition> partitions;
+
+        // Getters and Setters
+        public String getName() { return name; }
+        public void setName(String name) { this.name = name; }
+        
+        public Long getTotalSpace() { return totalSpace; }
+        public void setTotalSpace(Long totalSpace) { this.totalSpace = totalSpace; }
+        
+        public Double getTotalSpaceGB() { return totalSpaceGB; }
+        public void setTotalSpaceGB(Double totalSpaceGB) { this.totalSpaceGB = totalSpaceGB; }
+        
+        public Long getFreeSpace() { return freeSpace; }
+        public void setFreeSpace(Long freeSpace) { this.freeSpace = freeSpace; }
+        
+        public Double getFreeSpaceGB() { return freeSpaceGB; }
+        public void setFreeSpaceGB(Double freeSpaceGB) { this.freeSpaceGB = freeSpaceGB; }
+        
+        public Long getUsedSpace() { return usedSpace; }
+        public void setUsedSpace(Long usedSpace) { this.usedSpace = usedSpace; }
+        
+        public Double getUsedSpaceGB() { return usedSpaceGB; }
+        public void setUsedSpaceGB(Double usedSpaceGB) { this.usedSpaceGB = usedSpaceGB; }
+        
+        public Double getUsagePercent() { return usagePercent; }
+        public void setUsagePercent(Double usagePercent) { this.usagePercent = usagePercent; }
+        
+        public Integer getMediaType() { return mediaType; }
+        public void setMediaType(Integer mediaType) { this.mediaType = mediaType; }
+        
+        public String getMediaTypeDesc() { return mediaTypeDesc; }
+        public void setMediaTypeDesc(String mediaTypeDesc) { this.mediaTypeDesc = mediaTypeDesc; }
+        
+        public Integer getBusType() { return busType; }
+        public void setBusType(Integer busType) { this.busType = busType; }
+        
+        public String getBusTypeDesc() { return busTypeDesc; }
+        public void setBusTypeDesc(String busTypeDesc) { this.busTypeDesc = busTypeDesc; }
+        
+        public Integer getVolumeType() { return volumeType; }
+        public void setVolumeType(Integer volumeType) { this.volumeType = volumeType; }
+        
+        public String getVolumeTypeDesc() { return volumeTypeDesc; }
+        public void setVolumeTypeDesc(String volumeTypeDesc) { this.volumeTypeDesc = volumeTypeDesc; }
+        
+        public Integer getState() { return state; }
+        public void setState(Integer state) { this.state = state; }
+        
+        public String getStateDesc() { return stateDesc; }
+        public void setStateDesc(String stateDesc) { this.stateDesc = stateDesc; }
+        
+        public Integer getPhysicNo() { return physicNo; }
+        public void setPhysicNo(Integer physicNo) { this.physicNo = physicNo; }
+        
+        public Integer getLogicNo() { return logicNo; }
+        public void setLogicNo(Integer logicNo) { this.logicNo = logicNo; }
+        
+        public String getParent() { return parent; }
+        public void setParent(String parent) { this.parent = parent; }
+        
+        public String getModule() { return module; }
+        public void setModule(String module) { this.module = module; }
+        
+        public String getSerial() { return serial; }
+        public void setSerial(String serial) { this.serial = serial; }
+        
+        public String getFirmware() { return firmware; }
+        public void setFirmware(String firmware) { this.firmware = firmware; }
+        
+        public Integer getPartitionNum() { return partitionNum; }
+        public void setPartitionNum(Integer partitionNum) { this.partitionNum = partitionNum; }
+        
+        public Integer getOpState() { return opState; }
+        public void setOpState(Integer opState) { this.opState = opState; }
+        
+        public String getOpStateDesc() { return opStateDesc; }
+        public void setOpStateDesc(String opStateDesc) { this.opStateDesc = opStateDesc; }
+        
+        public List<StoragePartition> getPartitions() { return partitions; }
+        public void setPartitions(List<StoragePartition> partitions) { this.partitions = partitions; }
+    }
+    
+    /**
+     * 存储分区信息
+     */
+    public static class StoragePartition implements Serializable {
+        
+        private static final long serialVersionUID = 1L;
+        
+        /**
+         * 分区名称
+         */
+        private String name;
+        
+        /**
+         * 分区路径
+         */
+        private String path;
+        
+        /**
+         * 总空间(字节)
+         */
+        private Long totalSpace;
+        
+        /**
+         * 总空间(GB)
+         */
+        private Double totalSpaceGB;
+        
+        /**
+         * 剩余空间(字节)
+         */
+        private Long freeSpace;
+        
+        /**
+         * 剩余空间(GB)
+         */
+        private Double freeSpaceGB;
+        
+        /**
+         * 分区类型
+         */
+        private Integer type;
+        
+        /**
+         * 分区状态
+         */
+        private Integer state;
+
+        // Getters and Setters
+        public String getName() { return name; }
+        public void setName(String name) { this.name = name; }
+        
+        public String getPath() { return path; }
+        public void setPath(String path) { this.path = path; }
+        
+        public Long getTotalSpace() { return totalSpace; }
+        public void setTotalSpace(Long totalSpace) { this.totalSpace = totalSpace; }
+        
+        public Double getTotalSpaceGB() { return totalSpaceGB; }
+        public void setTotalSpaceGB(Double totalSpaceGB) { this.totalSpaceGB = totalSpaceGB; }
+        
+        public Long getFreeSpace() { return freeSpace; }
+        public void setFreeSpace(Long freeSpace) { this.freeSpace = freeSpace; }
+        
+        public Double getFreeSpaceGB() { return freeSpaceGB; }
+        public void setFreeSpaceGB(Double freeSpaceGB) { this.freeSpaceGB = freeSpaceGB; }
+        
+        public Integer getType() { return type; }
+        public void setType(Integer type) { this.type = type; }
+        
+        public Integer getState() { return state; }
+        public void setState(Integer state) { this.state = state; }
+    }
+}

+ 41 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaSystemParam.java

@@ -0,0 +1,41 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备系统参数
+ *
+ * @author ruoyi
+ */
+public class DahuaSystemParam implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 视频制式
+     * 0-PAL
+     * 1-NTSC
+     * 2-SECAM
+     */
+    private Integer videoStandard;
+
+    /**
+     * 国家/地区配置
+     */
+    private String country;
+
+    public Integer getVideoStandard() {
+        return videoStandard;
+    }
+
+    public void setVideoStandard(Integer videoStandard) {
+        this.videoStandard = videoStandard;
+    }
+
+    public String getCountry() {
+        return country;
+    }
+
+    public void setCountry(String country) {
+        this.country = country;
+    }
+}

+ 148 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaSystemResourceInfo.java

@@ -0,0 +1,148 @@
+package com.ruoyi.dahua.api.domain;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备系统资源状态信息
+ */
+public class DahuaSystemResourceInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * CPU使用率(%)
+     */
+    private Double cpuUsage;
+
+    /**
+     * 总内存(字节)
+     */
+    private Long totalMemory;
+
+    /**
+     * 已用内存(字节)
+     */
+    private Long usedMemory;
+
+    /**
+     * 剩余内存(字节)
+     */
+    private Long freeMemory;
+
+    /**
+     * 内存使用率(%)
+     */
+    private Double memoryUsage;
+
+    /**
+     * 总内存(MB)
+     */
+    private Double totalMemoryMB;
+
+    /**
+     * 已用内存(MB)
+     */
+    private Double usedMemoryMB;
+
+    /**
+     * 剩余内存(MB)
+     */
+    private Double freeMemoryMB;
+
+    /**
+     * IP通道接入速度(kbps)
+     */
+    private Integer ipChannelIn;
+
+    /**
+     * 网络接收剩余能力(kbps)
+     */
+    private Integer netRemain;
+
+    /**
+     * 网络接收总能力(kbps)
+     */
+    private Integer netCapability;
+
+    /**
+     * 远程预览能力(kbps)
+     */
+    private Integer remotePreview;
+
+    /**
+     * 远程回放及下载能力(kbps)
+     */
+    private Integer remotePlayDownload;
+
+    /**
+     * 远程发送剩余能力(kbps)
+     */
+    private Integer remoteSendRemain;
+
+    /**
+     * 远程发送总能力(kbps)
+     */
+    private Integer remoteSendCapability;
+
+    /**
+     * 是否获取成功
+     */
+    private Boolean success;
+
+    /**
+     * 错误信息
+     */
+    private String errorMessage;
+
+    // Getters and Setters
+    public Double getCpuUsage() { return cpuUsage; }
+    public void setCpuUsage(Double cpuUsage) { this.cpuUsage = cpuUsage; }
+
+    public Long getTotalMemory() { return totalMemory; }
+    public void setTotalMemory(Long totalMemory) { this.totalMemory = totalMemory; }
+
+    public Long getUsedMemory() { return usedMemory; }
+    public void setUsedMemory(Long usedMemory) { this.usedMemory = usedMemory; }
+
+    public Long getFreeMemory() { return freeMemory; }
+    public void setFreeMemory(Long freeMemory) { this.freeMemory = freeMemory; }
+
+    public Double getMemoryUsage() { return memoryUsage; }
+    public void setMemoryUsage(Double memoryUsage) { this.memoryUsage = memoryUsage; }
+
+    public Double getTotalMemoryMB() { return totalMemoryMB; }
+    public void setTotalMemoryMB(Double totalMemoryMB) { this.totalMemoryMB = totalMemoryMB; }
+
+    public Double getUsedMemoryMB() { return usedMemoryMB; }
+    public void setUsedMemoryMB(Double usedMemoryMB) { this.usedMemoryMB = usedMemoryMB; }
+
+    public Double getFreeMemoryMB() { return freeMemoryMB; }
+    public void setFreeMemoryMB(Double freeMemoryMB) { this.freeMemoryMB = freeMemoryMB; }
+
+    public Integer getIpChannelIn() { return ipChannelIn; }
+    public void setIpChannelIn(Integer ipChannelIn) { this.ipChannelIn = ipChannelIn; }
+
+    public Integer getNetRemain() { return netRemain; }
+    public void setNetRemain(Integer netRemain) { this.netRemain = netRemain; }
+
+    public Integer getNetCapability() { return netCapability; }
+    public void setNetCapability(Integer netCapability) { this.netCapability = netCapability; }
+
+    public Integer getRemotePreview() { return remotePreview; }
+    public void setRemotePreview(Integer remotePreview) { this.remotePreview = remotePreview; }
+
+    public Integer getRemotePlayDownload() { return remotePlayDownload; }
+    public void setRemotePlayDownload(Integer remotePlayDownload) { this.remotePlayDownload = remotePlayDownload; }
+
+    public Integer getRemoteSendRemain() { return remoteSendRemain; }
+    public void setRemoteSendRemain(Integer remoteSendRemain) { this.remoteSendRemain = remoteSendRemain; }
+
+    public Integer getRemoteSendCapability() { return remoteSendCapability; }
+    public void setRemoteSendCapability(Integer remoteSendCapability) { this.remoteSendCapability = remoteSendCapability; }
+
+    public Boolean getSuccess() { return success; }
+    public void setSuccess(Boolean success) { this.success = success; }
+
+    public String getErrorMessage() { return errorMessage; }
+    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+}

+ 67 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/DahuaVideoParam.java

@@ -0,0 +1,67 @@
+package com.ruoyi.dahua.api.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 大华设备视频参数
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DahuaVideoParam implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 码流类型: 0-主码流, 1-辅码流1, 2-辅码流2
+     */
+    private Integer formatType;
+
+    /**
+     * 视频使能: 0-关闭, 1-开启
+     */
+    private Integer videoEnable;
+
+    /**
+     * 视频压缩格式
+     */
+    private Integer compression;
+
+    /**
+     * 视频宽度
+     */
+    private Integer width;
+
+    /**
+     * 视频高度
+     */
+    private Integer height;
+
+    /**
+     * 码流控制模式
+     */
+    private Integer bitRateControl;
+
+    /**
+     * 视频码流(kbps)
+     */
+    private Integer bitRate;
+
+    /**
+     * 视频帧率
+     */
+    private Float frameRate;
+
+    /**
+     * I帧间隔
+     */
+    private Integer iframeInterval;
+
+    /**
+     * 图像质量
+     */
+    private Integer imageQuality;
+}

+ 55 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/domain/LoginDevice.java

@@ -0,0 +1,55 @@
+package com.ruoyi.dahua.api.domain;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+
+import java.io.Serializable;
+
+/**
+ * 海康设备登录信息
+ *
+ * @FileName LoginDevice
+ * @Description
+ * @Author fengcheng
+ * @date 2026-03-28
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Validated
+public class LoginDevice implements Serializable {
+
+    /**
+     * 设备IP
+     */
+    @NotBlank(groups = {LoginDevice.class}, message = "IP不能为空")
+    private String ipAddress;
+
+    /**
+     * 设备端口
+     */
+    @NotNull(groups = {LoginDevice.class}, message = "端口不能为空")
+    private Integer port;
+
+    /**
+     * 用户名
+     */
+    private String userName;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 设备id
+     */
+    private String deviceId;
+
+    /** 上线类型(1=主动添加, 2=主动注册) */
+    private String onlineType;
+}

+ 172 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/java/com/ruoyi/dahua/api/factory/RemoteDaHuaFallbackFactory.java

@@ -0,0 +1,172 @@
+package com.ruoyi.dahua.api.factory;
+
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.domain.RtpServerParam;
+import com.ruoyi.dahua.api.RemoteDaHuaService;
+import com.ruoyi.dahua.api.domain.DahuaDevice;
+import com.ruoyi.dahua.api.domain.LoginDevice;
+import com.ruoyi.dahua.api.domain.DahuaRecordDownloadRequest;
+import com.ruoyi.dahua.api.domain.DahuaRecordDownloadResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.openfeign.FallbackFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * 大华sdk服务降级处理
+ *
+ * @FileName RemoteDaHuaFallbackFactory
+ * @Description
+ * @Author fengcheng
+ * @date 2026-03-30
+ **/
+@Component
+public class RemoteDaHuaFallbackFactory implements FallbackFactory<RemoteDaHuaService> {
+
+    private static final Logger log = LoggerFactory.getLogger(RemoteDaHuaFallbackFactory.class);
+
+
+    @Override
+    public RemoteDaHuaService create(Throwable throwable) {
+        log.error("大华sdk服务调用失败:{}", throwable.getMessage());
+        return new RemoteDaHuaService() {
+            @Override
+            public R<Void> loginDevice(LoginDevice loginDevice, String source) {
+                return R.fail("大华sdk登录设备失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Boolean> isUserId(String ip, String source) {
+                return R.fail("大华sdk查询是否登录失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<String> getTime(String ip, String source) {
+                return R.fail("大华sdk设备获取时间失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Boolean> setTime(Long id, String date, boolean type, String source) {
+                return R.fail("大华sdk设备设置时间失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Boolean> reboot(Long id, String source) {
+                return R.fail("大华sdk设备重启失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<DahuaDevice> getDahuaDevice(String ip, String source) {
+                return R.fail("大华sdk获取主动上线设备失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Boolean> logoutDevice(String ip, String source) {
+                return R.fail("大华sdk退出设备失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> startPlay(RtpServerParam rtpServerParam, String source) {
+                return R.fail("大华sdk开始播放失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> stopPlay(Long id, String source) {
+                return R.fail("大华sdk停止播放失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Boolean> ptzControlUpStart(Long id, int channelId, String direction, Integer speed, String source) {
+                return R.fail("大华sdk云台控制开始失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Boolean> ptzControlUpEnd(Long id, int channelId, String direction, String source) {
+                return R.fail("大华sdk云台控制停止失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<ArrayList<HashMap<String, Object>>> getPresetList(Long id, int channelId, String source) {
+                return R.fail("大华sdk获取预置点列表失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> setPreset(Long id, int channelId, int presetIndex, String source) {
+                return R.fail("大华sdk设置预置点失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> delPreset(Long id, int channelId, int presetIndex, String source) {
+                return R.fail("大华sdk删除预置点失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> invokePreset(Long id, int channelId, int presetIndex, String source) {
+                return R.fail("大华sdk调用预置点失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> controlLight(Long id, int channelId, int action, String source) {
+                return R.fail("大华sdk灯光控制失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> controlWiper(Long id, int channelId, int action, String source) {
+                return R.fail("大华sdk雨刷控制失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> startTour(Long id, int channelId, int tourIndex, String source) {
+                return R.fail("大华sdk开始巡航失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> stopTour(Long id, int channelId, String source) {
+                return R.fail("大华sdk停止巡航失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> addPresetToTour(Long id, int channelId, int tourIndex, int presetIndex, String source) {
+                return R.fail("大华sdk添加预置点到巡航线路失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> removePresetFromTour(Long id, int channelId, int tourIndex, int presetIndex, String source) {
+                return R.fail("大华sdk从巡航线路删除预置点失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> clearTour(Long id, int channelId, int tourIndex, String source) {
+                return R.fail("大华sdk清除巡航线路失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<ArrayList<HashMap<String, Object>>> queryRecord(Long id, int channelId, String startTime, String endTime, String source) {
+                return R.fail("大华sdk查询录像失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> startPlayback(RtpServerParam rtpServerParam, String source) {
+                return R.fail("大华sdk开始录像回放失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Void> stopPlayback(Long id, String source) {
+                return R.fail("大华sdk停止录像回放失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<Long> captureAndSave(Long id, int channelId, String snapshotType, String source) {
+                return R.fail("大华sdk抓图并保存失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<DahuaRecordDownloadResponse> downloadRecord(DahuaRecordDownloadRequest request, String source) {
+                return R.fail("大华sdk录像下载失败:" + throwable.getMessage());
+            }
+        };
+    }
+}

+ 1 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-dahua/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -0,0 +1 @@
+com.ruoyi.dahua.api.factory.RemoteDaHuaFallbackFactory

+ 53 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/pom.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.ruoyi</groupId>
+        <artifactId>ruoyi-api</artifactId>
+        <version>3.6.7</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-api-gb28181</artifactId>
+
+    <description>
+        ruoyi-api-gb28181 国标28181接口模块
+    </description>
+
+    <dependencies>
+
+        <!-- RuoYi Common Core-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
+            <version>4.5.0</version>
+        </dependency>
+
+        <!-- sip协议栈 -->
+        <dependency>
+            <groupId>javax.sip</groupId>
+            <artifactId>jain-sip-ri</artifactId>
+            <version>1.3.0-91</version>
+        </dependency>
+
+        <!-- xml解析库 -->
+        <dependency>
+            <groupId>org.dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>2.1.4</version>
+        </dependency>
+
+        <!-- 泉视接口 -->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-api-qs</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 667 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/RemoteGb28181Service.java

@@ -0,0 +1,667 @@
+package com.ruoyi.gb28181.api;
+
+
+import com.ruoyi.common.core.constant.SecurityConstants;
+import com.ruoyi.common.core.constant.ServiceNameConstants;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.domain.RtpServerParam;
+import com.ruoyi.gb28181.api.domain.CatalogRequest;
+import com.ruoyi.gb28181.api.domain.Device;
+import com.ruoyi.gb28181.api.domain.DeviceChannel;
+import com.ruoyi.gb28181.api.domain.DeviceConfig;
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.gb28181.api.domain.Gb28181Platform;
+import com.ruoyi.gb28181.api.factory.RemoteGb28181FallbackFactory;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * gb28181 服务
+ *
+ * @FileName RemoteGb28181Service
+ * @Description
+ * @Author fengcheng
+ * @date 2026-03-30
+ **/
+@FeignClient(contextId = "remoteGb28181Service", value = ServiceNameConstants.GB28181_SERVICE, fallbackFactory = RemoteGb28181FallbackFactory.class)
+public interface RemoteGb28181Service {
+
+
+    /**
+     * 根据设备id获取设备
+     *
+     * @param gbDeviceId
+     * @param inner
+     * @return
+     */
+    @GetMapping("/api/gb28181/getDeviceByDeviceId/{gbDeviceId}")
+    R<Device> getDeviceByDeviceId(@PathVariable String gbDeviceId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 请求预览视频流
+     *
+     * @param rtpServer
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/playStreamCmd")
+    R<Void> playStreamCmd(@RequestBody RtpServerParam rtpServer, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 请求回放视频流
+     *
+     * @param rtpServer
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/playbackStreamCmd")
+    R<Void> playbackStreamCmd(@RequestBody RtpServerParam rtpServer, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 根据设备id和通道获取设备通道
+     *
+     * @param gbDeviceId
+     * @param gbChannelId
+     * @param inner
+     * @return
+     */
+    @GetMapping("/api/gb28181/getDeviceChannelByChannelId/{gbDeviceId}/{gbChannelId}")
+    R<DeviceChannel> getDeviceChannelByChannelId(@PathVariable String gbDeviceId, @PathVariable String gbChannelId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 停止视频流
+     *
+     * @param rtpServer
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/streamByeCmd")
+    R<Void> streamByeCmd(@RequestBody RtpServerParam rtpServer, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 获取全部设备
+     *
+     * @param inner
+     * @return
+     */
+    @GetMapping("/api/gb28181/getAllDevices")
+    R<List<Device>> getAllDevices(@RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 通用前端控制命令(参考国标文档A.3.1指令格式)
+     *
+     * @param deviceId     设备国标编号
+     * @param channelId    通道国标编号
+     * @param cmdCode      指令码(对应国标文档指令格式中的字节4)
+     * @param parameter1   数据一(对应国标文档指令格式中的字节5, 范围0-255)
+     * @param parameter2   数据二(对应国标文档指令格式中的字节6, 范围0-255)
+     * @param combindCode2 组合码二(对应国标文档指令格式中的字节7, 范围0-15)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/common/ptz/{deviceId}/{channelId}")
+    R<Void> frontEndCommand(@PathVariable String deviceId, @PathVariable String channelId,
+                           @RequestParam Integer cmdCode, @RequestParam Integer parameter1,
+                           @RequestParam Integer parameter2, @RequestParam Integer combindCode2,
+                           @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 云台控制
+     *
+     * @param deviceId      设备国标编号
+     * @param channelId     通道国标编号
+     * @param command       控制指令,允许值: left, right, up, down, upleft, upright, downleft, downright, zoomin, zoomout, stop
+     * @param horizonSpeed  水平速度(0-255)
+     * @param verticalSpeed 垂直速度(0-255)
+     * @param zoomSpeed     缩放速度(0-15)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/ptz/{deviceId}/{channelId}")
+    R<Void> ptz(@PathVariable String deviceId, @PathVariable String channelId,
+               @RequestParam String command, @RequestParam Integer horizonSpeed,
+               @RequestParam Integer verticalSpeed, @RequestParam Integer zoomSpeed,
+               @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 光圈控制
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param command   控制指令,允许值: in, out, stop
+     * @param speed     光圈速度(0-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/fi/iris/{deviceId}/{channelId}")
+    R<Void> iris(@PathVariable String deviceId, @PathVariable String channelId,
+                @RequestParam String command, @RequestParam Integer speed,
+                @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 聚焦控制
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param command   控制指令,允许值: near, far, stop
+     * @param speed     聚焦速度(0-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/fi/focus/{deviceId}/{channelId}")
+    R<Void> focus(@PathVariable String deviceId, @PathVariable String channelId,
+                 @RequestParam String command, @RequestParam Integer speed,
+                 @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 查询预置位
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param inner
+     * @return
+     */
+    @GetMapping("/api/gb28181/preset/query/{deviceId}/{channelId}")
+    R<Object> queryPreset(@PathVariable String deviceId, @PathVariable String channelId,
+                          @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 预置位指令-设置预置位
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param presetId  预置位编号(1-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/preset/add/{deviceId}/{channelId}")
+    R<Void> addPreset(@PathVariable String deviceId, @PathVariable String channelId,
+                      @RequestParam Integer presetId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 预置位指令-调用预置位
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param presetId  预置位编号(1-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/preset/call/{deviceId}/{channelId}")
+    R<Void> callPreset(@PathVariable String deviceId, @PathVariable String channelId,
+                      @RequestParam Integer presetId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 预置位指令-删除预置位
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param presetId  预置位编号(1-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/preset/delete/{deviceId}/{channelId}")
+    R<Void> deletePreset(@PathVariable String deviceId, @PathVariable String channelId,
+                         @RequestParam Integer presetId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 巡航指令-加入巡航点
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param cruiseId  巡航组号(0-255)
+     * @param presetId  预置位编号(1-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/cruise/point/add/{deviceId}/{channelId}")
+    R<Void> addCruisePoint(@PathVariable String deviceId, @PathVariable String channelId,
+                          @RequestParam Integer cruiseId, @RequestParam Integer presetId,
+                          @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 巡航指令-删除一个巡航点
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param cruiseId  巡航组号(1-255)
+     * @param presetId  预置位编号(0-255, 为0时删除整个巡航)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/cruise/point/delete/{deviceId}/{channelId}")
+    R<Void> deleteCruisePoint(@PathVariable String deviceId, @PathVariable String channelId,
+                             @RequestParam Integer cruiseId, @RequestParam Integer presetId,
+                             @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 巡航指令-设置巡航速度
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param cruiseId  巡航组号(0-255)
+     * @param speed     巡航速度(1-4095)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/cruise/speed/{deviceId}/{channelId}")
+    R<Void> setCruiseSpeed(@PathVariable String deviceId, @PathVariable String channelId,
+                          @RequestParam Integer cruiseId, @RequestParam Integer speed,
+                          @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 巡航指令-设置巡航停留时间
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param cruiseId  巡航组号
+     * @param time      巡航停留时间(1-4095)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/cruise/time/{deviceId}/{channelId}")
+    R<Void> setCruiseTime(@PathVariable String deviceId, @PathVariable String channelId,
+                         @RequestParam Integer cruiseId, @RequestParam Integer time,
+                         @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 巡航指令-开始巡航
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param cruiseId  巡航组号
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/cruise/start/{deviceId}/{channelId}")
+    R<Void> startCruise(@PathVariable String deviceId, @PathVariable String channelId,
+                       @RequestParam Integer cruiseId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 巡航指令-停止巡航
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param cruiseId  巡航组号
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/cruise/stop/{deviceId}/{channelId}")
+    R<Void> stopCruise(@PathVariable String deviceId, @PathVariable String channelId,
+                      @RequestParam Integer cruiseId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 扫描指令-开始自动扫描
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param scanId    扫描组号(0-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/scan/start/{deviceId}/{channelId}")
+    R<Void> startScan(@PathVariable String deviceId, @PathVariable String channelId,
+                     @RequestParam Integer scanId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 扫描指令-停止自动扫描
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param scanId    扫描组号(0-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/scan/stop/{deviceId}/{channelId}")
+    R<Void> stopScan(@PathVariable String deviceId, @PathVariable String channelId,
+                    @RequestParam Integer scanId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 扫描指令-设置自动扫描左边界
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param scanId    扫描组号(0-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/scan/set/left/{deviceId}/{channelId}")
+    R<Void> setScanLeft(@PathVariable String deviceId, @PathVariable String channelId,
+                       @RequestParam Integer scanId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 扫描指令-设置自动扫描右边界
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param scanId    扫描组号(0-255)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/scan/set/right/{deviceId}/{channelId}")
+    R<Void> setScanRight(@PathVariable String deviceId, @PathVariable String channelId,
+                        @RequestParam Integer scanId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 扫描指令-设置自动扫描速度
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param scanId    扫描组号(0-255)
+     * @param speed     自动扫描速度(1-4095)
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/scan/set/speed/{deviceId}/{channelId}")
+    R<Void> setScanSpeed(@PathVariable String deviceId, @PathVariable String channelId,
+                        @RequestParam Integer scanId, @RequestParam Integer speed,
+                        @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 辅助开关控制指令-雨刷控制
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param command   控制指令,允许值: on, off
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/wiper/{deviceId}/{channelId}")
+    R<Void> wiper(@PathVariable String deviceId, @PathVariable String channelId,
+                 @RequestParam String command, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 辅助开关控制指令
+     *
+     * @param deviceId  设备国标编号
+     * @param channelId 通道国标编号
+     * @param command   控制指令,允许值: on, off
+     * @param switchId  开关编号
+     * @param inner
+     */
+    @GetMapping("/api/gb28181/auxiliary/{deviceId}/{channelId}")
+    R<Void> auxiliarySwitch(@PathVariable String deviceId, @PathVariable String channelId,
+                           @RequestParam String command, @RequestParam Integer switchId,
+                           @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 平台级联 - 注册
+     *
+     * @param platform 平台配置
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/platform/cascade/register")
+    R<Void> registerPlatform(@RequestBody Gb28181Platform platform, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 平台级联 - 注销
+     *
+     * @param platform 平台配置
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/platform/cascade/unregister")
+    R<Void> unregisterPlatform(@RequestBody Gb28181Platform platform, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 平台级联 - 发送心跳
+     *
+     * @param platform 平台配置
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/platform/cascade/heartbeat")
+    R<Void> sendHeartbeat(@RequestBody Gb28181Platform platform, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 平台级联 - 发送设备信息
+     *
+     * @param platform 平台配置
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/platform/cascade/deviceInfo")
+    R<Void> sendDeviceInfo(@RequestBody Gb28181Platform platform, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 平台级联 - 发送目录
+     *
+     * @param catalogRequest 目录请求
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/platform/cascade/catalog")
+    R<Void> sendCatalog(@RequestBody CatalogRequest catalogRequest, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 平台级联 - 启动单个平台
+     *
+     * @param platformId 平台ID
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/platform/cascade/start/{platformId}")
+    R<Void> startPlatformCascade(@PathVariable Long platformId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 平台级联 - 停止单个平台
+     *
+     * @param platformId 平台ID
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/platform/cascade/stop/{platformId}")
+    R<Void> stopPlatformCascade(@PathVariable Long platformId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 平台级联 - 重启单个平台
+     *
+     * @param platformId 平台ID
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/platform/cascade/restart/{platformId}")
+    R<Void> restartPlatformCascade(@PathVariable Long platformId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 平台级联 - 手动推送目录
+     *
+     * @param platformId 平台ID
+     * @param inner
+     * @return
+     */
+    @PostMapping("/api/gb28181/platform/cascade/catalog/{platformId}")
+    R<Void> pushCatalog(@PathVariable Long platformId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 查询设备配置
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param configType 配置类型,多个用/分隔
+     * @param inner
+     * @return 设备配置
+     */
+    @GetMapping("/api/gb28181/config/{gbDeviceId}")
+    R<Object> queryDeviceConfig(@PathVariable String gbDeviceId, @RequestParam String configType, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 修改设备配置
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param deviceConfig 设备配置
+     * @param inner
+     * @return 操作结果
+     */
+    @PostMapping("/api/gb28181/config/{gbDeviceId}")
+    R<Object> updateDeviceConfig(@PathVariable String gbDeviceId, @RequestBody DeviceConfig deviceConfig, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 查询看守位
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param inner
+     * @return 看守位信息
+     */
+    @GetMapping("/api/gb28181/homePosition/{gbDeviceId}")
+    R<Object> queryHomePosition(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 设置看守位
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param deviceConfig 看守位配置
+     * @param inner
+     * @return 操作结果
+     */
+    @PostMapping("/api/gb28181/homePosition/{gbDeviceId}")
+    R<Object> updateHomePosition(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestBody DeviceConfig deviceConfig, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 查询巡航轨迹列表
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param inner
+     * @return 巡航轨迹列表
+     */
+    @GetMapping("/api/gb28181/cruiseTrackList/{gbDeviceId}")
+    R<Object> queryCruiseTrackList(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 查询巡航轨迹
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param number 轨迹编号:0-第一条轨迹,1-第二条轨迹
+     * @param inner
+     * @return 巡航轨迹信息
+     */
+    @GetMapping("/api/gb28181/cruiseTrack/{gbDeviceId}")
+    R<Object> queryCruiseTrack(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestParam Integer number, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * PTZ精准状态查询
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param inner
+     * @return PTZ精准状态信息
+     */
+    @GetMapping("/api/gb28181/ptzPosition/{gbDeviceId}")
+    R<Object> queryPTZPosition(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 存储卡状态查询
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param inner
+     * @return 存储卡状态信息
+     */
+    @GetMapping("/api/gb28181/sdCardStatus/{gbDeviceId}")
+    R<Object> querySDCardStatus(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 报警复位控制
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param alarmMethod 报警方式(可选),0-全部,1-电话报警,2-设备报警,3-短信报警,4-GPS报警,5-视频报警,6-设备故障报警,7-其他报警
+     * @param alarmType 报警类型(可选)
+     * @param inner
+     * @return 报警复位控制结果
+     */
+    @PostMapping("/api/gb28181/alarmReset/{gbDeviceId}")
+    R<Object> alarmResetControl(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestParam(required = false) String alarmMethod, @RequestParam(required = false) String alarmType, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 强制关键帧控制
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param inner
+     * @return 强制关键帧控制结果
+     */
+    @PostMapping("/api/gb28181/iFrame/{gbDeviceId}")
+    R<Object> iFrameControl(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 看守位控制
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param deviceConfig 设备配置,包含看守位配置
+     * @param inner
+     * @return 看守位控制结果
+     */
+    @PostMapping("/api/gb28181/homePosition/{gbDeviceId}")
+    R<Object> homePositionControl(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestBody DeviceConfig deviceConfig, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * PTZ精准控制
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param ptzPreciseCtrl PTZ精准控制参数
+     * @param inner
+     * @return PTZ精准控制结果
+     */
+    @PostMapping("/api/gb28181/ptzPrecise/{gbDeviceId}")
+    R<Object> ptzPreciseControl(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId, @RequestBody JSONObject ptzPreciseCtrl, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 设备软件升级控制
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param firmware 设备固件版本
+     * @param fileURL 升级文件的完整路径
+     * @param manufacturer 设备厂商
+     * @param sessionID 会话ID
+     * @param inner
+     * @return 设备软件升级控制结果
+     */
+    @PostMapping("/api/gb28181/deviceUpgrade/{gbDeviceId}")
+    R<Object> deviceUpgradeControl(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId,
+        @RequestParam String firmware, @RequestParam String fileURL, @RequestParam String manufacturer,
+        @RequestParam String sessionID, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 存储卡格式化控制
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param sdCardId SD卡编号(0表示所有存储卡)
+     * @param inner
+     * @return 存储卡格式化控制结果
+     */
+    @PostMapping("/api/gb28181/formatSDCard/{gbDeviceId}")
+    R<Object> formatSDCardControl(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId,
+        @RequestParam Integer sdCardId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 目标跟踪控制
+     *
+     * @param gbDeviceId 设备国标编号(球机通道)
+     * @param channelId 通道国标编号(可选,指球机通道)
+     * @param targetTrack 跟踪类型:Auto/Manual/Stop
+     * @param deviceId2 目标设备编码(可选,指全景相机中的全景通道ID)
+     * @param targetArea 目标区域(可选,手动跟踪时需要)
+     * @param inner
+     * @return 目标跟踪控制结果
+     */
+    @PostMapping("/api/gb28181/targetTrack/{gbDeviceId}")
+    R<Object> targetTrackControl(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId,
+        @RequestParam String targetTrack, @RequestParam(required = false) String deviceId2,
+        @RequestBody(required = false) JSONObject targetArea, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+     /**
+     * 抓图控制
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param channelId 通道国标编号(可选)
+     * @param snapshotType 抓图类型(可选)
+     * @param inner
+     * @return 抓图记录ID
+     */
+    @PostMapping("/api/gb28181/captureAndSave/{gbDeviceId}")
+    R<Long> captureAndSave(@PathVariable String gbDeviceId, @RequestParam(required = false) String channelId,
+        @RequestParam(required = false) String snapshotType, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+    /**
+     * 设备校时控制
+     *
+     * @param gbDeviceId 设备国标编号
+     * @param inner
+     * @return 校时结果
+     */
+    @PostMapping("/api/gb28181/timeCheck/{gbDeviceId}")
+    R<Object> timeCheckCmd(@PathVariable String gbDeviceId, @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
+
+}

+ 13 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/DeviceNotFoundEvent.java

@@ -0,0 +1,13 @@
+package com.ruoyi.gb28181.api.bean;
+
+import lombok.Data;
+
+@Data
+public class DeviceNotFoundEvent {
+
+    private String callId;
+
+    public DeviceNotFoundEvent(String callId) {
+        this.callId = callId;
+    }
+}

+ 6 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/ErrorCallback.java

@@ -0,0 +1,6 @@
+package com.ruoyi.gb28181.api.bean;
+
+public interface ErrorCallback<T> {
+
+    void run(int code, String msg, T data);
+}

+ 46 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/Gb28181Sdp.java

@@ -0,0 +1,46 @@
+package com.ruoyi.gb28181.api.bean;
+
+import javax.sdp.SessionDescription;
+
+/**
+ * 28181 的SDP解析器
+ */
+public class Gb28181Sdp {
+    private SessionDescription baseSdb;
+    private String ssrc;
+
+    private String mediaDescription;
+
+    public static Gb28181Sdp getInstance(SessionDescription baseSdb, String ssrc, String mediaDescription) {
+        Gb28181Sdp gb28181Sdp = new Gb28181Sdp();
+        gb28181Sdp.setBaseSdb(baseSdb);
+        gb28181Sdp.setSsrc(ssrc);
+        gb28181Sdp.setMediaDescription(mediaDescription);
+        return gb28181Sdp;
+    }
+
+
+    public SessionDescription getBaseSdb() {
+        return baseSdb;
+    }
+
+    public void setBaseSdb(SessionDescription baseSdb) {
+        this.baseSdb = baseSdb;
+    }
+
+    public String getSsrc() {
+        return ssrc;
+    }
+
+    public void setSsrc(String ssrc) {
+        this.ssrc = ssrc;
+    }
+
+    public String getMediaDescription() {
+        return mediaDescription;
+    }
+
+    public void setMediaDescription(String mediaDescription) {
+        this.mediaDescription = mediaDescription;
+    }
+}

+ 43 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/MessageResponseTask.java

@@ -0,0 +1,43 @@
+package com.ruoyi.gb28181.api.bean;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+import org.dom4j.Element;
+
+import java.util.List;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
+
+public class MessageResponseTask<T> implements Delayed {
+
+    @Getter
+    @Setter
+    private Element element;
+
+    @Getter
+    @Setter
+    private List<T> data;
+
+    @Getter
+    @Setter
+    private String key;
+
+
+    /**
+     * 超时时间(单位: 毫秒)
+     */
+    @Getter
+    @Setter
+    private long delayTime;
+
+    @Override
+    public long getDelay(@NotNull TimeUnit unit) {
+        return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+    public int compareTo(@NotNull Delayed o) {
+        return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
+    }
+}

+ 12 - 0
ruoyi-qs-nvr-master/ruoyi-api/ruoyi-api-gb28181/src/main/java/com/ruoyi/gb28181/api/bean/Preset.java

@@ -0,0 +1,12 @@
+package com.ruoyi.gb28181.api.bean;
+
+
+import lombok.Data;
+
+@Data
+public class Preset {
+
+    private String presetId;
+
+    private String presetName;
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов