添加 uipro,更新 wiki

This commit is contained in:
eafonyang
2026-07-10 11:25:45 +08:00
parent 6bb39e9172
commit f88ff46427
163 changed files with 30244 additions and 151 deletions
+5 -14
View File
@@ -3,23 +3,14 @@ schema_version: 1
locale: zh-CN
branch: main
nodes_managed: true
exported_at: "2026-07-09T02:41:34Z"
exported_at: "2026-07-10T03:11:01Z"
modules:
"":
dir_name: 耳机品牌与 OTA 升级管理平台(前后端编排
title: 耳机品牌与 OTA 升级管理平台(前后端编排
scope:
- .gitignore
- README.md
- DEPLOY.md
- docker-compose.yml
- scripts/
- .env
- .env.example
dir_name: 音频设备管理仪表盘(前后端单体仓库
title: 音频设备管理仪表盘(前后端单体仓库
scope: []
source_files: []
children:
- backend
- frontend
children: []
depends_on: []
related_to: []
backend:
@@ -0,0 +1,41 @@
---
kind: dependency_management
name: pnpm 多包依赖管理(前后端双 package.json
category: dependency_management
scope:
- '**'
source_files:
- backend/package.json
- backend/pnpm-lock.yaml
- frontend/package.json
- frontend/pnpm-workspace.yaml
- frontend/pnpm-lock.yaml
- frontend/package-lock.json
---
本仓库采用 pnpm 作为统一的 Node.js 包管理器,前后端各自维护独立的 package.json,通过 lockfile 锁定依赖版本,未启用 monorepo workspace 模式。
1. 使用的系统/工具
- 包管理器:pnpm v11.5.2,在 backend/package.json 与 frontend/package.json 中均通过 packageManager 字段声明,确保团队成员使用一致版本。
- Lockfile:后端使用 pnpm-lock.yamllockfileVersion 9.0),前端同时存在 pnpm-lock.yaml 与 package-lock.json(后者为历史遗留)。
- 构建工具:前端基于 Vitevite.config.js),后端无构建步骤,直接运行 src/app.js。
2. 关键文件
- backend/package.json — 后端依赖声明(Express、Sequelize、MySQL2、AWS S3 SDK、Redis、Zod 等)
- backend/pnpm-lock.yaml — 后端精确锁定的依赖树
- frontend/package.json — 前端依赖声明(Vue3、Element Plus、Axios、Vite 等)
- frontend/pnpm-workspace.yaml — 仅开启 allowBuilds.esbuild: true,未定义任何 workspace 包
- frontend/pnpm-lock.yaml / frontend/package-lock.json — 前端锁文件(二者并存)
3. 架构与约定
- 双包结构:前后端各自独立,不存在共享的 packages/ 或 workspace: 引用;pnpm-workspace.yaml 为空配置,说明当前不是 monorepo。
- 版本策略:所有依赖均采用 ^ 语义化版本范围(如 express: ^4.21、vue: ^3.3.4),实际安装版本由 lockfile 固定。
- 私有源/代理:未发现 .npmrc、.pnpmrc 或 registry 相关配置,默认使用 npm 官方源;也未见 @scope 私有包引用。
- 缓存:根目录存在 .pnpm-store/v11/,表明 pnpm 全局存储已启用。
4. 开发者应遵循的规则
- 统一使用 pnpm 安装/更新依赖,避免混用 npm/yarn,以免生成冲突的 lockfile。
- 新增依赖时只修改对应子目录的 package.json,提交后让 CI 重新生成 lockfile。
- 不要手动编辑 lockfile;如需升级,使用 pnpm up <pkg> 或 pnpm update。
- 清理前端的 package-lock.json,统一以 pnpm-lock.yaml 为准,消除双锁文件带来的歧义。
- 若未来引入共享包,应在 pnpm-workspace.yaml 中显式声明 workspace,并迁移到 monorepo 模式。
@@ -0,0 +1,32 @@
---
kind: error_handling
name: 前后端统一错误响应与拦截机制
category: error_handling
scope:
- '**'
source_files:
- backend/src/utils/response.js
- backend/src/middleware/auth.js
- backend/src/app.js
- frontend/src/utils/request.js
---
本仓库采用「后端统一响应体 + 前端 Axios 拦截器」的轻量级错误处理方案,未引入专门的错误类型库或全局异常中间件。
**后端(Express**
- 统一响应封装:`backend/src/utils/response.js` 提供 `ApiResponse.success / error / noData` 三个工厂方法,约定 `code=1` 成功、`code=0` 业务错误、`code=2` 无数据;`PageData` 用于分页结构。
- 路由层自行 try/catch:各 `routes/*.js` 在控制器内捕获异常,记录 `logger.error(e.message)` 后返回 `ApiResponse.error(...)`,错误消息多为硬编码中文提示,未使用 HTTP 状态码区分语义。
- 认证中间件 `middleware/auth.js` 单独处理鉴权错误:401 返回 `{ detail: '...' }`,403 返回权限不足信息,与业务错误体结构不同。
- 服务层 `services/*.js` 直接 `throw new Error(...)` 向上抛出具体错误(如 Redis/S3/曲线接口失败),由调用方路由捕获。
- 应用入口 `app.js` 仅在启动阶段同步数据库时 try/catch,未注册全局 Express 错误处理中间件(`app.use((err, req, res, next) => ...)`)。
**前端(Vue3 + Axios**
- `frontend/src/utils/request.js` 通过 Axios 拦截器集中处理:
- 请求拦截:自动注入 `Authorization: Bearer <token>`,跳过 `/auth/login`
- 响应拦截:当 `res.code === 0` 时,若 `config.skipErrorToast` 未设置则弹出 `ElMessage.error`,并将 `responseData` 挂载到抛出的 Error 对象上供上层消费。
- HTTP 错误:401 清除本地 token、跳转登录页并携带 redirect;403 显示警告;其他网络错误统一 `ElMessage.error`
- 业务 API 模块(`frontend/src/api/*.js`)基于此 request 实例发起请求,依赖 Promise reject 分支处理业务错误。
**设计决策与不足**
- 优点:前后端对 `code/msg/data` 协议一致,前端拦截器屏蔽了重复的错误提示逻辑。
- 不足:缺少统一的错误码枚举、HTTP 状态码未与业务错误解耦、未定义全局错误中间件导致未捕获异常可能返回默认 HTML 500 页面。
@@ -0,0 +1,47 @@
---
kind: logging_system
name: 基于 Winston 的日志系统
category: logging_system
scope:
- '**'
source_files:
- backend/src/config/logger.js
- backend/src/app.js
- backend/src/config/database.js
- backend/package.json
---
## 1. 使用的系统与框架
- 后端采用 **Winston v3** 作为统一日志框架,通过 `backend/src/config/logger.js` 集中创建并导出单例 logger。
- 前端(Vue3)未发现专用日志库,未在前端代码中引入结构化日志输出。
- Sequelize 在开发环境将 SQL 查询直接 `console.log` 到控制台,生产环境关闭 SQL 日志。
## 2. 核心文件与包
- `backend/src/config/logger.js` — Winston 实例定义、格式与传输配置
- `backend/src/app.js` — 应用启动时记录数据库同步、服务监听等关键事件
- `backend/package.json` — 依赖声明 `winston: ^3.14`
- `backend/logs/app.log` — 默认文件日志输出路径
- `backend/src/config/database.js` — Sequelize 的 `logging` 开关逻辑
## 3. 架构与约定
- **单例导出**`logger.js` 使用 `winston.createLogger()` 创建全局 logger,并通过 `module.exports = logger` 供各模块 `require('../config/logger')` 复用。
- **日志级别**:全局默认 level 为 `info`;业务代码中使用 `logger.info / warn / error` 三个级别,未见 `debug` 调用。
- **输出格式**:时间戳 + 级别 + 消息 + 可选 JSON meta 字段,形如:
```
2026-06-09 12:34:56 - info - User admin logged in {}
```
- **双通道输出**:同时写入 Console 和文件 `backend/logs/app.log`,编码 UTF-8。
- **无按级别/日期分片**:当前仅一个 `app.log` 文件,未启用 `FileTransport` 的 `maxsize`、`maxFiles`、`filename` 模板等滚动策略。
- **Sequelize SQL 日志**:仅在 `isDevelopment` 时开启,输出到 `console.log`,不经过 Winston。
- **中间件层**:未集成 Express 请求日志中间件(如 `morgan`),HTTP 访问日志未统一采集。
## 4. 开发者应遵循的规则
- **统一入口**:所有日志必须通过 `const logger = require('../config/logger')` 获取,禁止直接使用 `console.log` 输出业务日志。
- **级别选择**
- `info`:正常业务流程事件(登录成功、密码修改、数据操作完成等)
- `warn`:可恢复异常或潜在问题(登录失败、参数校验警告等)
- `error`:不可恢复错误(数据库异常、外部服务调用失败等)
- **结构化字段**:通过第三个参数传入对象以附加上下文,例如 `logger.warn({ username, ip }, 'Login failed')`,该对象会被序列化为 JSON 追加到消息末尾。
- **敏感信息**:避免在日志中记录明文密码、完整 token 等敏感内容。
- **SQL 调试**:如需查看底层 SQL,确保环境变量处于开发模式以使 Sequelize logging 生效;生产环境应保持关闭以避免性能损耗。
- **日志轮转**:当前未配置自动轮转,部署时应配合外部工具(如 `logrotate`、Docker log driver)管理 `backend/logs/app.log` 大小。
@@ -0,0 +1,89 @@
---
kind: build_system
name: 构建与部署体系(Docker Compose + pnpm + Vite
category: build_system
scope:
- '**'
source_files:
- docker-compose.yml
- backend/Dockerfile
- frontend/Dockerfile
- frontend/vite.config.js
- scripts/upload.sh
- DEPLOY.md
- backend/package.json
- frontend/package.json
---
## 1. 使用的系统与方法
- **包管理器**pnpm@11.5.2,前后端均通过 `packageManager` 字段锁定版本。
- **前端构建**Vite 6 + Vue 3,开发端口 3000,生产构建产物输出到 `frontend/dist/`,并通过 Rollup `manualChunks` 将 vue、element-plus 等拆分为独立 chunk。
- **后端运行**Express + Sequelize,入口 `backend/src/app.js`,默认监听 8000(容器内),本地开发可通过 `.env``PORT=8083` 覆盖。
- **容器编排**Docker Compose 定义两个服务——`backend`node:22-alpine)和 `frontend`nginx:alpine),共享自定义 bridge 网络 `audio-network`
- **发布脚本**`scripts/upload.sh` 基于 rsync+ssh 将前端 dist、后端源码、compose 文件同步至远程服务器 `/data/project/dashboard/`
## 2. 关键文件与位置
| 类别 | 文件 | 作用 |
|------|------|------|
| 编排 | `docker-compose.yml` | 定义 backend/frontend 服务、端口映射、日志轮转、数据卷挂载 |
| 后端镜像 | `backend/Dockerfile` | node:22-alpine,仅安装 prod 依赖,CMD 启动 `src/app.js` |
| 前端镜像 | `frontend/Dockerfile` | 多阶段构建:node:18-alpine 构建 → nginx:alpine 托管静态资源 |
| 前端构建配置 | `frontend/vite.config.js` | 开发代理 `/api→localhost:8083`、chunk 拆分、别名 `@` |
| 上传脚本 | `scripts/upload.sh` | rsync 推送 frontend/backend/compose 三套预设目标 |
| 部署文档 | `DEPLOY.md` | 完整的首次部署、增量更新、环境变量说明、目录结构约定 |
| 后端脚本 | `backend/start.sh / stop.sh / restart.sh` | 非 Docker 场景下的进程启停辅助 |
## 3. 架构与约定
### 3.1 构建流水线
```
本地开发
├─ frontend/pnpm dev (vite, :3000) → 代理 /api → localhost:8083
└─ backend/pnpm start (node src/app.js, :8000 或 .env PORT)
本地构建
├─ pnpm --dir frontend build → frontend/dist/
└─ scripts/upload.sh [frontend|backend|compose|all]
服务器部署
├─ docker compose build --no-cache backend # 首次或依赖变更
├─ docker compose up -d # 启动全部服务
└─ docker compose restart frontend # 仅前端热更
```
- 前端采用**多阶段 Docker 构建**,最终镜像仅包含 nginx + 静态文件,体积最小化。
- 后端镜像使用 `--frozen-lockfile --prod` 安装,确保构建可重复且不携带 devDependencies。
- 宿主机通过 volume 挂载 `/data/projects/source` 给后端容器,用于 X9 OTA 升级包本地存储;前端 `dist/``nginx.conf` 也通过 volume 挂载,避免重建镜像。
### 3.2 端口与环境变量约定
| 组件 | 容器内端口 | 宿主机映射 | 备注 |
|------|-----------|-----------|------|
| frontend (nginx) | 80 | 8082 | 反向代理 `/api``http://backend:8000` |
| backend (Node) | 8000 | 8083 | 由 Compose 强制覆盖 `PORT=8000` |
| 本地开发 (vite) | 3000 | — | 通过 proxy 转发 `/api` 到 8083 |
- 所有环境变量统一放在根目录 `.env`Compose 通过 `env_file` 注入,不再各自维护 `.env`
- 敏感信息(JWT_SECRET、数据库密码等)不随 `upload.sh` 上传,需在服务器单独维护。
### 3.3 上传策略
`scripts/upload.sh` 定义了三个预设集合:
- `frontend`:仅 `frontend/dist/`
- `backend``backend/src/` + `package.json` + `pnpm-lock.yaml`(不含 Dockerfile
- `compose``docker-compose.yml`
支持 `-n` dry-run 预览、任意路径透传、自动创建远端目录。
## 4. 开发者应遵循的规则
1. **新增依赖**:在对应子模块执行 `pnpm add ...`,确保 `pnpm-lock.yaml` 提交到 Git,以便 `--frozen-lockfile` 构建成功。
2. **修改前端路由/样式**:直接 `pnpm dev` 本地调试,无需重新构建镜像;生产发布前执行 `pnpm build``./scripts/upload.sh frontend`
3. **修改后端接口**`./scripts/upload.sh backend` 后在服务器执行 `docker compose build --no-cache backend && docker compose up -d backend`
4. **修改 Compose 配置**`./scripts/upload.sh compose``docker compose up -d` 即可生效。
5. **不要**在代码中硬编码端口或路径,一律通过 `.env` 或 Compose `environment` 注入。
6. **OTA 包存放**:仅通过 volume 挂载的 `/data/projects/source` 写入,不要改动 Dockerfile 中的 COPY 范围。
7. **本地非 Docker 开发**:先 `cd backend && pnpm start`,再 `cd frontend && pnpm dev`,确保根目录 `.env``PORT=8083`
@@ -0,0 +1,47 @@
---
kind: configuration_system
name: 环境变量与配置加载体系
category: configuration_system
scope:
- '**'
source_files:
- backend/src/app.js
- backend/src/config/loadEnv.js
- backend/src/config/env.js
- backend/src/config/database.js
- backend/src/config/redis.js
- .env.example
- docker-compose.yml
---
## 系统概览
本仓库采用「进程级 .env 文件 + 环境变量」的轻量配置方案,由后端在启动时统一加载,未引入第三方配置中心或 YAML/JSON 配置文件。所有运行时参数通过 `process.env` 注入,开发环境与生产环境通过 `APP_ENV` 区分。
## 核心机制
- **统一入口加载**`backend/src/app.js` 首行 `require('./config/loadEnv')`,确保应用启动前完成 `.env` 解析。
- **dotenv 加载策略**`loadEnv.js` 固定从仓库根目录读取 `.env``path.resolve(__dirname, '../../../.env')`),仅在文件存在时调用 `dotenv.config()`Docker 部署时通过 `docker-compose.yml``env_file` 注入,容器内无 `.env` 也不会覆盖已存在的环境变量。
- **环境判断工具**`config/env.js` 暴露 `APP_ENV``isDevelopment``isProduction`,供各模块按环境切换行为(如数据库日志开关)。
## 配置项分类与约定
| 类别 | 关键变量 | 默认值 / 说明 |
|---|---|---|
| 数据库 | `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_NAME`, `DATABASE_USER`, `DATABASE_PASSWORD` | MySQLSequelize 直连,`dialectOptions.charset='utf8mb4'`,开发模式打印 SQL |
| 应用 | `APP_NAME`, `APP_ENV`, `PORT` | `APP_ENV=development|production`;本地默认 8083Docker 内 8000 |
| 认证 | `JWT_SECRET`, `DASHBOARD_ADMIN_USERNAME`, `DASHBOARD_ADMIN_PASSWORD` | 首次启动自动创建超级管理员 |
| S3 存储 | `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_S3_OTA_BUCKET`, `AWS_S3_MEASUREMENT_BUCKET` | 正式环境可通过 IAM 角色免 AK/SK 访问 |
| OTA 地址 | `OTA_X8_PUBLIC_BASE`, `OTA_X9_URL_BASE`, `OTA_UPLOAD_DIR` | X8/X9 升级包基 URL;上传目录仅生产环境需显式配置 |
| Redis 缓存 | `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD`, `REDIS_EQ_DB` | ioredis 单例,连接失败记录错误日志 |
| 外部服务 | `MEILISEARCH_*`, `CURVE_API_BASE_URL` | 搜索与曲线 API 基础地址 |
## 架构与约定
- **单一来源**`.env.example` 是配置清单,实际 `.env` 不应提交到版本库(已在 `.gitignore` 中忽略)。
- **分层组织**`backend/src/config/` 下每个子模块只负责自身依赖的配置读取(database、redis、logger),不互相耦合。
- **环境变量优先**:所有配置均从 `process.env` 读取,并带合理默认值,保证本地可零配置运行。
- **Docker 集成**`docker-compose.yml` 通过 `env_file: [.env]``environment:` 覆盖端口与环境变量,实现同一份 `.env` 同时驱动本地与容器。
## 开发者规则
1. 新增配置项先在 `.env.example` 中添加注释与默认值,再在对应 `config/*.js` 中读取。
2. 敏感信息(密码、密钥)一律走环境变量,禁止硬编码或写入代码。
3. 使用 `APP_ENV` 做环境分支逻辑,不要直接检查主机名或路径。
4. Docker 部署时通过 compose 的 `environment` 覆盖必要变量,保持 `.env` 最小化。
5. 若某配置有默认值且允许空值,务必在读取处提供 fallback,避免启动期崩溃。
@@ -0,0 +1,7 @@
schema_version: 1
module_path: ""
title: 音频设备管理仪表盘(前后端单体仓库)
scope: []
source_files: []
depends_on: []
related_to: []
@@ -0,0 +1 @@
后端:Express 4 + Sequelize 6 + mysql2 + jsonwebtoken + multer + @aws-sdk/client-s3 + winston + ioredis + zod;前端:Vue 3 + vue-router 4 + Element Plus(含 dark css-vars+ vite 6 + axios;部署:Docker Composebackend 镜像自 buildfrontend 使用 nginx:alpine 静态托管)。
@@ -0,0 +1,5 @@
仓库采用前后端分离的单体结构:
- `backend/src` 为 Express API 服务,入口 `app.js` 统一挂载 CORS、JSON 解析、`bodyLimit` 中间件,并通过 `routes/index.js` 聚合 auth/brands/models/ota/blacklist/otaTargetDevice/shareCodeLogs/users/dashboard 等路由;数据层使用 Sequelize + mysql2,模型集中在 `models/` 并导出到 `models/index.js`;外部依赖通过 `services/` 抽象(curveClient 调用第三方曲线服务、eqCacheStorage/squiglink 处理 EQ 缓存、measurementStorage/otaStorage 对接 S3、userBootstrap 负责超级管理员初始化);鉴权由 `middleware/auth.js` + `utils/jwt.js` 实现。
- `frontend/src` 为 Vite + Vue3 + Element Plus SPA`router/index.js` 集中声明所有页面路由并在 `beforeEach` 中做 token 校验与超级管理员权限拦截;`api/` 下每个文件对应一个后端模块的 axios 封装;`views/` 按功能域分目录组织页面,`components/` 存放全局复用组件(ChangePasswordDialog、SidebarLogo、TabsView),`layout/index.vue` 提供侧边栏+标签页布局。
- 顶层 `docker-compose.yml` 编排 backendNode)与 frontendnginx:alpine 静态托管 dist),共享 `audio-network` 网络;`.env.example` 提供环境变量模板。
- 依赖方向单向:前端 → 后端 REST API,后端 → MySQL/S3/Redis/第三方 curve 服务,无跨包反向引用。
@@ -0,0 +1 @@
基于 Vue3 + Express/Sequelize 的耳机品牌、型号、OTA 与用户管理后台,提供曲线上传、S3 存储与 Element Plus 驱动的 Web 界面。
@@ -0,0 +1 @@
开发:`pnpm install` 后分别进入 `backend``frontend` 执行 `pnpm dev`;生产:`cd frontend && pnpm build` 生成 `dist/`,再 `docker compose up -d --build` 启动双容器,需提前准备 `.env`(参考 `.env.example`)并挂载 `/data/projects/source` 供 S3 本地模拟访问。
@@ -0,0 +1,5 @@
- 后端路由以独立文件暴露 express router,再由 `routes/index.js` 统一收集注册,避免在 app.js 内散写 use()。
- Sequelize 模型按领域单文件定义(Brand/Model/Ota/BlackList 等),并通过 `models/index.js` 集中 re-export 给 routes/services 使用。
- 前端路由采用懒加载 `() => import('@/views/...')` 形式,meta 字段声明 title/icon/requiresAuth/requiresSuperAdmin 控制导航与守卫。
- 前端 API 调用按业务域拆分到 `src/api/*.js`,每个文件对应一个后端路由模块,统一通过 `axios` 实例发起请求。
- 前端页面按功能域在 `views/<domain>/index.vue` 下组织,复杂页面内部再拆 `components/``composables/` 子目录。
@@ -14,6 +14,14 @@
- [frontend/src/views/login/index.vue](file://frontend/src/views/login/index.vue)
</cite>
## 更新摘要
**所做更改**
- 更新了侧边栏导航系统架构,从六个独立菜单项简化为三个主要分类
- 新增了侧边栏轨道导航(Rail Navigation)功能,提供快速展开侧边栏的交互体验
- 改进了导航链接实现方式,采用普通锚元素配合点击处理器替代Vue Router链接
- 增强了用户体验,实现了自动展开侧边栏的智能交互逻辑
- 更新了导航分类结构,重新组织了耳机管理、升级管理和分享码三大功能模块
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
@@ -29,9 +37,14 @@
本项目采用现代化的Vue 3 + Element Plus前端技术栈构建,布局组件是整个系统的骨架结构,负责组织页面的整体架构。该布局组件实现了响应式设计,支持桌面端和移动端的自适应布局,提供了完整的导航体系和主题适配功能。
**最新更新** 导航系统进行了重大改进,采用了创新的三层导航架构:
- **侧边栏轨道导航**:轻量化的图标导航条,提供快速访问入口
- **主菜单导航**:分类化的三级菜单结构,包含耳机管理、升级管理和分享码三大模块
- **顶部面包屑导航**:动态生成的路径导航,增强用户定位能力
布局组件的核心特色包括:
- **层导航系统**侧边栏主导航 + 顶部面包屑导航
- **动态侧边栏**:支持展开/收起的玻璃拟态设计
- **层导航系统**轨道导航 + 分类菜单 + 面包屑导航
- **智能侧边栏**:支持展开/收起的玻璃拟态设计,具备自动展开功能
- **标签页管理**:多标签页浏览和持久化存储
- **深色主题**:基于CSS变量的主题系统
- **响应式适配**:针对不同屏幕尺寸的优化布局
@@ -67,18 +80,18 @@ end
```
**图表来源**
- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338)
- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91)
- [frontend/src/layout/index.vue:1-349](file://frontend/src/layout/index.vue#L1-L349)
- [frontend/src/router/index.js:1-103](file://frontend/src/router/index.js#L1-L103)
**章节来源**
- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338)
- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91)
- [frontend/src/layout/index.vue:1-349](file://frontend/src/layout/index.vue#L1-L349)
- [frontend/src/router/index.js:1-103](file://frontend/src/router/index.js#L1-L103)
## 核心组件
### 主布局组件架构
主布局组件采用Element Plus的容器布局系统,实现了经典的三段式布局:
主布局组件采用Element Plus的容器布局系统,实现了经典的三段式布局,并集成了全新的三层导航架构
```mermaid
graph LR
@@ -91,12 +104,18 @@ B --> G[ElAside<br/>侧边栏容器]
G --> H[SidebarInner<br/>侧边栏内部容器]
H --> I[SidebarLogo<br/>Logo组件]
H --> J[SidebarNavWrap<br/>导航包装器]
J --> K[SidebarRail<br/>侧边栏导航]
J --> L[LuxMenu<br/>菜单]
J --> K[SidebarRail<br/>轨道导航]
J --> L[LuxMenu<br/>分类菜单]
K --> M[耳机管理图标]
K --> N[升级管理图标]
K --> O[分享码图标]
L --> P[耳机管理子菜单]
L --> Q[升级管理子菜单]
L --> R[分享码子菜单]
```
**图表来源**
- [frontend/src/layout/index.vue:9-138](file://frontend/src/layout/index.vue#L9-L138)
- [frontend/src/layout/index.vue:9-146](file://frontend/src/layout/index.vue#L9-L146)
### 组件层次结构
@@ -109,6 +128,8 @@ class LuxLayout {
+railNavItems : Array
+breadcrumbTitle : ComputedRef
+breadcrumbSection : ComputedRef
+handleRailClick()
+resolveOpenedMenus()
+handleLogout()
+handleUserMenuCommand()
}
@@ -134,12 +155,12 @@ LuxLayout --> ChangePasswordDialog : "使用"
```
**图表来源**
- [frontend/src/layout/index.vue:144-222](file://frontend/src/layout/index.vue#L144-L222)
- [frontend/src/layout/index.vue:152-233](file://frontend/src/layout/index.vue#L152-L233)
- [frontend/src/components/SidebarLogo.vue:52-58](file://frontend/src/components/SidebarLogo.vue#L52-L58)
- [frontend/src/components/TabsView.vue:55-63](file://frontend/src/components/TabsView.vue#L55-L63)
**章节来源**
- [frontend/src/layout/index.vue:144-222](file://frontend/src/layout/index.vue#L144-L222)
- [frontend/src/layout/index.vue:152-233](file://frontend/src/layout/index.vue#L152-L233)
## 架构概览
@@ -148,89 +169,108 @@ LuxLayout --> ChangePasswordDialog : "使用"
```mermaid
sequenceDiagram
participant User as 用户
participant Rail as 轨道导航
participant Menu as 主菜单
participant Router as Vue Router
participant Layout as 布局组件
participant Tabs as 标签页组件
participant View as 页面视图
User->>Router : 访问页面
User->>Rail : 点击轨道图标
Rail->>Layout : handleRailClick()
Layout->>Layout : isSidebarCollapsed = false
Note over Layout : 自动展开侧边栏
User->>Menu : 选择菜单项
Menu->>Router : 路由跳转
Router->>Layout : 加载布局
Layout->>Layout : 初始化状态
Layout->>Tabs : 渲染标签页
Tabs->>View : 加载页面内容
View-->>User : 显示页面
Note over Layout,Tabs : 动态标签页管理
Note over Layout,View : 路由变化触发更新
```
**图表来源**
- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88)
- [frontend/src/layout/index.vue:173-179](file://frontend/src/layout/index.vue#L173-L179)
- [frontend/src/layout/index.vue:195-197](file://frontend/src/layout/index.vue#L195-L197)
- [frontend/src/router/index.js:76-100](file://frontend/src/router/index.js#L76-L100)
### 数据流架构
```mermaid
flowchart TD
A[用户交互] --> B[路由变化监听]
B --> C[激活菜单项计算]
C --> D[面包屑标题计算]
D --> E[侧边栏展开状态]
F[页面内容] --> G[标签页管理]
G --> H[会话存储持久化]
H --> I[页面缓存控制]
J[用户菜单] --> K[权限检查]
K --> L[功能访问控制]
L --> M[页面跳转]
A[用户交互] --> B{轨道导航点击}
B --> |是| C[handleRailClick()]
C --> D[展开侧边栏]
B --> |否| E[路由变化监听]
E --> F[激活菜单项计算]
F --> G[面包屑标题计算]
G --> H[侧边栏展开状态]
I[页面内容] --> J[标签页管理]
J --> K[会话存储持久化]
K --> L[页面缓存控制]
M[用户菜单] --> N[权限检查]
N --> O[功能访问控制]
O --> P[页面跳转]
```
**图表来源**
- [frontend/src/layout/index.vue:154-221](file://frontend/src/layout/index.vue#L154-L221)
- [frontend/src/layout/index.vue:174-212](file://frontend/src/layout/index.vue#L174-L212)
**章节来源**
- [frontend/src/layout/index.vue:154-221](file://frontend/src/layout/index.vue#L154-L221)
- [frontend/src/layout/index.vue:174-212](file://frontend/src/layout/index.vue#L174-L212)
## 详细组件分析
### 主布局组件详解
#### 布局结构设计
#### 三层导航结构设计
主布局组件采用了响应式设计原则,通过CSS Grid和Flexbox实现灵活的布局:
主布局组件采用了创新的三层导航架构,通过CSS Grid和Flexbox实现灵活的布局:
```mermaid
graph TB
subgraph "桌面端布局"
A[侧边栏 64px] --> B[展开时 220px]
C[右侧内容区] --> D[弹性增长]
E[顶部导航] --> F[44px高度]
G[底部版权] --> H[自动高度]
subgraph "轨道导航层"
A[SidebarRail<br/>64px宽度] --> B[三个分类图标]
B --> C[耳机管理图标]
B --> D[升级管理图标]
B --> E[分享码图标]
end
subgraph "移动端适配"
I[触摸手势] --> J[侧边栏滑动]
K[小屏优化] --> L[图标导航优先]
M[响应式断点] --> N[768px以下]
subgraph "主菜单层"
F[LuxMenu<br/>220px宽度] --> G[耳机管理子菜单]
F --> H[升级管理子菜单]
F --> I[分享码子菜单]
G --> J[品牌管理]
G --> K[型号管理]
H --> L[OTA管理]
H --> M[黑名单管理]
H --> N[定向升级]
I --> O[分享日志]
end
subgraph "面包屑层"
P[顶部导航] --> Q[动态路径生成]
Q --> R[当前页面标识]
end
```
**图表来源**
- [frontend/src/layout/index.vue:10-15](file://frontend/src/layout/index.vue#L10-L15)
- [frontend/src/styles/lux-theme.css:101-130](file://frontend/src/styles/lux-theme.css#L101-L130)
- [frontend/src/layout/index.vue:22-91](file://frontend/src/layout/index.vue#L22-L91)
- [frontend/src/layout/index.vue:189-193](file://frontend/src/layout/index.vue#L189-L193)
#### 导航系统实现
#### 智能导航系统实现
布局组件实现了层导航系统:
布局组件实现了智能化的三层导航系统:
1. **侧边栏主导航**使用`SidebarRail``LuxMenu`实现
2. **顶部面包屑导航**:动态生成面包屑路径
3. **用户下拉菜单**:权限相关的用户操作
1. **轨道导航**轻量化的图标导航,点击后自动展开侧边栏
2. **主菜单层**:分类化的三级菜单结构,支持展开/收起
3. **面包屑导航层**:动态生成面包屑路径,提供清晰的页面定位
**更新** 轨道导航采用普通锚元素配合点击处理器,提供了更灵活的导航行为和更好的用户体验。
**章节来源**
- [frontend/src/layout/index.vue:18-137](file://frontend/src/layout/index.vue#L18-L137)
- [frontend/src/layout/index.vue:22-91](file://frontend/src/layout/index.vue#L22-L91)
### 侧边栏组件分析
#### 设计特点
#### 创新的双层设计
侧边栏采用了创新的玻璃拟态设计:
侧边栏采用了创新的玻璃拟态双层设计:
```mermaid
classDiagram
@@ -241,25 +281,28 @@ class SidebarGlass {
+borderRight : 1px solid rgba(255,255,255,0.08)
+transition : width 0.30s ease
}
class SidebarRail {
+position : absolute
+visibility : hidden/visible
+opacity : 0/1
+pointerEvents : none/auto
+railNavItems : Array
}
class SidebarLogo {
+collapsed : Boolean
+animation : slide/fade
+responsive : true
}
class SidebarNavWrap {
+position : absolute
+position : relative
+overflow : hidden
+flex : 1
}
class SidebarRail {
+visibility : hidden/visible
+opacity : 0/1
+pointerEvents : none/auto
}
class LuxMenu {
+expanded : true/false
+activeItem : highlight
+hoverEffect : gradient
+elSubMenus : Array
}
SidebarGlass --> SidebarLogo
SidebarGlass --> SidebarNavWrap
@@ -268,12 +311,12 @@ SidebarNavWrap --> LuxMenu
```
**图表来源**
- [frontend/src/layout/index.vue:10-86](file://frontend/src/layout/index.vue#L10-L86)
- [frontend/src/layout/index.vue:10-93](file://frontend/src/layout/index.vue#L10-L93)
- [frontend/src/styles/lux-theme.css:101-195](file://frontend/src/styles/lux-theme.css#L101-L195)
#### 交互逻辑
#### 智能交互逻辑
侧边栏的交互逻辑通过Vue的响应式系统实现:
侧边栏的交互逻辑通过Vue的响应式系统实现,新增了智能展开功能
```mermaid
flowchart TD
@@ -283,17 +326,62 @@ B --> |false| D[保持状态]
E[鼠标离开] --> F{isSidebarCollapsed}
F --> |false| G[设置为true]
F --> |true| H[保持状态]
I[菜单点击] --> J[更新activeMenu]
J --> K[同步面包屑]
K --> L[更新openedMenus]
I[轨道导航点击] --> J[handleRailClick()]
J --> K[强制展开侧边栏]
K --> L[设置isSidebarCollapsed = false]
M[菜单点击] --> N[更新activeMenu]
N --> O[同步面包屑]
O --> P[更新openedMenus]
```
**图表来源**
- [frontend/src/layout/index.vue:13-14](file://frontend/src/layout/index.vue#L13-L14)
- [frontend/src/layout/index.vue:166-179](file://frontend/src/layout/index.vue#L166-L179)
- [frontend/src/layout/index.vue:195-197](file://frontend/src/layout/index.vue#L195-L197)
- [frontend/src/layout/index.vue:181-187](file://frontend/src/layout/index.vue#L181-L187)
**更新** 新增了`handleRailClick()`函数,当用户点击轨道导航图标时,会自动展开侧边栏,提供更好的用户体验。
**章节来源**
- [frontend/src/layout/index.vue:10-86](file://frontend/src/layout/index.vue#L10-L86)
- [frontend/src/layout/index.vue:10-93](file://frontend/src/layout/index.vue#L10-L93)
### 导航分类重构
#### 三大功能模块
导航系统重构为三个主要功能模块:
1. **耳机管理模块** (`index="1"`)
- 品牌管理 (`/brand`)
- 型号管理 (`/model`)
2. **升级管理模块** (`index="upgrade"`)
- OTA 管理 (`/ota`)
- 黑名单管理 (`/blacklist`)
- 定向升级 (`/ota-target-device`)
3. **分享码模块** (`index="share-code"`)
- 分享日志 (`/share-code/log`)
#### 智能菜单展开逻辑
```mermaid
flowchart TD
A[路由路径] --> B{路径匹配}
B --> |/brand 或 /model| C[展开耳机管理]
B --> |/ota 或 /blacklist 或 /ota-target-device| D[展开升级管理]
B --> |/share-code/*| E[展开分享码]
B --> |其他路径| F[不展开任何菜单]
C --> G[openedMenus = ['1']]
D --> H[openedMenus = ['upgrade']]
E --> I[openedMenus = ['share-code']]
F --> J[openedMenus = []]
```
**图表来源**
- [frontend/src/layout/index.vue:174-179](file://frontend/src/layout/index.vue#L174-L179)
**章节来源**
- [frontend/src/layout/index.vue:49-90](file://frontend/src/layout/index.vue#L49-L90)
### 标签页组件分析
@@ -408,10 +496,13 @@ M[Vue Router] --> N[路由导航]
N --> O[权限控制]
P[Auth Utils] --> Q[用户认证]
Q --> R[权限验证]
S[Icons] --> T[Headset, Upload, Share等图标]
T --> U[轨道导航图标]
T --> V[菜单项图标]
```
**图表来源**
- [frontend/src/layout/index.vue:149-152](file://frontend/src/layout/index.vue#L149-L152)
- [frontend/src/layout/index.vue:156-160](file://frontend/src/layout/index.vue#L156-L160)
- [frontend/src/router/index.js:1-5](file://frontend/src/router/index.js#L1-L5)
### 外部依赖分析
@@ -425,8 +516,10 @@ Q --> R[权限验证]
| 路由管理 | vue-router | 最新版 | 页面导航 |
| 图标系统 | @element-plus/icons-vue | 最新版 | 图标组件 |
**更新** 新增了多个图标组件的使用,包括Headset、Upload、Share等用于新的导航系统。
**章节来源**
- [frontend/src/layout/index.vue:144-152](file://frontend/src/layout/index.vue#L144-L152)
- [frontend/src/layout/index.vue:156-160](file://frontend/src/layout/index.vue#L156-L160)
- [frontend/src/router/index.js:1-5](file://frontend/src/router/index.js#L1-L5)
## 性能考虑
@@ -439,6 +532,7 @@ Q --> R[权限验证]
2. **懒加载**:路由级别的组件懒加载
3. **缓存机制**:标签页内容的KeepAlive缓存
4. **事件节流**:侧边栏交互事件的处理
5. **计算属性优化**:使用computed缓存导航状态计算结果
### 内存管理
@@ -452,6 +546,8 @@ F --> G[释放内存]
G --> H[垃圾回收]
I[标签页切换] --> J[KeepAlive缓存]
J --> K[避免重复渲染]
L[导航状态变化] --> M[响应式更新]
M --> N[最小化重渲染]
```
**图表来源**
@@ -461,6 +557,20 @@ J --> K[避免重复渲染]
### 常见问题及解决方案
#### 导航系统问题
**问题**:轨道导航点击无反应
**原因**`handleRailClick`函数未正确绑定
**解决**:检查模板中的`@click.prevent="handleRailClick"`绑定
**问题**:侧边栏无法展开
**原因**`isSidebarCollapsed`状态异常
**解决**:检查watch监听器和状态更新逻辑
**问题**:菜单分类不正确
**原因**`resolveOpenedMenus`函数路径匹配错误
**解决**:验证路由路径前缀匹配逻辑
#### 布局显示异常
**问题**:侧边栏宽度不正确
@@ -482,16 +592,25 @@ J --> K[避免重复渲染]
**解决**:确保在组件卸载时清理所有监听器
**章节来源**
- [frontend/src/layout/index.vue:173-179](file://frontend/src/layout/index.vue#L173-L179)
- [frontend/src/layout/index.vue:195-197](file://frontend/src/layout/index.vue#L195-L197)
- [frontend/src/layout/index.vue:174-187](file://frontend/src/layout/index.vue#L174-L187)
- [frontend/src/components/TabsView.vue:276-286](file://frontend/src/components/TabsView.vue#L276-L286)
## 结论
本布局组件展现了现代前端开发的最佳实践,通过精心设计的架构实现了:
1. **优秀的用户体验**:响应式设计和流畅的交互效果
2. **可维护性**:清晰的组件分离和模块化设计
3. **可扩展性**:灵活的主题系统和配置选项
4. **性能优化**合理的渲染策略和资源管理
1. **创新的三层导航系统**:轨道导航 + 分类菜单 + 面包屑导航,提供丰富的导航体验
2. **智能交互设计**:自动展开侧边栏、智能菜单展开、流畅的过渡动画
3. **优秀的用户体验**:响应式设计和流畅的交互效果
4. **可维护**清晰的组件分离和模块化设计
5. **可扩展性**:灵活的主题系统和配置选项
6. **性能优化**:合理的渲染策略和资源管理
该布局组件为整个Dashboard系统提供了坚实的基础,支持未来功能的扩展和定制化需求。通过合理的架构设计和实现细节,确保了系统的稳定性和可维护性。
**最新更新亮点**
- **简化的导航结构**:从六个独立菜单项重构为三个主要分类,提升了导航效率
- **创新的轨道导航**:轻量化的图标导航条,提供快速访问入口
- **智能的用户体验**:点击轨道图标自动展开侧边栏,减少操作步骤
- **灵活的导航实现**:采用普通锚元素配合点击处理器,提供更灵活的导航行为
该布局组件为整个Dashboard系统提供了坚实的基础,支持未来功能的扩展和定制化需求。通过合理的架构设计和实现细节,确保了系统的稳定性和可维护性。新的导航系统不仅提升了用户体验,也为后续的功能扩展提供了良好的架构基础。
@@ -15,6 +15,13 @@
- [frontend/package.json](file://frontend/package.json)
</cite>
## 更新摘要
**变更内容**
- 版本唯一性约束从'verCode + model'升级为'verCode + model + beta',支持同一设备型号下存在多个不同beta状态的版本
- 在创建/更新接口中新增对beta字段的支持,允许设置灰度发布状态
- 前端新增beta筛选功能,支持按灰度状态过滤版本列表
- 实现基于(model, beta)组合的最新版本标识显示逻辑
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
@@ -30,11 +37,12 @@
## 简介
本文件为OTA固件管理API的完整RESTful接口文档,涵盖固件版本管理的HTTP方法、URL模式、请求/响应格式以及文件上传处理流程。内容包括:
- 固件版本列表查询、详情获取、创建、更新、删除接口
- 设备端最新版本检查接口
- 设备端"最新版本检查"接口
- 文件上传(Luxsin-X8上传至S3Luxsin-X9保存到本地目录)
- 存储服务配置与使用示例
- 固件版本比较、强制更新策略与兼容性检查机制
- 下载链接生成、版本升级通知与错误处理实现指南
- **新增**:Beta版本支持与灰度发布管理功能
## 项目结构
后端采用Express + Sequelize + MySQL架构,前端基于Vue3 + Element Plus。OTA相关逻辑集中在路由、模型、服务层与验证器中,并通过统一响应封装返回。
@@ -65,20 +73,20 @@ STORE --> ENV
```
图表来源
- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292)
- [backend/src/routes/ota.js:1-295](file://backend/src/routes/ota.js#L1-L295)
- [frontend/src/api/ota.js:1-68](file://frontend/src/api/ota.js#L1-L68)
- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628)
- [frontend/src/views/ota/index.vue:1-1068](file://frontend/src/views/ota/index.vue#L1-L1068)
章节来源
- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292)
- [backend/src/routes/ota.js:1-295](file://backend/src/routes/ota.js#L1-L295)
- [frontend/src/api/ota.js:1-68](file://frontend/src/api/ota.js#L1-L68)
- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628)
- [frontend/src/views/ota/index.vue:1-1068](file://frontend/src/views/ota/index.vue#L1-L1068)
## 核心组件
- 路由层:定义所有OTA相关HTTP接口,包含设备端最新版本检查和后台管理接口。
- 路由层:定义所有OTA相关HTTP接口,包含设备端"最新版本检查"和后台管理接口。
- 认证中间件:保护后台接口,要求Bearer Token。
- 参数校验:使用Zod对创建/更新请求体进行严格校验。
- 数据模型:Sequelize定义的OTA表结构,包含版本号、MD5、强制更新、定向灰度、时间窗口等字段。
- 参数校验:使用Zod对创建/更新请求体进行严格校验,支持beta字段验证
- 数据模型:Sequelize定义的OTA表结构,包含版本号、MD5、强制更新、定向灰度、时间窗口等字段**新增beta字段支持**
- 存储服务:根据设备型号选择不同存储路径(S3或本地),并生成公开下载链接。
- 响应封装:统一封装成功/错误/无数据三类响应格式。
@@ -117,7 +125,7 @@ Router->>Logger : 记录查询结果
## 详细组件分析
### 设备端最新版本检查
### 设备端"最新版本检查"
- 方法与路径:GET /api/ota/latest/check
- 请求参数:
- currentVerCode: 当前设备版本号(整数)
@@ -145,10 +153,13 @@ Router->>Logger : 记录查询结果
- verName: 模糊匹配版本名称
- model: 模糊匹配设备型号
- status: 状态(0/1
- **beta: 灰度状态筛选(0/1**
- 响应:分页数据(items、total、skip、limit
**更新** 新增beta参数支持,可按灰度状态筛选版本列表
章节来源
- [backend/src/routes/ota.js:107-143](file://backend/src/routes/ota.js#L107-L143)
- [backend/src/routes/ota.js:107-145](file://backend/src/routes/ota.js#L107-L145)
#### 获取指定OTA详情
- 方法与路径:GET /api/ota/:ota_id
@@ -156,12 +167,12 @@ Router->>Logger : 记录查询结果
- 响应:单条记录或无数据
章节来源
- [backend/src/routes/ota.js:145-160](file://backend/src/routes/ota.js#L145-L160)
- [backend/src/routes/ota.js:147-162](file://backend/src/routes/ota.js#L147-L162)
#### 创建OTA版本
- 方法与路径:POST /api/ota/
- 请求体字段(必填/可选见校验规则):
- verCode: 整数(唯一性约束:同model下不可重复)
- verCode: 整数(**唯一性约束:同model+beta下不可重复**
- verName: 字符串(1~20
- url: 字符串(下载地址或上传后生成的URL)
- md5: 32位十六进制字符串
@@ -170,13 +181,15 @@ Router->>Logger : 记录查询结果
- model: 设备型号(可空)
- hw: 硬件版本号(默认0
- target: 是否定向(0/1,默认0
- beta: 是否灰度(0/1,默认0
- **beta: 是否灰度(0/1,默认0**
- startTime/endTime: 时间字符串(可空)
- status: 状态(0/1,默认1
- 响应:创建成功的记录
**更新** 版本唯一性约束已更新为'verCode + model + beta'组合,允许同一设备型号下存在多个不同beta状态的版本
章节来源
- [backend/src/routes/ota.js:162-194](file://backend/src/routes/ota.js#L162-L194)
- [backend/src/routes/ota.js:164-196](file://backend/src/routes/ota.js#L164-L196)
- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36)
- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97)
@@ -185,11 +198,13 @@ Router->>Logger : 记录查询结果
- 请求体字段:同创建接口(部分字段可为空表示不更新)
- 响应:更新后的记录
- 注意:
- 若更新版本号设备型号,需保证新的组合在同model下唯一
- **若更新版本号设备型号或灰度状态,需保证新的组合在同model+beta下唯一**
- 日期字段会自动转换为Date类型
**更新** 版本冲突检查逻辑已更新,现在考虑beta字段参与唯一性验证
章节来源
- [backend/src/routes/ota.js:196-247](file://backend/src/routes/ota.js#L196-L247)
- [backend/src/routes/ota.js:198-250](file://backend/src/routes/ota.js#L198-L250)
- [backend/src/validators/ota.js:19-33](file://backend/src/validators/ota.js#L19-L33)
#### 删除OTA版本
@@ -197,7 +212,7 @@ Router->>Logger : 记录查询结果
- 响应:删除成功消息
章节来源
- [backend/src/routes/ota.js:249-268](file://backend/src/routes/ota.js#L249-L268)
- [backend/src/routes/ota.js:252-271](file://backend/src/routes/ota.js#L252-L271)
### 文件上传与存储
@@ -255,14 +270,18 @@ Router-->>Client : 成功响应
- 前端API模块提供:
- 列表、详情、创建、更新、删除、上传包等方法
- OTA页面视图:
- 支持搜索(版本名、设备型号、状态、版本号)
- 支持搜索(版本名、设备型号、状态、版本号、**灰度状态**
- 分页与表格展示
- **新增beta筛选下拉框,支持按灰度状态过滤**
- **实现基于(model, beta)组合的最新版本标识显示**
- 上传升级包(X8/X9)并回填URL与MD5
- 表单校验与提交
**更新** 前端新增beta筛选功能和智能最新版本标识显示逻辑
章节来源
- [frontend/src/api/ota.js:1-68](file://frontend/src/api/ota.js#L1-L68)
- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628)
- [frontend/src/views/ota/index.vue:1-1068](file://frontend/src/views/ota/index.vue#L1-L1068)
## 依赖关系分析
@@ -317,7 +336,7 @@ OtaRoute --> ApiResponse : "统一响应"
```
图表来源
- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292)
- [backend/src/routes/ota.js:1-295](file://backend/src/routes/ota.js#L1-L295)
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36)
@@ -326,13 +345,14 @@ OtaRoute --> ApiResponse : "统一响应"
## 性能考量
- 列表查询限制每页最大1000条,避免一次性返回过多数据。
- 最新版本检查接口按verCode降序查询第一条,索引建议:
- "最新版本检查"接口按verCode降序查询第一条,索引建议:
- 在verCode、model、status上建立复合索引以提升查询效率。
- **建议增加beta字段的索引以优化灰度版本筛选查询**。
- 文件上传使用内存存储(multer.memoryStorage),大文件可能影响内存占用,建议:
- 控制上传文件大小与超时时间(前端已设置较长超时)。
- 对于X8大文件,优先考虑流式上传或分片上传策略(当前实现为一次性上传)。
[本节为通用性能建议,不直接分析具体文件]
**更新** 建议为beta字段添加数据库索引以优化灰度版本筛选性能
## 故障排查指南
- 认证失败(401):
@@ -340,24 +360,28 @@ OtaRoute --> ApiResponse : "统一响应"
- 确认Token未过期
- 参数校验失败:
- 按照Zod校验规则修正请求体字段(长度、类型、取值范围)
- 版本冲突:
- 创建/更新时若verCodemodel组合重复,会返回该版本已存在
- **版本冲突**
- **创建/更新时若verCodemodel和beta组合重复,会返回"该版本已存在(相同版本+灰度状态)"**
- **确保在同一设备型号和灰度状态下版本号的唯一性**
- S3上传失败:
- 检查AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY与AWS_S3_OTA_BUCKET配置
- 确认S3权限与存储桶存在
- 无可用版本:
- 设备端查询不到更高版本时返回无数据,确认目标设备型号、硬件版本与状态
- 设备端查询不到更高版本时返回"无数据",确认目标设备型号、硬件版本与状态
**更新** 版本冲突错误信息已更新,明确说明需要检查verCode + model + beta组合的唯一性
章节来源
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36)
- [backend/src/routes/ota.js:174-181](file://backend/src/routes/ota.js#L174-L181)
- [backend/src/routes/ota.js:176-183](file://backend/src/routes/ota.js#L176-L183)
- [backend/src/routes/ota.js:223-231](file://backend/src/routes/ota.js#L223-L231)
- [backend/src/services/otaStorage.js:72-103](file://backend/src/services/otaStorage.js#L72-L103)
## 结论
本OTA固件API提供了完善的版本管理能力,支持设备端最新版本检查与后台管理功能,结合S3与本地存储策略满足不同设备型号的升级包分发需求。通过严格的参数校验与统一响应封装,提升了接口的稳定性与易用性。建议在生产环境中完善索引、优化大文件上传策略,并加强S3权限与监控告警。
本OTA固件API提供了完善的版本管理能力,支持设备端"最新版本检查"与后台管理功能,结合S3与本地存储策略满足不同设备型号的升级包分发需求。**新增的beta版本支持功能使得系统能够管理同一设备型号下的多个灰度版本,提升了版本发布的灵活性和可控性**。通过严格的参数校验与统一响应封装,提升了接口的稳定性与易用性。建议在生产环境中完善索引、优化大文件上传策略,并加强S3权限与监控告警。
[本节为总结性内容,不直接分析具体文件]
**更新** 系统现已支持完整的灰度发布管理,允许在同一设备型号下并行管理稳定版和测试版固件。
## 附录
@@ -373,16 +397,38 @@ OtaRoute --> ApiResponse : "统一响应"
- 版本比较:仅返回verCode大于当前版本且状态为可用的最高版本
- 强制更新:由force字段控制,客户端据此决定是否强制升级
- 定向/灰度:target/beta字段可用于控制发布范围
- **新版本管理**:系统支持同一设备型号下存在多个不同beta状态的版本,每个(beta, model)组合都有独立的最新版本标识
**更新** 最新版本标识逻辑已更新,现在基于(model, beta)组合来计算和显示latest标签
章节来源
- [backend/src/routes/ota.js:77-89](file://backend/src/routes/ota.js#L77-L89)
- [backend/src/models/Ota.js:33-66](file://backend/src/models/Ota.js#L33-L66)
- [frontend/src/views/ota/index.vue:428-443](file://frontend/src/views/ota/index.vue#L428-L443)
### 前端调用示例(参考)
- 列表查询:传入skip、limit、verName、model、status、verCode
- 列表查询:传入skip、limit、verName、model、status、verCode、**beta**
- 上传包:构造FormData,包含package_file与model,设置Content-Type为multipart/form-data
- 提交表单:根据设备型号决定是否需要先上传包再填写URL/MD5
- **beta筛选**:在searchForm中添加beta字段,值为0或1进行灰度状态筛选
**更新** 前端API调用示例已更新,包含beta参数的使用方法
章节来源
- [frontend/src/api/ota.js:13-67](file://frontend/src/api/ota.js#L13-L67)
- [frontend/src/views/ota/index.vue:420-449](file://frontend/src/views/ota/index.vue#L420-L449)
- [frontend/src/views/ota/index.vue:412-418](file://frontend/src/views/ota/index.vue#L412-L418)
- [frontend/src/views/ota/index.vue:597-599](file://frontend/src/views/ota/index.vue#L597-L599)
### Beta版本管理特性
- **版本唯一性**:同一设备型号下,相同版本号但不同beta状态的版本可以共存
- **灰度发布**:通过beta字段控制版本是否为灰度版本(0=否,1=是)
- **智能标识**:前端自动计算并显示每个(model, beta)组合下的最新版本标签
- **筛选功能**:支持按beta状态筛选版本列表,便于管理不同发布阶段的版本
**新增** Beta版本管理功能的详细说明
章节来源
- [backend/src/routes/ota.js:176-183](file://backend/src/routes/ota.js#L176-L183)
- [backend/src/routes/ota.js:218-231](file://backend/src/routes/ota.js#L218-L231)
- [frontend/src/views/ota/index.vue:428-443](file://frontend/src/views/ota/index.vue#L428-L443)
- [frontend/src/views/ota/index.vue:35-45](file://frontend/src/views/ota/index.vue#L35-L45)
@@ -12,15 +12,15 @@
- [backend/src/routes/ota.js](file://backend/src/routes/ota.js)
- [backend/src/services/squiglink.js](file://backend/src/services/squiglink.js)
- [frontend/src/views/model/components/ModelFormDialog.vue](file://frontend/src/views/model/components/ModelFormDialog.vue)
- [backend/src/services/measurementStorage.js](file://backend/src/services/measurementStorage.js)
</cite>
## 更新摘要
**变更内容**
- 新增squig.link外部URL数据源抓取功能
- 增强模型创建/更新流程支持外部频响数据源
- 添加squiglink_csv字段支持直接上传CSV内容
- 新增squiglink-fetch接口用于从外部URL获取频响数据
- 前端ModelFormDialog组件集成squig.link导入功能
- 新增测量文件S3自动迁移功能,当更新型号的路径相关字段时自动迁移现有CSV文件
- 增强型号更新接口的智能文件处理逻辑
- 实现S3服务端文件复制与删除操作,确保数据一致性
- 优化型号管理流程,减少手动文件干预需求
## 目录
1. [简介](#简介)
@@ -34,16 +34,16 @@
9. [结论](#结论)
## 简介
本文件为型号管理API的详细RESTful API文档,覆盖型号的CRUD操作、查询筛选与排序、数据验证规则,以及与OTA固件的一对多关联关系与级联操作。文档同时提供前端调用示例与后端实现细节,帮助开发者快速集成与维护。**最新更新**:新增squig.link外部数据源支持,增强模型创建/更新流程以支持外部URL数据源
本文件为型号管理API的详细RESTful API文档,覆盖型号的CRUD操作、查询筛选与排序、数据验证规则,以及与OTA固件的一对多关联关系与级联操作。文档同时提供前端调用示例与后端实现细节,帮助开发者快速集成与维护。**最新更新**:新增squig.link外部数据源支持及测量文件S3自动迁移功能,显著提升型号数据管理的自动化程度和数据一致性保障
## 项目结构
型号管理API位于后端Express应用中,采用模块化设计:
- 路由层:集中于 models.js,提供型号的增删改查、搜索推送、频响文件处理、**squig.link数据抓取**等接口
- 路由层:集中于 models.js,提供型号的增删改查、搜索推送、频响文件处理、**squig.link数据抓取**、**S3文件自动迁移**等接口
- 模型层:Model.js 定义数据库表结构
- 验证层:model.js 使用Zod进行请求体验证
- 工具层:response.js 统一响应格式
- 中间件:auth.js 提供鉴权保护
- **服务层**squiglink.js 提供squig.link外部数据源抓取服务
- **服务层**squiglink.js 提供squig.link外部数据源抓取服务measurementStorage.js 提供S3存储与文件迁移服务
- 前端封装:frontend/src/api/model.js 提供HTTP调用封装
- **前端组件**ModelFormDialog.vue 集成squig.link导入功能
@@ -55,11 +55,13 @@ R --> V["验证层<br/>backend/src/validators/model.js"]
R --> U["工具层<br/>backend/src/utils/response.js"]
R --> A["中间件<br/>backend/src/middleware/auth.js"]
R --> S["服务层<br/>backend/src/services/squiglink.js"]
R --> MS["存储服务<br/>backend/src/services/measurementStorage.js"]
R -. 关联 .-> OTA["OTA模型<br/>backend/src/models/Ota.js"]
MS -. 存储 .-> S3["S3对象存储"]
```
**图表来源**
- [backend/src/routes/models.js:1-659](file://backend/src/routes/models.js#L1-L659)
- [backend/src/routes/models.js:1-668](file://backend/src/routes/models.js#L1-L668)
- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53)
- [backend/src/validators/model.js:1-22](file://backend/src/validators/model.js#L1-L22)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
@@ -67,10 +69,11 @@ R -. 关联 .-> OTA["OTA模型<br/>backend/src/models/Ota.js"]
- [frontend/src/api/model.js:1-165](file://frontend/src/api/model.js#L1-L165)
- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97)
- [backend/src/services/squiglink.js:1-322](file://backend/src/services/squiglink.js#L1-L322)
- [backend/src/services/measurementStorage.js:1-165](file://backend/src/services/measurementStorage.js#L1-L165)
- [frontend/src/views/model/components/ModelFormDialog.vue:1-555](file://frontend/src/views/model/components/ModelFormDialog.vue#L1-L555)
**章节来源**
- [backend/src/routes/models.js:1-659](file://backend/src/routes/models.js#L1-L659)
- [backend/src/routes/models.js:1-668](file://backend/src/routes/models.js#L1-L668)
- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53)
- [backend/src/validators/model.js:1-22](file://backend/src/validators/model.js#L1-L22)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
@@ -78,15 +81,17 @@ R -. 关联 .-> OTA["OTA模型<br/>backend/src/models/Ota.js"]
- [frontend/src/api/model.js:1-165](file://frontend/src/api/model.js#L1-L165)
- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97)
- [backend/src/services/squiglink.js:1-322](file://backend/src/services/squiglink.js#L1-L322)
- [backend/src/services/measurementStorage.js:1-165](file://backend/src/services/measurementStorage.js#L1-L165)
- [frontend/src/views/model/components/ModelFormDialog.vue:1-555](file://frontend/src/views/model/components/ModelFormDialog.vue#L1-L555)
## 核心组件
- 路由控制器:models.js 提供型号的列表查询、详情获取、创建、更新、删除、搜索推送、频响文件上传与查询、**squig.link数据抓取**等接口
- 路由控制器:models.js 提供型号的列表查询、详情获取、创建、更新、删除、搜索推送、频响文件处理、**squig.link数据抓取**、**S3文件自动迁移**等接口
- 数据模型:Model.js 定义型号字段及约束
- 请求验证:model.js 使用Zod Schema进行创建/更新的输入校验
- 统一响应:response.js 提供统一的响应结构
- 鉴权中间件:auth.js 实现Bearer Token鉴权
- **squig.link服务**squiglink.js 提供外部数据源抓取功能
- **S3存储服务**measurementStorage.js 提供文件上传、下载、迁移等存储服务
- 前端封装:frontend/src/api/model.js 提供HTTP调用封装
- **前端组件**ModelFormDialog.vue 集成squig.link导入功能
@@ -97,11 +102,12 @@ R -. 关联 .-> OTA["OTA模型<br/>backend/src/models/Ota.js"]
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26)
- [backend/src/services/squiglink.js:1-322](file://backend/src/services/squiglink.js#L1-L322)
- [backend/src/services/measurementStorage.js:1-165](file://backend/src/services/measurementStorage.js#L1-L165)
- [frontend/src/api/model.js:13-165](file://frontend/src/api/model.js#L13-L165)
- [frontend/src/views/model/components/ModelFormDialog.vue:158-464](file://frontend/src/views/model/components/ModelFormDialog.vue#L158-L464)
## 架构概览
型号管理API采用分层架构,路由层负责HTTP协议与参数解析,模型层负责数据持久化,验证层确保输入合法性,工具层统一输出格式,中间件提供安全控制,**服务层提供外部数据源集成**。
型号管理API采用分层架构,路由层负责HTTP协议与参数解析,模型层负责数据持久化,验证层确保输入合法性,工具层统一输出格式,中间件提供安全控制,**服务层提供外部数据源集成与S3存储管理**。
```mermaid
sequenceDiagram
@@ -110,6 +116,7 @@ participant R as "路由(models.js)"
participant V as "验证(model.js)"
participant M as "模型(Model.js)"
participant S as "服务(squiglink.js)"
participant MS as "存储服务(measurementStorage.js)"
participant U as "响应(response.js)"
participant A as "鉴权(auth.js)"
C->>R : "HTTP请求"
@@ -119,6 +126,8 @@ R->>V : "请求体验证"
V-->>R : "验证结果"
R->>S : "外部数据源抓取可选"
S-->>R : "抓取结果"
R->>MS : "S3文件操作(上传/迁移)"
MS-->>R : "操作结果"
R->>M : "数据库操作"
M-->>R : "结果"
R->>U : "封装响应"
@@ -130,6 +139,7 @@ U-->>C : "统一响应"
- [backend/src/validators/model.js:3-19](file://backend/src/validators/model.js#L3-L19)
- [backend/src/models/Model.js:4-50](file://backend/src/models/Model.js#L4-L50)
- [backend/src/services/squiglink.js:261-310](file://backend/src/services/squiglink.js#L261-L310)
- [backend/src/services/measurementStorage.js:116-157](file://backend/src/services/measurementStorage.js#L116-L157)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26)
@@ -240,11 +250,14 @@ datetime create_at
- 路径参数:model_id(整数)
- 表单字段:同创建,支持部分字段更新(传入'null'表示保持原值)
- 文件处理:同创建,若上传需提供source与form
- **智能文件迁移**:当未上传新文件且路径相关字段(source、form、brand_name、name)发生变更时,系统自动将现有CSV文件从旧路径迁移到新路径
- 成功响应:更新后的型号信息
- 异常响应:未找到、重复、格式不支持、通用错误
**新增** 智能S3文件自动迁移功能,确保数据一致性与完整性
**章节来源**
- [backend/src/routes/models.js:439-526](file://backend/src/routes/models.js#L439-L526)
- [backend/src/routes/models.js:439-535](file://backend/src/routes/models.js#L439-L535)
- [backend/src/validators/model.js:12-19](file://backend/src/validators/model.js#L12-L19)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26)
@@ -260,7 +273,7 @@ datetime create_at
- 异常响应:未找到、Meilisearch删除失败、通用错误
**章节来源**
- [backend/src/routes/models.js:528-554](file://backend/src/routes/models.js#L528-L554)
- [backend/src/routes/models.js:537-563](file://backend/src/routes/models.js#L537-L563)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26)
@@ -309,7 +322,7 @@ string model
- 输出:推送成功数量、任务ID与推送数据
**章节来源**
- [backend/src/routes/models.js:556-656](file://backend/src/routes/models.js#L556-L656)
- [backend/src/routes/models.js:565-665](file://backend/src/routes/models.js#L565-L665)
### 频响文件上传与查询
- 上传:POST /api/models/multipart/form-data),支持TXT自动转换为CSV**新增squiglink_csv字段**
@@ -362,15 +375,65 @@ string model
**新增** 完整的squig.link外部数据源支持
**章节来源**
- [backend/src/routes/models.js:307-369](file://backend/src/routes/models.js#L307-L369)
- [backend/src/routes/models.js:307-369](file://backend/src/routes/models.js#L307-369)
- [backend/src/services/squiglink.js:1-322](file://backend/src/services/squiglink.js#L1-L322)
- [frontend/src/views/model/components/ModelFormDialog.vue:158-464](file://frontend/src/views/model/components/ModelFormDialog.vue#L158-L464)
### S3文件自动迁移功能
#### 智能文件迁移机制
- **触发条件**:更新型号时未上传新文件且路径相关字段发生变更
- **路径字段**:source(来源)、form(佩戴方式)、brand_name(品牌名)、name(型号名)
- **迁移策略**:服务端直接复制后删除,无需下载再上传
- **原子操作**:复制成功后才删除旧文件,确保数据完整性
#### S3存储服务功能
- **文件路径构建**autoeq/measurements/{source}/data/{form}/{brandFirstChar}/{brand model}.csv
- **上传服务**uploadMeasurementToS3 - 支持CSV文件上传到S3
- **读取服务**getMeasurementFromS3 - 从S3读取CSV文件内容
- **迁移服务**moveMeasurementOnS3 - 实现S3文件的智能迁移
- **路径生成**buildMeasurementKey - 根据参数生成标准S3 Key
#### 迁移流程详解
```mermaid
flowchart TD
A[更新型号请求] --> B{是否上传新文件?}
B --> |是| C[上传新文件到S3]
B --> |否| D{路径字段是否变更?}
D --> |否| E[直接更新数据库]
D --> |是| F[计算新旧S3路径]
F --> G{路径是否相同?}
G --> |是| H[跳过迁移]
G --> |否| I[执行S3复制操作]
I --> J[复制成功后删除旧文件]
J --> K[更新数据库]
C --> L[返回成功响应]
E --> L
H --> L
K --> L
```
**图表来源**
- [backend/src/routes/models.js:502-509](file://backend/src/routes/models.js#L502-L509)
- [backend/src/services/measurementStorage.js:116-157](file://backend/src/services/measurementStorage.js#L116-L157)
#### 错误处理与日志记录
- **文件不存在**:跳过迁移并记录日志,不影响更新操作
- **网络异常**:抛出明确错误信息,便于问题排查
- **权限问题**:详细的错误描述,指导权限配置
- **路径冲突**:自动检测路径变化,避免不必要的操作
**新增** 完整的S3文件自动迁移功能,提升数据管理自动化水平
**章节来源**
- [backend/src/routes/models.js:502-509](file://backend/src/routes/models.js#L502-L509)
- [backend/src/services/measurementStorage.js:110-165](file://backend/src/services/measurementStorage.js#L110-L165)
## 依赖分析
- 路由依赖:models.js 依赖Model模型、Zod验证器、响应工具、鉴权中间件,并与Meilisearch、S3服务交互,**新增squiglink服务依赖**
- 路由依赖:models.js 依赖Model模型、Zod验证器、响应工具、鉴权中间件,并与Meilisearch、S3服务交互,**新增squiglink服务依赖与measurementStorage服务依赖**
- 模型依赖:Model.js 依赖Sequelize ORM
- 前端依赖:frontend/src/api/model.js 依赖通用请求封装
- **服务依赖**squiglink.js 依赖axios、logger,提供外部数据源抓取功能
- **服务依赖**squiglink.js 依赖axios、logger,提供外部数据源抓取功能measurementStorage.js 依赖AWS SDK、logger,提供S3存储服务
```mermaid
graph LR
@@ -379,21 +442,24 @@ R --> V["model.js(Zod)"]
R --> U["response.js"]
R --> A["auth.js"]
R --> S["squiglink.js"]
R --> MS["measurementStorage.js"]
R -. 外部 .-> MS["Meilisearch"]
R -. 外部 .-> S3["S3存储"]
S -. 外部 .-> SL["squig.link"]
MS -. 外部 .-> AWS["AWS SDK"]
```
**图表来源**
- [backend/src/routes/models.js:1-659](file://backend/src/routes/models.js#L1-L659)
- [backend/src/routes/models.js:1-668](file://backend/src/routes/models.js#L1-L668)
- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53)
- [backend/src/validators/model.js:1-22](file://backend/src/validators/model.js#L1-L22)
- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25)
- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36)
- [backend/src/services/squiglink.js:1-322](file://backend/src/services/squiglink.js#L1-L322)
- [backend/src/services/measurementStorage.js:1-165](file://backend/src/services/measurementStorage.js#L1-L165)
**章节来源**
- [backend/src/routes/models.js:1-659](file://backend/src/routes/models.js#L1-L659)
- [backend/src/routes/models.js:1-668](file://backend/src/routes/models.js#L1-L668)
## 性能考虑
- 分页限制:列表查询limit上限为1000,避免一次性返回过多数据
@@ -402,6 +468,8 @@ S -. 外部 .-> SL["squig.link"]
- 验证前置:使用Zod在进入数据库操作前完成字段校验,减少无效请求
- **squig.link抓取超时**:设置15秒超时,避免外部服务影响系统性能
- **squigsites.json缓存**1小时TTL减少对外部服务的频繁请求
- **S3迁移优化**:服务端直接复制,避免网络传输开销,提高迁移效率
- **路径变更检测**:智能判断是否需要迁移,避免不必要的S3操作
## 故障排除指南
- 401 未登录/无效凭证:检查Authorization头是否为Bearer Token且有效
@@ -412,6 +480,8 @@ S -. 外部 .-> SL["squig.link"]
- Meilisearch异常:检查服务连通性与API密钥
- **squig.link抓取失败**:检查share_url格式、网络连通性、目标站点可用性
- **squig.link文件下载失败**:确认文件存在、权限正确、支持的文件后缀
- **S3迁移失败**:检查AWS凭证配置、S3 Bucket权限、网络连接状态
- **文件路径错误**:确认source、form、brand_name、name字段值符合规范
**章节来源**
- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26)
@@ -419,6 +489,7 @@ S -. 外部 .-> SL["squig.link"]
- [backend/src/routes/models.js:322-325](file://backend/src/routes/models.js#L322-L325)
- [backend/src/routes/models.js:450-455](file://backend/src/routes/models.js#L450-L455)
- [backend/src/services/squiglink.js:33-47](file://backend/src/services/squiglink.js#L33-L47)
- [backend/src/services/measurementStorage.js:149-156](file://backend/src/services/measurementStorage.js#L149-L156)
## 结论
型号管理API提供了完善的CRUD能力、灵活的查询过滤与排序、严格的输入验证、以及与搜索与存储系统的集成。**最新更新**:新增squig.link外部数据源支持,显著提升了型号数据的获取效率和准确性。结合OTA模型的关联关系,可支撑从型号到固件升级的完整业务闭环。建议在生产环境中关注分页与超时配置、文件上传性能与安全策略、**squig.link抓取的超时与缓存策略**,并在删除型号前做好OTA关联清理。
型号管理API提供了完善的CRUD能力、灵活的查询过滤与排序、严格的输入验证、以及与搜索与存储系统的集成。**最新更新**:新增squig.link外部数据源支持及测量文件S3自动迁移功能,显著提升了型号数据的获取效率和数据一致性保障。智能文件迁移机制确保了在更新型号路径相关字段时,现有CSV文件能够自动迁移到新路径,无需人工干预。结合OTA模型的关联关系,可支撑从型号到固件升级的完整业务闭环。建议在生产环境中关注分页与超时配置、文件上传性能与安全策略、**squig.link抓取的超时与缓存策略**、**S3迁移的性能监控与错误处理**,并在删除型号前做好OTA关联清理。
@@ -33,6 +33,13 @@
- [frontend/src/views/system/users/index.vue](file://frontend/src/views/system/users/index.vue)
</cite>
## 更新摘要
**变更内容**
- OTA固件管理功能已更新以支持beta版本特性
- 版本唯一性规则从'verCode + model'变更为'verCode + model + beta'组合
- 允许同一设备型号下存在多个不同beta状态的固件版本
- 前端界面新增beta状态筛选和显示功能
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
@@ -99,7 +106,8 @@ ROUTER --> UTILS_AUTH
- 型号管理
- 支持型号增删改查、频响文件上传(CSV/TXT/JSON)、S3 存储、Meilisearch 推送与校验、Redis EQ 缓存读取。
- OTA 固件管理
- 支持 X8/X9 设备固件包上传(S3 或本地),设备端最新版本检查接口,后台管理列表与编辑。
- 支持 X8/X9 设备固件包上传(S3 或本地),设备端"最新版本检查"接口,后台管理列表与编辑。
- **新增**:支持beta版本管理,允许同一设备型号下存在多个不同beta状态的固件版本。
- 分享码日志管理
- 提供分享码导出/导入日志的查询接口,支持多维过滤与排序。
- 权限模型
@@ -111,7 +119,7 @@ ROUTER --> UTILS_AUTH
- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58)
- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147)
- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569)
- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292)
- [backend/src/routes/ota.js:1-295](file://backend/src/routes/ota.js#L1-L295)
- [backend/src/routes/shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88)
- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91)
@@ -153,7 +161,7 @@ end
- 登录流程
- 前端提交用户名与密码,后端校验账号是否存在且启用,验证密码哈希,更新最近登录时间,签发 Access Token 并返回用户信息。
- 当前用户
- 需携带有效 Token 调用获取当前用户,后端返回用户基础信息。
- 需携带有效 Token 调用"获取当前用户",后端返回用户基础信息。
- 修改密码
- 需携带有效 Token,校验旧密码,长度不少于 6 位,成功后更新密码哈希。
- 鉴权中间件
@@ -290,17 +298,20 @@ ModelR-->>FE : 返回字段值
### OTA 固件管理
- 功能点
- 设备端最新版本检查:无需登录,按当前版本号、设备型号与硬件版本筛选可用升级包。
- 设备端"最新版本检查":无需登录,按当前版本号、设备型号与硬件版本筛选可用升级包。
- 后台上传固件包:支持 X8(S3)、X9(本地);自动计算 MD5,返回下载地址与存储键。
- 后台管理:列表查询、详情、创建、更新(版本号+型号唯一性校验)、删除。
- 后台管理:列表查询、详情、创建、更新(版本号+型号+灰度状态唯一性校验)、删除。
- **新增**:Beta版本支持,允许同一设备型号下存在多个不同beta状态的固件版本。
- 关键参数
- 最新版本检查:currentVerCode、model、hw。
- 上传:model、package_file。
- 列表:verCode、verName、model、status、skip、limit。
- 列表:verCode、verName、model、status、beta、skip、limit。
- 创建/更新:verCode、verName、url、md5、force、desc、model、hw、target、beta、startTime、endTime、status。
- 返回值
- 统一 ApiResponse 包裹,成功时返回列表、单条记录或上传结果。
**更新** 版本唯一性规则已从'verCode + model'组合变更为'verCode + model + beta'组合,允许同一设备型号下存在多个不同beta状态的固件版本。
```mermaid
sequenceDiagram
participant Device as "设备端"
@@ -315,19 +326,23 @@ Admin->>OTAR : POST /api/ota/upload-package
OTAR->>OtaSvc : 校验并保存升级包
OtaSvc-->>OTAR : 返回 md5/filename/url/s3_key
OTAR-->>Admin : 返回上传结果
Admin->>OTAR : POST /api/ota/ (含beta字段)
OTAR->>DB : 检查verCode+model+beta唯一性
DB-->>OTAR : 唯一性检查结果
OTAR-->>Admin : 创建结果
```
图表来源
- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102)
- [backend/src/routes/ota.js:24-66](file://backend/src/routes/ota.js#L24-L66)
- [backend/src/routes/ota.js:107-143](file://backend/src/routes/ota.js#L107-L143)
- [backend/src/routes/ota.js:162-194](file://backend/src/routes/ota.js#L162-L194)
- [backend/src/routes/ota.js:196-247](file://backend/src/routes/ota.js#L196-L247)
- [backend/src/routes/ota.js:249-268](file://backend/src/routes/ota.js#L249-L268)
- [backend/src/routes/ota.js:107-145](file://backend/src/routes/ota.js#L107-L145)
- [backend/src/routes/ota.js:165-196](file://backend/src/routes/ota.js#L165-L196)
- [backend/src/routes/ota.js:198-250](file://backend/src/routes/ota.js#L198-L250)
- [backend/src/routes/ota.js:252-271](file://backend/src/routes/ota.js#L252-L271)
- [backend/src/services/otaStorage.js](file://backend/src/services/otaStorage.js)
章节来源
- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292)
- [backend/src/routes/ota.js:1-295](file://backend/src/routes/ota.js#L1-L295)
### 用户权限管理
- 角色模型
@@ -447,6 +462,7 @@ Services --> Cache["Redis"]
- 文件格式不支持:仅允许 CSV/TXT/JSONTXT 将被自动转换为 CSV。
- OTA 上传
- 仅支持指定设备型号;S3 未配置或上传失败会返回明确错误。
- **新增**:版本唯一性冲突检查包含beta状态,确保verCode+model+beta组合唯一。
- Meilisearch 集成
- 推送/删除失败:检查服务可达性与 API Key;关注返回的任务 UID。
- 分享码日志
@@ -458,11 +474,12 @@ Services --> Cache["Redis"]
- [backend/src/routes/brands.js:62-80](file://backend/src/routes/brands.js#L62-L80)
- [backend/src/routes/models.js:319-335](file://backend/src/routes/models.js#L319-L335)
- [backend/src/routes/ota.js:27-58](file://backend/src/routes/ota.js#L27-L58)
- [backend/src/routes/ota.js:176-183](file://backend/src/routes/ota.js#L176-L183)
- [backend/src/routes/models.js:543-561](file://backend/src/routes/models.js#L543-L561)
- [backend/src/routes/shareCodeLogs.js:37-48](file://backend/src/routes/shareCodeLogs.js#L37-L48)
## 结论
本系统围绕认证—权限—数据模型—业务路由—服务集成的清晰分层组织,通过统一的响应封装与中间件机制保障了接口一致性与安全性。品牌、型号、OTA、分享码日志等核心功能均具备完善的 CRUD、校验与外部集成能力,适合在生产环境中稳定运行。建议持续完善监控与告警、日志分级与外部服务降级策略,以进一步提升稳定性与可观测性。
本系统围绕"认证—权限—数据模型—业务路由—服务集成"的清晰分层组织,通过统一的响应封装与中间件机制保障了接口一致性与安全性。品牌、型号、OTA、分享码日志等核心功能均具备完善的 CRUD、校验与外部集成能力,适合在生产环境中稳定运行。**新增的beta版本支持功能进一步增强了OTA固件管理的灵活性,允许在同一设备型号下管理多个不同灰度状态的版本**。建议持续完善监控与告警、日志分级与外部服务降级策略,以进一步提升稳定性与可观测性。
## 附录
- 前端页面与路由对应关系
File diff suppressed because one or more lines are too long