# SkyNet **Repository Path**: jaydomchen/sky-net ## Basic Information - **Project Name**: SkyNet - **Description**: sky-net 是面向山林防火场景的无人机管控平台,需求涵盖"感知层 → 通信层 → 数据层 → 平台服务层 → 应用层 → 展现层"6 层架构与 7 大业务模块(设备 / 告警 / 飞行任务 / 灭火派发 / GIS 一张图 / 视频中心 / 系统管理)。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2026-07-14 - **Last Updated**: 2026-09-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # sky-net · 森林防火无人机管控平台 > **全自主无人机森林防火应急系统的控制软件与低空管控平台** > Vue3 + Go 重写,6 容器 Docker 一键部署,内网私有化,等保 2.0 三级 --- ## 一、项目简介 **sky-net** 是面向山林防火场景的无人机管控平台,需求涵盖"感知层 → 通信层 → 数据层 → 平台服务层 → 应用层 → 展现层"6 层架构与 7 大业务模块(设备 / 告警 / 飞行任务 / 灭火派发 / GIS 一张图 / 视频中心 / 系统管理)。 参考项目 `NexusHive-v2`(PHP/ThinkPHP/BuildAdmin 派生的 DJI 无人机云平台):复用其前端基建、RBAC 模型、CRUD 范式、表结构、部署编排;后端从 PHP 重写为 Go(Gin + GORM)。表前缀 `nz_`。 **已通过 10 轮迭代端到端验证**(smoke-test 25 阶段全绿): | 轮次 | 主题 | 关键交付 | |---|---|---| | 1 | 架构骨架 + 通用后台 | 5 容器一键起 / 登录 / RBAC / 泛型 CRUD / MQTT-WS 桥接 / 双 Token 刷新 | | 2 | 核心业务 CRUD 闭环 | 设备 / 航线 / 飞行任务 / 告警 + 自定义 action + MQTT OSD 落库 | | 3 | 灭火闭环最小骨架 | 派发 → `flighttask_prepare/execute` 下行 → `services_reply` → `progress` → 状态机 `sent→flying→done` | | 4 | GIS 一张图 + WebSocket 实时推送 | leaflet marker + 8 处 broadcast + smoke 阶段 10 | | 5 | 多级联动权限 | GB/T 2260 行政区划数据隔离(省→市→县)+ smoke 阶段 11 + 区域管理页 | | 6 | 灭火闭环完善 | 投弹下行 + 换弹换电 + undo 回滚 + 断点续飞 + smoke 阶段 12-15 | | 7 | 视频双推流 + GCJ02 坐标系 | ZLMediaKit 容器化(GB28181+RTSP)+ WGS84↔GCJ02↔BD09 批量转换 + tileUrl 切 _w/_c/_b 底图 + smoke 阶段 16-18 | | 8 | AI 烟火识别 + 等保 2.0 三级 | AI events 解析 + 模型/复核/样本/统计/配置 5 表 + AES-256-GCM 加密 + 审计哈希链 + HTTPS + MQTT TLS + smoke 阶段 19-22 | | 9 | 视频中心深化 | 录像(手动+告警联动)+ PTZ 双轨(DJI MQTT / GB28181 SIP XML)+ GB28181 点播/回放 + smoke 阶段 23-24 | | 10 | 灭火指挥增强 | 高空喊话(手动+航点自动+告警联动)+ 15km 影响范围标绘 + 火势蔓延椭圆预测(30/60/120min)+ smoke 阶段 25 | ## 二、核心功能 ### 业务模块 - **设备管理**:飞行器 / 负载 / 遥控 / 机场 4 类设备 CRUD + 实时状态(OSD 落库)+ 在线/离线 - **告警管理**:火点 / 烟情告警入库 + 状态流转(待处理 → 已确认 → 已关闭)+ 实时广播 - **航线管理**:KMZ 航线 CRUD + 航点 / 投弹航点配置 - **飞行任务**:手动 / 派发生成 2 类任务 + 状态机(sent/in_progress/ok/failed/paused/canceled)+ **断点续飞**(电量低自动回充后 resume) - **灭火派发**:半自动派发(admin 确认告警 → 选设备/航线 → 下行)+ 状态机 + MQTT 闭环 + **undo 回滚**(admin 主动 + 告警解绑) - **灭火闭环**(第六轮完善): - **投弹下行**(按 waypoint 自动)— `payload_drop` DJI 协议 + 投弹计数 - **换弹换电**(飞行器 done 后自动)— `dock_replace_battery` + `dock_reload_payload` - **GIS 一张图**:leaflet 实时地图 + 火点 / 设备 / 处置 marker + **GCJ02 坐标系转换**(按 gis_coord_type 自动批量转换 marker 坐标 + tileUrl 切 _w/_c/_b 底图)+ WebSocket 实时刷新 - **灭火指挥增强**(第十轮):**高空喊话**(DJI 喊话器 MQTT 下行,手动 / 航点自动 / 告警联动)+ **15km 影响范围标绘**(告警确认后 GIS 画圆 + 范围内设备 haversine 查询)+ **火势蔓延预测**(Rothermel 椭圆蔓延模型 30/60/120min 多边形 + WS 推送) - **媒体中心**:媒体文件 CRUD + RTMP 推流配置 - **方舱固件**:固件版本管理 + 固件升级任务(execute / cancel 状态流转) - **视频中心 / 实时推流**(第七轮):ZLMediaKit 容器化支持 RTSP 拉流 + RTMP 推流 + HLS/FLV/WebRTC 播放 + **GB28181 国标平台注册**(下级域接入国标上级) - **系统管理**:用户 / 角色 / 权限 / 区域 / 配置中心 ### 平台能力 - **RBAC**:admin / group / rule 三级权限模型 + `allAuth` / `personal` / `parent` 三种数据权限 - **多级联动权限**(GB/T 2260):admin 绑定 `area_code` + `area_level` → 后端 `applyDataLimit` 按级别截前缀 LIKE 过滤 - **双 Token 刷新**:access token (短) + refresh token (长) + 自动续期 - **统一响应**:`{code, msg, data}` 格式 + 错误码体系 - **WebSocket 实时推送**:13 个 topic 覆盖设备 / 告警 / 处置 / 维护 / 投弹 / 喊话 / 视频控制 / 火势蔓延全场景 - **流媒体服务**(ZLMediaKit):单进程 6 协议(RTSP/RTMP/HLS/FLV/WebRTC/GB28181)+ 拉流保活 worker(30s 断流重拉) - **配置中心**:基础配置 + 运行时配置 + 自动升级(WMTS → XYZ)+ 坐标系列表(wgs84/gcj02/bd09) - **审计日志**:增删改查全留痕(基础) ## 三、技术栈 ### 后端(`backend/`) - **语言**:Go 1.22+ - **Web 框架**:Gin - **ORM**:GORM v2 - **MQTT 客户端**:paho.mqtt.golang - **WebSocket**:nhooyr/websocket(自实现 hub) - **Redis 客户端**:go-redis/v9 - **流媒体客户端**:HTTP API 封装 ZLMediaKit(`internal/service/zlmediakit/`) - **配置**:环境变量 + Cobra CLI - **认证**:JWT(双 Token) ### 前端(`frontend/`) - **框架**:Vue 3.5 + TypeScript 5.7 - **UI 库**:Element Plus 2.11 - **构建**:Vite 6.3 - **状态管理**:Pinia 2.3 + pinia-plugin-persistedstate - **路由**:vue-router 4(hash 模式) - **地图**:Leaflet 1.9 + 坐标转换工具(`utils/coordTransform.ts`,国测局火星算法) - **图表**:ECharts 6 - **视频**:rtmpLive 组件(webrtc/flv/hls 三协议切换) - **HTTP**:axios 1.9 - **i18n**:vue-i18n 11 - **单测**:vitest(coordTransform 8 测试用例) - **代码生成**:基于 BuildAdmin 派生 ### 基础设施 - **6 容器 Docker Compose**: - `app`(Go 后端,8080/8088) - `mysql`(3306) - `mqtt`(1883+8083 ws) - `redis`(6379) - `web`(nginx 80) - `zlmediakit`(流媒体:554 RTSP / 11935 RTMP / 18080 HTTP API+HLS+FLV+WebRTC / 5060 SIP-GB28181) - **Nginx**:SPA 前端 + `/admin` `/api` `/ws` 反向代理到 app - **MQTT Broker**:eclipse-mosquitto 2.0 - **数据库**:MySQL 8.0(utf8mb4) - **流媒体**:ZLMediaKit 官方镜像 `zlmediakit/zlmediakit:master` ## 四、系统架构 ``` ┌──────────────────────────────────────────────────────────────┐ │ nginx (web:80) │ │ ├─ / SPA 前端(vue dist) │ │ ├─ /admin/ 反代 → app:8080(后端 API) │ │ ├─ /api/ 反代 → app:8080(公共/健康检查) │ │ ├─ /ws 反代 → app:8088(WebSocket 实时推送) │ │ └─ /mqtt 反代 → mqtt:8083(MQTT over WebSocket) │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌──────────────┐ │ app │ │ mysql │ │ redis │ │ mqtt │ │ zlmediakit │ │ Go+Gin │ │ 8.0 │ │ 7 │ │ 2.0 │ │ 6 协议流媒体 │ │ 8080/ │ │ 3306 │ │ 6379 │ │ 1883/ │ │ 554/11935/ │ │ 8088 │ │ │ │ │ │ 8083 │ │ 18080/5060 │ └────────┘ └────────┘ └────────┘ └────────┘ └──────────────┘ ``` **网络**:6 容器在 `skynet_net` bridge 网络互通;app 通过 `mysql:3306` / `redis:6379` / `mqtt:1883` / `zlmediakit:80` 内部访问;web 通过反代暴露 80 端口给浏览器。 ## 五、部署方法 ### 1. 环境要求 - **Docker** 20.10+ & **Docker Compose** v2 - **宿主机端口**:80(web)、554(RTSP,第七轮新增)、18080(zlmediakit HTTP,避 8080 冲突)、5060(SIP-GB28181)、3306(mysql,可改)、6379(redis,可改)、1883/8083(mqtt,可改) - **磁盘**:≥ 10GB(mysql + uploads + zlmediakit 流) - **内存**:≥ 4GB ### 2. 克隆与初始化 ```bash git clone https://gitee.com/jaydomchen/sky-net.git cd sky-net/deploy make init # 复制 .env.example → .env ``` 按需编辑 `deploy/.env`(默认密码仅适用于内网测试,**生产环境必须修改**): ```ini # 数据库 MYSQL_ROOT_PASSWORD=your_root_pwd MYSQL_PASSWORD=your_db_pwd # JWT 密钥(生产环境必须 32+ 字符随机串) JWT_SECRET=your_random_32_char_secret # Web 端口(默认 80) WEB_PORT=80 ``` ### 3. 一键启动 ```bash make up # 启动 6 容器(首次会自动 build app + web + zlmediakit 镜像) make ps # 查看容器状态(等 mysql 显示 healthy 再继续) ``` ### 4. 数据库迁移与初始管理员 ```bash make migrate # AutoMigrate 建表 + 种子数据(区划/菜单/角色/zlmediakit 配置等) make create-admin # 默认创建 super admin: admin / Admin@123 ``` 自定义管理员(带区划): ```bash docker compose exec -T app /app/skynet create-admin \ --user hn_admin --pass Pass@123 \ --nick "湖南管理员" \ --area 430000 --area-name "湖南省" --area-level 1 ``` ### 5. 访问入口 - **Web UI**:http://localhost(默认账号 `admin` / `Admin@123`) - **后端 API**:http://localhost/admin//(header `batoken: `) - **健康检查**:`curl http://localhost/api/health` → `{"status":"ok"}` - **WebSocket**:`ws://localhost/ws`(前端 utils/ws.ts 已封装) - **ZLMediaKit API**(第七轮):http://localhost:18080/index/api/getApiList?secret=...(流代理管理) - **ZLMediaKit RTSP**(第七轮):`rtsp://localhost:554/live/.live.ts`(设备原生 RTSP 拉流转 HLS/FLV/WebRTC) ### 6. 端到端验证(可选) ```bash make smoke-test # 跑全部 25 阶段冒烟测试 ``` 预期输出 `smoke-test 全部通过`,含: - 阶段 1-6:基础可达 + 登录 + 8 业务模块 index + 告警/固件状态流转 + MQTT OSD 落库 - 阶段 7-9:灭火派发 + services_reply + progress 状态闭环 - 阶段 10:GIS 实时推送(OSD / 新告警广播) - 阶段 11:多级联动权限(super/hn_admin/cs_admin/cs_furong 4 角色告警数据隔离) - 阶段 12:投弹下行(按 waypoint 自动 + 投弹计数) - 阶段 13:换弹换电(done 后自动下发 + 计数) - 阶段 14:undo 回滚(admin 主动 + 告警解绑) - 阶段 15:断点续飞(电量回升后自动 resume) - 阶段 16-18:RTSP 拉流转推(ZLMediaKit)/ GCJ02 转换(前端 vitest)/ GB28181 国标平台注册 - 阶段 19-20:非超管菜单(GetMenus 父节点自动补齐)/ 等保身份鉴别(密码复杂度 + 登录失败锁定 + 登录审计 + 限流 + 密码过期 + 默认密钥校验) - 阶段 21-22:AI 烟火识别(events 解析 + 人工复核 + 统计 + 阈值下发 + 双模型校验)/ 等保剩余(AES-256-GCM 加密 + 审计哈希链 + HTTPS + MQTT TLS) - 阶段 23-24:视频录像(手动 + 告警联动)/ PTZ 双轨(DJI MQTT + GB28181 SIP XML)/ GB28181 点播回放 - 阶段 25:灭火增强(喊话手动下行 + 航点自动喊话 + 计数回写 + 15km 范围查询 + 火势蔓延预测 + 告警联动) ## 六、目录结构 ``` sky-net/ ├── backend/ # Go 后端 │ ├── cmd/skynet/ # CLI 入口(migrate / create-admin / serve / worker / all) │ │ ├── main.go # Cobra 根命令 │ │ ├── serve.go # API + WS 服务 │ │ ├── worker.go # MQTT 落库 worker │ │ ├── migrate.go # AutoMigrate + 种子数据 │ │ ├── create_admin.go # 初始化管理员 │ │ └── area_data.go # GB/T 2260 行政区划种子 │ ├── internal/ │ │ ├── config/ # 环境变量加载 │ │ ├── db/ # MySQL/Redis 连接 │ │ ├── log/ # zap logger │ │ ├── lib/ # 通用工具(mqtt, jwt, response, ws hub) │ │ ├── model/ # GORM 模型(admin, area, biz/*) │ │ ├── middleware/ # Gin 中间件(admin_auth 鉴权 + ctx 注入) │ │ ├── router/ # 路由注册 │ │ ├── controller/ # 业务 controller(含 BaseCRUD 泛型 + 标准 CRUD) │ │ │ ├── stream_proxy.go # 第七轮:RTSP 拉流转 HLS/FLV/WebRTC │ │ │ ├── gb28181.go # 第七轮:国标平台注册 │ │ │ ├── biz_speaker.go # 第十轮:高空喊话下行(play/stop/test) │ │ │ └── biz_firespread.go # 第十轮:火势蔓延预测(predict/refresh/history) │ │ ├── service/ │ │ │ ├── auth/ # JWT 鉴权 │ │ │ ├── crud/ # 泛型 BaseCRUD + applyDataLimit │ │ │ ├── dispatcher/ # 灭火派发编排(Redis 锁 + payload + 状态机) │ │ │ ├── mqtt_handler/ # OSD/events/services_reply 落库 │ │ │ ├── zlmediakit/ # 第七轮:ZLMediaKit HTTP API 客户端 │ │ │ ├── firespread/ # 第十轮:椭圆蔓延模型预测 │ │ │ ├── speaker/ # 第十轮:告警联动喊话 │ │ │ └── configcenter/ # 运行时配置 + 自动升级 │ │ └── task/cron.go # 定时任务(第七轮加流保活 worker) │ ├── go.mod / go.sum │ └── Dockerfile # 多阶段构建(deploy/backend/Dockerfile) │ ├── frontend/ # Vue3 前端 │ ├── src/ │ │ ├── api/ # axios 接口封装 │ │ ├── components/ # 通用组件(baTable / baInput / icon / rtmpLive 视频) │ │ ├── lang/ # vue-i18n 文案(zh-cn / en) │ │ ├── router/ # vue-router 路由(hash 模式) │ │ ├── stores/ # pinia stores(adminInfo / config / runtimeConfig) │ │ ├── utils/ # 工具(axios / ws / coordTransform 坐标转换) │ │ │ └── coordTransform.ts # 第七轮:WGS84↔GCJ02↔BD09 转换 + tileUrl 选择 │ │ └── views/ # 业务页面(backend/ + frontend/) │ │ └── backend/monitor/ # 监控中心:实时视频 + 告警 + 处置 + leaflet + GCJ02 渲染 │ ├── public/ # 静态资源 │ ├── types/ # TypeScript 类型声明 │ ├── vite.config.ts # Vite 配置 │ ├── vitest.config.ts # vitest 单测配置 │ ├── package.json │ └── Dockerfile # 构建 SPA + nginx │ ├── deploy/ # 部署 │ ├── docker-compose.yml # 6 服务编排 │ ├── docker-entrypoint.sh # app 容器入口 │ ├── mosquitto.conf # MQTT broker 配置 │ ├── nginx/default.conf # 反向代理 + SPA fallback │ ├── backend/Dockerfile # Go 多阶段构建 │ ├── frontend/Dockerfile # 前端构建 + nginx │ ├── zlmediakit/ # 第七轮:流媒体容器 │ │ ├── Dockerfile # 基于 zlmediakit/zlmediakit:master │ │ └── config.ini # GB28181 + RTSP/RTMP/HLS 配置 │ ├── scripts/ │ │ ├── smoke-test.sh # 25 阶段端到端测试 │ │ └── backup.sh # 数据库备份 │ ├── Makefile # init / up / migrate / smoke-test / 各种 shell │ └── .env.example # 环境变量模板 │ ├── .gitignore # 忽略 node_modules / dist / .claude / 需求/ 等 └── README.md # 本文档 ``` ## 七、运维常用命令 ```bash # 容器管理 make up / down / restart / ps / logs make app-shell # 进入 app 容器 make mysql-shell # 进入 mysql 客户端 make redis-shell # 进入 redis 客户端 # ZLMediaKit 运维(第七轮) docker exec skynet_zlmediakit cat /opt/media/bin/config.ini | grep secret # 读取 ZLMediaKit 自动生成的 secret(master 镜像 -s 参数被 reject) docker exec skynet_zlmediakit wget -qO- 'http://localhost:80/index/api/getApiList?secret=' # 验证 ZLMediaKit API 可达 # 数据管理 make migrate # 增量迁移(添加字段/索引) make backup # 数据库备份 # 重建镜像(代码更新后) make rebuild # 等价于 make build + make up # 注意:migrate 在 rebuild 之前会保留旧表结构,rebuild 后必须再跑 make migrate 加新字段 # 清理 make clean-volumes # 删除所有卷(含数据,不可恢复) make prune # 清理 dangling 镜像 ``` ## 八、开发说明 ### 本地开发(不依赖 Docker) ```bash # 后端 cd backend go mod download go run ./cmd/skynet all # 启动 API+WS(默认读 .env 配置,需连外部 mysql/redis/mqtt) # 前端 cd frontend npm install npm run dev # 默认端口 2819,proxy 指向 backend npm test # 跑 vitest 单测(含 coordTransform 8 用例) ``` ### 添加新业务模块 1. `backend/internal/model/biz/.go` — GORM 模型(含 `AreaCode` 字段) 2. `backend/internal/model/register.go` — 加入 `AllModels` 3. `backend/internal/controller/.go` — `BaseCRUD[biz.X]` + 自定义 action 4. `backend/internal/controller/register.go` — `Register("biz.", NewCtrl())` 5. `backend/cmd/skynet/migrate.go` — 菜单 seed 6. `frontend/src/api/backend.ts` — 接口 URL 注册 7. `frontend/src/views/backend/biz//` — 列表/表单页(用 baTable 模式) 8. `frontend/src/lang/backend/zh-cn/.ts` — i18n 9. `frontend/src/lang/autoload.ts` — 注册 i18n 路径 ### 调试 MQTT / ZLMediaKit ```bash # 订阅 MQTT docker exec skynet_mqtt mosquitto_sub -h localhost -t 'thing/product/+/+' -v # 发布 MQTT docker exec skynet_mqtt mosquitto_pub -h localhost -t thing/product/SMOKE_SN/osd \ -m '{"host":{"sn":"SMOKE_SN"},"data":{"latitude":30.5,"longitude":114.3,"battery_percent":80,"mode_code":1}}' # RTSP 拉流转推(第七轮) docker exec skynet_app wget -qO- "http://zlmediakit:80/index/api/addStreamProxy?secret=&vhost=__defaultVhost__&app=live&stream=test&url=rtsp://..." # 列出 ZLMediaKit 活跃流 docker exec skynet_zlmediakit wget -qO- 'http://localhost:80/index/api/getMediaList?secret=' ``` ## 九、安全说明 - **生产环境必须修改**:`JWT_SECRET`、`MYSQL_ROOT_PASSWORD`、`MYSQL_PASSWORD` - **等保 2.0 三级**:已实现双 Token + 操作审计 + 数据权限隔离 + 核心身份鉴别(登录失败锁定 / 密码复杂度校验 / 密码定期更换 + 强制改密 / 登录审计 / 登录限流 / 默认密钥启动校验);待加固:敏感字段加密存储 / HTTPS / 审计日志完整性 - **内网私有化部署**:默认配置面向内网,生产请关闭端口对外暴露(`docker-compose.yml` 移除 `ports` 段或绑定 `127.0.0.1`) - **行政区划数据**:当前 seed 34 省级 + 333 市级 + 长沙 9 区县(377 条),其余地市县级后续补录 - **投弹/换弹安全**:第 6 轮投弹下行使用 `extinguishing_bomb` 固定载荷 + `LatLng{}` 占位坐标,生产部署前必须接入真实 KMZ 解析 + 投弹权限二次确认 - **喊话/蔓延安全**(第十轮):喊话 `speaker_audio_play` method/字段为推断(真机可能需 audio_url),蔓延椭圆无地形/植被修正(仅辅助决策);生产前需真机联调 + 按植被类型校准 `fire_spread.base_rate` - **ZLMediaKit 集成**(第七轮):master 镜像 `-s` 参数被 reject,启动后自动生成新 secret;smoke-test 16 自动从容器内 `config.ini` 读当前 secret 同步。生产环境建议:固定一个 ZLMediaKit 接受的 secret(32 字符合法字符集),写入自定义 spec 镜像 ## 十、版本 - **当前版本**:1.0.0(10 轮迭代完成) - **许可证**:Apache-2.0 - **技术栈版本**:Go 1.22+ / Vue 3.5 / Element Plus 2.11 / Leaflet 1.9 / GORM v2 / MySQL 8.0 / ZLMediaKit master ## 附录:常用链接 - **Gitee 仓库**:https://gitee.com/jaydomchen/sky-net - **需求文档**:`需求/` 目录下 2 份 docx(控制软件分析文档 + 项目计划书) - **变更日志**:见 git log(按轮次 commit:initial → README → 第七轮) --- 如有问题或建议,欢迎在 Gitee 提 Issue。