From 08da2792750350663680c85dbc6b6947f35500d7 Mon Sep 17 00:00:00 2001 From: eafonyang Date: Tue, 30 Jun 2026 14:46:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=A1=B9=E7=9B=AE=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_module.yaml | 15 + .../build_system.md | 35 ++ .qoder/repowiki/knowledge/zh/_index.yaml | 129 ++++ .../zh/全栈错误处理与响应规范/_module.yaml | 13 + .../全栈错误处理与响应规范/error_handling.md | 38 ++ .../zh/后端日志系统 (Winston)/_module.yaml | 11 + .../后端日志系统 (Winston)/logging_system.md | 26 + .../_module.yaml | 14 + .../dependency_management.md | 27 + .../_module.yaml | 14 + .../configuration_system.md | 48 ++ .../_module.yaml | 12 + .../frontend_style.md | 35 ++ .../zh/音频设备管理全栈平台/_module.yaml | 14 + .../zh/音频设备管理全栈平台/架构设计.md | 4 + .../knowledge/zh/音频设备管理全栈平台/概述.md | 1 + .../zh/音频设备管理全栈平台/特殊配置与命令.md | 2 + .../zh/音频设备管理全栈平台/编码规范.md | 2 + .../音频设备管理后台前端/_module.yaml | 9 + .../音频设备管理后台前端/技术栈.md | 1 + .../音频设备管理后台前端/架构设计.md | 4 + .../音频设备管理后台前端/概述.md | 1 + .../音频设备管理后台前端/编码规范.md | 3 + .../音频设备管理后端 API/_module.yaml | 9 + .../音频设备管理后端 API/技术栈.md | 5 + .../音频设备管理后端 API/架构设计.md | 5 + .../音频设备管理后端 API/概述.md | 1 + .../音频设备管理后端 API/特殊配置与命令.md | 3 + .../音频设备管理后端 API/编码规范.md | 4 + .../zh/content/前端组件/业务组件/业务组件.md | 344 +++++++++++ .../前端组件/业务组件/侧边栏Logo组件.md | 463 ++++++++++++++ .../前端组件/业务组件/密码修改对话框.md | 466 ++++++++++++++ .../前端组件/业务组件/标签页视图组件.md | 312 ++++++++++ .../repowiki/zh/content/前端组件/前端组件.md | 418 +++++++++++++ .../repowiki/zh/content/前端组件/布局组件.md | 497 +++++++++++++++ .../前端组件/页面组件/OTA固件管理页面.md | 388 ++++++++++++ .../前端组件/页面组件/分享码日志页面.md | 483 +++++++++++++++ .../content/前端组件/页面组件/品牌管理页面.md | 391 ++++++++++++ .../content/前端组件/页面组件/型号管理页面.md | 408 ++++++++++++ .../zh/content/前端组件/页面组件/登录页面.md | 480 +++++++++++++++ .../前端组件/页面组件/系统用户管理页面.md | 462 ++++++++++++++ .../zh/content/前端组件/页面组件/页面组件.md | 527 ++++++++++++++++ .../content/前端组件/页面组件/首页仪表板.md | 368 +++++++++++ .../zh/content/后端API文档/OTA固件API.md | 388 ++++++++++++ .../zh/content/后端API文档/仪表板API.md | 418 +++++++++++++ .../zh/content/后端API文档/分享码日志API.md | 421 +++++++++++++ .../zh/content/后端API文档/后端API文档.md | 423 +++++++++++++ .../zh/content/后端API文档/品牌管理API.md | 434 +++++++++++++ .../zh/content/后端API文档/型号管理API.md | 347 +++++++++++ .../zh/content/后端API文档/用户管理API.md | 460 ++++++++++++++ .../zh/content/后端API文档/认证系统API.md | 426 +++++++++++++ .qoder/repowiki/zh/content/开发指南.md | 399 ++++++++++++ .qoder/repowiki/zh/content/快速开始.md | 297 +++++++++ .../zh/content/数据库设计/OTA固件模型.md | 424 +++++++++++++ .../zh/content/数据库设计/分享码日志模型.md | 323 ++++++++++ .../zh/content/数据库设计/品牌模型.md | 411 +++++++++++++ .../zh/content/数据库设计/型号模型.md | 390 ++++++++++++ .../zh/content/数据库设计/实体关系设计.md | 434 +++++++++++++ .../zh/content/数据库设计/数据库设计.md | 505 +++++++++++++++ .../zh/content/数据库设计/用户模型.md | 369 +++++++++++ .../zh/content/核心功能模块/OTA固件管理.md | 476 ++++++++++++++ .../zh/content/核心功能模块/分享码日志管理.md | 345 +++++++++++ .../zh/content/核心功能模块/品牌管理.md | 362 +++++++++++ .../zh/content/核心功能模块/型号管理.md | 382 ++++++++++++ .../zh/content/核心功能模块/核心功能模块.md | 476 ++++++++++++++ .../zh/content/核心功能模块/用户权限管理.md | 462 ++++++++++++++ .../zh/content/核心功能模块/用户认证系统.md | 520 ++++++++++++++++ .../repowiki/zh/content/系统架构/前端架构.md | 375 +++++++++++ .../repowiki/zh/content/系统架构/后端架构.md | 581 ++++++++++++++++++ .../zh/content/系统架构/数据流设计.md | 362 +++++++++++ .../repowiki/zh/content/系统架构/系统架构.md | 482 +++++++++++++++ .../repowiki/zh/content/系统架构/集成模式.md | 404 ++++++++++++ .../zh/content/部署与运维/故障排除.md | 507 +++++++++++++++ .../zh/content/部署与运维/环境配置.md | 351 +++++++++++ .../zh/content/部署与运维/监控运维.md | 348 +++++++++++ .../zh/content/部署与运维/部署与运维.md | 349 +++++++++++ .../zh/content/部署与运维/部署指南.md | 377 ++++++++++++ .qoder/repowiki/zh/content/项目概述.md | 339 ++++++++++ .../repowiki/zh/meta/repowiki-metadata.json | 1 + 79 files changed, 20860 insertions(+) create mode 100644 .qoder/repowiki/knowledge/zh/Docker Compose 编排与 rsync 增量部署/_module.yaml create mode 100644 .qoder/repowiki/knowledge/zh/Docker Compose 编排与 rsync 增量部署/build_system.md create mode 100644 .qoder/repowiki/knowledge/zh/_index.yaml create mode 100644 .qoder/repowiki/knowledge/zh/全栈错误处理与响应规范/_module.yaml create mode 100644 .qoder/repowiki/knowledge/zh/全栈错误处理与响应规范/error_handling.md create mode 100644 .qoder/repowiki/knowledge/zh/后端日志系统 (Winston)/_module.yaml create mode 100644 .qoder/repowiki/knowledge/zh/后端日志系统 (Winston)/logging_system.md create mode 100644 .qoder/repowiki/knowledge/zh/基于 pnpm 与 Docker 的前后端依赖管理/_module.yaml create mode 100644 .qoder/repowiki/knowledge/zh/基于 pnpm 与 Docker 的前后端依赖管理/dependency_management.md create mode 100644 .qoder/repowiki/knowledge/zh/基于环境变量与 Docker Compose 的分层配置体系/_module.yaml create mode 100644 .qoder/repowiki/knowledge/zh/基于环境变量与 Docker Compose 的分层配置体系/configuration_system.md create mode 100644 .qoder/repowiki/knowledge/zh/深色玻璃拟态主题系统 (Lux Theme)/_module.yaml create mode 100644 .qoder/repowiki/knowledge/zh/深色玻璃拟态主题系统 (Lux Theme)/frontend_style.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/_module.yaml create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/架构设计.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/概述.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/特殊配置与命令.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/编码规范.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/_module.yaml create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/技术栈.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/架构设计.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/概述.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/编码规范.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/_module.yaml create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/技术栈.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/架构设计.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/概述.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/特殊配置与命令.md create mode 100644 .qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/编码规范.md create mode 100644 .qoder/repowiki/zh/content/前端组件/业务组件/业务组件.md create mode 100644 .qoder/repowiki/zh/content/前端组件/业务组件/侧边栏Logo组件.md create mode 100644 .qoder/repowiki/zh/content/前端组件/业务组件/密码修改对话框.md create mode 100644 .qoder/repowiki/zh/content/前端组件/业务组件/标签页视图组件.md create mode 100644 .qoder/repowiki/zh/content/前端组件/前端组件.md create mode 100644 .qoder/repowiki/zh/content/前端组件/布局组件.md create mode 100644 .qoder/repowiki/zh/content/前端组件/页面组件/OTA固件管理页面.md create mode 100644 .qoder/repowiki/zh/content/前端组件/页面组件/分享码日志页面.md create mode 100644 .qoder/repowiki/zh/content/前端组件/页面组件/品牌管理页面.md create mode 100644 .qoder/repowiki/zh/content/前端组件/页面组件/型号管理页面.md create mode 100644 .qoder/repowiki/zh/content/前端组件/页面组件/登录页面.md create mode 100644 .qoder/repowiki/zh/content/前端组件/页面组件/系统用户管理页面.md create mode 100644 .qoder/repowiki/zh/content/前端组件/页面组件/页面组件.md create mode 100644 .qoder/repowiki/zh/content/前端组件/页面组件/首页仪表板.md create mode 100644 .qoder/repowiki/zh/content/后端API文档/OTA固件API.md create mode 100644 .qoder/repowiki/zh/content/后端API文档/仪表板API.md create mode 100644 .qoder/repowiki/zh/content/后端API文档/分享码日志API.md create mode 100644 .qoder/repowiki/zh/content/后端API文档/后端API文档.md create mode 100644 .qoder/repowiki/zh/content/后端API文档/品牌管理API.md create mode 100644 .qoder/repowiki/zh/content/后端API文档/型号管理API.md create mode 100644 .qoder/repowiki/zh/content/后端API文档/用户管理API.md create mode 100644 .qoder/repowiki/zh/content/后端API文档/认证系统API.md create mode 100644 .qoder/repowiki/zh/content/开发指南.md create mode 100644 .qoder/repowiki/zh/content/快速开始.md create mode 100644 .qoder/repowiki/zh/content/数据库设计/OTA固件模型.md create mode 100644 .qoder/repowiki/zh/content/数据库设计/分享码日志模型.md create mode 100644 .qoder/repowiki/zh/content/数据库设计/品牌模型.md create mode 100644 .qoder/repowiki/zh/content/数据库设计/型号模型.md create mode 100644 .qoder/repowiki/zh/content/数据库设计/实体关系设计.md create mode 100644 .qoder/repowiki/zh/content/数据库设计/数据库设计.md create mode 100644 .qoder/repowiki/zh/content/数据库设计/用户模型.md create mode 100644 .qoder/repowiki/zh/content/核心功能模块/OTA固件管理.md create mode 100644 .qoder/repowiki/zh/content/核心功能模块/分享码日志管理.md create mode 100644 .qoder/repowiki/zh/content/核心功能模块/品牌管理.md create mode 100644 .qoder/repowiki/zh/content/核心功能模块/型号管理.md create mode 100644 .qoder/repowiki/zh/content/核心功能模块/核心功能模块.md create mode 100644 .qoder/repowiki/zh/content/核心功能模块/用户权限管理.md create mode 100644 .qoder/repowiki/zh/content/核心功能模块/用户认证系统.md create mode 100644 .qoder/repowiki/zh/content/系统架构/前端架构.md create mode 100644 .qoder/repowiki/zh/content/系统架构/后端架构.md create mode 100644 .qoder/repowiki/zh/content/系统架构/数据流设计.md create mode 100644 .qoder/repowiki/zh/content/系统架构/系统架构.md create mode 100644 .qoder/repowiki/zh/content/系统架构/集成模式.md create mode 100644 .qoder/repowiki/zh/content/部署与运维/故障排除.md create mode 100644 .qoder/repowiki/zh/content/部署与运维/环境配置.md create mode 100644 .qoder/repowiki/zh/content/部署与运维/监控运维.md create mode 100644 .qoder/repowiki/zh/content/部署与运维/部署与运维.md create mode 100644 .qoder/repowiki/zh/content/部署与运维/部署指南.md create mode 100644 .qoder/repowiki/zh/content/项目概述.md create mode 100644 .qoder/repowiki/zh/meta/repowiki-metadata.json diff --git a/.qoder/repowiki/knowledge/zh/Docker Compose 编排与 rsync 增量部署/_module.yaml b/.qoder/repowiki/knowledge/zh/Docker Compose 编排与 rsync 增量部署/_module.yaml new file mode 100644 index 0000000..7242da1 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/Docker Compose 编排与 rsync 增量部署/_module.yaml @@ -0,0 +1,15 @@ +schema_version: 1 +module_path: build_system +title: Docker Compose 编排与 rsync 增量部署 +scope: [] +source_files: + - docker-compose.yml + - backend/Dockerfile + - frontend/Dockerfile + - frontend/nginx.conf + - scripts/upload.sh + - DEPLOY.md + - backend/package.json + - frontend/package.json +depends_on: [] +related_to: [] diff --git a/.qoder/repowiki/knowledge/zh/Docker Compose 编排与 rsync 增量部署/build_system.md b/.qoder/repowiki/knowledge/zh/Docker Compose 编排与 rsync 增量部署/build_system.md new file mode 100644 index 0000000..7894378 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/Docker Compose 编排与 rsync 增量部署/build_system.md @@ -0,0 +1,35 @@ +## 1. 构建系统与工具链 +项目采用 **Docker Compose** 作为核心编排工具,结合 **pnpm** 进行依赖管理。整体架构分为前端(Vue 3 + Vite)和后端(Node.js + Express)两个独立服务。 + +- **包管理器**:前后端均使用 `pnpm`,并在 `package.json` 中通过 `packageManager` 字段锁定版本(`pnpm@11.5.2`),确保环境一致性。 +- **前端构建**:使用 `Vite` 进行编译打包,产物输出至 `frontend/dist`。 +- **后端运行**:基于 `node:22-alpine` 镜像,直接运行 `src/app.js`。 + +## 2. 容器化策略 +### 后端 (backend/Dockerfile) +- **基础镜像**:`node:22-alpine`。 +- **构建逻辑**:采用单层结构,先安装生产依赖(`pnpm install --prod`),再拷贝源码。 +- **端口**:容器内固定监听 `8000` 端口。 + +### 前端 (frontend/Dockerfile & docker-compose.yml) +- **混合模式**:虽然提供了多阶段构建的 `Dockerfile`(Builder -> Nginx),但在生产环境的 `docker-compose.yml` 中,前端服务直接使用官方 `nginx:alpine` 镜像。 +- **挂载部署**:通过 Volume 将宿主机的 `frontend/dist` 和 `nginx.conf` 挂载到容器中。这种方式避免了每次前端更新都重新构建 Docker 镜像,提升了部署效率。 +- **反向代理**:Nginx 配置了 `/api` 路径的反向代理,将请求转发至 `http://backend:8000`,解决了跨域问题并统一了入口。 + +## 3. 部署流程与自动化 +项目实现了一套基于 **rsync** 的半自动化部署方案,核心脚本为 `scripts/upload.sh`。 + +### 部署步骤 +1. **本地构建**:在本地执行 `pnpm build` 生成前端静态资源。 +2. **代码同步**:运行 `./scripts/upload.sh all`,通过 SSH/rsync 将前端产物、后端源码及 `docker-compose.yml` 同步至远程服务器(默认路径 `/data/project/dashboard`)。 +3. **远程启动**:在服务器上执行 `docker compose build --no-cache backend` 和 `docker compose up -d` 完成服务重启。 + +### 关键约定 +- **环境变量**:所有配置统一由根目录的 `.env` 文件管理,并通过 `env_file` 注入后端容器。`.env` 文件不随脚本上传,需在服务器手动维护。 +- **日志管理**:Compose 文件中定义了 `json-file` 驱动,限制日志最大大小为 10MB,保留 5 个文件,防止磁盘爆满。 +- **OTA 存储**:通过 Volume 将宿主机的 `/data/projects/source` 映射到后端容器,用于存储大型 OTA 升级包。 + +## 4. 开发者规范 +- **端口映射**:本地开发时后端默认使用 `8083`,而容器内固定为 `8000`。开发者需注意 `PORT` 环境变量在不同环境下的覆盖逻辑。 +- **依赖更新**:若修改了 `package.json`,必须同步更新 `pnpm-lock.yaml` 并重新上传后端相关文件,否则 Docker 构建可能失败或使用旧依赖。 +- **前端更新**:仅更新前端时,只需重新构建并同步 `dist` 目录,然后重启 `frontend` 容器即可,无需重建镜像。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/_index.yaml b/.qoder/repowiki/knowledge/zh/_index.yaml new file mode 100644 index 0000000..6a2035f --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/_index.yaml @@ -0,0 +1,129 @@ +# 知识卡导出索引文件 +schema_version: 1 +locale: zh-CN +branch: main +nodes_managed: true +exported_at: "2026-06-30T06:40:47Z" +modules: + "": + dir_name: 音频设备管理全栈平台 + title: 音频设备管理全栈平台 + scope: + - .gitignore + - README.md + - DEPLOY.md + - docker-compose.yml + - scripts/ + - .env + - .env.example + source_files: [] + children: + - backend + - frontend + depends_on: [] + related_to: [] + backend: + dir_name: 音频设备管理后端 API + title: 音频设备管理后端 API + scope: + - backend/ + source_files: [] + children: [] + depends_on: [] + related_to: + - path: frontend + build_system: + dir_name: Docker Compose 编排与 rsync 增量部署 + title: Docker Compose 编排与 rsync 增量部署 + scope: [] + source_files: + - docker-compose.yml + - backend/Dockerfile + - frontend/Dockerfile + - frontend/nginx.conf + - scripts/upload.sh + - DEPLOY.md + - backend/package.json + - frontend/package.json + children: [] + depends_on: [] + related_to: [] + configuration_system: + dir_name: 基于环境变量与 Docker Compose 的分层配置体系 + title: 基于环境变量与 Docker Compose 的分层配置体系 + scope: [] + source_files: + - .env.example + - backend/src/config/loadEnv.js + - backend/src/config/env.js + - backend/src/config/database.js + - backend/src/config/redis.js + - docker-compose.yml + - frontend/vite.config.js + children: [] + depends_on: [] + related_to: [] + dependency_management: + dir_name: 基于 pnpm 与 Docker 的前后端依赖管理 + title: 基于 pnpm 与 Docker 的前后端依赖管理 + scope: [] + source_files: + - backend/package.json + - frontend/package.json + - backend/pnpm-lock.yaml + - frontend/pnpm-lock.yaml + - backend/Dockerfile + - frontend/Dockerfile + - frontend/pnpm-workspace.yaml + children: [] + depends_on: [] + related_to: [] + error_handling: + dir_name: 全栈错误处理与响应规范 + title: 全栈错误处理与响应规范 + scope: [] + source_files: + - backend/src/utils/response.js + - backend/src/app.js + - backend/src/middleware/auth.js + - backend/src/routes/models.js + - backend/src/routes/auth.js + - frontend/src/utils/request.js + children: [] + depends_on: [] + related_to: [] + frontend: + dir_name: 音频设备管理后台前端 + title: 音频设备管理后台前端 + scope: + - frontend/ + source_files: [] + children: [] + depends_on: [] + related_to: + - path: backend + frontend_style: + dir_name: 深色玻璃拟态主题系统 (Lux Theme) + title: 深色玻璃拟态主题系统 (Lux Theme) + scope: [] + source_files: + - frontend/src/styles/lux-theme.css + - frontend/src/layout/index.vue + - frontend/src/main.js + - frontend/src/App.vue + - frontend/package.json + children: [] + depends_on: [] + related_to: [] + logging_system: + dir_name: 后端日志系统 (Winston) + title: 后端日志系统 (Winston) + scope: [] + source_files: + - backend/src/config/logger.js + - backend/src/app.js + - backend/src/routes/auth.js + - backend/src/config/database.js + children: [] + depends_on: [] + related_to: [] diff --git a/.qoder/repowiki/knowledge/zh/全栈错误处理与响应规范/_module.yaml b/.qoder/repowiki/knowledge/zh/全栈错误处理与响应规范/_module.yaml new file mode 100644 index 0000000..9e8e1f8 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/全栈错误处理与响应规范/_module.yaml @@ -0,0 +1,13 @@ +schema_version: 1 +module_path: error_handling +title: 全栈错误处理与响应规范 +scope: [] +source_files: + - backend/src/utils/response.js + - backend/src/app.js + - backend/src/middleware/auth.js + - backend/src/routes/models.js + - backend/src/routes/auth.js + - frontend/src/utils/request.js +depends_on: [] +related_to: [] diff --git a/.qoder/repowiki/knowledge/zh/全栈错误处理与响应规范/error_handling.md b/.qoder/repowiki/knowledge/zh/全栈错误处理与响应规范/error_handling.md new file mode 100644 index 0000000..c5bc9ab --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/全栈错误处理与响应规范/error_handling.md @@ -0,0 +1,38 @@ +### 1. 核心策略:统一响应结构与业务码 +该仓库采用**基于 HTTP 200 的业务状态码**模式,而非依赖 HTTP 协议层的状态码来区分业务逻辑的成功与失败。 + +- **后端 (Node.js/Express)**: + - 所有接口(除认证中间件外)均返回 `HTTP 200`。 + - 通过 `ApiResponse` 工具类封装响应体,包含 `code`、`msg` 和 `data` 字段。 + - **成功**:`code: 1`。 + - **失败**:`code: 0`(通用错误)或 `code: 2`(无数据)。 + - **异常捕获**:在路由层使用 `try...catch` 包裹异步逻辑,捕获异常后记录日志并返回 `ApiResponse.error()`。 + +- **前端 (Vue 3/Axios)**: + - 在 `request.js` 中配置响应拦截器。 + - 当检测到 `res.code === 0` 时,自动触发 `ElMessage.error` 提示用户,并将 Promise 标记为 `reject`。 + - 支持 `skipErrorToast` 配置项,允许特定请求(如进度轮询)静默处理错误。 + +### 2. 关键文件与实现细节 + +#### 后端:响应工具与中间件 +- **`backend/src/utils/response.js`**:定义了全局统一的响应格式。`ApiResponse.success`、`ApiResponse.error` 和 `ApiResponse.noData` 是后端返回数据的唯一出口。 +- **`backend/src/middleware/auth.js`**:**例外情况**。认证中间件直接操作 `res.status(401)` 或 `res.status(403)`。这是为了在前端拦截器中能准确识别身份失效并执行重定向逻辑。 +- **`backend/src/routes/*.js`**:各业务路由文件(如 `models.js`, `auth.js`)遵循“捕获即返回”原则。例如在 `models.js` 中,数据库查询或 S3 上传失败均被捕获并转换为友好的中文错误提示。 + +#### 前端:拦截器与权限联动 +- **`frontend/src/utils/request.js`**: + - **401 处理**:自动清除本地 Token (`clearAuth`) 并重定向至登录页。 + - **403 处理**:弹出“无权限”警告。 + - **网络错误**:捕获非业务逻辑的网络层异常(如超时、断网),统一提示“网络错误”。 + +### 3. 架构约定与开发规则 +1. **禁止直接抛出未捕获异常**:后端路由处理器必须包含 `try...catch` 块,确保任何内部错误(DB、S3、Meilisearch)都不会导致进程崩溃或返回原始堆栈信息。 + +2. **敏感信息脱敏**:在 `catch` 块中返回给前端的 `msg` 应为通用提示(如“error”或“登录失败”),具体错误详情仅通过 `logger.error` 记录在服务器日志中。 + +3. **前端错误消费**: + - 默认情况下,前端无需在每个 API 调用处编写 `catch` 逻辑来处理 UI 提示,拦截器已自动完成。 + - 若需自定义错误处理(如表单校验反馈),应在 API 调用处捕获 `Promise.reject` 并阻止默认弹窗。 + +4. **认证优先原则**:涉及权限的接口,先由中间件进行 Token 校验。若校验失败,直接中断请求链路并返回标准 HTTP 401/403,不进入业务逻辑层的 `try...catch`。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/后端日志系统 (Winston)/_module.yaml b/.qoder/repowiki/knowledge/zh/后端日志系统 (Winston)/_module.yaml new file mode 100644 index 0000000..d35b70e --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/后端日志系统 (Winston)/_module.yaml @@ -0,0 +1,11 @@ +schema_version: 1 +module_path: logging_system +title: 后端日志系统 (Winston) +scope: [] +source_files: + - backend/src/config/logger.js + - backend/src/app.js + - backend/src/routes/auth.js + - backend/src/config/database.js +depends_on: [] +related_to: [] diff --git a/.qoder/repowiki/knowledge/zh/后端日志系统 (Winston)/logging_system.md b/.qoder/repowiki/knowledge/zh/后端日志系统 (Winston)/logging_system.md new file mode 100644 index 0000000..7520e8e --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/后端日志系统 (Winston)/logging_system.md @@ -0,0 +1,26 @@ +## 1. 核心框架与配置 +- **框架**: 使用 `winston` 作为后端 Node.js 应用的统一日志框架。 +- **配置文件**: `backend/src/config/logger.js` 负责初始化 logger 实例。 +- **日志级别**: 默认设置为 `info`,涵盖 info, warn, error 等级别。 +- **输出格式**: + - 采用自定义的文本格式:`${timestamp} - ${level} - ${message} ${JSON.stringify(meta)}`。 + - 时间戳格式为 `YYYY-MM-DD HH:mm:ss`。 + - 额外元数据(meta)会被序列化为 JSON 字符串附加在消息后。 + +## 2. 日志输出目标 (Transports) +- **控制台 (Console)**: 所有级别的日志都会输出到标准输出,便于本地开发和容器日志采集。 +- **文件 (File)**: 所有日志同时写入 `backend/logs/app.log` 文件。 + - 目录 `logs/` 若不存在会在初始化时自动创建。 + - 目前未配置日志轮转(Log Rotation),长期运行需注意文件大小。 + +## 3. 使用规范与模式 +- **引入方式**: 在各业务模块中通过 `require('../config/logger')` 获取单例 logger。 +- **记录模式**: + - **信息类**: `logger.info('描述性消息')`,如服务启动、用户登录成功、数据库同步完成。 + - **警告类**: `logger.warn('异常但可恢复的情况')`,如登录失败、资源未找到。 + - **错误类**: `logger.error('错误详情')`,通常在 catch 块中记录异常信息 `e.message`。 +- **上下文记录**: 建议在 message 中包含关键业务 ID 或参数,例如 `User ${username} logged in` 或 `id=${brandId}`。 + +## 4. 特殊场景处理 +- **数据库日志**: 在 `backend/src/config/database.js` 中,Sequelize 的 SQL 日志仅在开发环境 (`APP_ENV === 'development'`) 下通过 `console.log` 输出,生产环境关闭以避免性能损耗和日志污染。 +- **前端日志**: 前端项目 (`frontend/`) 目前未发现统一的日志封装,主要依赖浏览器控制台默认的 `console` 输出。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/基于 pnpm 与 Docker 的前后端依赖管理/_module.yaml b/.qoder/repowiki/knowledge/zh/基于 pnpm 与 Docker 的前后端依赖管理/_module.yaml new file mode 100644 index 0000000..806383e --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/基于 pnpm 与 Docker 的前后端依赖管理/_module.yaml @@ -0,0 +1,14 @@ +schema_version: 1 +module_path: dependency_management +title: 基于 pnpm 与 Docker 的前后端依赖管理 +scope: [] +source_files: + - backend/package.json + - frontend/package.json + - backend/pnpm-lock.yaml + - frontend/pnpm-lock.yaml + - backend/Dockerfile + - frontend/Dockerfile + - frontend/pnpm-workspace.yaml +depends_on: [] +related_to: [] diff --git a/.qoder/repowiki/knowledge/zh/基于 pnpm 与 Docker 的前后端依赖管理/dependency_management.md b/.qoder/repowiki/knowledge/zh/基于 pnpm 与 Docker 的前后端依赖管理/dependency_management.md new file mode 100644 index 0000000..a395d66 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/基于 pnpm 与 Docker 的前后端依赖管理/dependency_management.md @@ -0,0 +1,27 @@ +## 1. 核心系统与工具 +该项目采用 **pnpm** 作为前后端统一的 JavaScript/TypeScript 包管理器,并通过 **Docker Compose** 进行容器化编排。项目明确指定了 `packageManager` 字段(`pnpm@11.5.2`),利用 Corepack 机制确保开发环境与生产环境使用完全一致的包管理版本。 + +- **包管理器**: pnpm (v11.5.2) +- **锁定文件**: `pnpm-lock.yaml` +- **运行时**: Node.js (Backend: v22-alpine, Frontend Builder: v18-alpine) +- **部署编排**: Docker Compose + +## 2. 关键文件与配置 +- **`backend/package.json` / `frontend/package.json`**: 分别定义了后端 API 和前端 Vue 应用的依赖清单。后端依赖包括 `express`, `sequelize`, `mysql2`, `ioredis` 等;前端依赖包括 `vue`, `element-plus`, `axios` 等。 +- **`pnpm-lock.yaml`**: 存在于 `backend/` 和 `frontend/` 目录下,用于精确锁定依赖树,确保构建的可重复性。 +- **`frontend/pnpm-workspace.yaml`**: 虽然目前仅包含 `allowBuilds` 配置,但表明前端目录具备向 pnpm Workspace 演进的潜力或已预留相关配置入口。 +- **`Dockerfile`**: + - 后端:通过 `corepack enable pnpm` 启用 pnpm,并使用 `--frozen-lockfile` 参数安装生产依赖。 + - 前端:采用多阶段构建,在 `builder` 阶段安装依赖并打包,最终产物由 `nginx:alpine` 托管。 + +## 3. 架构与约定 +- **依赖隔离**: 前后端拥有独立的 `node_modules` 和锁定文件,互不干扰。 +- **生产环境优化**: + - 后端 Docker 镜像仅安装 `dependencies` (`--prod`),排除 `devDependencies`(如 `nodemon`),减小镜像体积。 + - 前端通过多阶段构建,最终镜像不包含 `node_modules` 或构建工具,仅保留静态资源。 +- **版本一致性**: 通过在 `package.json` 中声明 `packageManager` 字段,配合 CI/CD 或本地开发时的 Corepack 支持,强制统一工具链版本。 + +## 4. 开发者规范 +- **安装依赖**: 必须使用 `pnpm install`,禁止使用 `npm install` 或 `yarn`,以避免锁定文件冲突。 +- **更新依赖**: 修改 `package.json` 后,需重新运行 `pnpm install` 并同步提交更新后的 `pnpm-lock.yaml`。 +- **容器化构建**: 生产环境部署应优先使用 `docker-compose up --build`,确保依赖安装过程遵循 Dockerfile 中定义的 `--frozen-lockfile` 约束,防止意外引入未锁定的新版本。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/基于环境变量与 Docker Compose 的分层配置体系/_module.yaml b/.qoder/repowiki/knowledge/zh/基于环境变量与 Docker Compose 的分层配置体系/_module.yaml new file mode 100644 index 0000000..b2bd245 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/基于环境变量与 Docker Compose 的分层配置体系/_module.yaml @@ -0,0 +1,14 @@ +schema_version: 1 +module_path: configuration_system +title: 基于环境变量与 Docker Compose 的分层配置体系 +scope: [] +source_files: + - .env.example + - backend/src/config/loadEnv.js + - backend/src/config/env.js + - backend/src/config/database.js + - backend/src/config/redis.js + - docker-compose.yml + - frontend/vite.config.js +depends_on: [] +related_to: [] diff --git a/.qoder/repowiki/knowledge/zh/基于环境变量与 Docker Compose 的分层配置体系/configuration_system.md b/.qoder/repowiki/knowledge/zh/基于环境变量与 Docker Compose 的分层配置体系/configuration_system.md new file mode 100644 index 0000000..82d0a89 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/基于环境变量与 Docker Compose 的分层配置体系/configuration_system.md @@ -0,0 +1,48 @@ +## 1. 核心系统与工具 +该项目采用 **环境变量(Environment Variables)** 作为唯一的配置来源,结合 **`dotenv`** 库进行本地开发时的文件加载,并通过 **Docker Compose** 在部署时注入环境变量。这种模式遵循了 [12-Factor App](https://12factor.net/zh-cn/config) 的配置原则,实现了配置与代码的分离。 + +- **后端 (Node.js/Express)**: 使用 `dotenv` 加载根目录 `.env` 文件。 +- **前端 (Vue 3/Vite)**: 依赖 Vite 的默认行为,通过 `vite.config.js` 中的代理配置处理开发环境 API 路由,生产环境配置通常由构建产物或 Nginx 静态配置决定。 +- **编排工具**: 使用 `docker-compose.yml` 统一管理多服务的环境变量注入和端口映射。 + +## 2. 关键文件与职责 + +| 文件路径 | 职责描述 | +| :--- | :--- | +| `/.env` & `/.env.example` | **全局配置模板**。定义了数据库、Redis、S3、JWT 密钥等所有服务的运行时参数。 | +| `/backend/src/config/loadEnv.js` | **环境加载入口**。在后端应用启动初期,自动检测并加载项目根目录的 `.env` 文件。 | +| `/backend/src/config/env.js` | **环境状态管理**。统一导出 `APP_ENV`、`isDevelopment`、`isProduction` 标志,供其他模块判断运行模式。 | +| `/backend/src/config/database.js` | **数据库配置**。从环境变量读取 MySQL 连接信息,并根据环境标志决定是否开启 SQL 日志。 | +| `/backend/src/config/redis.js` | **缓存配置**。从环境变量读取 Redis 连接信息,实现单例模式的客户端初始化。 | +| `/docker-compose.yml` | **部署配置**。通过 `env_file` 将 `.env` 注入后端容器,并强制覆盖部分变量(如容器内端口)。 | +| `/frontend/vite.config.js` | **前端开发配置**。定义了开发服务器的端口及指向后端的 API 代理规则。 | + +## 3. 架构设计与分层逻辑 + +### 3.1 配置加载流程 +1. **初始化阶段**: `backend/src/app.js` 第一行即调用 `require('./config/loadEnv')`,确保后续所有模块能访问到 `process.env`。 +2. **本地开发**: `loadEnv.js` 检查根目录是否存在 `.env`,若存在则通过 `dotenv.config()` 将其载入内存。 +3. **容器部署**: Docker Compose 通过 `env_file: - .env` 将变量注入容器。此时容器内可能不存在 `.env` 文件,但环境变量已由 Docker 守护进程提供。 + +### 3.2 环境隔离策略 +- **逻辑环境**: 通过 `APP_ENV` 变量区分 `development` 和 `production`。该变量控制日志输出级别、数据库同步行为等。 +- **物理环境**: + - **本地**: 后端监听 `8083` 端口,前端通过 Vite Proxy 转发请求。 + - **Docker**: 后端在容器内监听 `8000` 端口(由 Compose 强制指定),外部映射为 `8083`;前端由 Nginx 托管,映射为 `8082`。 + +### 3.3 敏感信息管理 +- **示例文件**: 提供 `.env.example` 作为模板,避免敏感信息(如 `JWT_SECRET`, `AWS_ACCESS_KEY_ID`)直接提交到版本控制系统。 +- **默认值保护**: 在 `database.js` 和 `redis.js` 中为关键配置提供了硬编码的默认值(如 `root123`),防止因环境变量缺失导致应用崩溃,但在生产环境中应始终通过 `.env` 覆盖这些默认值。 + +## 4. 开发者规范 + +1. **新增配置项**: + - 必须在 `.env.example` 中添加对应的键名和说明。 + - 在 `backend/src/config/` 下创建或更新对应的配置模块,通过 `process.env.VAR_NAME` 获取值。 +2. **环境判断**: + - 严禁在业务代码中直接读取 `process.env.APP_ENV`。 + - 必须使用 `src/config/env.js` 导出的 `isDevelopment` 或 `isProduction` 布尔值,以保持逻辑一致性。 +3. **端口一致性**: + - 修改后端端口时,需同步更新 `.env` 中的 `PORT`、`docker-compose.yml` 中的 `environment` 覆盖项以及 `ports` 映射。 +4. **前端代理**: + - 若后端开发端口变更,需同步修改 `frontend/vite.config.js` 中的 `proxy.target`。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/深色玻璃拟态主题系统 (Lux Theme)/_module.yaml b/.qoder/repowiki/knowledge/zh/深色玻璃拟态主题系统 (Lux Theme)/_module.yaml new file mode 100644 index 0000000..41d3c3c --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/深色玻璃拟态主题系统 (Lux Theme)/_module.yaml @@ -0,0 +1,12 @@ +schema_version: 1 +module_path: frontend_style +title: 深色玻璃拟态主题系统 (Lux Theme) +scope: [] +source_files: + - frontend/src/styles/lux-theme.css + - frontend/src/layout/index.vue + - frontend/src/main.js + - frontend/src/App.vue + - frontend/package.json +depends_on: [] +related_to: [] diff --git a/.qoder/repowiki/knowledge/zh/深色玻璃拟态主题系统 (Lux Theme)/frontend_style.md b/.qoder/repowiki/knowledge/zh/深色玻璃拟态主题系统 (Lux Theme)/frontend_style.md new file mode 100644 index 0000000..60c99ac --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/深色玻璃拟态主题系统 (Lux Theme)/frontend_style.md @@ -0,0 +1,35 @@ +## 1. 核心系统与工具 +- **UI 框架**: Vue 3 + Element Plus。 +- **样式方案**: 原生 CSS + CSS Variables (CSS Custom Properties)。 +- **构建工具**: Vite。 +- **主题策略**: 基于 Element Plus 的 Dark Mode 基础,通过全局自定义 CSS (`lux-theme.css`) 进行深度覆盖和扩展,实现名为 "Lux" 的深色玻璃拟态(Glassmorphism)风格。 + +## 2. 关键文件与结构 +- **`frontend/src/styles/lux-theme.css`**: 核心主题文件。定义了全站的设计令牌(Design Tokens)、背景动效、组件覆盖样式。 +- **`frontend/src/layout/index.vue`**: 布局容器。应用 `.lux-shell` 类名,承载侧边栏、顶栏和主内容区,并包含背景光球(Orbs)的 DOM 结构。 +- **`frontend/src/main.js`**: 入口文件。按顺序引入 Element Plus 基础样式、Dark Mode 变量以及自定义的 `lux-theme.css`。 +- **`frontend/src/App.vue`**: 根组件。设置全局字体栈(Inter, PingFang SC, Microsoft YaHei)及抗锯齿渲染。 + +## 3. 架构与设计规范 +### 3.1 设计令牌 (Design Tokens) +在 `:root` 中定义了一套语义化的 CSS 变量,用于保持视觉一致性: +- **背景色**: `--lux-page-bg: #0a0e14` (深空黑), `--lux-card-bg: #1e293b` (深蓝灰)。 +- **主色调**: `--lux-cyan: #38bdf8` (青色), `--lux-indigo: #6366f1` (靛蓝), `--lux-violet: #7c3aed` (紫罗兰)。 +- **文本色**: `--lux-text-strong: #e2e8f0` (高亮文本), `--lux-text-muted: #94a3b8` (次要文本)。 +- **玻璃效果**: `--lux-glass-sidebar: rgba(15, 23, 42, 0.6)`,配合 `backdrop-filter: blur(18px)` 实现毛玻璃质感。 + +### 3.2 视觉风格:深色宇宙与玻璃拟态 +- **背景动效**: 使用 `.lux-shell-bg` 容器包裹三个绝对定位的 `.lux-orb` (光球),通过高斯模糊 (`blur(80px)`) 和低透明度营造深邃的宇宙氛围。 +- **卡片与容器**: 所有 `.el-card` 被强制设置为深色背景、圆角 (`16px`) 和微弱的边框光晕,以在深色背景上凸显层级。 +- **交互反馈**: 按钮和菜单项在 Hover 状态下使用半透明的白色或青色渐变背景,激活状态则带有内阴影 (`box-shadow inset`) 以增强立体感。 + +### 3.3 布局约定 +- **Shell 模式**: 整个应用包裹在 `.lux-shell` 中,采用 `min-height: 100vh` 和 `overflow: hidden` 确保全屏沉浸式体验。 +- **侧边栏**: 采用玻璃拟态设计,支持折叠(64px)与展开(220px)动画过渡。折叠时显示图标导航栏(Rail),展开时显示完整菜单。 +- **顶栏**: 悬浮的玻璃态条状区域,包含面包屑和用户操作下拉菜单。 + +## 4. 开发者指南 +- **类名约束**: 所有自定义样式应尽量限制在 `.lux-shell` 作用域下,避免污染全局或影响第三方组件的默认行为。 +- **组件覆盖**: 修改 Element Plus 组件样式时,优先使用 CSS 变量覆盖。若需强制覆盖,请使用 `.lux-shell .el-component` 的选择器优先级策略,并尽量保持 `!important` 的最小化使用(目前主题文件中存在部分 `!important` 以对抗组件库默认样式)。 +- **颜色使用**: 严禁硬编码颜色值。新增样式时应引用 `lux-theme.css` 中定义的 `--lux-*` 变量,以确保主题的统一性和后续的可维护性。 +- **响应式**: 目前布局主要面向桌面端管理后台,侧边栏采用固定宽度逻辑。若需适配移动端,需在 `.lux-shell` 媒体查询中增加侧边栏抽屉式交互的支持。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/_module.yaml b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/_module.yaml new file mode 100644 index 0000000..f126d7d --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/_module.yaml @@ -0,0 +1,14 @@ +schema_version: 1 +module_path: "" +title: 音频设备管理全栈平台 +scope: + - .gitignore + - README.md + - DEPLOY.md + - docker-compose.yml + - scripts/ + - .env + - .env.example +source_files: [] +depends_on: [] +related_to: [] diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/架构设计.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/架构设计.md new file mode 100644 index 0000000..f82e612 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/架构设计.md @@ -0,0 +1,4 @@ +- **服务编排**:使用 `docker-compose.yml` 定义 `backend` (Node.js) 和 `frontend` (Nginx) 服务,通过 `audio-network` 桥接网络实现内部通信。 +- **配置管理**:根目录 `.env` 作为唯一环境变量源,由 Compose 注入后端容器,前端通过 Nginx 反向代理 `/api` 至后端。 +- **部署流水线**:`scripts/upload.sh` 脚本基于 rsync/ssh 实现增量代码同步,配合 `DEPLOY.md` 规范了从本地构建到服务器重启的标准化运维路径。 +- **存储映射**:宿主机目录 `/data/projects/source` 挂载至后端容器,用于持久化存储 OTA 升级包。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/概述.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/概述.md new file mode 100644 index 0000000..5f85026 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/概述.md @@ -0,0 +1 @@ +通过 Docker Compose 统一编排前后端服务,提供标准化的本地构建、远程同步及容器化部署流程。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/特殊配置与命令.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/特殊配置与命令.md new file mode 100644 index 0000000..017db93 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/特殊配置与命令.md @@ -0,0 +1,2 @@ +- **一键同步**:执行 `./scripts/upload.sh all` 将前端产物、后端源码及编排文件同步至远程服务器。 +- **服务启动**:在服务器端执行 `docker compose build --no-cache backend && docker compose up -d` 完成全量更新与启动。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/编码规范.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/编码规范.md new file mode 100644 index 0000000..3d4ca4e --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/编码规范.md @@ -0,0 +1,2 @@ +- 所有服务共享根目录 `.env` 进行环境配置,禁止在各子模块中维护独立的环境变量文件。 +- 前端静态资源通过 Nginx 托管并代理 API 请求,后端统一暴露于 8000 端口(容器内)并通过 Compose 映射至宿主机 8083。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/_module.yaml b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/_module.yaml new file mode 100644 index 0000000..b97a7ef --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/_module.yaml @@ -0,0 +1,9 @@ +schema_version: 1 +module_path: frontend +title: 音频设备管理后台前端 +scope: + - frontend/ +source_files: [] +depends_on: [] +related_to: + - path: backend diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/技术栈.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/技术栈.md new file mode 100644 index 0000000..a79c124 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/技术栈.md @@ -0,0 +1 @@ +Vue 3, Vite, Element Plus, Axios, Vue Router \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/架构设计.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/架构设计.md new file mode 100644 index 0000000..600c36d --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/架构设计.md @@ -0,0 +1,4 @@ +- **技术栈**: 采用 Vue 3 (Composition API) + Vite 构建,UI 框架为 Element Plus,路由使用 vue-router。 +- **目录结构**: 遵循经典的前端分层架构:`src/api` 封装 Axios 请求与业务接口;`src/views` 存放页面级组件;`src/components` 存放通用 UI 组件;`src/layout` 定义整体布局(侧边栏、顶部导航);`src/utils` 提供认证、HTTP 拦截器等工具函数。 +- **核心机制**: `src/utils/request.js` 实现了统一的 HTTP 拦截器,处理 JWT Token 注入、401/403 错误自动跳转登录及全局错误提示。`src/router/index.js` 配置了基于角色的路由守卫,支持超级管理员权限控制。 +- **状态管理**: 未引入 Pinia/Vuex,认证状态(Token、用户信息)通过 `localStorage` 配合 `src/utils/auth.js` 中的工具函数进行持久化与管理。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/概述.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/概述.md new file mode 100644 index 0000000..f092dc4 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/概述.md @@ -0,0 +1 @@ +基于 Vue 3 和 Element Plus 构建的耳机品牌、型号及 OTA 升级管理的单页应用。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/编码规范.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/编码规范.md new file mode 100644 index 0000000..73d8f8b --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后台前端/编码规范.md @@ -0,0 +1,3 @@ +- API 模块按业务领域拆分(如 auth.js, brand.js),统一导出异步方法并依赖 @/utils/request 实例。 +- 视图组件采用路径映射命名规范,每个业务模块在 views 下拥有独立文件夹及 index.vue 入口文件。 +- 认证逻辑集中在 utils/auth.js,提供 getToken, isSuperAdmin, clearAuth 等原子操作供路由守卫和组件调用。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/_module.yaml b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/_module.yaml new file mode 100644 index 0000000..e26db3b --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/_module.yaml @@ -0,0 +1,9 @@ +schema_version: 1 +module_path: backend +title: 音频设备管理后端 API +scope: + - backend/ +source_files: [] +depends_on: [] +related_to: + - path: frontend diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/技术栈.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/技术栈.md new file mode 100644 index 0000000..fe402c7 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/技术栈.md @@ -0,0 +1,5 @@ +- **运行时与框架**:Node.js 22 (Alpine), Express.js v4。 +- **数据持久化**:MySQL (via `mysql2` and `sequelize` ORM)。 +- **缓存与搜索**:Redis (via `ioredis` for EQ cache), Meilisearch (via `axios` for model search)。 +- **文件存储**:AWS S3 (via `@aws-sdk/client-s3` for OTA packages and measurement files)。 +- **工具库**:`jsonwebtoken` (JWT), `zod` (Schema 验证), `multer` (文件上传), `winston` (日志)。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/架构设计.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/架构设计.md new file mode 100644 index 0000000..96211df --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/架构设计.md @@ -0,0 +1,5 @@ +- **分层架构**:采用经典的 MVC 模式,`routes/` 处理 HTTP 请求与响应,`models/` (Sequelize) 定义数据模型,`services/` 封装外部存储(S3, Redis)和业务逻辑。 +- **入口与初始化**:`src/app.js` 为应用入口,负责加载环境变量、同步数据库表结构 (`sequelize.sync()`) 并引导创建超级管理员 (`userBootstrap`)。 +- **路由组织**:`src/routes/index.js` 汇总所有业务路由(auth, brands, models, ota 等),通过 Express 中间件机制挂载。 +- **认证机制**:`middleware/auth.js` 实现基于 JWT 的身份验证,支持普通用户登录与超级管理员权限校验 (`requireSuperAdmin`)。 +- **外部集成**:通过 `services/` 目录下的模块与 AWS S3 (文件存储)、Redis (EQ 缓存)、Meilisearch (搜索索引) 及远程曲线服务进行交互。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/概述.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/概述.md new file mode 100644 index 0000000..e274216 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/概述.md @@ -0,0 +1 @@ +提供耳机品牌、型号、OTA 升级及用户管理的 RESTful API,集成 MySQL、Redis、S3 和 Meilisearch。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/特殊配置与命令.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/特殊配置与命令.md new file mode 100644 index 0000000..2f51e97 --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/特殊配置与命令.md @@ -0,0 +1,3 @@ +- **依赖管理**:使用 `pnpm` 作为包管理器 (`packageManager: pnpm@11.5.2`),安装命令为 `pnpm install --frozen-lockfile`。 +- **启动脚本**:提供 `start.sh`, `stop.sh`, `restart.sh` 用于进程管理;Docker 镜像基于 `node:22-alpine` 构建。 +- **环境引导**:首次启动时会自动执行 `ensureBootstrapSuperAdmin`,若数据库无用户则根据环境变量 `DASHBOARD_ADMIN_USERNAME/PASSWORD` 创建初始超级管理员。 \ No newline at end of file diff --git a/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/编码规范.md b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/编码规范.md new file mode 100644 index 0000000..0e242ba --- /dev/null +++ b/.qoder/repowiki/knowledge/zh/音频设备管理全栈平台/音频设备管理后端 API/编码规范.md @@ -0,0 +1,4 @@ +- 统一响应格式:所有 API 均通过 `utils/response.js` 中的 `ApiResponse` 对象返回标准化 JSON,包含 `code` (1:成功, 0:错误, 2:无数据), `msg` 和 `data` 字段。 +- 集中式日志记录:使用 `winston` 配置的 `logger` 记录关键业务操作(如登录、创建/更新/删除资源)及错误信息,日志输出至 `logs/app.log`。 +- 路由级认证保护:受保护的路由组(如 brands, models, ota)在路由文件顶部通过 `router.use(authMiddleware)` 全局启用 JWT 验证,仅公开接口(如 `/health`, `/api/ota/latest/check`)例外。 +- 参数空值处理:在更新操作中,显式检查请求体字段是否为 `undefined` 或 `'null'` 字符串,以区分“未提供”与“设为空”,避免意外覆盖现有数据。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/业务组件/业务组件.md b/.qoder/repowiki/zh/content/前端组件/业务组件/业务组件.md new file mode 100644 index 0000000..d35b232 --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/业务组件/业务组件.md @@ -0,0 +1,344 @@ +# 业务组件 + + +**本文引用的文件列表** +- [SidebarLogo.vue](file://frontend/src/components/SidebarLogo.vue) +- [TabsView.vue](file://frontend/src/components/TabsView.vue) +- [ChangePasswordDialog.vue](file://frontend/src/components/ChangePasswordDialog.vue) +- [index.vue](file://frontend/src/layout/index.vue) +- [tabs.js](file://frontend/src/utils/tabs.js) +- [auth.js](file://frontend/src/utils/auth.js) +- [index.js](file://frontend/src/router/index.js) +- [lux-theme.css](file://frontend/src/styles/lux-theme.css) +- [auth.js](file://frontend/src/api/auth.js) +- [index.vue](file://frontend/src/views/home/index.vue) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [组件详解](#组件详解) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件为业务组件的综合技术文档,聚焦于以下三个通用业务组件: +- 侧边栏Logo组件:负责品牌展示与侧边栏折叠态下的视觉呈现。 +- 标签页视图组件:提供页面级标签页导航、上下文菜单、持久化与缓存策略。 +- 密码修改对话框:提供安全的密码变更流程,含表单校验与后端交互。 + +文档将从设计理念、实现细节、接口定义、事件与插槽、样式定制、使用示例与最佳实践、组件协作与状态管理、可访问性与性能优化等方面进行系统阐述,并辅以可视化图表帮助理解。 + +## 项目结构 +该前端工程采用 Vue 3 + Element Plus 架构,组件位于 frontend/src/components,布局与路由位于 layout 与 router 目录,主题样式集中于 styles,工具函数与 API 封装分别在 utils 与 api。 + +```mermaid +graph TB +subgraph "布局层" +L["layout/index.vue"] +end +subgraph "组件层" +SL["components/SidebarLogo.vue"] +TV["components/TabsView.vue"] +CPD["components/ChangePasswordDialog.vue"] +end +subgraph "工具与配置" +RT["router/index.js"] +TABS["utils/tabs.js"] +AUTH["utils/auth.js"] +THEME["styles/lux-theme.css"] +end +subgraph "视图层" +HOME["views/home/index.vue"] +end +subgraph "API" +API_AUTH["api/auth.js"] +end +L --> SL +L --> TV +L --> CPD +L --> RT +TV --> TABS +L --> AUTH +L --> THEME +CPD --> API_AUTH +RT --> HOME +``` + +图表来源 +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [SidebarLogo.vue:1-135](file://frontend/src/components/SidebarLogo.vue#L1-L135) +- [TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) +- [auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) + +章节来源 +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 核心组件 +- 侧边栏Logo组件:通过 props 控制折叠态,渲染品牌标识与品牌名/标签,支持折叠时隐藏文字,保持视觉简洁。 +- 标签页视图组件:基于 Element Plus Tabs 实现,自动根据路由生成标签、支持右键上下文菜单、持久化到 sessionStorage、结合 KeepAlive 缓存页面。 +- 密码修改对话框:基于 Element Plus Dialog/Form,内置表单规则与加载态,调用后端接口完成密码变更。 + +章节来源 +- [SidebarLogo.vue:52-59](file://frontend/src/components/SidebarLogo.vue#L52-L59) +- [TabsView.vue:55-287](file://frontend/src/components/TabsView.vue#L55-L287) +- [ChangePasswordDialog.vue:51-127](file://frontend/src/components/ChangePasswordDialog.vue#L51-L127) + +## 架构总览 +组件间协作关系如下: +- 布局容器负责组织侧边栏、头部、主内容区与底部;在头部触发“修改密码”动作,打开密码修改对话框。 +- 标签页视图组件监听路由变化,动态增删标签并持久化;通过 KeepAlive 缓存页面,提升切换体验。 +- 侧边栏Logo组件接收折叠状态,影响品牌展示形态。 +- 密码修改对话框通过 API 层发起请求,成功后提示并关闭对话框。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant L as "布局容器" +participant H as "头部下拉菜单" +participant D as "密码修改对话框" +participant API as "认证API" +participant S as "会话存储" +U->>H : 点击“修改密码” +H->>L : 触发命令 +L->>D : 打开对话框(v-model) +U->>D : 输入旧/新/确认密码 +D->>D : 表单校验 +D->>API : 提交修改密码 +API-->>D : 返回结果 +D-->>U : 成功消息 +D->>L : 关闭对话框(v-model) +L->>S : 可选:清理相关状态 +``` + +图表来源 +- [index.vue:95-141](file://frontend/src/layout/index.vue#L95-L141) +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) +- [auth.js:14-23](file://frontend/src/api/auth.js#L14-L23) + +## 组件详解 + +### 侧边栏Logo组件(SidebarLogo) +- 设计理念 + - 在折叠态下仅保留品牌标识,非折叠态显示品牌名与标签,保证信息密度与可读性的平衡。 + - 使用 SVG 渐变与阴影增强品牌识别度,配合主题变量实现深色风格适配。 +- Props 接口 + - collapsed: Boolean,默认 false,控制是否处于折叠态。 +- 插槽与事件 + - 无插槽;无自定义事件。 +- 样式定制 + - 支持通过主题变量与容器类名调整尺寸、间距与颜色。 +- 使用示例 + - 在布局侧栏中直接使用,传入 isSidebarCollapsed 的响应式布尔值。 +- 最佳实践 + - 折叠态时隐藏文字,避免溢出;保持 SVG 图标尺寸与容器一致。 +- 可访问性 + - 品牌标识区域设置 aria-hidden;标题通过外部语义元素提供。 + +```mermaid +classDiagram +class SidebarLogo { ++Boolean collapsed +} +``` + +图表来源 +- [SidebarLogo.vue:52-59](file://frontend/src/components/SidebarLogo.vue#L52-L59) + +章节来源 +- [SidebarLogo.vue:1-135](file://frontend/src/components/SidebarLogo.vue#L1-L135) +- [lux-theme.css:100-148](file://frontend/src/styles/lux-theme.css#L100-L148) + +### 标签页视图组件(TabsView) +- 设计理念 + - 自动同步路由生成标签,支持点击切换、右键上下文菜单(关闭、关闭其他、关闭全部)、持久化与缓存。 + - 通过 KeepAlive 缓存页面实例,减少重复渲染与网络请求。 +- Props 接口 + - 无显式 props。 +- 事件与插槽 + - 无自定义事件;使用默认插槽渲染标签标题。 +- 数据模型与逻辑 + - 内部维护 tabs 数组与 activeKey,normalizeTabFromRoute 从路由元信息生成标签项。 + - 持久化键值:TABS_STORAGE_KEY;默认首页路径:HOME_PATH。 + - 上下文菜单命令处理:关闭、关闭其他、关闭全部。 +- 性能特性 + - 使用 computed 计算 keepAliveInclude,避免重复缓存同名组件。 + - watch 监听路由与 tabs/activeKey 变化,按需持久化。 +- 使用示例 + - 在布局主内容区直接引入 TabsView,即可获得完整的多标签页导航体验。 +- 最佳实践 + - 路由 meta.title 与 meta.icon 用于标签标题与图标;避免将根布局路由加入标签。 +- 可访问性 + - 标签项具备可点击与可关闭语义;上下文菜单提供键盘可达性。 + +```mermaid +flowchart TD +Start(["挂载"]) --> Restore["恢复标签与激活项"] +Restore --> Upsert["根据当前路由更新标签"] +Upsert --> WatchRoute["监听路由变化"] +WatchRoute --> Persist["持久化标签状态"] +Persist --> End(["运行中"]) +``` + +图表来源 +- [TabsView.vue:270-286](file://frontend/src/components/TabsView.vue#L270-L286) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) + +章节来源 +- [TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) + +### 密码修改对话框(ChangePasswordDialog) +- 设计理念 + - 安全优先:表单字段类型为 password,开启 show-password;提交前严格校验;加载态防止重复提交。 + - 用户友好:错误提示明确,成功后自动关闭并提示。 +- Props 接口 + - modelValue: Boolean,默认 false,双向绑定控制对话框显示/隐藏。 +- 事件 + - update:modelValue:用于父组件同步 visible 状态。 +- 插槽 + - 无插槽。 +- 样式定制 + - 基于 Element Plus 对话框样式,可借助主题变量统一风格。 +- 使用示例 + - 在布局头部下拉菜单中触发,通过 v-model 控制显示。 +- 最佳实践 + - 提交前先 validate;捕获异常并重置 loading;成功后清空表单。 +- 可访问性 + - 表单项具备 label 与占位提示;按钮具备可读性文本。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant L as "布局容器" +participant D as "密码修改对话框" +participant F as "表单校验" +participant API as "认证API" +U->>L : 点击“修改密码” +L->>D : v-model=true +U->>D : 输入旧/新/确认密码 +D->>F : validate() +F-->>D : 校验通过 +D->>API : changePassword(old,new) +API-->>D : 返回结果 +D-->>U : 显示成功消息 +D->>L : v-model=false +``` + +图表来源 +- [index.vue:118-123](file://frontend/src/layout/index.vue#L118-L123) +- [ChangePasswordDialog.vue:51-127](file://frontend/src/components/ChangePasswordDialog.vue#L51-L127) +- [auth.js:14-23](file://frontend/src/api/auth.js#L14-L23) + +章节来源 +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) +- [auth.js:14-23](file://frontend/src/api/auth.js#L14-L23) + +## 依赖关系分析 +- 组件耦合 + - TabsView 依赖路由与工具常量(TABS_STORAGE_KEY、HOME_PATH),并与 KeepAlive 协作实现缓存。 + - Layout 同时依赖 TabsView、SidebarLogo、ChangePasswordDialog,形成页面骨架与交互闭环。 + - ChangePasswordDialog 依赖 API 层与 Element Plus 组件。 +- 外部依赖 + - Vue 3、Vue Router、Element Plus、@element-plus/icons-vue。 +- 潜在循环依赖 + - 未发现组件间循环依赖;布局与组件分层清晰。 + +```mermaid +graph LR +TV["TabsView.vue"] --> RT["router/index.js"] +TV --> TABS["utils/tabs.js"] +L["layout/index.vue"] --> TV +L --> SL["SidebarLogo.vue"] +L --> CPD["ChangePasswordDialog.vue"] +CPD --> API["api/auth.js"] +L --> AUTH["utils/auth.js"] +L --> THEME["styles/lux-theme.css"] +``` + +图表来源 +- [TabsView.vue:55-59](file://frontend/src/components/TabsView.vue#L55-L59) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [SidebarLogo.vue:1-135](file://frontend/src/components/SidebarLogo.vue#L1-L135) +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) +- [auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +章节来源 +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 性能考量 +- 标签页缓存 + - 使用 KeepAlive 结合 computed 的 include 列表,避免重复渲染与网络请求。 +- 路由监听与持久化 + - 仅在 tabs/activeKey 发生变化时写入 sessionStorage,降低 IO 开销。 +- 折叠态 Logo + - 折叠时隐藏文字,减少 DOM 与重排成本。 +- 对话框加载态 + - 提交期间禁用按钮并显示 loading,避免重复提交与资源浪费。 +- 主题与样式 + - 使用 CSS 变量统一颜色与阴影,减少重复样式计算。 + +## 故障排查指南 +- 标签页不显示或丢失 + - 检查路由 meta.title/meta.icon 是否正确设置;确认 HOME_PATH 常量与默认首页一致。 + - 查看 sessionStorage 中的 TABS_STORAGE_KEY 是否被清理或损坏。 +- 密码修改失败 + - 确认旧密码正确且新密码满足长度要求;检查 API 返回码与网络状态。 + - 若出现重复提交,确认 loading 状态与 validate 流程。 +- 侧边栏折叠异常 + - 检查 isSidebarCollapsed 的绑定与鼠标事件;确认主题样式未被覆盖。 + +章节来源 +- [TabsView.vue:125-174](file://frontend/src/components/TabsView.vue#L125-L174) +- [ChangePasswordDialog.vue:108-126](file://frontend/src/components/ChangePasswordDialog.vue#L108-L126) +- [index.vue:10-15](file://frontend/src/layout/index.vue#L10-L15) + +## 结论 +本项目通过三个核心业务组件构建了清晰、可扩展的前端界面骨架:侧边栏Logo承担品牌展示职责,标签页视图提供高效导航与缓存,密码修改对话框保障安全交互。组件间通过布局容器与路由系统协同工作,配合主题样式与工具函数,实现了良好的可维护性与用户体验。 + +## 附录 + +### 组件接口速查 + +- 侧边栏Logo组件 + - Props: collapsed(Boolean) + - 事件: 无 + - 插槽: 无 + - 样式: 通过主题变量与容器类名定制 + +- 标签页视图组件 + - Props: 无 + - 事件: 无 + - 插槽: 默认插槽(label) + - 数据: tabs(Array), activeKey(String), keepAliveInclude(Set) + - 常量: TABS_STORAGE_KEY(String), HOME_PATH(String) + +- 密码修改对话框 + - Props: modelValue(Boolean) + - 事件: update:modelValue(Boolean) + - 插槽: 无 + - 表单: oldPassword, newPassword, confirmPassword + - 校验: 必填、最小长度、确认一致性 + +章节来源 +- [SidebarLogo.vue:52-59](file://frontend/src/components/SidebarLogo.vue#L52-L59) +- [TabsView.vue:55-287](file://frontend/src/components/TabsView.vue#L55-L287) +- [ChangePasswordDialog.vue:51-127](file://frontend/src/components/ChangePasswordDialog.vue#L51-L127) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/业务组件/侧边栏Logo组件.md b/.qoder/repowiki/zh/content/前端组件/业务组件/侧边栏Logo组件.md new file mode 100644 index 0000000..01c7e03 --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/业务组件/侧边栏Logo组件.md @@ -0,0 +1,463 @@ +# 侧边栏Logo组件 + + +**本文档引用的文件** +- [SidebarLogo.vue](file://frontend/src/components/SidebarLogo.vue) +- [index.vue](file://frontend/src/layout/index.vue) +- [lux-theme.css](file://frontend/src/styles/lux-theme.css) +- [main.js](file://frontend/src/main.js) +- [App.vue](file://frontend/src/App.vue) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +侧边栏Logo组件是Dashboard管理系统中的重要视觉标识组件,负责展示品牌标识和公司名称。该组件采用现代化的SVG图形设计,结合渐变色彩、阴影效果和流畅的动画过渡,为用户提供一致的品牌体验。 + +组件的核心特性包括: +- 响应式布局适配,支持展开和折叠两种状态 +- 基于SVG的矢量图形设计,确保清晰度和可缩放性 +- 渐变色彩系统,营造科技感和专业感 +- 平滑的动画过渡效果,提升用户体验 +- 无障碍访问设计,符合现代Web标准 + +## 项目结构 + +侧边栏Logo组件位于前端项目的组件目录中,与布局系统紧密集成: + +```mermaid +graph TB +subgraph "前端项目结构" +A[frontend/] --> B[src/] +B --> C[components/] +B --> D[layout/] +B --> E[styles/] +C --> F[SidebarLogo.vue] +D --> G[index.vue] +E --> H[lux-theme.css] +I[main.js] --> J[App.vue] +J --> K[router-view] +K --> L[layout/index.vue] +L --> M[SidebarLogo.vue] +end +``` + +**图表来源** +- [SidebarLogo.vue:1-135](file://frontend/src/components/SidebarLogo.vue#L1-L135) +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) + +**章节来源** +- [SidebarLogo.vue:1-135](file://frontend/src/components/SidebarLogo.vue#L1-L135) +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) + +## 核心组件 + +### 组件架构设计 + +SidebarLogo组件采用Vue 3 Composition API设计,通过props接收collapsed状态,实现响应式布局切换: + +```mermaid +classDiagram +class SidebarLogo { ++Boolean collapsed ++String name ++String tag ++Object gradients ++Object shadow ++render() VNode ++animateTransition() void +} +class SVGGraphics { ++LinearGradient grad1 ++LinearGradient grad2 ++Filter shadow ++Rectangles shapes ++Paths curves +} +class LayoutSystem { ++Boolean isSidebarCollapsed ++String sidebarWidth ++handleMouseEvents() void ++toggleSidebar() void +} +SidebarLogo --> SVGGraphics : "uses" +LayoutSystem --> SidebarLogo : "controls" +``` + +**图表来源** +- [SidebarLogo.vue:52-59](file://frontend/src/components/SidebarLogo.vue#L52-L59) +- [index.vue:158-158](file://frontend/src/layout/index.vue#L158-L158) + +### 属性系统 + +组件通过collapsed属性控制布局状态: + +| 属性名 | 类型 | 默认值 | 描述 | +|--------|------|--------|------| +| collapsed | Boolean | false | 控制侧边栏折叠状态 | + +**章节来源** +- [SidebarLogo.vue:52-59](file://frontend/src/components/SidebarLogo.vue#L52-L59) + +## 架构概览 + +### 整体系统架构 + +```mermaid +graph TD +subgraph "应用层" +A[App.vue] --> B[Router View] +B --> C[Layout Component] +end +subgraph "布局系统" +C --> D[Sidebar Container] +C --> E[Main Content] +D --> F[Sidebar Logo] +D --> G[Navigation Rail] +D --> H[Menu System] +end +subgraph "Logo组件" +F --> I[SVG Graphics] +F --> J[Text Elements] +F --> K[Animation System] +end +subgraph "样式系统" +L[Lux Theme CSS] --> M[Global Styles] +M --> N[Component Specific Styles] +N --> O[Responsive Breakpoints] +end +subgraph "交互系统" +P[Mouse Events] --> Q[State Management] +Q --> R[Layout Transitions] +R --> S[Visual Feedback] +end +F -.-> L +C -.-> P +``` + +**图表来源** +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +### 数据流架构 + +```mermaid +sequenceDiagram +participant User as 用户 +participant Layout as 布局组件 +participant Logo as Logo组件 +participant State as 状态管理 +participant Style as 样式系统 +User->>Layout : 鼠标悬停/离开 +Layout->>State : 更新collapsed状态 +State->>Logo : 传递collapsed属性 +Logo->>Style : 应用样式类 +Style->>Logo : 触发CSS动画 +Logo-->>User : 显示更新后的界面 +Note over Layout,Logo : 展开/折叠状态切换 +``` + +**图表来源** +- [index.vue:13-14](file://frontend/src/layout/index.vue#L13-L14) +- [index.vue:18-18](file://frontend/src/layout/index.vue#L18-L18) + +## 详细组件分析 + +### SVG图形设计实现 + +#### 渐变色定义系统 + +组件使用了精心设计的渐变色彩系统,营造科技感的品牌形象: + +```mermaid +flowchart TD +A[渐变色彩系统] --> B[主渐变色] +A --> C[发光渐变色] +A --> D[阴影效果] +B --> E[luxMarkGrad] +E --> F[#38bdf8 → #818cf8 → #a78bfa] +E --> G[对角线渐变] +C --> H[luxMarkGlow] +H --> I[#38bdf8 → #6366f1] +H --> J[透明度渐变] +D --> K[luxMarkShadow] +K --> L[阴影参数] +L --> M[偏移: 0,2] +L --> N[模糊: 2.5] +L --> O[颜色: #38bdf8] +L --> P[透明度: 0.35] +``` + +**图表来源** +- [SidebarLogo.vue:6-17](file://frontend/src/components/SidebarLogo.vue#L6-L17) + +#### 图形元素构成 + +SVG图形由多个几何元素组成,形成独特的品牌标识: + +| 元素类型 | 数量 | 尺寸 | 特殊属性 | +|----------|------|------|----------| +| 外层矩形 | 1 | 36×36 | 圆角11px,发光效果 | +| 内层矩形 | 1 | 34.5×34.5 | 圆角10.25px,描边渐变 | +| 竖条元素 | 3 | 3.2×13/15.5/11 | 渐变填充,圆角1.6px | +| 曲线元素 | 1 | 自定义路径 | 渐变描边,圆角端点 | + +**章节来源** +- [SidebarLogo.vue:4-42](file://frontend/src/components/SidebarLogo.vue#L4-L42) + +### 动画过渡机制 + +#### 折叠状态动画 + +组件实现了平滑的折叠动画,通过CSS过渡实现: + +```mermaid +stateDiagram-v2 +[*] --> 展开状态 +展开状态 --> 折叠状态 : collapsed=true +折叠状态 --> 展开状态 : collapsed=false +展开状态 : 完整显示 +展开状态 : 文字标记可见 +展开状态 : 间距10px +折叠状态 : 缩小宽度 +折叠状态 : 文字标记隐藏 +折叠状态 : 间距0px +折叠状态 : 居中对齐 +``` + +**图表来源** +- [SidebarLogo.vue:120-133](file://frontend/src/components/SidebarLogo.vue#L120-L133) + +#### 过渡效果配置 + +| 动画属性 | 持续时间 | 缓动函数 | 影响元素 | +|----------|----------|----------|----------| +| 透明度变化 | 0.2秒 | ease | 文字标记容器 | +| 位移变换 | 0.2秒 | ease | 文字标记容器 | +| 宽度变化 | 0.3秒 | ease | 整个Logo容器 | +| 阴影变化 | 0.3秒 | ease | 侧边栏容器 | + +**章节来源** +- [SidebarLogo.vue:89-89](file://frontend/src/components/SidebarLogo.vue#L89-L89) +- [lux-theme.css:117-117](file://frontend/src/styles/lux-theme.css#L117-L117) + +### CSS样式体系 + +#### Flex布局系统 + +组件采用现代Flexbox布局,确保元素的灵活排列: + +```mermaid +flowchart LR +A[sidebar-brand容器] --> B[flex布局] +B --> C[align-items: center] +B --> D[gap: 10px] +B --> E[min-width: 0] +F[sidebar-brand-mark] --> G[固定尺寸36×36] +F --> H[flex-shrink: 0] +I[sidebar-brand-wordmark] --> J[column布局] +I --> K[align-items: flex-start] +I --> L[gap: 2px] +I --> M[transition: opacity/transform] +``` + +**图表来源** +- [SidebarLogo.vue:62-89](file://frontend/src/components/SidebarLogo.vue#L62-L89) + +#### 字体和文本样式 + +| 文本元素 | 字体族 | 字号 | 字重 | 字母间距 | +|----------|--------|------|------|----------| +| 品牌名称 | Outfit, sans-serif | 17px | 700 | 0.14em | +| 标记标签 | Outfit, sans-serif | 10px | 600 | 0.22em | + +**章节来源** +- [SidebarLogo.vue:92-118](file://frontend/src/components/SidebarLogo.vue#L92-L118) + +### 响应式布局适配 + +#### 断点设计 + +组件支持多种屏幕尺寸的自适应: + +```mermaid +graph TD +A[响应式断点] --> B[桌面端: ≥1024px] +A --> C[平板端: 768px-1023px] +A --> D[移动端: <768px] +B --> E[完整Logo显示] +B --> F[220px侧边栏宽度] +C --> G[简化Logo显示] +C --> H[160px侧边栏宽度] +D --> I[最小Logo显示] +D --> J[64px侧边栏宽度] +``` + +**图表来源** +- [lux-theme.css:101-130](file://frontend/src/styles/lux-theme.css#L101-L130) + +#### 状态切换逻辑 + +```mermaid +flowchart TD +A[鼠标事件] --> B{悬停检测} +B --> |进入| C[isSidebarCollapsed = false] +B --> |离开| D[isSidebarCollapsed = true] +C --> E[展开状态] +D --> F[折叠状态] +E --> G[显示完整Logo] +F --> H[显示简化Logo] +G --> I[文字标记可见] +H --> J[文字标记隐藏] +``` + +**图表来源** +- [index.vue:13-14](file://frontend/src/layout/index.vue#L13-L14) + +**章节来源** +- [index.vue:158-158](file://frontend/src/layout/index.vue#L158-L158) + +## 依赖关系分析 + +### 组件间依赖 + +```mermaid +graph LR +A[Layout Component] --> B[SidebarLogo Component] +A --> C[Navigation Rail] +A --> D[Menu System] +B --> E[SVG Graphics] +B --> F[CSS Styles] +B --> G[Theme Variables] +H[Theme System] --> I[Global Styles] +H --> J[Component Styles] +K[Event System] --> L[Mouse Events] +K --> M[State Management] +L --> N[Layout Updates] +M --> O[Component Re-render] +O --> P[Style Application] +``` + +**图表来源** +- [index.vue:151-151](file://frontend/src/layout/index.vue#L151-L151) +- [lux-theme.css:1-25](file://frontend/src/styles/lux-theme.css#L1-L25) + +### 外部依赖 + +组件依赖以下外部库和资源: + +| 依赖项 | 版本 | 用途 | +|--------|------|------| +| Vue 3 | 最新版本 | 组件框架 | +| Element Plus | UI组件库 | 布局和导航组件 | +| CSS变量 | 浏览器原生 | 主题定制 | +| SVG渐变 | 浏览器原生 | 图形渲染 | + +**章节来源** +- [main.js:1-9](file://frontend/src/main.js#L1-L9) + +## 性能考虑 + +### SVG渲染优化 + +组件采用SVG而非位图的优势: +- 矢量图形,无损缩放 +- 文件体积小,加载速度快 +- 支持CSS动画,GPU加速 +- 可访问性强,语义化好 + +### 动画性能优化 + +```mermaid +flowchart TD +A[性能优化策略] --> B[硬件加速] +A --> C[最小重绘] +A --> D[内存管理] +B --> E[transform属性] +B --> F[opacity属性] +B --> G[backface-visibility] +C --> H[避免强制同步布局] +C --> I[批量DOM操作] +C --> J[CSS动画优先] +D --> K[组件卸载清理] +D --> L[事件监听器移除] +D --> M[内存泄漏预防] +``` + +### 加载性能 + +- SVG内联到HTML中,减少HTTP请求 +- CSS变量缓存,避免重复计算 +- 动画使用transform和opacity,启用GPU加速 +- 响应式设计,适配不同设备性能 + +## 故障排除指南 + +### 常见问题及解决方案 + +#### Logo显示异常 + +**问题症状**:Logo在某些浏览器中显示不完整 +**可能原因**: +- SVG渐变不被支持的浏览器 +- CSS变量未正确解析 +- 容器尺寸设置错误 + +**解决步骤**: +1. 检查浏览器兼容性 +2. 验证CSS变量定义 +3. 确认容器尺寸设置 + +#### 动画卡顿问题 + +**问题症状**:折叠/展开动画不流畅 +**可能原因**: +- 过多的DOM操作 +- CSS动画属性选择不当 +- 浏览器性能限制 + +**优化方案**: +1. 使用transform替代width/height +2. 减少动画层级 +3. 启用硬件加速 + +#### 无障碍访问问题 + +**问题症状**:屏幕阅读器无法正确读取Logo信息 +**解决方案**: +- 保持aria-hidden="true"用于装饰性Logo +- 确保品牌名称作为文本内容存在 +- 提供适当的标题属性 + +**章节来源** +- [SidebarLogo.vue:3-3](file://frontend/src/components/SidebarLogo.vue#L3-L3) + +## 结论 + +侧边栏Logo组件展现了现代前端开发的最佳实践,通过精心设计的SVG图形、优雅的动画过渡和完善的响应式布局,为用户提供了优秀的视觉体验。 + +### 设计亮点 + +1. **技术实现**:SVG矢量图形确保了清晰度和可扩展性 +2. **视觉设计**:渐变色彩系统营造了专业的科技感 +3. **用户体验**:流畅的动画过渡提升了交互质量 +4. **可维护性**:模块化的代码结构便于后续扩展 + +### 扩展建议 + +1. **主题定制**:支持动态主题切换 +2. **性能优化**:考虑Web Workers处理复杂图形 +3. **国际化**:支持多语言品牌名称 +4. **可访问性**:增强屏幕阅读器支持 + +该组件为整个Dashboard系统的视觉统一奠定了坚实基础,是现代前端开发的优秀范例。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/业务组件/密码修改对话框.md b/.qoder/repowiki/zh/content/前端组件/业务组件/密码修改对话框.md new file mode 100644 index 0000000..028d4ab --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/业务组件/密码修改对话框.md @@ -0,0 +1,466 @@ +# 密码修改对话框 + + +**本文档引用的文件** +- [ChangePasswordDialog.vue](file://frontend/src/components/ChangePasswordDialog.vue) +- [auth.js](file://frontend/src/api/auth.js) +- [request.js](file://frontend/src/utils/request.js) +- [auth.js](file://frontend/src/utils/auth.js) +- [auth.js](file://backend/src/routes/auth.js) +- [password.js](file://backend/src/utils/password.js) +- [jwt.js](file://backend/src/utils/jwt.js) +- [auth.js](file://backend/src/middleware/auth.js) +- [DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [response.js](file://backend/src/utils/response.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +本文件详细说明了密码修改对话框的安全交互机制,包括密码强度验证规则、表单验证流程、API调用流程以及安全最佳实践。该系统采用前后端分离架构,前端使用Vue.js和Element Plus构建用户界面,后端使用Node.js和Express提供RESTful API服务。 + +## 项目结构 + +密码修改功能涉及以下关键文件: + +```mermaid +graph TB +subgraph "前端层" +CPD[ChangePasswordDialog.vue
密码修改对话框] +API[auth.js
认证API封装] +REQ[request.js
HTTP请求拦截器] +AUTH[auth.js
认证工具函数] +end +subgraph "后端层" +ROUTE[auth.js
认证路由] +PASS[password.js
密码加密工具] +JWT[jwt.js
JWT令牌处理] +MWARE[auth.js
认证中间件] +MODEL[DashboardUser.js
用户模型] +RESP[response.js
响应格式化] +end +CPD --> API +API --> REQ +REQ --> ROUTE +ROUTE --> PASS +ROUTE --> JWT +ROUTE --> MWARE +ROUTE --> MODEL +ROUTE --> RESP +AUTH --> REQ +``` + +**图表来源** +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) +- [auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +**章节来源** +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) +- [auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [request.js:1-72](file://frontend/src/utils/request.js#L1-L72) + +## 核心组件 + +### 密码修改对话框组件 + +密码修改对话框是一个基于Vue.js的可复用组件,提供完整的密码修改功能: + +- **表单字段**: + - 原密码(必需,至少6位) + - 新密码(必需,至少6位) + - 确认密码(必需,必须与新密码一致) + +- **验证规则**: + - 实时验证:使用Element Plus的表单验证 + - 自定义验证:确认密码必须与新密码完全匹配 + - 错误提示:清晰的错误消息反馈 + +- **用户体验**: + - 密码可见性切换 + - 自动完成属性设置 + - 加载状态指示 + - 表单重置功能 + +**章节来源** +- [ChangePasswordDialog.vue:14-40](file://frontend/src/components/ChangePasswordDialog.vue#L14-L40) +- [ChangePasswordDialog.vue:78-99](file://frontend/src/components/ChangePasswordDialog.vue#L78-L99) +- [ChangePasswordDialog.vue:108-126](file://frontend/src/components/ChangePasswordDialog.vue#L108-L126) + +### API封装层 + +前端通过专门的API模块封装所有认证相关的HTTP请求: + +- **changePassword函数**:负责密码修改请求 +- **统一的请求配置**:自动添加Authorization头 +- **错误处理**:统一的错误响应处理 + +**章节来源** +- [auth.js:14-23](file://frontend/src/api/auth.js#L14-L23) +- [request.js:12-25](file://frontend/src/utils/request.js#L12-L25) + +## 架构概览 + +密码修改的完整交互流程如下: + +```mermaid +sequenceDiagram +participant U as 用户 +participant D as 密码修改对话框 +participant F as 前端API +participant R as 认证路由 +participant P as 密码工具 +participant J as JWT工具 +participant M as 认证中间件 +participant DB as 数据库 +U->>D : 打开密码修改对话框 +D->>D : 输入原密码/新密码 +D->>F : 调用changePassword() +F->>R : PUT /api/auth/password +R->>M : 验证JWT令牌 +M->>J : 解析JWT令牌 +J-->>M : 用户信息 +M-->>R : 通过认证 +R->>R : 验证原密码 +R->>P : 验证密码哈希 +P-->>R : 验证结果 +R->>DB : 更新密码哈希 +DB-->>R : 更新成功 +R-->>F : 返回成功响应 +F-->>D : 显示成功消息 +D-->>U : 关闭对话框 +``` + +**图表来源** +- [ChangePasswordDialog.vue:108-126](file://frontend/src/components/ChangePasswordDialog.vue#L108-L126) +- [auth.js:14-23](file://frontend/src/api/auth.js#L14-L23) +- [auth.js:79-109](file://backend/src/routes/auth.js#L79-L109) +- [auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [password.js:16-34](file://backend/src/utils/password.js#L16-L34) + +## 详细组件分析 + +### 密码强度验证规则 + +系统实现了多层次的密码强度验证机制: + +#### 前端验证规则 + +```mermaid +flowchart TD +Start([开始验证]) --> CheckOld["检查原密码
必需且至少6位"] +CheckOld --> CheckNew["检查新密码
必需且至少6位"] +CheckNew --> CheckConfirm["检查确认密码
必须与新密码一致"] +CheckConfirm --> Valid{"验证通过?"} +Valid --> |是| Submit["允许提交"] +Valid --> |否| ShowError["显示错误信息"] +ShowError --> End([结束]) +Submit --> End +``` + +**图表来源** +- [ChangePasswordDialog.vue:90-99](file://frontend/src/components/ChangePasswordDialog.vue#L90-L99) +- [ChangePasswordDialog.vue:78-88](file://frontend/src/components/ChangePasswordDialog.vue#L78-L88) + +#### 后端验证规则 + +后端实施了更严格的验证逻辑: + +- **必填验证**:原密码和新密码都必须提供 +- **长度验证**:新密码至少6个字符 +- **存在性验证**:用户必须存在且状态为启用 +- **原密码验证**:使用PBKDF2算法验证原密码 +- **密码哈希**:使用PBKDF2算法生成新的密码哈希 + +**章节来源** +- [auth.js:83-88](file://backend/src/routes/auth.js#L83-L88) +- [auth.js:90-98](file://backend/src/routes/auth.js#L90-L98) +- [password.js:10-14](file://backend/src/utils/password.js#L10-L14) + +### 表单验证流程 + +#### 实时验证机制 + +```mermaid +stateDiagram-v2 +[*] --> 初始状态 +初始状态 --> 输入原密码 : 用户输入 +输入原密码 --> 输入新密码 : 原密码有效 +输入新密码 --> 输入确认密码 : 新密码有效 +输入确认密码 --> 验证中 : 提交表单 +验证中 --> 成功 : 验证通过 +验证中 --> 失败 : 验证失败 +成功 --> [*] +失败 --> 输入原密码 : 修正错误 +失败 --> 输入新密码 : 修正错误 +失败 --> 输入确认密码 : 修正错误 +``` + +**图表来源** +- [ChangePasswordDialog.vue:78-99](file://frontend/src/components/ChangePasswordDialog.vue#L78-L99) +- [ChangePasswordDialog.vue:108-126](file://frontend/src/components/ChangePasswordDialog.vue#L108-L126) + +#### 错误提示和状态管理 + +- **加载状态**:提交过程中显示加载指示器 +- **成功提示**:使用Element Plus的消息提示 +- **错误处理**:捕获并显示具体的错误信息 +- **表单重置**:操作完成后重置表单状态 + +**章节来源** +- [ChangePasswordDialog.vue:70-76](file://frontend/src/components/ChangePasswordDialog.vue#L70-L76) +- [ChangePasswordDialog.vue:118-121](file://frontend/src/components/ChangePasswordDialog.vue#L118-L121) + +### API调用流程 + +#### 密码修改API设计 + +```mermaid +classDiagram +class ChangePasswordDialog { ++visible : boolean ++loading : boolean ++form : object ++handleSubmit() ++resetForm() +} +class AuthAPI { ++changePassword(data) +} +class RequestInterceptor { ++request(config) ++response(response) +} +class AuthRoute { ++PUT /api/auth/password ++verifyPassword() ++hashPassword() +} +class PasswordUtils { ++hashPassword() ++verifyPassword() +} +ChangePasswordDialog --> AuthAPI : 使用 +AuthAPI --> RequestInterceptor : 通过 +AuthAPI --> AuthRoute : 调用 +AuthRoute --> PasswordUtils : 使用 +``` + +**图表来源** +- [ChangePasswordDialog.vue:51-127](file://frontend/src/components/ChangePasswordDialog.vue#L51-L127) +- [auth.js:14-23](file://frontend/src/api/auth.js#L14-L23) +- [request.js:12-69](file://frontend/src/utils/request.js#L12-L69) +- [auth.js:79-109](file://backend/src/routes/auth.js#L79-L109) +- [password.js:10-34](file://backend/src/utils/password.js#L10-L34) + +#### 请求参数和响应格式 + +- **请求URL**:`/api/auth/password` +- **请求方法**:PUT +- **请求头**:Authorization: Bearer {token} +- **请求体**: + - old_password: 原密码 + - new_password: 新密码 +- **响应格式**:统一的ApiResponse格式 + +**章节来源** +- [auth.js:14-23](file://frontend/src/api/auth.js#L14-L23) +- [auth.js:79-109](file://backend/src/routes/auth.js#L79-L109) +- [response.js:1-13](file://backend/src/utils/response.js#L1-L13) + +### 安全最佳实践 + +#### 密码加密传输 + +系统采用了多层安全保护机制: + +1. **传输层安全**:所有API请求通过HTTPS传输 +2. **密码哈希**:使用PBKDF2算法进行密码哈希 +3. **盐值随机化**:每次哈希生成新的随机盐值 +4. **安全常量**:使用定时安全比较防止时序攻击 + +#### 防重放攻击 + +- **JWT令牌**:使用JSON Web Token进行身份验证 +- **令牌过期**:12小时有效期,自动过期 +- **中间件验证**:每个受保护路由都经过认证中间件验证 +- **令牌刷新**:过期后自动重定向到登录页面 + +#### 会话管理 + +- **本地存储**:令牌和用户信息存储在localStorage +- **自动清理**:401响应时自动清除认证信息 +- **权限控制**:区分普通用户和超级管理员权限 +- **状态同步**:用户状态变化时同步更新 + +**章节来源** +- [password.js:10-34](file://backend/src/utils/password.js#L10-L34) +- [jwt.js:7-25](file://backend/src/utils/jwt.js#L7-L25) +- [auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [request.js:46-58](file://frontend/src/utils/request.js#L46-L58) + +### 用户体验优化 + +#### 密码可见性切换 + +- **show-password属性**:支持密码明文/密文切换 +- **用户体验**:允许用户临时查看输入的密码 +- **安全性**:默认以密文形式显示 + +#### 自动完成支持 + +- **autocomplete属性**:设置适当的自动完成功能 +- **current-password**:用于原密码字段 +- **new-password**:用于新密码字段 + +#### 键盘导航支持 + +- **Tab键导航**:支持标准的键盘导航 +- **Enter键提交**:支持回车键快速提交 +- **焦点管理**:自动聚焦到第一个输入框 + +**章节来源** +- [ChangePasswordDialog.vue:18-38](file://frontend/src/components/ChangePasswordDialog.vue#L18-L38) + +## 依赖关系分析 + +### 组件间依赖关系 + +```mermaid +graph TD +CPD[ChangePasswordDialog.vue] --> API[auth.js] +API --> REQ[request.js] +REQ --> AUTH[auth.js] +CPD --> EL[Element Plus] +API --> AXIOS[Axios] +REQ --> JWT[JWT] +AUTH --> LS[localStorage] +subgraph "后端依赖" +ROUTE[auth.js] --> PASS[password.js] +ROUTE --> JWT[utils/jwt.js] +ROUTE --> MWARE[middleware/auth.js] +ROUTE --> MODEL[models/DashboardUser.js] +ROUTE --> RESP[utils/response.js] +end +``` + +**图表来源** +- [ChangePasswordDialog.vue:54](file://frontend/src/components/ChangePasswordDialog.vue#L54) +- [auth.js:1](file://frontend/src/api/auth.js#L1) +- [request.js:1](file://frontend/src/utils/request.js#L1) +- [auth.js:1](file://frontend/src/utils/auth.js#L1) + +### 外部依赖 + +- **Element Plus**:UI组件库,提供对话框和表单组件 +- **Axios**:HTTP客户端,处理API请求 +- **Crypto**:Node.js内置加密模块,提供PBKDF2算法 +- **Jsonwebtoken**:JWT令牌处理库 + +**章节来源** +- [password.js:1](file://backend/src/utils/password.js#L1) +- [jwt.js:1](file://backend/src/utils/jwt.js#L1) + +## 性能考虑 + +### 前端性能优化 + +- **组件懒加载**:对话框组件按需加载 +- **表单验证缓存**:避免重复的验证计算 +- **请求去抖**:防止频繁的API调用 +- **内存管理**:及时清理事件监听器和定时器 + +### 后端性能优化 + +- **数据库索引**:用户名字段建立唯一索引 +- **连接池**:使用连接池管理数据库连接 +- **缓存策略**:对常用查询结果进行缓存 +- **异步处理**:所有I/O操作采用异步模式 + +## 故障排除指南 + +### 常见问题及解决方案 + +#### 认证失败 + +**症状**:401未授权错误 +**原因**: +- 令牌缺失或格式错误 +- 令牌已过期 +- 服务器配置错误 + +**解决方法**: +- 检查localStorage中的令牌 +- 自动重定向到登录页面 +- 重新登录获取新令牌 + +#### 密码修改失败 + +**症状**:原密码错误或修改失败 +**原因**: +- 原密码输入错误 +- 新密码不符合要求 +- 用户状态异常 + +**解决方法**: +- 验证原密码正确性 +- 检查新密码长度和格式 +- 确认用户账户状态正常 + +#### 网络请求错误 + +**症状**:网络超时或连接失败 +**原因**: +- 服务器不可达 +- 网络连接问题 +- CORS跨域限制 + +**解决方法**: +- 检查服务器状态 +- 验证网络连接 +- 配置正确的CORS设置 + +**章节来源** +- [request.js:46-68](file://frontend/src/utils/request.js#L46-L68) +- [auth.js:83-108](file://backend/src/routes/auth.js#L83-L108) + +## 结论 + +密码修改对话框系统提供了完整的安全密码管理功能,具有以下特点: + +### 安全特性 +- 多层验证机制确保数据完整性 +- PBKDF2算法提供强密码哈希 +- JWT令牌实现安全的身份验证 +- 定时安全比较防止时序攻击 + +### 用户体验 +- 清晰的表单验证反馈 +- 支持密码可见性切换 +- 自动完成和键盘导航支持 +- 加载状态和错误提示 + +### 技术架构 +- 前后端分离的设计模式 +- 统一的API响应格式 +- 中间件驱动的认证机制 +- 可扩展的模块化架构 + +该系统为用户提供了安全、便捷的密码修改体验,同时确保了系统的整体安全性和可靠性。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/业务组件/标签页视图组件.md b/.qoder/repowiki/zh/content/前端组件/业务组件/标签页视图组件.md new file mode 100644 index 0000000..ea193b0 --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/业务组件/标签页视图组件.md @@ -0,0 +1,312 @@ +# 标签页视图组件 + + +**本文引用的文件** +- [TabsView.vue](file://frontend/src/components/TabsView.vue) +- [tabs.js](file://frontend/src/utils/tabs.js) +- [index.js](file://frontend/src/router/index.js) +- [index.vue](file://frontend/src/layout/index.vue) +- [lux-theme.css](file://frontend/src/styles/lux-theme.css) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件为标签页视图组件的综合技术文档,聚焦于标签页的状态管理、数据结构设计、事件处理系统、生命周期管理、主题与图标配置以及与路由系统的集成与状态同步机制。该组件基于 Vue 3 Composition API 与 Element Plus Tabs 实现,支持标签页的激活、关闭、右键菜单操作、持久化存储,并通过 KeepAlive 实现组件缓存与内存优化。 + +## 项目结构 +标签页视图组件位于前端工程的组件目录中,与路由、布局及主题样式协同工作: +- 组件层:标签页视图组件负责标签集合的渲染、状态管理与事件处理 +- 工具层:标签页常量与持久化工具函数 +- 路由层:定义页面路由与元信息,驱动标签页标题与图标 +- 布局层:承载标签页视图组件并提供面包屑导航与用户菜单 +- 样式层:深色主题与标签页视觉样式 + +```mermaid +graph TB +subgraph "前端应用" +L["Layout 布局
index.vue"] +TV["标签页视图组件
TabsView.vue"] +R["路由配置
router/index.js"] +T["标签页工具
utils/tabs.js"] +ST["主题样式
styles/lux-theme.css"] +end +L --> TV +TV --> R +TV --> T +L --> ST +``` + +图表来源 +- [index.vue:131-133](file://frontend/src/layout/index.vue#L131-L133) +- [TabsView.vue:1-53](file://frontend/src/components/TabsView.vue#L1-L53) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +章节来源 +- [index.vue:131-133](file://frontend/src/layout/index.vue#L131-L133) +- [TabsView.vue:1-53](file://frontend/src/components/TabsView.vue#L1-L53) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 核心组件 +- 标签页视图组件:负责标签集合的渲染、激活切换、关闭、右键菜单、持久化与 KeepAlive 缓存 +- 路由系统:提供页面元信息(标题、图标),驱动标签页标题与图标生成 +- 工具模块:提供标签页存储键名、首页路径等常量与清理函数 +- 布局容器:承载标签页视图组件并提供面包屑导航与用户菜单 +- 主题样式:提供深色主题变量与标签页视觉样式 + +章节来源 +- [TabsView.vue:55-287](file://frontend/src/components/TabsView.vue#L55-L287) +- [index.js:6-56](file://frontend/src/router/index.js#L6-L56) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [index.vue:131-133](file://frontend/src/layout/index.vue#L131-L133) +- [lux-theme.css:10-471](file://frontend/src/styles/lux-theme.css#L10-L471) + +## 架构总览 +标签页视图组件通过路由钩子监听路由变化,动态生成或更新标签项;通过 Element Plus 的 Tabs 组件展示标签,通过 KeepAlive 实现组件缓存;通过 sessionStorage 持久化标签状态;通过右键菜单提供关闭、关闭其他、关闭全部等操作。 + +```mermaid +sequenceDiagram +participant Router as "路由系统" +participant TV as "标签页视图组件" +participant Store as "会话存储" +participant View as "路由视图" +Router->>TV : 触发路由变更 +TV->>TV : upsertTab(标准化路由为标签) +TV->>Store : persist() 写入标签状态 +TV->>View : 渲染当前路由组件(KeepAlive) +View-->>TV : 组件实例缓存 +TV->>TV : handleTabClick/右键菜单/关闭 +TV->>Store : persist() 更新状态 +``` + +图表来源 +- [TabsView.vue:176-286](file://frontend/src/components/TabsView.vue#L176-L286) +- [index.js:64-88](file://frontend/src/router/index.js#L64-L88) + +章节来源 +- [TabsView.vue:176-286](file://frontend/src/components/TabsView.vue#L176-L286) +- [index.js:64-88](file://frontend/src/router/index.js#L64-L88) + +## 详细组件分析 + +### 数据结构设计 +标签页数据结构包含以下关键字段: +- key:唯一标识,通常使用路由 fullPath +- fullPath/path/name:用于定位与跳转 +- title:标签标题,来源于路由 meta.title 或 name 或 path +- icon:图标键值,映射到 Element Plus 图标组件 +- closable:是否可关闭,首页不可关闭 + +```mermaid +classDiagram +class Tab { ++string key ++string fullPath ++string path ++string name ++string title ++string icon ++boolean closable +} +``` + +图表来源 +- [TabsView.vue:88-103](file://frontend/src/components/TabsView.vue#L88-L103) +- [TabsView.vue:151-162](file://frontend/src/components/TabsView.vue#L151-L162) + +章节来源 +- [TabsView.vue:88-103](file://frontend/src/components/TabsView.vue#L88-L103) +- [TabsView.vue:151-162](file://frontend/src/components/TabsView.vue#L151-L162) + +### 状态管理机制 +- 激活状态:activeKey 双向绑定至 Element Plus Tabs,点击标签即激活 +- 关闭操作:removeTabByKey 根据 key 移除标签,若关闭的是当前激活标签则自动切换到相邻标签或首页 +- 重新加载:通过 router-view 的 key 基于 fullPath 变更触发组件重新渲染(非标签页层面的“刷新”) + +```mermaid +flowchart TD +Start(["开始"]) --> Click["点击标签"] +Click --> Activate["设置 activeKey 并匹配当前路由"] +Activate --> Push{"需要路由跳转?"} +Push --> |是| RoutePush["router.push(fullPath)"] +Push --> |否| End +RoutePush --> End(["结束"]) +``` + +图表来源 +- [TabsView.vue:193-200](file://frontend/src/components/TabsView.vue#L193-L200) + +章节来源 +- [TabsView.vue:193-200](file://frontend/src/components/TabsView.vue#L193-L200) + +### 事件处理系统 +- 标签点击:handleTabClick -> activateByKey +- 标签移除:handleTabRemove -> removeTabByKey +- 右键菜单:上下文菜单命令 close/close_others/close_all -> 对应处理函数 +- 路由变化:watch(route.fullPath) -> upsertTab + +```mermaid +sequenceDiagram +participant User as "用户" +participant Tabs as "Element Plus Tabs" +participant TV as "标签页视图组件" +User->>Tabs : 点击标签 +Tabs-->>TV : @tab-click +TV->>TV : handleTabClick(key) +TV->>TV : activateByKey(key) +User->>Tabs : 右键标签 +Tabs-->>TV : 上下文菜单命令 +TV->>TV : handleContextCommand(cmd, key) +alt 关闭 +TV->>TV : removeTabByKey(key) +else 关闭其他 +TV->>TV : handleCloseOthers(currentKey) +else 关闭全部 +TV->>TV : handleCloseAll() +end +``` + +图表来源 +- [TabsView.vue:202-268](file://frontend/src/components/TabsView.vue#L202-L268) + +章节来源 +- [TabsView.vue:202-268](file://frontend/src/components/TabsView.vue#L202-L268) + +### 生命周期管理与缓存策略 +- 组件挂载:onMounted 中恢复标签状态并确保当前路由存在对应标签 +- KeepAlive 缓存:computed 计算 keepAliveInclude,基于所有有 name 的标签 name 去重后传入 KeepAlive include +- 内存优化:通过 include 白名单控制缓存范围,减少不必要的组件实例保活 +- 性能监控:watch 监听 tabs 与 activeKey 变化以触发持久化,避免频繁写入 + +```mermaid +flowchart TD +Mount["onMounted"] --> Restore["restore() 恢复标签状态"] +Restore --> Upsert["upsertTab 当前路由"] +Watch["watch(route.fullPath)"] --> Upsert +Watch2["watch(tabs + activeKey)"] --> Persist["persist() 持久化"] +KeepAlive["computed keepAliveInclude"] --> Cache["KeepAlive include"] +``` + +图表来源 +- [TabsView.vue:270-286](file://frontend/src/components/TabsView.vue#L270-L286) +- [TabsView.vue:120-123](file://frontend/src/components/TabsView.vue#L120-L123) + +章节来源 +- [TabsView.vue:270-286](file://frontend/src/components/TabsView.vue#L270-L286) +- [TabsView.vue:120-123](file://frontend/src/components/TabsView.vue#L120-L123) + +### 与路由系统的集成与状态同步 +- 路由元信息:路由 meta.title 提供标签标题,meta.icon 提供图标键值 +- 首页特殊处理:HOME_PATH 对应标签不可关闭 +- 路由跳转:激活标签时若 fullPath 与当前不同则执行 router.push +- 子路由处理:根布局路由(path='/')不加入标签,children 的实际页面才加入 + +```mermaid +sequenceDiagram +participant Router as "路由系统" +participant TV as "标签页视图组件" +participant Route as "当前路由" +Router->>TV : beforeEach/to +TV->>TV : normalizeTabFromRoute(Route) +TV->>TV : upsertTab(标准化后的标签) +TV->>TV : activateByKey(匹配 key) +alt 需要跳转 +TV->>Router : router.push(fullPath) +end +``` + +图表来源 +- [TabsView.vue:88-103](file://frontend/src/components/TabsView.vue#L88-L103) +- [TabsView.vue:180-191](file://frontend/src/components/TabsView.vue#L180-L191) +- [TabsView.vue:193-200](file://frontend/src/components/TabsView.vue#L193-L200) +- [index.js:64-88](file://frontend/src/router/index.js#L64-L88) + +章节来源 +- [TabsView.vue:88-103](file://frontend/src/components/TabsView.vue#L88-L103) +- [TabsView.vue:180-191](file://frontend/src/components/TabsView.vue#L180-L191) +- [TabsView.vue:193-200](file://frontend/src/components/TabsView.vue#L193-L200) +- [index.js:64-88](file://frontend/src/router/index.js#L64-L88) + +### 主题定制、图标配置与动态内容渲染 +- 主题定制:深色主题变量集中于 lux-theme.css,标签页样式通过 :deep 选择器覆盖 Element Plus 默认样式 +- 图标配置:通过 icon 键值映射到 Element Plus 图标组件,支持 document/list/upload/collection/home/user 等 +- 动态内容渲染:router-view 结合 KeepAlive,通过 key 基于 fullPath 变更触发组件重新渲染 + +章节来源 +- [lux-theme.css:10-471](file://frontend/src/styles/lux-theme.css#L10-L471) +- [TabsView.vue:64-76](file://frontend/src/components/TabsView.vue#L64-L76) +- [TabsView.vue:46-50](file://frontend/src/components/TabsView.vue#L46-L50) + +## 依赖关系分析 +- 组件依赖:TabsView.vue 依赖 vue-router、@element-plus/icons-vue、utils/tabs 常量 +- 路由依赖:路由配置提供 meta.title/meta.icon,影响标签标题与图标 +- 布局依赖:Layout 将 TabsView 作为主内容区的一部分 + +```mermaid +graph LR +TV["TabsView.vue"] --> VR["vue-router"] +TV --> EP["@element-plus/icons-vue"] +TV --> UT["utils/tabs.js"] +UT --> C["常量: TABS_STORAGE_KEY, HOME_PATH"] +TV --> RT["router/index.js"] +L["layout/index.vue"] --> TV +``` + +图表来源 +- [TabsView.vue:58-59](file://frontend/src/components/TabsView.vue#L58-L59) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [index.vue:131-133](file://frontend/src/layout/index.vue#L131-L133) + +章节来源 +- [TabsView.vue:58-59](file://frontend/src/components/TabsView.vue#L58-L59) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [index.vue:131-133](file://frontend/src/layout/index.vue#L131-L133) + +## 性能考量 +- KeepAlive 缓存:仅缓存有 name 的标签组件,避免无意义的实例保活 +- 持久化频率:通过 watch 监听 tabs 与 activeKey 变化进行持久化,减少频繁写入 +- DOM 重绘:标签标题与图标采用固定宽度与省略号,避免布局抖动 +- 路由跳转:仅在 fullPath 与当前不同才执行跳转,避免重复导航 + +## 故障排查指南 +- 标签无法关闭:检查 closable 字段,首页标签默认不可关闭 +- 标题显示异常:检查路由 meta.title 是否存在,否则回退到 name 或 path +- 图标不显示:检查 meta.icon 键值是否正确且在 iconMap 中有对应映射 +- 标签状态丢失:检查 sessionStorage 写入权限与容量限制 +- 路由跳转无效:检查 fullPath 与当前路由是否一致,避免不必要的 router.push + +章节来源 +- [TabsView.vue:101-101](file://frontend/src/components/TabsView.vue#L101-L101) +- [TabsView.vue:78-81](file://frontend/src/components/TabsView.vue#L78-L81) +- [TabsView.vue:64-76](file://frontend/src/components/TabsView.vue#L64-L76) +- [TabsView.vue:125-141](file://frontend/src/components/TabsView.vue#L125-L141) +- [TabsView.vue:197-199](file://frontend/src/components/TabsView.vue#L197-L199) + +## 结论 +标签页视图组件通过清晰的数据结构、完善的事件处理与路由集成,实现了标签的激活、关闭、右键菜单与持久化。结合 KeepAlive 缓存与主题样式,提供了良好的用户体验与性能表现。建议在扩展新功能时遵循现有模式,保持标签状态与路由状态的一致性,并注意缓存范围与持久化策略的平衡。 + +## 附录 +- 常用配置项 + - 存储键名:TABS_STORAGE_KEY + - 首页路径:HOME_PATH + - 图标映射:document/list/upload/collection/home/user +- 最佳实践 + - 在路由 meta 中提供 title 与 icon,确保标签显示一致性 + - 控制 KeepAlive include 范围,避免过度缓存 + - 使用 sessionStorage 进行轻量级状态持久化,避免频繁写入 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/前端组件.md b/.qoder/repowiki/zh/content/前端组件/前端组件.md new file mode 100644 index 0000000..8783596 --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/前端组件.md @@ -0,0 +1,418 @@ +# 前端组件 + + +**本文引用的文件** +- [SidebarLogo.vue](file://frontend/src/components/SidebarLogo.vue) +- [TabsView.vue](file://frontend/src/components/TabsView.vue) +- [index.vue](file://frontend/src/layout/index.vue) +- [index.vue](file://frontend/src/views/home/index.vue) +- [index.vue](file://frontend/src/views/brand/index.vue) +- [ChangePasswordDialog.vue](file://frontend/src/components/ChangePasswordDialog.vue) +- [lux-theme.css](file://frontend/src/styles/lux-theme.css) +- [tabs.js](file://frontend/src/utils/tabs.js) +- [index.js](file://frontend/src/router/index.js) +- [main.js](file://frontend/src/main.js) +- [App.vue](file://frontend/src/App.vue) +- [package.json](file://frontend/package.json) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [组件详解](#组件详解) +6. [依赖关系分析](#依赖关系分析) +7. [性能与可访问性](#性能与可访问性) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件为该前端项目的UI组件文档,聚焦于侧边栏Logo、标签页视图、布局容器以及各功能页面组件的设计与实现。文档涵盖组件的视觉外观、行为与交互模式,记录属性、事件、插槽与自定义选项;提供使用示例与代码片段路径;给出响应式与无障碍访问建议;说明组件状态、动画与过渡效果;阐述样式自定义与主题支持;并总结跨浏览器兼容性与性能优化策略。同时,文档梳理组件组合模式与与路由、Element Plus等外部库的集成方式。 + +## 项目结构 +该项目采用Vue 3 + Vite + Element Plus的前端技术栈,采用基于目录的模块化组织: +- 组件层:通用UI组件位于src/components,如侧边栏Logo、标签页视图、修改密码对话框等 +- 视图层:业务页面位于src/views,如首页、品牌管理、型号管理、OTA管理、分享码日志、系统用户管理等 +- 布局层:全局布局位于src/layout,负责侧边栏、头部、面包屑、主内容区与页脚的整体排布 +- 样式层:主题样式位于src/styles,提供深色宇宙风主题变量与覆盖 +- 工具与路由:src/utils与src/router提供路由守卫、会话存储键值等 +- 应用入口:src/main.js与src/App.vue负责应用初始化与挂载 + +```mermaid +graph TB +A["App.vue
应用根节点"] --> B["main.js
应用初始化"] +B --> C["Element Plus
UI库"] +B --> D["路由 index.js
路由配置与守卫"] +D --> E["Layout 布局 index.vue
侧边栏/头部/主内容/页脚"] +E --> F["TabsView 标签页 index.vue
多页签与路由联动"] +E --> G["SidebarLogo 侧边栏Logo
折叠态与文案展示"] +E --> H["ChangePasswordDialog
修改密码对话框"] +E --> I["视图 Home/Brand 等
业务页面"] +J["lux-theme.css
主题样式与变量"] --> E +K["tabs.js
标签页持久化键值"] --> F +``` + +图表来源 +- [App.vue:1-30](file://frontend/src/App.vue#L1-L30) +- [main.js:1-26](file://frontend/src/main.js#L1-L26) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [SidebarLogo.vue:1-135](file://frontend/src/components/SidebarLogo.vue#L1-L135) +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) + +章节来源 +- [App.vue:1-30](file://frontend/src/App.vue#L1-L30) +- [main.js:1-26](file://frontend/src/main.js#L1-L26) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 核心组件 +- 侧边栏Logo组件:用于在侧边栏中展示品牌标识与文字,支持折叠态隐藏文字,具备渐变与阴影效果 +- 标签页视图组件:封装Element Plus的标签页,提供右键上下文菜单、标签页持久化、动态标题与图标解析、路由联动与缓存控制 +- 布局容器:整合侧边栏、头部、主内容区与页脚,提供面包屑、用户下拉菜单、菜单展开/收起逻辑 +- 功能页面:首页、品牌管理、型号管理、OTA管理、分享码日志、系统用户管理等,均通过路由懒加载与Element Plus组件构建 +- 修改密码对话框:提供表单校验、提交与消息反馈,支持双向绑定 + +章节来源 +- [SidebarLogo.vue:1-135](file://frontend/src/components/SidebarLogo.vue#L1-L135) +- [TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) +- [index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) + +## 架构总览 +应用采用“布局容器 + 多视图 + 组件库”的分层架构。布局容器承载导航与用户交互,标签页视图负责页面切换与缓存,业务视图通过路由懒加载按需渲染。Element Plus提供统一的UI能力,主题样式集中管理。 + +```mermaid +graph TB +subgraph "应用层" +App["App.vue"] +Main["main.js"] +end +subgraph "路由层" +Router["router/index.js"] +end +subgraph "布局层" +Layout["layout/index.vue"] +Tabs["components/TabsView.vue"] +Logo["components/SidebarLogo.vue"] +Dialog["components/ChangePasswordDialog.vue"] +end +subgraph "视图层" +Home["views/home/index.vue"] +Brand["views/brand/index.vue"] +end +subgraph "样式层" +Theme["styles/lux-theme.css"] +end +App --> Main +Main --> Router +Router --> Layout +Layout --> Tabs +Layout --> Logo +Layout --> Dialog +Tabs --> Home +Tabs --> Brand +Layout --> Theme +``` + +图表来源 +- [App.vue:1-30](file://frontend/src/App.vue#L1-L30) +- [main.js:1-26](file://frontend/src/main.js#L1-L26) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [SidebarLogo.vue:1-135](file://frontend/src/components/SidebarLogo.vue#L1-L135) +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) +- [index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) +- [index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 组件详解 + +### 侧边栏Logo组件(SidebarLogo) +- 视觉外观 + - 品牌标识由SVG图形构成,包含渐变背景、描边与阴影滤镜,呈现科技感 + - 文字部分包含品牌名与标签,使用渐变文本与半透明背景 + - 折叠态时隐藏文字,仅保留图标,通过CSS类切换实现 +- 行为与交互 + - 接收collapsed布尔属性控制折叠态 + - 在折叠态下,文字块透明度与可见性被禁用,避免占用空间 +- 属性 + - collapsed: Boolean,默认false +- 插槽与事件 + - 无插槽与事件 +- 使用示例 + - 在布局容器中以组件形式使用,并传入isSidebarCollapsed状态 +- 样式与主题 + - 使用主题变量控制字体、颜色与背景 +- 可访问性 + - 图标内联SVG,配合aria-hidden隐藏对读屏器的干扰 +- 性能 + - SVG内联,无需额外资源请求 + +章节来源 +- [SidebarLogo.vue:1-135](file://frontend/src/components/SidebarLogo.vue#L1-L135) + +### 标签页视图组件(TabsView) +- 视觉外观 + - 使用Element Plus卡片式标签页,标签宽度与滚动控制良好 + - 活动标签图标高亮,提供上下文菜单(关闭、关闭其他、关闭全部) +- 行为与交互 + - 自动根据路由生成/更新标签,支持点击激活、右键菜单、关闭标签 + - 支持标签持久化到sessionStorage,刷新后恢复 + - 使用KeepAlive缓存页面组件,提升切换性能 +- 属性 + - 无显式props +- 事件 + - 无显式emit +- 插槽 + - 通过Element Plus插槽自定义标签标签内容 +- 自定义选项 + - 支持通过路由meta.title/meta.icon动态设置标签标题与图标 + - 内置图标映射:document/list/upload/collection/home/user +- 状态与生命周期 + - 初始化时恢复标签,监听路由变化自动更新 + - 计算keepAliveInclude,基于页面name去重 +- 使用示例 + - 在布局容器的主内容区直接引入 +- 样式与主题 + - 深色主题下的标签页与图标颜色适配 +- 可访问性 + - 标签项具备键盘可达性,上下文菜单支持键盘触发 +- 性能 + - 使用sessionStorage减少重复加载 + - KeepAlive避免重复渲染 + +```mermaid +sequenceDiagram +participant R as "路由" +participant TV as "TabsView" +participant S as "sessionStorage" +participant KV as "keepAliveInclude" +R->>TV : fullPath变更 +TV->>TV : normalizeTabFromRoute() +TV->>TV : upsertTab() +TV->>KV : 计算include集合 +TV->>S : persist() +S-->>TV : 恢复标签 +TV->>R : push(activeKey) +``` + +图表来源 +- [TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) + +章节来源 +- [TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) + +### 布局容器(Layout) +- 视觉外观 + - 侧边栏采用玻璃拟态,支持展开/折叠动画 + - 头部为深色玻璃,右侧用户下拉菜单 + - 主内容区为卡片风格,页脚简洁 +- 行为与交互 + - 侧边栏鼠标悬停展开,离开收起 + - 菜单项与路由联动,面包屑根据路由meta生成 + - 用户下拉菜单支持切换密码、跳转账号管理、退出登录 +- 组合模式 + - 包含TabsView作为主内容区 + - 包含SidebarLogo与菜单组件 + - 引入ChangePasswordDialog用于修改密码 +- 样式与主题 + - 通过lux-theme.css统一深色主题与变量 +- 可访问性 + - 导航与菜单具备aria-label与title提示 +- 性能 + - 侧边栏切换使用opacity/visibility控制,避免重排 + - KeepAlive在TabsView中实现 + +```mermaid +flowchart TD +Start(["进入布局"]) --> Hover["鼠标悬停侧边栏"] +Hover --> Collapse{"是否折叠?"} +Collapse --> |是| Expand["展开侧边栏"] +Collapse --> |否| Collapse["收起侧边栏"] +Expand --> Menu["菜单项点击"] +Collapse --> Menu +Menu --> Route["路由跳转"] +Route --> Tabs["TabsView 更新标签"] +``` + +图表来源 +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) + +章节来源 +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +### 首页视图(Home) +- 视觉外观 + - 英雄卡片突出欢迎语与图标 + - 快捷入口网格布局,卡片悬停有位移动画 + - 今日新增卡片网格,支持加载态与空态 +- 行为与交互 + - 进入页面异步加载今日统计数据 + - 点击快捷入口跳转对应路由 +- 数据流 + - 通过API接口获取统计信息,格式化时间显示 +- 样式与主题 + - 深色卡片与图标高亮,网格布局自适应 + +章节来源 +- [index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) + +### 品牌管理视图(Brand) +- 视觉外观 + - 搜索表单与表格卡片,分页控件居右 + - 对话框用于新增/编辑品牌 +- 行为与交互 + - 支持搜索、重置、分页大小与页码变更 + - 表格操作列提供编辑与删除 + - 删除前二次确认 +- 数据流 + - 通过API加载品牌列表,提交表单创建/更新 +- 样式与主题 + - 表格与分页在深色主题下保持一致性 + +章节来源 +- [index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) + +### 修改密码对话框(ChangePasswordDialog) +- 视觉外观 + - 对话框内含三段密码输入,底部操作按钮 +- 行为与交互 + - 双向绑定modelValue控制显示/隐藏 + - 表单校验:旧密码必填、新密码长度≥6、确认密码一致性 + - 提交后关闭对话框并提示成功 +- 属性 + - modelValue: Boolean +- 事件 + - update:modelValue +- 插槽与自定义选项 + - 无插槽 +- 样式与主题 + - 深色主题下的表单与按钮样式 + +章节来源 +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) + +## 依赖关系分析 +- 应用入口依赖Element Plus与路由,注入主题样式 +- 布局容器依赖TabsView、SidebarLogo、ChangePasswordDialog +- TabsView依赖路由与sessionStorage进行标签持久化 +- 视图组件依赖Element Plus组件与API模块 +- 主题样式通过CSS变量统一控制颜色与阴影 + +```mermaid +graph LR +Pkg["package.json 依赖"] --> Vue["vue"] +Pkg --> Router["vue-router"] +Pkg --> EP["element-plus"] +Pkg --> Icons["@element-plus/icons-vue"] +Main["main.js"] --> EP +Main --> Router +Main --> Theme["lux-theme.css"] +Layout["layout/index.vue"] --> Tabs["components/TabsView.vue"] +Layout --> Logo["components/SidebarLogo.vue"] +Layout --> Dialog["components/ChangePasswordDialog.vue"] +Tabs --> Router +Tabs --> TabsStore["utils/tabs.js"] +Brand["views/brand/index.vue"] --> API["api/brand.js"] +Home["views/home/index.vue"] --> API2["api/dashboard.js"] +``` + +图表来源 +- [package.json:1-24](file://frontend/package.json#L1-L24) +- [main.js:1-26](file://frontend/src/main.js#L1-L26) +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) + +章节来源 +- [package.json:1-24](file://frontend/package.json#L1-L24) +- [main.js:1-26](file://frontend/src/main.js#L1-L26) +- [index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 性能与可访问性 +- 性能 + - 使用KeepAlive缓存标签页组件,减少重复渲染 + - 标签页持久化使用sessionStorage,避免白屏等待 + - 侧边栏切换使用opacity/visibility,避免强制重排 + - 图标与Logo采用SVG内联,减少HTTP请求 +- 可访问性 + - 导航与菜单提供aria-label/title + - 表单控件具备占位符与错误提示 + - 对话框与下拉菜单具备键盘可达性 +- 响应式 + - 网格布局与卡片自适应不同屏幕尺寸 + - 侧边栏宽度与折叠态适配小屏设备 +- 跨浏览器兼容 + - 使用CSS变量与现代特性,结合Element Plus暗色主题 + - 避免使用过时的CSS属性,确保主流浏览器兼容 + +[本节为通用指导,不直接分析具体文件] + +## 故障排查指南 +- 标签页未恢复 + - 检查sessionStorage键值与数据结构是否正确 + - 确认路由meta.title/meta.icon是否正确设置 +- 侧边栏无法展开/收起 + - 检查isSidebarCollapsed状态与事件绑定 + - 确认CSS类切换逻辑 +- 修改密码无效 + - 检查表单校验规则与API返回码 + - 确认对话框双向绑定是否生效 +- 面包屑不显示 + - 检查路由meta.title与路径匹配逻辑 + +章节来源 +- [TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [ChangePasswordDialog.vue:1-128](file://frontend/src/components/ChangePasswordDialog.vue#L1-L128) + +## 结论 +该前端项目通过清晰的分层架构与主题化样式,实现了现代化的深色界面与良好的用户体验。侧边栏Logo、标签页视图、布局容器与功能页面组件协同工作,结合Element Plus与路由机制,提供了可扩展、可维护的UI基础。建议在后续迭代中进一步完善国际化、无障碍细节与性能监控。 + +[本节为总结性内容,不直接分析具体文件] + +## 附录 + +### 组件属性与事件速览 +- SidebarLogo + - 属性:collapsed(Boolean) +- TabsView + - 无显式props;内部事件:tab-click、tab-remove;上下文命令:close/close_others/close_all +- ChangePasswordDialog + - 属性:modelValue(Boolean) + - 事件:update:modelValue + +章节来源 +- [SidebarLogo.vue:52-59](file://frontend/src/components/SidebarLogo.vue#L52-L59) +- [TabsView.vue:3-43](file://frontend/src/components/TabsView.vue#L3-L43) +- [ChangePasswordDialog.vue:56-68](file://frontend/src/components/ChangePasswordDialog.vue#L56-L68) + +### 主题与样式定制 +- 主题变量集中在CSS变量中,便于统一调整 +- 深色卡片、玻璃拟态、渐变主色与阴影构成整体风格 +- 可通过覆盖CSS变量快速实现主题切换 + +章节来源 +- [lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +### 路由与权限 +- 路由守卫处理登录态与超级管理员权限 +- 业务页面通过meta配置标题与图标,参与标签页生成 + +章节来源 +- [index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [index.vue:100-148](file://frontend/src/views/home/index.vue#L100-L148) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/布局组件.md b/.qoder/repowiki/zh/content/前端组件/布局组件.md new file mode 100644 index 0000000..fd44fd0 --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/布局组件.md @@ -0,0 +1,497 @@ +# 布局组件 + + +**本文档引用的文件** +- [frontend/src/layout/index.vue](file://frontend/src/layout/index.vue) +- [frontend/src/App.vue](file://frontend/src/App.vue) +- [frontend/src/main.js](file://frontend/src/main.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [frontend/src/components/SidebarLogo.vue](file://frontend/src/components/SidebarLogo.vue) +- [frontend/src/components/TabsView.vue](file://frontend/src/components/TabsView.vue) +- [frontend/src/styles/lux-theme.css](file://frontend/src/styles/lux-theme.css) +- [frontend/src/utils/tabs.js](file://frontend/src/utils/tabs.js) +- [frontend/src/views/home/index.vue](file://frontend/src/views/home/index.vue) +- [frontend/src/views/login/index.vue](file://frontend/src/views/login/index.vue) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +本项目采用现代化的Vue 3 + Element Plus前端技术栈构建,布局组件是整个系统的骨架结构,负责组织页面的整体架构。该布局组件实现了响应式设计,支持桌面端和移动端的自适应布局,提供了完整的导航体系和主题适配功能。 + +布局组件的核心特色包括: +- **双层导航系统**:侧边栏主导航 + 顶部面包屑导航 +- **动态侧边栏**:支持展开/收起的玻璃拟态设计 +- **标签页管理**:多标签页浏览和持久化存储 +- **深色主题**:基于CSS变量的主题系统 +- **响应式适配**:针对不同屏幕尺寸的优化布局 + +## 项目结构 + +项目采用模块化的文件组织方式,布局组件位于前端项目的专门目录中: + +```mermaid +graph TB +subgraph "前端项目结构" +A[frontend/] --> B[src/] +B --> C[layout/] +B --> D[components/] +B --> E[views/] +B --> F[router/] +B --> G[styles/] +B --> H[utils/] +C --> I[index.vue
主布局组件] +D --> J[SidebarLogo.vue
侧边栏Logo组件] +D --> K[TabsView.vue
标签页组件] +E --> L[home/] +E --> M[login/] +E --> N[brand/] +E --> O[model/] +E --> P[ota/] +E --> Q[share-code/] +E --> R[system/] +F --> S[index.js
路由配置] +G --> T[lux-theme.css
主题样式] +H --> U[tabs.js
标签页工具] +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-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 核心组件 + +### 主布局组件架构 + +主布局组件采用Element Plus的容器布局系统,实现了经典的三段式布局: + +```mermaid +graph LR +A[LuxShell
主容器] --> B[LuxShellBody
主体容器] +B --> C[ElContainer
右侧列容器] +C --> D[ElHeader
顶部导航栏] +C --> E[ElMain
主要内容区] +C --> F[ElFooter
底部版权区] +B --> G[ElAside
侧边栏容器] +G --> H[SidebarInner
侧边栏内部容器] +H --> I[SidebarLogo
Logo组件] +H --> J[SidebarNavWrap
导航包装器] +J --> K[SidebarRail
侧边栏导航条] +J --> L[LuxMenu
主菜单] +``` + +**图表来源** +- [frontend/src/layout/index.vue:9-138](file://frontend/src/layout/index.vue#L9-L138) + +### 组件层次结构 + +```mermaid +classDiagram +class LuxLayout { ++activeMenu : ComputedRef ++isSidebarCollapsed : Ref ++openedMenus : Ref ++railNavItems : Array ++breadcrumbTitle : ComputedRef ++breadcrumbSection : ComputedRef ++handleLogout() ++handleUserMenuCommand() +} +class SidebarLogo { ++collapsed : Boolean ++render() +} +class TabsView { ++tabs : Ref ++activeKey : Ref ++keepAliveInclude : ComputedRef ++upsertTab() ++handleTabClick() ++removeTabByKey() +} +class ChangePasswordDialog { ++visible : Ref ++render() +} +LuxLayout --> SidebarLogo : "使用" +LuxLayout --> TabsView : "使用" +LuxLayout --> ChangePasswordDialog : "使用" +``` + +**图表来源** +- [frontend/src/layout/index.vue:144-222](file://frontend/src/layout/index.vue#L144-L222) +- [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) + +## 架构概览 + +### 整体架构流程 + +```mermaid +sequenceDiagram +participant User as 用户 +participant Router as Vue Router +participant Layout as 布局组件 +participant Tabs as 标签页组件 +participant View as 页面视图 +User->>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) + +### 数据流架构 + +```mermaid +flowchart TD +A[用户交互] --> B[路由变化监听] +B --> C[激活菜单项计算] +C --> D[面包屑标题计算] +D --> E[侧边栏展开状态] +F[页面内容] --> G[标签页管理] +G --> H[会话存储持久化] +H --> I[页面缓存控制] +J[用户菜单] --> K[权限检查] +K --> L[功能访问控制] +L --> M[页面跳转] +``` + +**图表来源** +- [frontend/src/layout/index.vue:154-221](file://frontend/src/layout/index.vue#L154-L221) + +**章节来源** +- [frontend/src/layout/index.vue:154-221](file://frontend/src/layout/index.vue#L154-L221) + +## 详细组件分析 + +### 主布局组件详解 + +#### 布局结构设计 + +主布局组件采用了响应式设计原则,通过CSS Grid和Flexbox实现灵活的布局: + +```mermaid +graph TB +subgraph "桌面端布局" +A[侧边栏 64px] --> B[展开时 220px] +C[右侧内容区] --> D[弹性增长] +E[顶部导航] --> F[44px高度] +G[底部版权] --> H[自动高度] +end +subgraph "移动端适配" +I[触摸手势] --> J[侧边栏滑动] +K[小屏优化] --> L[图标导航优先] +M[响应式断点] --> N[768px以下] +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) + +#### 导航系统实现 + +布局组件实现了双层导航系统: + +1. **侧边栏主导航**:使用`SidebarRail`和`LuxMenu`实现 +2. **顶部面包屑导航**:动态生成面包屑路径 +3. **用户下拉菜单**:权限相关的用户操作 + +**章节来源** +- [frontend/src/layout/index.vue:18-137](file://frontend/src/layout/index.vue#L18-L137) + +### 侧边栏组件分析 + +#### 设计特点 + +侧边栏采用了创新的玻璃拟态设计: + +```mermaid +classDiagram +class SidebarGlass { ++width : 64px/220px ++backdropFilter : blur(18px) ++backgroundColor : rgba(15,23,42,0.6) ++borderRight : 1px solid rgba(255,255,255,0.08) ++transition : width 0.30s ease +} +class SidebarLogo { ++collapsed : Boolean ++animation : slide/fade ++responsive : true +} +class SidebarNavWrap { ++position : absolute ++overflow : hidden ++flex : 1 +} +class SidebarRail { ++visibility : hidden/visible ++opacity : 0/1 ++pointerEvents : none/auto +} +class LuxMenu { ++expanded : true/false ++activeItem : highlight ++hoverEffect : gradient +} +SidebarGlass --> SidebarLogo +SidebarGlass --> SidebarNavWrap +SidebarNavWrap --> SidebarRail +SidebarNavWrap --> LuxMenu +``` + +**图表来源** +- [frontend/src/layout/index.vue:10-86](file://frontend/src/layout/index.vue#L10-L86) +- [frontend/src/styles/lux-theme.css:101-195](file://frontend/src/styles/lux-theme.css#L101-L195) + +#### 交互逻辑 + +侧边栏的交互逻辑通过Vue的响应式系统实现: + +```mermaid +flowchart TD +A[鼠标悬停] --> B{isSidebarCollapsed} +B --> |true| C[设置为false] +B --> |false| D[保持状态] +E[鼠标离开] --> F{isSidebarCollapsed} +F --> |false| G[设置为true] +F --> |true| H[保持状态] +I[菜单点击] --> J[更新activeMenu] +J --> K[同步面包屑] +K --> L[更新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:10-86](file://frontend/src/layout/index.vue#L10-L86) + +### 标签页组件分析 + +#### 多标签页管理 + +TabsView组件实现了完整的标签页管理系统: + +```mermaid +sequenceDiagram +participant Route as 路由 +participant Tabs as 标签页组件 +participant Storage as 会话存储 +participant KeepAlive as 缓存管理 +Route->>Tabs : 路由变化 +Tabs->>Tabs : upsertTab() +Tabs->>Tabs : 更新activeKey +Tabs->>Storage : persist() +Note over Tabs,Storage : 持久化标签页状态 +Tabs->>KeepAlive : include更新 +KeepAlive->>Route : 渲染新页面 +Route-->>Tabs : 页面加载完成 +``` + +**图表来源** +- [frontend/src/components/TabsView.vue:180-191](file://frontend/src/components/TabsView.vue#L180-L191) +- [frontend/src/components/TabsView.vue:276-286](file://frontend/src/components/TabsView.vue#L276-L286) + +#### 标签页持久化机制 + +标签页状态通过sessionStorage进行持久化存储: + +```mermaid +flowchart TD +A[应用启动] --> B[restore()] +B --> C{是否有存储数据} +C --> |是| D[恢复标签页列表] +C --> |否| E[初始化默认标签页] +F[标签页变化] --> G[persist()] +G --> H[序列化数据] +H --> I[写入sessionStorage] +J[页面关闭] --> K[数据保留] +K --> L[下次访问恢复] +``` + +**图表来源** +- [frontend/src/components/TabsView.vue:143-174](file://frontend/src/components/TabsView.vue#L143-L174) +- [frontend/src/components/TabsView.vue:125-141](file://frontend/src/components/TabsView.vue#L125-L141) + +**章节来源** +- [frontend/src/components/TabsView.vue:55-287](file://frontend/src/components/TabsView.vue#L55-L287) + +### 主题系统分析 + +#### 深色主题实现 + +项目采用了基于CSS变量的主题系统: + +```mermaid +graph TB +A[主题变量定义] --> B[:root变量] +B --> C[--lux-page-bg: #0a0e14] +B --> D[--lux-card-bg: #1e293b] +B --> E[--lux-text-strong: #e2e8f0] +F[组件样式] --> G[使用CSS变量] +G --> H[统一颜色管理] +G --> I[主题一致性] +J[运行时切换] --> K[变量值替换] +K --> L[即时主题更新] +``` + +**图表来源** +- [frontend/src/styles/lux-theme.css:10-25](file://frontend/src/styles/lux-theme.css#L10-L25) +- [frontend/src/styles/lux-theme.css:27-35](file://frontend/src/styles/lux-theme.css#L27-L35) + +#### 样式覆盖策略 + +```mermaid +flowchart TD +A[全局样式] --> B[lux-theme.css] +B --> C[组件级样式] +C --> D[scoped样式] +D --> E[深度选择器(:deep)] +E --> F[子组件样式覆盖] +G[主题变量] --> H[--lux-cyan: #38bdf8] +H --> I[统一色彩规范] +I --> J[一致的视觉体验] +``` + +**图表来源** +- [frontend/src/styles/lux-theme.css:352-377](file://frontend/src/styles/lux-theme.css#L352-L377) +- [frontend/src/layout/index.vue:330-336](file://frontend/src/layout/index.vue#L330-L336) + +**章节来源** +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 依赖关系分析 + +### 组件依赖关系 + +```mermaid +graph TD +A[LuxLayout] --> B[SidebarLogo] +A --> C[TabsView] +A --> D[ChangePasswordDialog] +E[Router] --> F[Layout] +F --> G[Views] +H[ElementPlus] --> I[UI组件库] +I --> J[Layout组件] +I --> K[Menu组件] +I --> L[Dropdown组件] +M[Vue Router] --> N[路由导航] +N --> O[权限控制] +P[Auth Utils] --> Q[用户认证] +Q --> R[权限验证] +``` + +**图表来源** +- [frontend/src/layout/index.vue:149-152](file://frontend/src/layout/index.vue#L149-L152) +- [frontend/src/router/index.js:1-5](file://frontend/src/router/index.js#L1-L5) + +### 外部依赖分析 + +项目的主要外部依赖包括: + +| 依赖类型 | 包名 | 版本 | 用途 | +|---------|------|------|------| +| Vue框架 | vue | 最新版 | 响应式框架 | +| UI组件库 | element-plus | 最新版 | 组件基础 | +| 路由管理 | vue-router | 最新版 | 页面导航 | +| 图标系统 | @element-plus/icons-vue | 最新版 | 图标组件 | + +**章节来源** +- [frontend/src/layout/index.vue:144-152](file://frontend/src/layout/index.vue#L144-L152) +- [frontend/src/router/index.js:1-5](file://frontend/src/router/index.js#L1-L5) + +## 性能考虑 + +### 渲染性能优化 + +布局组件在性能方面采用了多项优化策略: + +1. **条件渲染**:侧边栏导航条和菜单根据状态动态显示 +2. **懒加载**:路由级别的组件懒加载 +3. **缓存机制**:标签页内容的KeepAlive缓存 +4. **事件节流**:侧边栏交互事件的处理 + +### 内存管理 + +```mermaid +flowchart TD +A[组件挂载] --> B[初始化状态] +B --> C[注册事件监听] +C --> D[开始渲染] +E[组件卸载] --> F[清理事件监听] +F --> G[释放内存] +G --> H[垃圾回收] +I[标签页切换] --> J[KeepAlive缓存] +J --> K[避免重复渲染] +``` + +**图表来源** +- [frontend/src/components/TabsView.vue:47-49](file://frontend/src/components/TabsView.vue#L47-L49) + +## 故障排除指南 + +### 常见问题及解决方案 + +#### 布局显示异常 + +**问题**:侧边栏宽度不正确 +**原因**:CSS变量未正确加载 +**解决**:检查主题样式文件是否正确引入 + +**问题**:标签页不显示 +**原因**:路由配置错误 +**解决**:验证路由配置和组件导入 + +#### 性能问题 + +**问题**:页面切换卡顿 +**原因**:组件渲染过多 +**解决**:检查KeepAlive配置和组件复杂度 + +**问题**:内存泄漏 +**原因**:事件监听器未清理 +**解决**:确保在组件卸载时清理所有监听器 + +**章节来源** +- [frontend/src/layout/index.vue:173-179](file://frontend/src/layout/index.vue#L173-L179) +- [frontend/src/components/TabsView.vue:276-286](file://frontend/src/components/TabsView.vue#L276-L286) + +## 结论 + +本布局组件展现了现代前端开发的最佳实践,通过精心设计的架构实现了: + +1. **优秀的用户体验**:响应式设计和流畅的交互效果 +2. **可维护性**:清晰的组件分离和模块化设计 +3. **可扩展性**:灵活的主题系统和配置选项 +4. **性能优化**:合理的渲染策略和资源管理 + +该布局组件为整个Dashboard系统提供了坚实的基础,支持未来功能的扩展和定制化需求。通过合理的架构设计和实现细节,确保了系统的稳定性和可维护性。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/页面组件/OTA固件管理页面.md b/.qoder/repowiki/zh/content/前端组件/页面组件/OTA固件管理页面.md new file mode 100644 index 0000000..f7bb1cf --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/页面组件/OTA固件管理页面.md @@ -0,0 +1,388 @@ +# OTA固件管理页面 + + +**本文档引用的文件** +- [Ota.js](file://backend/src/models/Ota.js) +- [ota.js](file://backend/src/routes/ota.js) +- [otaStorage.js](file://backend/src/services/otaStorage.js) +- [index.vue](file://frontend/src/views/ota/index.vue) +- [ota.js](file://frontend/src/api/ota.js) +- [response.js](file://backend/src/utils/response.js) +- [env.js](file://backend/src/config/env.js) +- [request.js](file://frontend/src/utils/request.js) +- [router/index.js](file://frontend/src/router/index.js) +- [DEPLOY.md](file://DEPLOY.md) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文件面向OTA固件管理页面的使用者与维护者,系统性阐述固件版本管理功能,涵盖固件上传、版本控制、强制更新配置、发布状态管理、兼容性检查、更新策略配置、用户通知机制、下载统计、版本历史与回滚功能,以及进度监控、错误处理与用户体验优化方案。文档以仓库现有代码为依据,结合前后端交互流程,提供可操作的实践指导。 + +## 项目结构 +系统采用前后端分离架构,前端使用Vue 3 + Element Plus,后端使用Node.js + Express + Sequelize,数据库为MySQL。OTA模块位于独立的路由与模型中,存储策略针对不同设备型号采用差异化方案(X8上传至S3,X9本地存储)。 + +```mermaid +graph TB +FE["前端界面
views/ota/index.vue"] --> API["API封装
api/ota.js"] +API --> AXIOS["HTTP请求封装
utils/request.js"] +AXIOS --> ROUTER["路由守卫
router/index.js"] +ROUTER --> BE["后端服务
routes/ota.js"] +BE --> MODEL["数据模型
models/Ota.js"] +BE --> STORAGE["存储服务
services/otaStorage.js"] +STORAGE --> ENV["环境配置
config/env.js"] +``` + +图表来源 +- [index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) +- [ota.js:1-68](file://frontend/src/api/ota.js#L1-L68) +- [request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [env.js:1-13](file://backend/src/config/env.js#L1-L13) + +章节来源 +- [index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) +- [ota.js:1-68](file://frontend/src/api/ota.js#L1-L68) +- [request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [env.js:1-13](file://backend/src/config/env.js#L1-L13) + +## 核心组件 +- 前端视图组件:负责搜索、分页、表单校验、上传与CRUD操作,提供友好的用户交互体验。 +- API封装:统一封装GET/POST/PUT/DELETE请求,处理超时与认证头注入。 +- 后端路由:提供OTA版本列表、详情、创建、更新、删除与升级包上传接口。 +- 数据模型:定义OTA版本的数据结构与约束,确保版本号唯一性与字段完整性。 +- 存储服务:根据设备型号选择不同的存储策略(S3/X9本地),并生成公开访问链接。 +- 响应封装:统一返回格式,便于前端处理与展示。 +- 环境配置:区分开发/生产环境,影响存储目录与S3凭据策略。 + +章节来源 +- [index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) +- [ota.js:1-68](file://frontend/src/api/ota.js#L1-L68) +- [ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [env.js:1-13](file://backend/src/config/env.js#L1-L13) + +## 架构总览 +OTA固件管理页面的端到端流程如下: +- 用户在前端页面进行搜索与分页浏览; +- 通过API封装发起HTTP请求; +- 后端路由接收请求,进行鉴权与参数校验; +- 数据模型层保证数据一致性; +- 存储服务根据设备型号执行差异化存储; +- 统一响应格式返回给前端,前端渲染结果。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant FE as "前端视图
index.vue" +participant API as "API封装
api/ota.js" +participant AX as "HTTP封装
utils/request.js" +participant RT as "后端路由
routes/ota.js" +participant MD as "数据模型
models/Ota.js" +participant ST as "存储服务
services/otaStorage.js" +U->>FE : 搜索/分页/新增/编辑 +FE->>API : 调用列表/创建/更新/删除/上传 +API->>AX : 发起HTTP请求 +AX->>RT : 路由处理鉴权/参数校验 +RT->>MD : 查询/写入数据库 +RT->>ST : 上传升级包按设备型号 +ST-->>RT : 返回存储结果URL/MD5/S3Key +RT-->>AX : 统一响应格式 +AX-->>API : 返回数据 +API-->>FE : 渲染结果 +``` + +图表来源 +- [index.vue:420-579](file://frontend/src/views/ota/index.vue#L420-L579) +- [ota.js:13-67](file://frontend/src/api/ota.js#L13-L67) +- [request.js:11-69](file://frontend/src/utils/request.js#L11-L69) +- [ota.js:24-268](file://backend/src/routes/ota.js#L24-L268) +- [Ota.js:4-94](file://backend/src/models/Ota.js#L4-L94) +- [otaStorage.js:46-103](file://backend/src/services/otaStorage.js#L46-L103) + +## 详细组件分析 + +### 前端页面组件(OTA管理) +- 搜索与筛选:支持按版本名称、设备型号、状态、版本号精确/模糊查询。 +- 表格展示:显示版本号、版本名、设备型号、硬件版本、包地址、强升、灰度、状态等字段。 +- 表单与校验:版本号必填且为整数,版本名1-20字符,MD5必须为32位十六进制,下载地址在非上传模式下必填。 +- 上传流程:仅当设备型号为X8/X9时显示上传按钮,自动计算MD5并生成公开下载地址。 +- CRUD操作:支持新增、编辑、复制(基于现有行)、删除,均通过API封装调用后端接口。 +- 分页与加载:支持每页数量切换与页码切换,加载状态通过Element Plus的loading指示。 + +```mermaid +flowchart TD +Start(["进入页面"]) --> LoadData["加载数据
getOtaList()"] +LoadData --> Render["渲染表格与分页"] +Render --> Search["用户输入搜索条件"] +Search --> Apply["应用筛选并重新加载"] +Apply --> Render +Render --> Action{"用户操作"} +Action --> |新增| OpenAdd["打开新增对话框"] +Action --> |编辑| OpenEdit["打开编辑对话框"] +Action --> |复制| CopyRow["复制行数据到表单"] +Action --> |删除| ConfirmDel["确认删除"] +OpenAdd --> Submit["提交表单"] +OpenEdit --> Submit +CopyRow --> Submit +ConfirmDel --> Delete["调用删除接口"] +Submit --> Reload["刷新列表"] +Delete --> Reload +Reload --> Render +``` + +图表来源 +- [index.vue:420-579](file://frontend/src/views/ota/index.vue#L420-L579) +- [ota.js:13-49](file://frontend/src/api/ota.js#L13-L49) + +章节来源 +- [index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) +- [ota.js:1-68](file://frontend/src/api/ota.js#L1-L68) + +### 后端路由与控制器 +- 接口设计: + - 上传升级包:POST /api/ota/upload-package(需登录),支持X8/X9两种设备型号,返回MD5、文件名、URL等。 + - 最新版本检查:GET /api/ota/latest/check(无需登录),设备端调用,返回满足条件的最新版本。 + - 列表查询:GET /api/ota/(需登录),支持分页与多条件过滤。 + - 详情查询:GET /api/ota/:ota_id(需登录)。 + - 创建:POST /api/ota/(需登录),校验版本号唯一性与字段合法性。 + - 更新:PUT /api/ota/:ota_id(需登录),支持部分字段更新与版本号冲突检测。 + - 删除:DELETE /api/ota/:ota_id(需登录)。 +- 参数校验:使用Zod Schema进行严格的字段类型与长度校验。 +- 错误处理:统一使用ApiResponse封装,区分成功、错误与无数据三类返回码。 + +```mermaid +sequenceDiagram +participant FE as "前端" +participant RT as "后端路由
routes/ota.js" +participant VL as "校验器
validators/ota.js" +participant MD as "模型
models/Ota.js" +participant ST as "存储服务
services/otaStorage.js" +FE->>RT : POST /api/ota/upload-package +RT->>VL : 校验请求体 +RT->>ST : 读取内容并计算MD5 +alt X9 +RT->>ST : 本地保存并生成URL +else X8 +RT->>ST : 上传S3并生成URL +end +ST-->>RT : 返回存储结果 +RT-->>FE : ApiResponse.success() +FE->>RT : POST /api/ota/ +RT->>VL : 校验创建Schema +RT->>MD : 检查版本号唯一性 +RT->>MD : 写入数据库 +MD-->>RT : 返回新记录 +RT-->>FE : ApiResponse.success() +``` + +图表来源 +- [ota.js:24-268](file://backend/src/routes/ota.js#L24-L268) +- [ota.js:3-33](file://backend/src/validators/ota.js#L3-L33) +- [Ota.js:4-94](file://backend/src/models/Ota.js#L4-L94) +- [otaStorage.js:46-103](file://backend/src/services/otaStorage.js#L46-L103) + +章节来源 +- [ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +### 数据模型与约束 +- 关键字段: + - verCode:整数版本号,用于排序与比较。 + - verName:版本名称,最大20字符。 + - url:升级包下载地址。 + - md5:32位十六进制MD5值,用于完整性校验。 + - force:是否强制更新(0/1)。 + - model:设备型号(Luxsin-X8/Luxsin-X9)。 + - hw:硬件版本号。 + - target/beta/status:定向发布、灰度发布与启用状态。 + - startTime/endTime:发布时间窗口。 +- 唯一性约束:verCode+model组合唯一,防止重复版本。 +- 默认值:force、target、beta、status等字段提供合理默认值。 + +```mermaid +erDiagram +OTA { +int id PK +int verCode +string verName +string url +string md5 +smallint force +string desc +string model +int hw +smallint target +smallint beta +datetime startTime +datetime endTime +smallint status +datetime create_at +} +``` + +图表来源 +- [Ota.js:4-94](file://backend/src/models/Ota.js#L4-L94) + +章节来源 +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +### 存储策略与安全 +- 设备型号差异化: + - Luxsin-X8:上传至S3,生成公开访问URL,支持显式凭证或IAM角色。 + - Luxsin-X9:保存到本地目录(/data/projects/source),按年月与MD5前缀组织目录结构,生成公开URL。 +- 目录与URL构建: + - X8:S3 Key为 `ota/{YYYYMM}/x8/{md5前5位}/LUXSIN_X8.PKG`,公开URL基于配置拼接。 + - X9:本地路径为 `{OTA_UPLOAD_DIR}/ota/{YYYYMM}/x9/{md5前5位}/LUXSIN.PKG`,公开URL基于配置拼接。 +- 环境变量: + - AWS_REGION、AWS_S3_OTA_BUCKET、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY。 + - OTA_X8_PUBLIC_BASE、OTA_X9_URL_BASE、OTA_UPLOAD_DIR。 + - APP_ENV决定开发/生产环境,影响存储目录与S3凭据策略。 + +```mermaid +flowchart TD +Upload["上传请求"] --> Detect["识别设备型号"] +Detect --> |X8| S3["上传S3"] +Detect --> |X9| Local["本地保存"] +S3 --> BuildX8["构建S3 Key与URL"] +Local --> BuildX9["构建本地路径与URL"] +BuildX8 --> Return["返回MD5/URL/S3Key"] +BuildX9 --> Return +``` + +图表来源 +- [otaStorage.js:46-103](file://backend/src/services/otaStorage.js#L46-L103) +- [env.js:1-13](file://backend/src/config/env.js#L1-L13) + +章节来源 +- [otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [env.js:1-13](file://backend/src/config/env.js#L1-L13) + +### 兼容性检查与更新策略 +- 设备端最新版本检查: + - 接口:GET /api/ota/latest/check,参数包含当前版本号、设备型号与硬件版本。 + - 逻辑:查询状态为可用、版本号大于当前版本、匹配设备型号与硬件版本的最高版本。 + - 结果:若找到则返回该版本信息,否则返回无数据。 +- 强制更新与定向发布: + - 强制更新:force=1时,客户端应阻止用户跳过更新。 + - 定向发布:target=1时,仅对特定用户或设备生效。 + - 灰度发布:beta=1时,按比例或规则逐步放量。 +- 时间窗口: + - startTime/endTime限定发布时间范围,超出范围的版本不应被推送。 + +章节来源 +- [ota.js:68-102](file://backend/src/routes/ota.js#L68-L102) + +### 用户体验与错误处理 +- 前端: + - 加载状态:表格区域整体loading,避免闪烁。 + - 表单校验:实时校验版本号、版本名、MD5与下载地址,错误提示明确。 + - 上传反馈:上传成功后自动填充MD5与URL,失败时给出具体错误信息。 + - 删除确认:二次确认对话框,防止误删。 + - 分页与重置:支持页码与每页数量调整,重置搜索条件。 +- 后端: + - 统一响应格式:code=1成功、code=0错误、code=2无数据。 + - 错误分类:参数错误、业务冲突(版本已存在)、存储异常(S3上传失败)等。 + - 日志记录:关键操作与异常均有日志输出,便于排查。 + +章节来源 +- [index.vue:305-338](file://frontend/src/views/ota/index.vue#L305-L338) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [ota.js:25-66](file://backend/src/routes/ota.js#L25-L66) + +## 依赖关系分析 +- 前端依赖: + - Element Plus:UI组件库,提供表格、表单、对话框、分页等。 + - Axios:HTTP客户端,封装基础URL与拦截器。 + - Vue Router:路由守卫,控制访问权限与超级管理员限制。 +- 后端依赖: + - Express:Web框架,提供REST接口。 + - Sequelize:ORM,连接MySQL并管理模型。 + - Zod:Schema校验,确保请求参数合法。 + - Multer:内存存储上传文件缓冲区。 + - AWS SDK:S3上传能力。 +- 环境变量: + - 前后端共享的关键变量:JWT密钥、数据库连接、S3配置、OTA相关URL与存储目录。 + +```mermaid +graph LR +FE["前端"] --> EP["Element Plus"] +FE --> AX["Axios"] +FE --> VR["Vue Router"] +BE["后端"] --> EX["Express"] +BE --> SQ["Sequelize"] +BE --> ZD["Zod"] +BE --> ML["Multer"] +BE --> AW["AWS SDK"] +``` + +图表来源 +- [request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) +- [otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +章节来源 +- [request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) +- [otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +## 性能考虑 +- 文件上传: + - 使用内存存储缓冲区,适合中小文件;大文件建议分片上传或流式传输。 + - 上传超时设置为5分钟,适用于较大包体的上传场景。 +- 数据查询: + - 列表接口限制每页最大1000条,避免一次性返回过多数据。 + - 搜索条件尽量使用索引字段(如verCode、model、status),减少全表扫描。 +- 存储策略: + - X8使用S3,具备高可用与全球分发优势;X9本地存储需关注磁盘空间与IO瓶颈。 + - 目录按年月与MD5前缀组织,有利于快速定位与清理。 +- 响应格式: + - 统一的响应结构便于前端缓存与错误处理,减少重复解析成本。 + +## 故障排除指南 +- 上传失败: + - 检查设备型号是否在支持列表(Luxsin-X8/Luxsin-X9)。 + - 确认S3配置(区域、桶名、凭据)或本地存储目录权限。 + - 查看后端日志中的错误信息(如S3上传失败)。 +- 版本冲突: + - 创建/更新时提示“该版本已存在”,请修改版本号或设备型号组合。 +- 权限问题: + - 未登录或Token过期时会被重定向到登录页;超级管理员权限不足时会被拒绝访问。 +- 网络异常: + - 前端请求拦截器会捕获401/403错误并提示,同时清除本地认证信息。 +- 页面空白或API失败: + - 检查Nginx代理是否指向后端服务,确认容器健康状态与日志输出。 + +章节来源 +- [ota.js:25-66](file://backend/src/routes/ota.js#L25-L66) +- [request.js:44-69](file://frontend/src/utils/request.js#L44-L69) +- [DEPLOY.md:226-256](file://DEPLOY.md#L226-L256) + +## 结论 +OTA固件管理页面通过清晰的前后端职责划分与统一的响应格式,实现了从版本上传、存储、查询到发布的完整闭环。X8/X9差异化存储策略兼顾了可扩展性与易用性,配合严格的参数校验与完善的错误处理,为设备端的兼容性检查与更新策略提供了可靠支撑。建议在后续迭代中进一步完善下载统计、版本历史与回滚功能,并持续优化上传体验与性能表现。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/页面组件/分享码日志页面.md b/.qoder/repowiki/zh/content/前端组件/页面组件/分享码日志页面.md new file mode 100644 index 0000000..3e53f1b --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/页面组件/分享码日志页面.md @@ -0,0 +1,483 @@ +# 分享码日志页面 + + +**本文档引用的文件** +- [log.vue](file://frontend/src/views/share-code/log.vue) +- [shareCodeLog.js](file://frontend/src/api/shareCodeLog.js) +- [ShareCodeLog.js](file://backend/src/models/ShareCodeLog.js) +- [shareCodeLogs.js](file://backend/src/routes/shareCodeLogs.js) +- [response.js](file://backend/src/utils/response.js) +- [auth.js](file://backend/src/middleware/auth.js) +- [index.js](file://frontend/src/router/index.js) +- [app.js](file://backend/src/app.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +分享码日志页面是音频仪表板系统中的一个重要功能模块,用于记录和分析分享码的使用情况。该页面提供了完整的分享码使用记录查询、筛选和分析功能,包括日志列表展示、时间筛选、用户搜索和统计分析。 + +该系统采用前后端分离架构,前端使用Vue.js框架构建用户界面,后端基于Express.js提供RESTful API服务。通过详细的日志记录,管理员可以追踪每个分享码的完整生命周期,从生成到使用的全过程监控。 + +## 项目结构 + +分享码日志功能涉及前端视图组件和后端API服务两个主要部分: + +```mermaid +graph TB +subgraph "前端层" +FE_View[分享码日志视图
log.vue] +FE_API[API封装
shareCodeLog.js] +FE_Router[路由配置
router/index.js] +end +subgraph "后端层" +BE_Routes[路由处理
shareCodeLogs.js] +BE_Model[数据模型
ShareCodeLog.js] +BE_Utils[响应工具
response.js] +BE_Auth[认证中间件
auth.js] +end +subgraph "数据库层" +DB_Table[分享码日志表
share_code_log] +end +FE_View --> FE_API +FE_API --> BE_Routes +BE_Routes --> BE_Model +BE_Model --> DB_Table +BE_Routes --> BE_Utils +BE_Routes --> BE_Auth +``` + +**图表来源** +- [log.vue:1-353](file://frontend/src/views/share-code/log.vue#L1-L353) +- [shareCodeLog.js:1-26](file://frontend/src/api/shareCodeLog.js#L1-L26) +- [shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) +- [ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) + +**章节来源** +- [log.vue:1-353](file://frontend/src/views/share-code/log.vue#L1-L353) +- [shareCodeLog.js:1-26](file://frontend/src/api/shareCodeLog.js#L1-L26) +- [shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) +- [ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) + +## 核心组件 + +### 前端视图组件 + +分享码日志页面采用Element Plus组件库构建,包含以下核心功能: + +- **搜索表单**:支持MAC地址、分享码、操作类型、IP地址和时间范围的多维度过滤 +- **数据表格**:展示分享码日志的完整信息,包括设备信息、操作详情和时间戳 +- **分页控制**:支持自定义每页条数和页码导航 +- **对话框展示**:提供EQ数据快照的可视化查看功能 + +### 后端API服务 + +后端提供RESTful API接口,实现完整的数据查询和过滤功能: + +- **认证授权**:所有接口均需登录验证 +- **数据查询**:支持多字段组合查询和排序 +- **分页处理**:限制最大查询数量,确保系统性能 +- **响应格式**:统一的API响应格式,便于前端处理 + +**章节来源** +- [log.vue:148-278](file://frontend/src/views/share-code/log.vue#L148-L278) +- [shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) + +## 架构概览 + +分享码日志系统的整体架构采用经典的三层架构设计: + +```mermaid +sequenceDiagram +participant User as 用户 +participant Frontend as 前端应用 +participant API as API网关 +participant Auth as 认证中间件 +participant Route as 路由处理器 +participant Model as 数据模型 +participant DB as 数据库 +User->>Frontend : 访问分享码日志页面 +Frontend->>API : GET /api/share-code/logs +API->>Auth : 验证JWT令牌 +Auth-->>API : 验证通过 +API->>Route : 转发请求 +Route->>Model : 查询数据 +Model->>DB : 执行SQL查询 +DB-->>Model : 返回查询结果 +Model-->>Route : 处理后的数据 +Route-->>API : 统一响应格式 +API-->>Frontend : 返回JSON数据 +Frontend->>Frontend : 渲染表格和分页 +``` + +**图表来源** +- [log.vue:233-250](file://frontend/src/views/share-code/log.vue#L233-L250) +- [shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) +- [auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) + +### 数据流分析 + +系统遵循标准的数据流向模式: + +1. **前端请求**:用户通过搜索表单输入查询条件 +2. **参数构建**:前端将查询条件转换为API参数 +3. **后端处理**:后端解析参数,构建查询条件 +4. **数据库查询**:执行SQL查询,返回结果集 +5. **数据转换**:将数据库结果转换为统一格式 +6. **响应返回**:前端接收并渲染数据 + +**章节来源** +- [log.vue:214-231](file://frontend/src/views/share-code/log.vue#L214-L231) +- [shareCodeLogs.js:31-60](file://backend/src/routes/shareCodeLogs.js#L31-L60) + +## 详细组件分析 + +### 前端组件分析 + +#### 搜索表单组件 + +前端搜索表单提供了丰富的筛选选项: + +```mermaid +classDiagram +class SearchForm { ++string mac_addr ++string share_code ++string action ++string ip_addr ++Array timeRange ++buildQueryParams() Object ++handleSearch() void ++handleReset() void +} +class Pagination { ++number page ++number pageSize ++number total ++handleSizeChange() void ++handlePageChange() void +} +class TableData { ++Array items ++formatDateTime(value) string ++handleViewEq(row) void +} +SearchForm --> Pagination : "使用" +SearchForm --> TableData : "管理" +``` + +**图表来源** +- [log.vue:170-180](file://frontend/src/views/share-code/log.vue#L170-L180) +- [log.vue:159-163](file://frontend/src/views/share-code/log.vue#L159-L163) +- [log.vue:157-158](file://frontend/src/views/share-code/log.vue#L157-L158) + +#### 数据表格组件 + +表格组件展示了分享码日志的完整信息: + +| 字段名 | 显示名称 | 数据类型 | 描述 | +|--------|----------|----------|------| +| id | ID | 整数 | 日志记录唯一标识符 | +| mac_addr | MAC地址 | 字符串 | 设备MAC地址 | +| share_code | 分享码 | 字符串 | 5位分享码 | +| action | 动作类型 | 枚举 | 导出/导入 | +| ip_addr | IP地址 | 字符串 | 用户IP地址 | +| expire_at | 到期时间 | 日期时间 | 分享码到期时间 | +| create_at | 操作时间 | 日期时间 | 操作发生时间 | + +**章节来源** +- [log.vue:78-104](file://frontend/src/views/share-code/log.vue#L78-L104) + +### 后端API分析 + +#### 路由处理逻辑 + +后端路由实现了完整的查询功能: + +```mermaid +flowchart TD +Start([请求到达]) --> ParseParams["解析查询参数"] +ParseParams --> ValidateParams{"参数验证"} +ValidateParams --> |有效| BuildWhere["构建WHERE条件"] +ValidateParams --> |无效| ReturnError["返回错误响应"] +BuildWhere --> SetLimit["设置分页限制"] +SetLimit --> ExecuteQuery["执行数据库查询"] +ExecuteQuery --> CheckResult{"是否有结果"} +CheckResult --> |有| TransformData["转换数据格式"] +CheckResult --> |无| ReturnEmpty["返回空数据响应"] +TransformData --> ReturnSuccess["返回成功响应"] +ReturnError --> End([结束]) +ReturnEmpty --> End +ReturnSuccess --> End +``` + +**图表来源** +- [shareCodeLogs.js:15-84](file://backend/src/routes/shareCodeLogs.js#L15-L84) + +#### 数据模型设计 + +后端数据模型定义了分享码日志的结构: + +```mermaid +erDiagram +SHARE_CODE_LOG { +INTEGER id PK +STRING mac_addr +CHAR(5) share_code +ENUM action +STRING ip_addr +JSON eq_data +DATETIME expire_at +DATETIME create_at +} +INDEX idx_mac_addr ON share_code_log(mac_addr) +INDEX idx_share_code ON share_code_log(share_code) +INDEX idx_create_at ON share_code_log(create_at) +``` + +**图表来源** +- [ShareCodeLog.js:4-56](file://backend/src/models/ShareCodeLog.js#L4-L56) + +**章节来源** +- [shareCodeLogs.js:15-84](file://backend/src/routes/shareCodeLogs.js#L15-L84) +- [ShareCodeLog.js:4-56](file://backend/src/models/ShareCodeLog.js#L4-L56) + +### API接口规范 + +#### 请求参数规范 + +| 参数名 | 类型 | 必填 | 默认值 | 描述 | +|--------|------|------|--------|------| +| skip | number | 否 | 0 | 跳过记录数 | +| limit | number | 否 | 100 | 每页记录数(最大1000) | +| mac_addr | string | 否 | - | MAC地址模糊匹配 | +| share_code | string | 否 | - | 分享码模糊匹配 | +| action | enum | 否 | - | 操作类型:export/import | +| ip_addr | string | 否 | - | IP地址模糊匹配 | +| start_at | string | 否 | - | 开始时间(ISO格式) | +| end_at | string | 否 | - | 结束时间(ISO格式) | +| sort_by | enum | 否 | id | 排序字段:id/create_at | +| sort_order | enum | 否 | desc | 排序方向:asc/desc | + +#### 响应数据结构 + +```mermaid +classDiagram +class ApiResponse { ++number code ++string msg ++Object data ++success(data, msg) ApiResponse ++error(msg, code) ApiResponse ++noData(msg) ApiResponse +} +class PageData { ++Array items ++number total ++number skip ++number limit +} +ApiResponse --> PageData : "包含" +``` + +**图表来源** +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +**章节来源** +- [shareCodeLog.js:3-24](file://frontend/src/api/shareCodeLog.js#L3-L24) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 依赖关系分析 + +### 组件依赖图 + +```mermaid +graph TD +subgraph "前端依赖" +log_vue[log.vue] +share_api[shareCodeLog.js] +router_index[router/index.js] +end +subgraph "后端依赖" +route_handler[shareCodeLogs.js] +data_model[ShareCodeLog.js] +auth_middleware[auth.js] +response_utils[response.js] +app_entry[app.js] +end +log_vue --> share_api +share_api --> route_handler +route_handler --> data_model +route_handler --> auth_middleware +route_handler --> response_utils +app_entry --> route_handler +router_index --> log_vue +``` + +**图表来源** +- [log.vue:154](file://frontend/src/views/share-code/log.vue#L154) +- [shareCodeLog.js:17](file://frontend/src/api/shareCodeLog.js#L17) +- [shareCodeLogs.js:6](file://backend/src/routes/shareCodeLogs.js#L6) +- [ShareCodeLog.js:2](file://backend/src/models/ShareCodeLog.js#L2) +- [auth.js:9](file://backend/src/middleware/auth.js#L9) +- [response.js:8](file://backend/src/utils/response.js#L8) +- [app.js:10](file://backend/src/app.js#L10) + +### 数据流依赖 + +系统各组件之间的数据依赖关系如下: + +1. **前端视图依赖API封装** + - log.vue通过shareCodeLog.js调用后端API + - API封装负责HTTP请求和参数传递 + +2. **API封装依赖后端路由** + - shareCodeLog.js向/share-code/logs发送GET请求 + - 后端路由处理具体业务逻辑 + +3. **后端路由依赖数据模型** + - shareCodeLogs.js使用ShareCodeLog模型进行数据库操作 + - 数据模型定义了表结构和索引 + +4. **认证依赖** + - 所有路由都经过authMiddleware中间件验证 + - 确保只有认证用户可以访问 + +**章节来源** +- [log.vue:154](file://frontend/src/views/share-code/log.vue#L154) +- [shareCodeLog.js:17](file://frontend/src/api/shareCodeLog.js#L17) +- [shareCodeLogs.js:6](file://backend/src/routes/shareCodeLogs.js#L6) + +## 性能考虑 + +### 前端性能优化 + +#### 分页加载机制 +- **默认每页50条记录**:平衡加载速度和用户体验 +- **懒加载策略**:仅在需要时加载下一页数据 +- **虚拟滚动**:对于大量数据时可考虑实现虚拟滚动 + +#### 缓存策略 +- **请求缓存**:对相同查询条件的结果进行缓存 +- **本地存储**:将最近查询结果保存在localStorage中 +- **防抖处理**:搜索输入时添加防抖,避免频繁请求 + +#### 渲染优化 +- **虚拟DOM优化**:合理使用v-if/v-show减少DOM操作 +- **组件拆分**:将大组件拆分为更小的子组件 +- **事件委托**:使用事件委托减少事件监听器数量 + +### 后端性能优化 + +#### 数据库优化 +- **索引优化**:为常用查询字段建立索引 +- **查询优化**:使用LIMIT限制结果集大小 +- **连接池**:合理配置数据库连接池参数 + +#### API优化 +- **响应压缩**:启用Gzip压缩减少传输数据量 +- **超时控制**:设置合理的请求超时时间 +- **并发控制**:限制同时处理的请求数量 + +#### 缓存策略 +- **Redis缓存**:对热点数据进行缓存 +- **CDN加速**:静态资源使用CDN分发 +- **数据库查询缓存**:缓存常用的查询结果 + +### 实时更新机制 + +系统目前采用轮询方式实现数据刷新: + +```mermaid +sequenceDiagram +participant Timer as 定时器 +participant Frontend as 前端 +participant API as API接口 +participant Backend as 后端 +Timer->>Frontend : 触发定时任务 +Frontend->>API : 发送数据刷新请求 +API->>Backend : 查询最新数据 +Backend-->>API : 返回最新数据 +API-->>Frontend : 更新表格内容 +Frontend->>Frontend : 重新渲染界面 +``` + +**图表来源** +- [log.vue:233-250](file://frontend/src/views/share-code/log.vue#L233-L250) + +## 故障排除指南 + +### 常见问题及解决方案 + +#### 登录认证问题 +- **问题**:401未授权错误 +- **原因**:JWT令牌缺失或过期 +- **解决**:重新登录获取新令牌 + +#### 数据查询异常 +- **问题**:查询结果为空 +- **原因**:查询条件过于严格或数据不存在 +- **解决**:放宽查询条件或检查数据源 + +#### 性能问题 +- **问题**:页面加载缓慢 +- **原因**:数据量过大或网络延迟 +- **解决**:调整分页大小或优化查询条件 + +#### 前端渲染问题 +- **问题**:表格显示异常 +- **原因**:数据格式不正确或组件版本冲突 +- **解决**:检查数据格式或更新组件版本 + +### 错误处理机制 + +系统采用统一的错误处理机制: + +```mermaid +flowchart TD +Request[请求发起] --> Validate[参数验证] +Validate --> Validated{验证通过?} +Validated --> |否| ReturnError[返回错误] +Validated --> |是| Process[处理请求] +Process --> Success{处理成功?} +Success --> |否| HandleError[处理错误] +Success --> |是| ReturnSuccess[返回成功] +HandleError --> ReturnError +``` + +**图表来源** +- [shareCodeLogs.js:80-83](file://backend/src/routes/shareCodeLogs.js#L80-L83) + +**章节来源** +- [auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [shareCodeLogs.js:80-83](file://backend/src/routes/shareCodeLogs.js#L80-L83) + +## 结论 + +分享码日志页面是一个功能完整、架构清晰的日志管理系统。通过前后端分离的设计,实现了良好的用户体验和系统性能。 + +### 主要优势 + +1. **功能完整性**:提供了完整的查询、筛选、分页和展示功能 +2. **用户体验**:直观的界面设计和响应式交互 +3. **数据安全**:完善的认证授权机制 +4. **性能优化**:合理的分页策略和数据处理 + +### 改进建议 + +1. **实时更新**:考虑实现WebSocket实现实时数据推送 +2. **数据导出**:增加CSV/Excel格式的数据导出功能 +3. **统计分析**:添加图表化的数据统计和趋势分析 +4. **搜索增强**:支持更复杂的搜索语法和保存常用查询 + +该系统为音频仪表板提供了重要的审计和监控能力,为后续的功能扩展奠定了良好的基础。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/页面组件/品牌管理页面.md b/.qoder/repowiki/zh/content/前端组件/页面组件/品牌管理页面.md new file mode 100644 index 0000000..22ec70c --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/页面组件/品牌管理页面.md @@ -0,0 +1,391 @@ +# 品牌管理页面 + + +**本文档引用的文件** +- [frontend/src/views/brand/index.vue](file://frontend/src/views/brand/index.vue) +- [backend/src/routes/brands.js](file://backend/src/routes/brands.js) +- [backend/src/models/Brand.js](file://backend/src/models/Brand.js) +- [frontend/src/api/brand.js](file://frontend/src/api/brand.js) +- [backend/src/validators/brand.js](file://backend/src/validators/brand.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [frontend/src/utils/auth.js](file://frontend/src/utils/auth.js) +- [frontend/src/layout/index.vue](file://frontend/src/layout/index.vue) +- [frontend/src/styles/lux-theme.css](file://frontend/src/styles/lux-theme.css) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文件为品牌管理页面的完整技术文档,涵盖从前端界面到后端服务的全链路实现细节。重点包括: +- 品牌数据的增删改查(CRUD)功能与交互流程 +- 品牌列表展示、搜索过滤、分页处理与批量操作支持 +- 品牌表单的验证规则、数据绑定与提交流程 +- 图片上传与预览能力(扩展建议) +- 权限控制、数据同步与缓存策略 +- 关联数据处理、级联删除与数据完整性保障 +- 性能优化、用户体验改进与错误处理最佳实践 + +## 项目结构 +品牌管理页面采用前后端分离架构,前端基于 Vue 3 + Element Plus,后端基于 Express + Sequelize,数据库为 MySQL。 + +```mermaid +graph TB +subgraph "前端" +FE_View["品牌视图
frontend/src/views/brand/index.vue"] +FE_API["品牌API封装
frontend/src/api/brand.js"] +FE_Router["路由与鉴权
frontend/src/router/index.js"] +FE_Layout["布局与主题
frontend/src/layout/index.vue
frontend/src/styles/lux-theme.css"] +end +subgraph "后端" +BE_Routes["品牌路由
backend/src/routes/brands.js"] +BE_Model["品牌模型
backend/src/models/Brand.js"] +BE_Validators["品牌校验器
backend/src/validators/brand.js"] +BE_MW_Auth["鉴权中间件
backend/src/middleware/auth.js"] +BE_Utils_Response["响应封装
backend/src/utils/response.js"] +BE_App["应用入口
backend/src/app.js"] +BE_DB["数据库配置
backend/src/config/database.js"] +BE_JWT["JWT工具
backend/src/utils/jwt.js"] +end +FE_View --> FE_API +FE_API --> BE_Routes +BE_Routes --> BE_Model +BE_Routes --> BE_Validators +BE_Routes --> BE_MW_Auth +BE_Routes --> BE_Utils_Response +BE_App --> BE_Routes +BE_App --> BE_DB +FE_Router --> FE_View +FE_Layout --> FE_View +``` + +**图表来源** +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [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/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) + +**章节来源** +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [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) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 核心组件 +- 品牌视图组件:负责渲染搜索表单、品牌表格、分页控件与新增/编辑对话框;封装加载数据、搜索、重置、分页变更、新增、编辑、删除、表单提交等逻辑。 +- 品牌API封装:对后端品牌接口进行统一调用,支持获取列表、获取单条、创建、更新、删除。 +- 品牌路由:定义品牌管理的REST接口,包含鉴权中间件保护。 +- 品牌模型:定义数据库表结构与约束(唯一性、非空等)。 +- 校验器:使用 Zod 定义创建/更新时的数据校验规则。 +- 鉴权中间件:统一处理 Bearer Token 认证与超级管理员权限校验。 +- 响应封装:统一返回格式 code/msg/data,便于前端判断状态。 +- 应用入口:初始化数据库、启动服务、挂载路由。 +- 数据库配置:连接 MySQL,设置方言与日志级别。 +- JWT 工具:生成与解析访问令牌,设置过期时间。 +- 路由守卫:全局鉴权与超级管理员页面访问限制。 +- 布局与主题:深色宇宙风格的主题样式与侧边导航。 + +**章节来源** +- [frontend/src/views/brand/index.vue:109-276](file://frontend/src/views/brand/index.vue#L109-L276) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [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/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 架构总览 +品牌管理页面的请求流从浏览器发起,经由前端路由与API封装,到达后端路由层,再通过模型与数据库完成持久化。鉴权中间件确保接口安全,响应封装统一返回格式。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant V as "品牌视图组件
index.vue" +participant A as "品牌API
brand.js" +participant R as "品牌路由
brands.js" +participant M as "品牌模型
Brand.js" +participant D as "数据库
MySQL" +U->>V : 打开品牌管理页面 +V->>A : 调用 getBrands(params) +A->>R : GET /api/brands/ +R->>M : findAndCountAll(where, offset, limit) +M->>D : 查询品牌数据 +D-->>M : 返回数据与总数 +M-->>R : 映射为items与total +R-->>A : ApiResponse.success({items,total}) +A-->>V : 返回数据并更新表格与分页 +V-->>U : 展示品牌列表 +U->>V : 点击“新增/编辑” +V->>A : 调用 createBrand 或 updateBrand +A->>R : POST/PUT /api/brands/ +R->>M : create/update +M->>D : 写入/更新 +D-->>M : 成功 +M-->>R : 返回新/更新后的品牌 +R-->>A : ApiResponse.success(...) +A-->>V : 成功提示并刷新列表 +``` + +**图表来源** +- [frontend/src/views/brand/index.vue:146-275](file://frontend/src/views/brand/index.vue#L146-L275) +- [frontend/src/api/brand.js:10-65](file://frontend/src/api/brand.js#L10-L65) +- [backend/src/routes/brands.js:14-144](file://backend/src/routes/brands.js#L14-L144) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +## 详细组件分析 + +### 品牌视图组件(index.vue) +- 搜索与过滤 + - 支持按品牌名称模糊查询,清空后重置分页至第1页。 + - 搜索触发后自动刷新列表。 +- 分页处理 + - 使用 Element Plus 分页组件,支持页大小切换与页码跳转。 + - 分页变更时重新加载数据。 +- 列表展示 + - 展示ID与品牌名称,右侧固定操作列包含“编辑”“删除”按钮。 +- 表单与对话框 + - 新增/编辑共用对话框,表单包含品牌名称字段与必填校验。 + - 提交前进行表单校验,根据是否存在id选择创建或更新。 +- 删除流程 + - 弹出确认对话框,确认后调用删除接口并提示结果,随后刷新列表。 + +```mermaid +flowchart TD +Start(["进入品牌管理"]) --> Load["加载数据
getBrands(skip,limit,name)"] +Load --> Render["渲染表格与分页"] +Render --> Search["搜索/重置"] +Search --> Load +Render --> AddEdit["新增/编辑"] +AddEdit --> Validate["表单校验"] +Validate --> |通过| Submit["提交创建/更新"] +Validate --> |失败| ShowError["显示错误提示"] +Submit --> Refresh["刷新列表"] +Render --> Delete["删除"] +Delete --> Confirm{"确认删除?"} +Confirm --> |是| DelCall["调用 deleteBrand"] +DelCall --> Refresh +Confirm --> |否| Render +``` + +**图表来源** +- [frontend/src/views/brand/index.vue:146-275](file://frontend/src/views/brand/index.vue#L146-L275) + +**章节来源** +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) + +### 品牌API封装(brand.js) +- 提供 getBrands、getBrand、createBrand、updateBrand、deleteBrand 方法,分别对应列表查询、详情查询、创建、更新、删除。 +- 统一使用 request 封装,隐藏底层HTTP细节。 + +**章节来源** +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) + +### 品牌路由(brands.js) +- 接口保护:所有品牌接口均受鉴权中间件保护。 +- 列表查询:支持 skip/limit 分页与 name 模糊过滤,最大limit限制为1000。 +- 单条查询:按id查询,不存在时返回无数据响应。 +- 创建:校验名称非空且唯一,创建成功返回新建品牌信息。 +- 更新:校验名称非空(可选传入),若修改名称需保证唯一性。 +- 删除:按id删除,不存在则返回无数据响应。 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant G as "GET /api/brands/" +participant F as "findAndCountAll" +participant DB as "MySQL" +C->>G : 请求列表(含skip/limit/name) +G->>F : 构建where条件与分页 +F->>DB : 查询 +DB-->>F : rows,count +F-->>G : items,total +G-->>C : ApiResponse.success({items,total}) +``` + +**图表来源** +- [backend/src/routes/brands.js:14-40](file://backend/src/routes/brands.js#L14-L40) + +**章节来源** +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) + +### 品牌模型(Brand.js) +- 字段:id(自增主键)、name(字符串,唯一且非空)。 +- 表名:brand,注释为“耳机品牌”。 + +**章节来源** +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +### 校验器(brand.js) +- 创建:要求 name 非空且长度不超过100字符。 +- 更新:name 可选,但若提供则长度不超过100字符。 + +**章节来源** +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) + +### 鉴权中间件与路由守卫 +- 后端:authMiddleware 校验 Authorization 头是否为 Bearer Token,并解析用户信息注入到 req.user;requireSuperAdmin 用于超级管理员页面访问控制。 +- 前端:路由守卫在进入受保护页面前检查本地Token有效性与过期状态;当页面meta标记为 requiresSuperAdmin 时进一步校验用户角色。 + +```mermaid +sequenceDiagram +participant R as "路由守卫" +participant T as "Token工具" +participant A as "鉴权中间件" +participant S as "超级管理员校验" +R->>T : 检查Token存在与未过期 +alt 未登录或过期 +R-->>R : 清理认证并跳转登录 +else 已登录 +R->>A : 校验Bearer Token +A-->>R : 注入req.user +R->>S : 若需超级管理员则校验 +S-->>R : 通过则放行 +end +``` + +**图表来源** +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +**章节来源** +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +### 响应封装与应用入口 +- ApiResponse:统一返回 code/msg/data 结构,便于前端分支处理。 +- 应用入口:初始化数据库、同步表结构、启动服务并挂载路由。 + +**章节来源** +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) + +### 数据库与JWT配置 +- 数据库:使用 Sequelize 连接 MySQL,开发模式下输出SQL日志,禁用时间戳与冻结表名。 +- JWT:使用 HS256 算法,Token有效期12小时,提供签名与解码工具。 + +**章节来源** +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) + +### 布局与主题 +- 深色宇宙风格主题,适配品牌管理页面的视觉体验。 +- 侧边导航集成品牌管理入口,面包屑与标题动态生成。 + +**章节来源** +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 依赖关系分析 +- 前端视图依赖API封装,API封装依赖request工具。 +- 品牌路由依赖鉴权中间件、响应封装与模型。 +- 模型依赖数据库配置。 +- 应用入口依赖路由与数据库配置。 + +```mermaid +graph LR +V["品牌视图
index.vue"] --> API["品牌API
brand.js"] +API --> Routes["品牌路由
brands.js"] +Routes --> MW["鉴权中间件
auth.js"] +Routes --> Resp["响应封装
response.js"] +Routes --> Model["品牌模型
Brand.js"] +Model --> DB["数据库配置
database.js"] +App["应用入口
app.js"] --> Routes +App --> DB +``` + +**图表来源** +- [frontend/src/views/brand/index.vue:113-113](file://frontend/src/views/brand/index.vue#L113-L113) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [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/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) + +**章节来源** +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [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/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) + +## 性能考虑 +- 分页与查询 + - 后端对 limit 设置上限(1000),避免过大请求导致数据库压力。 + - 前端分页参数与搜索条件组合,减少不必要的全量查询。 +- 响应与渲染 + - 列表加载时使用局部loading遮罩,避免整页闪烁。 + - 表格数据项精简,仅传输必要字段(id、name)。 +- 缓存策略 + - 当前未实现专用缓存层;可在网关或Redis层引入读缓存,写操作采用“先写后删”策略,降低数据库热点。 +- 并发与幂等 + - 提交按钮增加loading状态,防止重复提交。 + - 后端接口对重复名称进行唯一性校验,避免脏数据。 +- 用户体验 + - 搜索支持清空重置,提升可用性。 + - 对话框内表单即时校验,减少往返。 + +[本节为通用指导,不直接分析具体文件,故无“章节来源”] + +## 故障排除指南 +- 登录态异常 + - 前端:检查本地Token是否存在与是否过期;过期则清理并跳转登录。 + - 后端:鉴权中间件返回401时,确认Authorization头格式与签名有效。 +- 权限不足 + - 超级管理员页面访问被拒绝时,确认用户角色与路由meta配置。 +- 数据库问题 + - 启动阶段同步表结构失败时,检查数据库连接参数与权限。 +- 接口返回异常 + - 统一响应code=0或2表示错误或无数据,前端据此提示并记录日志。 + +**章节来源** +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/app.js:42-56](file://backend/src/app.js#L42-L56) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 结论 +品牌管理页面实现了完整的CRUD闭环,具备良好的鉴权与响应一致性。当前版本聚焦基础功能,后续可扩展批量操作、图片上传与预览、关联数据的级联处理与数据完整性校验、以及缓存与性能优化方案,以满足更复杂的业务场景与更高的用户体验要求。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/页面组件/型号管理页面.md b/.qoder/repowiki/zh/content/前端组件/页面组件/型号管理页面.md new file mode 100644 index 0000000..a3c6a8d --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/页面组件/型号管理页面.md @@ -0,0 +1,408 @@ +# 型号管理页面 + + +**本文档引用的文件** +- [frontend/src/views/model/index.vue](file://frontend/src/views/model/index.vue) +- [backend/src/routes/models.js](file://backend/src/routes/models.js) +- [backend/src/models/Model.js](file://backend/src/models/Model.js) +- [backend/src/validators/model.js](file://backend/src/validators/model.js) +- [frontend/src/api/model.js](file://frontend/src/api/model.js) +- [frontend/src/api/brand.js](file://frontend/src/api/brand.js) +- [backend/src/models/Brand.js](file://backend/src/models/Brand.js) +- [backend/src/routes/brands.js](file://backend/src/routes/brands.js) +- [backend/src/services/measurementStorage.js](file://backend/src/services/measurementStorage.js) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [frontend/src/utils/request.js](file://frontend/src/utils/request.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件面向“型号管理页面”的技术实现与使用说明,覆盖以下关键能力: +- 型号列表展示、搜索过滤、排序与分页 +- 型号详情查看与参数配置 +- 型号表单的数据结构、字段验证与复杂表单处理(含频响文件上传) +- 型号与品牌的关联关系、级联数据管理与外键约束处理 +- 型号参数的动态配置、数据格式验证与存储优化 +- 批量操作(复制、推送搜索)的实现方案 + +## 项目结构 +型号管理页面位于前端单页应用中,后端提供 REST 接口与数据模型支撑,前端通过 API 模块与后端交互。 + +```mermaid +graph TB +subgraph "前端" +FE_Model["型号视图
frontend/src/views/model/index.vue"] +FE_API_Model["型号 API
frontend/src/api/model.js"] +FE_API_Brand["品牌 API
frontend/src/api/brand.js"] +FE_Request["请求封装
frontend/src/utils/request.js"] +FE_Router["路由
frontend/src/router/index.js"] +end +subgraph "后端" +BE_Routes_Models["型号路由
backend/src/routes/models.js"] +BE_Models_Model["型号模型
backend/src/models/Model.js"] +BE_Validators_Model["型号校验器
backend/src/validators/model.js"] +BE_Routes_Brands["品牌路由
backend/src/routes/brands.js"] +BE_Models_Brand["品牌模型
backend/src/models/Brand.js"] +BE_Services_Measure["频响存储服务
backend/src/services/measurementStorage.js"] +BE_Services_EQ["EQ 缓存服务
backend/src/services/eqCacheStorage.js"] +end +FE_Model --> FE_API_Model +FE_Model --> FE_API_Brand +FE_API_Model --> FE_Request +FE_API_Brand --> FE_Request +FE_Router --> FE_Model +FE_API_Model --> BE_Routes_Models +FE_API_Brand --> BE_Routes_Brands +BE_Routes_Models --> BE_Models_Model +BE_Routes_Models --> BE_Validators_Model +BE_Routes_Models --> BE_Services_Measure +BE_Routes_Models --> BE_Services_EQ +BE_Routes_Brands --> BE_Models_Brand +``` + +图表来源 +- [frontend/src/views/model/index.vue:1-1575](file://frontend/src/views/model/index.vue#L1-L1575) +- [frontend/src/api/model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [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/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +章节来源 +- [frontend/src/views/model/index.vue:1-1575](file://frontend/src/views/model/index.vue#L1-L1575) +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) + +## 核心组件 +- 前端视图组件:负责渲染列表、表单、对话框、分页与批量操作,并通过 API 模块与后端交互。 +- 前端 API 模块:封装型号与品牌相关的 HTTP 请求,统一处理 Content-Type 与超时策略。 +- 后端路由:提供型号与品牌的 CRUD、搜索、排序、分页、推送搜索校验与推送、频响文件与 EQ 缓存查询等接口。 +- 数据模型:定义型号与品牌的数据结构、字段类型与约束。 +- 服务层:频响文件上传至 S3、EQ 缓存读取 Redis。 + +章节来源 +- [frontend/src/views/model/index.vue:1-1575](file://frontend/src/views/model/index.vue#L1-L1575) +- [frontend/src/api/model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +## 架构总览 +型号管理页面采用前后端分离架构,前端通过 Element Plus 组件与 Axios 进行交互,后端基于 Express 提供 REST 接口,数据持久化使用 Sequelize ORM,外部集成 S3 与 Redis。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant V as "型号视图
index.vue" +participant A as "API 模块
model.js/brand.js" +participant R as "后端路由
models.js/brands.js" +participant M as "模型
Model.js/Brand.js" +participant S3 as "S3 存储" +participant EQ as "Redis 缓存" +U->>V : 打开型号管理页面 +V->>A : 加载品牌列表 +A->>R : GET /api/brands/ +R->>M : 查询品牌 +M-->>R : 品牌数据 +R-->>A : 品牌列表 +A-->>V : 渲染品牌下拉 +U->>V : 搜索/排序/分页 +V->>A : 获取型号列表 +A->>R : GET /api/models/ +R->>M : 分页查询型号 +M-->>R : 型号数据 +R-->>A : 列表与总数 +A-->>V : 渲染表格 +U->>V : 新增/编辑型号 +V->>A : 提交表单含文件上传 +A->>R : POST/PUT /api/models/ +R->>S3 : 上传频响文件CSV/TXT/JSON +S3-->>R : S3 Key +R->>M : 保存型号记录 +M-->>R : 新建/更新结果 +R-->>A : 成功响应 +A-->>V : 关闭对话框并刷新列表 +``` + +图表来源 +- [frontend/src/views/model/index.vue:1-1575](file://frontend/src/views/model/index.vue#L1-L1575) +- [frontend/src/api/model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +## 详细组件分析 + +### 型号数据模型与表单结构 +- 数据模型字段 + - 主键:自增整型 ID + - 品牌名称:字符串,最大 100 字符,必填 + - 型号名称:字符串,最大 100 字符,必填 + - 形式:字符串,最大 100 字符,可空(入耳式/头戴式/耳塞式) + - 阻抗:字符串,最大 100 字符,可空 + - 来源:字符串,最大 100 字符,可空 + - EQ 键:字符串,最大 255 字符,可空 + - 创建时间:日期,默认当前时间 +- 表单字段与验证 + - 品牌名称:必填 + - 型号名称:必填,长度 1-100 + - 形式:可选枚举值 + - 阻抗:可选 + - 来源:可选 + - 频响文件:可选上传,支持 CSV/TXT/JSON,TXT 自动转换为 CSV +- 复杂表单处理 + - 文件上传采用 multipart/form-data + - 新增时若品牌不存在,先尝试创建品牌再保存型号 + - 文件名解析:优先按品牌接口返回的品牌名进行最长前缀匹配,否则按首个空格拆分 + +章节来源 +- [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) +- [frontend/src/views/model/index.vue:578-777](file://frontend/src/views/model/index.vue#L578-L777) +- [backend/src/routes/models.js:306-436](file://backend/src/routes/models.js#L306-L436) + +### 品牌关联与外键约束 +- 品牌模型 + - 主键:自增整型 ID + - 名称:唯一、非空、最大 100 字符 +- 型号与品牌的关系 + - 前端通过品牌下拉选择型号所属品牌 + - 后端在新增/编辑时检查品牌是否存在,不存在则创建 + - 当前模型字段为字符串类型的“品牌名称”,未建立显式的外键约束 +- 级联与一致性 + - 若后续迁移为外键关联,建议在数据库层面添加约束,并在删除品牌时处理级联或阻止删除 + +章节来源 +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [frontend/src/views/model/index.vue:664-693](file://frontend/src/views/model/index.vue#L664-L693) + +### 搜索过滤、排序与分页 +- 搜索条件 + - 品牌名称(模糊匹配) + - 型号名称(模糊匹配) +- 排序 + - 支持按 ID 与创建时间排序,升序/降序切换 +- 分页 + - 页面大小:10/20/50/100 + - 当前页变更时重置为第一页并重新加载 +- 后端实现 + - 使用 Sequelize 查询构建 where 条件与 order 排序 + - 限制每页最大 1000 条,总数统计用于分页控件 + +章节来源 +- [frontend/src/views/model/index.vue:541-550](file://frontend/src/views/model/index.vue#L541-L550) +- [frontend/src/views/model/index.vue:695-711](file://frontend/src/views/model/index.vue#L695-L711) +- [backend/src/routes/models.js:133-181](file://backend/src/routes/models.js#L133-L181) + +### 批量操作与推送搜索 +- 批量复制 + - 支持复制所选项的“品牌+型号”文本 +- 推送搜索 + - 校验:对选中型号调用曲线校验服务,返回校验失败项 + - 推送:将型号数据批量写入 Meilisearch 索引 + - 进度弹窗:显示校验与推送步骤状态、当前处理项与错误明细 +- 多媒体资源 + - 查看 EQ 缓存:读取 Redis Hash 字段,支持展开查看 JSON 结构 + - 查看 CSV:仅支持来源为特定值的型号,按佩戴方式拼接 S3 Key 并读取 + +```mermaid +sequenceDiagram +participant U as "用户" +participant V as "型号视图" +participant A as "API 模块" +participant R as "后端路由" +participant C as "曲线校验服务" +participant MS as "Meilisearch" +U->>V : 选择多个型号并点击“推送搜索” +V->>A : validatePushToMeilisearch(ids) +A->>R : POST /api/models/push-to-search/validate +R->>C : 校验曲线数据 +C-->>R : 校验结果 +R-->>A : 校验错误列表或通过 +A-->>V : 显示校验结果 +U->>V : 确认推送 +V->>A : pushToMeilisearch(ids) +A->>R : POST /api/models/push-to-search +R->>MS : 写入索引 +MS-->>R : 任务 UID +R-->>A : 推送结果 +A-->>V : 关闭进度弹窗并刷新 +``` + +图表来源 +- [frontend/src/views/model/index.vue:1-1575](file://frontend/src/views/model/index.vue#L1-L1575) +- [frontend/src/api/model.js:128-150](file://frontend/src/api/model.js#L128-L150) +- [backend/src/routes/models.js:466-566](file://backend/src/routes/models.js#L466-L566) + +章节来源 +- [frontend/src/views/model/index.vue:1-1575](file://frontend/src/views/model/index.vue#L1-L1575) +- [frontend/src/api/model.js:128-150](file://frontend/src/api/model.js#L128-L150) +- [backend/src/routes/models.js:466-566](file://backend/src/routes/models.js#L466-L566) + +### 频响文件上传与存储优化 +- 支持格式 + - CSV、TXT、JSON + - TXT 自动转换为 CSV(保留频率与幅度列) +- 存储路径 + - S3 Key 规则:autoeq/measurements/{source}/data/{form}/{brandFirstChar}/{brand model}.csv + - 上传成功后将 S3 Key 与型号记录关联 +- 读取与展示 + - 仅对特定来源与完整字段的型号允许读取 S3 中的 CSV 内容 + - 提供弹窗展示 CSV 文本内容 + +章节来源 +- [backend/src/routes/models.js:59-68](file://backend/src/routes/models.js#L59-L68) +- [backend/src/services/measurementStorage.js:48-108](file://backend/src/services/measurementStorage.js#L48-L108) +- [backend/src/routes/models.js:246-278](file://backend/src/routes/models.js#L246-L278) + +### EQ 缓存查看与动态配置 +- Redis Key 规则:{品牌名称} {型号名称} +- 功能 + - 列出可用的 Hash Key + - 展示指定 Key 的 JSON 值(带层级与图标) + - 支持加载状态指示与空状态提示 +- 适用场景 + - 动态配置 EQ 参数、调试频响数据结构 + +章节来源 +- [backend/src/services/eqCacheStorage.js:24-66](file://backend/src/services/eqCacheStorage.js#L24-L66) +- [backend/src/routes/models.js:183-223](file://backend/src/routes/models.js#L183-L223) +- [frontend/src/views/model/index.vue:303-383](file://frontend/src/views/model/index.vue#L303-L383) + +### 表单字段解析与文件名智能填充 +- 文件名预处理:去除扩展名、合并多余空格 +- 品牌解析策略 + - 优先使用品牌接口返回的品牌名进行最长前缀匹配(支持多词品牌) + - 回退为“第一个空格”左侧为品牌、右侧为型号 +- 默认阻抗:新增时若未填写,按规则自动填充 + +章节来源 +- [frontend/src/views/model/index.vue:588-637](file://frontend/src/views/model/index.vue#L588-L637) +- [frontend/src/views/model/index.vue:640-655](file://frontend/src/views/model/index.vue#L640-L655) + +## 依赖关系分析 +- 前端依赖 + - Element Plus UI 组件库 + - Axios 请求封装 + - Vue Router 路由守卫 +- 后端依赖 + - Express 路由 + - Sequelize ORM + - AWS SDK(S3) + - Redis 客户端 + - Meilisearch 客户端 + +```mermaid +graph LR +FE_View["前端视图
index.vue"] --> FE_API["前端 API
model.js/brand.js"] +FE_API --> FE_Request["请求封装
request.js"] +FE_API --> BE_Routes["后端路由
models.js/brands.js"] +BE_Routes --> BE_Models["数据模型
Model.js/Brand.js"] +BE_Routes --> BE_Services["服务层
measurementStorage.js/eqCacheStorage.js"] +BE_Routes --> S3["S3 存储"] +BE_Routes --> Redis["Redis 缓存"] +BE_Routes --> MS["Meilisearch"] +``` + +图表来源 +- [frontend/src/views/model/index.vue:1-1575](file://frontend/src/views/model/index.vue#L1-L1575) +- [frontend/src/api/model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +章节来源 +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) + +## 性能考虑 +- 分页与排序 + - 后端限制每页最大 1000 条,避免一次性传输大量数据 + - 排序字段限定为 ID 与创建时间,减少复杂索引需求 +- 文件上传 + - 仅允许特定格式,TXT 自动转换降低客户端处理成本 + - S3 上传采用内存存储,注意控制文件大小与并发 +- 缓存与索引 + - EQ 缓存仅列出 Hash Key,避免一次性返回大体积 JSON + - 推送搜索采用异步任务与进度弹窗,提升用户体验 + +## 故障排查指南 +- 登录与鉴权 + - 401:令牌失效或缺失,自动跳转登录页 + - 403:无权限执行操作 +- 网络与超时 + - 请求超时:检查后端服务与网络连通性 + - 响应错误:查看控制台日志与消息提示 +- 品牌与型号 + - 品牌名称重复:确保品牌唯一性 + - 型号重复:同一品牌下型号名称唯一 +- 文件上传 + - 不支持的文件格式:确认扩展名为 CSV/TXT/JSON + - TXT 转换失败:检查文件内容格式是否符合预期 +- S3 与 Redis + - 读取失败:确认 S3 Key 是否正确、对象是否存在 + - 缓存为空:确认型号 EQ 缓存是否已生成 + +章节来源 +- [frontend/src/utils/request.js:27-69](file://frontend/src/utils/request.js#L27-L69) +- [backend/src/routes/brands.js:59-81](file://backend/src/routes/brands.js#L59-L81) +- [backend/src/routes/models.js:306-361](file://backend/src/routes/models.js#L306-L361) +- [backend/src/services/measurementStorage.js:87-108](file://backend/src/services/measurementStorage.js#L87-L108) +- [backend/src/services/eqCacheStorage.js:47-66](file://backend/src/services/eqCacheStorage.js#L47-L66) + +## 结论 +型号管理页面提供了完整的型号生命周期管理能力:从列表检索、表单录入与校验,到文件上传与外部系统集成(S3、Redis、Meilisearch),再到批量操作与可视化展示。当前实现以字符串关联品牌,具备良好的扩展性;建议在后续版本中引入外键约束与更严格的级联策略,进一步提升数据一致性与安全性。 + +## 附录 +- API 一览 + - 获取型号列表:GET /api/models/ + - 获取单个型号:GET /api/models/:id + - 创建型号:POST /api/models/ + - 更新型号:PUT /api/models/:id + - 删除型号:DELETE /api/models/:id + - 推送搜索校验:POST /api/models/push-to-search/validate + - 推送搜索:POST /api/models/push-to-search + - 查看 Meilisearch 推送:GET /api/models/:id/meilisearch + - 查看频响 CSV:GET /api/models/:id/measurement + - 查看 EQ 缓存:GET /api/models/:id/eq-cache + - 查看 EQ 缓存字段:GET /api/models/:id/eq-cache/field?key=... + - 获取品牌列表:GET /api/brands/ + - 获取单个品牌:GET /api/brands/:id + - 创建品牌:POST /api/brands/ + - 更新品牌:PUT /api/brands/:id + - 删除品牌:DELETE /api/brands/:id + +章节来源 +- [frontend/src/api/model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/routes/models.js:133-566](file://backend/src/routes/models.js#L133-L566) +- [backend/src/routes/brands.js:14-147](file://backend/src/routes/brands.js#L14-L147) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/页面组件/登录页面.md b/.qoder/repowiki/zh/content/前端组件/页面组件/登录页面.md new file mode 100644 index 0000000..1261019 --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/页面组件/登录页面.md @@ -0,0 +1,480 @@ +# 登录页面 + + +**本文档引用的文件** +- [frontend/src/views/login/index.vue](file://frontend/src/views/login/index.vue) +- [frontend/src/api/auth.js](file://frontend/src/api/auth.js) +- [frontend/src/utils/auth.js](file://frontend/src/utils/auth.js) +- [frontend/src/utils/request.js](file://frontend/src/utils/request.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [frontend/src/utils/tabs.js](file://frontend/src/utils/tabs.js) +- [backend/src/routes/auth.js](file://backend/src/routes/auth.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文件面向登录页面的完整技术文档,涵盖前端登录表单设计、字段验证、提交处理与响应处理;后端认证机制、JWT 令牌生成与校验;登录状态持久化与路由守卫;安全措施(密码哈希、防暴力破解思路、会话管理);登录成功后的路由跳转、权限检查与用户信息初始化流程;错误处理、用户体验优化与移动端适配等实现细节。 + +## 项目结构 +登录功能涉及前后端协作:前端负责表单渲染、输入校验、请求发送与状态持久化;后端负责用户鉴权、密码校验、JWT 签发与中间件保护。 + +```mermaid +graph TB +subgraph "前端" +LoginView["登录视图
frontend/src/views/login/index.vue"] +AuthAPI["认证 API
frontend/src/api/auth.js"] +AuthUtil["认证工具
frontend/src/utils/auth.js"] +RequestUtil["HTTP 请求封装
frontend/src/utils/request.js"] +Router["路由守卫
frontend/src/router/index.js"] +TabsUtil["标签页工具
frontend/src/utils/tabs.js"] +end +subgraph "后端" +AuthRoute["认证路由
backend/src/routes/auth.js"] +JWTUtil["JWT 工具
backend/src/utils/jwt.js"] +PasswordUtil["密码工具
backend/src/utils/password.js"] +AuthMW["认证中间件
backend/src/middleware/auth.js"] +RespUtil["响应封装
backend/src/utils/response.js"] +end +LoginView --> AuthAPI +AuthAPI --> RequestUtil +RequestUtil --> AuthRoute +AuthRoute --> JWTUtil +AuthRoute --> PasswordUtil +AuthRoute --> RespUtil +RequestUtil --> AuthUtil +Router --> AuthUtil +Router --> TabsUtil +AuthRoute --> AuthMW +``` + +图表来源 +- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151) +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +章节来源 +- [frontend/src/views/login/index.vue:1-453](file://frontend/src/views/login/index.vue#L1-L453) +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +## 核心组件 +- 登录视图:负责表单渲染、字段校验、提交处理与成功/失败反馈。 +- 认证 API:封装登录接口调用,统一请求参数格式。 +- 认证工具:负责本地 Token 与用户信息的读取、设置、清理与解析。 +- 请求封装:全局注入 Authorization 头、处理 401 自动跳转登录。 +- 路由守卫:控制访问权限、超时自动登出、超级管理员限制。 +- 后端认证路由:处理登录、获取当前用户、修改密码。 +- JWT 工具:签发与解码 Access Token,定义 TTL。 +- 密码工具:PBKDF2 哈希与安全比对。 +- 认证中间件:校验 Bearer Token 并注入用户上下文。 + +章节来源 +- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151) +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [backend/src/routes/auth.js:24-77](file://backend/src/routes/auth.js#L24-L77) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +## 架构总览 +登录流程在前后端之间形成闭环:前端收集凭据并发起登录请求,后端验证用户与密码,签发 JWT,前端保存 Token 并重定向到首页;后续请求通过请求拦截器携带 Token,后端中间件校验并注入用户信息。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant LV as "登录视图
index.vue" +participant API as "认证 API
auth.js" +participant REQ as "请求封装
request.js" +participant AR as "认证路由
routes/auth.js" +participant PW as "密码工具
password.js" +participant JW as "JWT 工具
jwt.js" +participant AU as "认证工具
utils/auth.js" +participant RT as "路由守卫
router/index.js" +U->>LV : 输入账号/密码并点击登录 +LV->>LV : 表单校验 +LV->>API : 调用登录接口 +API->>REQ : 发送 POST /api/auth/login +REQ->>AR : 携带 Authorization非登录时 +AR->>PW : 验证密码 +AR->>JW : 签发 Access Token +AR-->>REQ : 返回 {access_token, user, expires_in} +REQ-->>LV : 返回响应数据 +LV->>AU : setToken(access_token) +LV->>AU : setUser(user) +LV->>RT : 清空标签页缓存并跳转首页 +``` + +图表来源 +- [frontend/src/views/login/index.vue:123-150](file://frontend/src/views/login/index.vue#L123-L150) +- [frontend/src/api/auth.js:3-12](file://frontend/src/api/auth.js#L3-L12) +- [frontend/src/utils/request.js:12-25](file://frontend/src/utils/request.js#L12-L25) +- [backend/src/routes/auth.js:24-64](file://backend/src/routes/auth.js#L24-L64) +- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34) +- [backend/src/utils/jwt.js:7-17](file://backend/src/utils/jwt.js#L7-L17) +- [frontend/src/utils/auth.js:8-26](file://frontend/src/utils/auth.js#L8-L26) +- [frontend/src/router/index.js:82-85](file://frontend/src/router/index.js#L82-L85) + +## 详细组件分析 + +### 登录视图(表单设计与交互) +- 表单字段: + - 账号:必填,自动去除首尾空白。 + - 密码:必填,支持显示/隐藏切换,回车触发提交。 +- 校验规则:账号与密码均为必填项。 +- 提交流程: + - 触发校验,通过后进入加载态。 + - 调用登录 API,接收响应后: + - 若返回 access_token,则保存 Token 与用户信息,清空标签页缓存,跳转首页。 + - 否则提示失败消息。 + - 最终关闭加载态。 + +```mermaid +flowchart TD +Start(["开始"]) --> Validate["表单校验"] +Validate --> Valid{"校验通过?"} +Valid --> |否| ShowError["显示错误提示"] +Valid --> |是| Loading["设置加载态"] +Loading --> CallAPI["调用登录 API"] +CallAPI --> RespOK{"响应包含 access_token?"} +RespOK --> |是| SaveToken["保存 Token 与用户信息"] +SaveToken --> ClearTabs["清空标签页缓存"] +ClearTabs --> Redirect["跳转首页"] +RespOK --> |否| Toast["提示失败消息"] +Toast --> End(["结束"]) +Redirect --> End +ShowError --> End +``` + +图表来源 +- [frontend/src/views/login/index.vue:118-150](file://frontend/src/views/login/index.vue#L118-L150) + +章节来源 +- [frontend/src/views/login/index.vue:45-91](file://frontend/src/views/login/index.vue#L45-L91) +- [frontend/src/views/login/index.vue:118-150](file://frontend/src/views/login/index.vue#L118-L150) + +### 认证 API 与请求封装 +- 认证 API: + - 登录接口:POST /api/auth/login,参数包含 username 与 password。 + - 修改密码接口:PUT /api/auth/password,参数包含 old_password 与 new_password。 +- 请求封装: + - 默认 baseURL 为 /api,超时 10 秒。 + - 请求拦截器:非登录接口自动附加 Authorization: Bearer token。 + - 响应拦截器: + - code=0 的业务错误:统一弹出错误提示并拒绝 Promise。 + - 401 未授权:清除本地认证信息,跳转登录页并附带 redirect 参数。 + - 403 无权限:提示无权限。 + - 其他错误:统一提示网络错误。 + +```mermaid +sequenceDiagram +participant LV as "登录视图" +participant API as "认证 API" +participant REQ as "请求封装" +participant AR as "认证路由" +participant RESP as "响应拦截器" +LV->>API : login({username,password}) +API->>REQ : request({url : '/auth/login', method : 'post'}) +REQ->>AR : 发送请求 +AR-->>REQ : 返回 {code,data,msg} +REQ->>RESP : 统一处理响应 +RESP-->>LV : 成功数据或抛错 +``` + +图表来源 +- [frontend/src/api/auth.js:3-12](file://frontend/src/api/auth.js#L3-L12) +- [frontend/src/utils/request.js:12-69](file://frontend/src/utils/request.js#L12-L69) + +章节来源 +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) + +### 认证工具(Token 与用户信息) +- Token 存储键名:localStorage 中的 dashboard_access_token。 +- 用户信息存储键名:localStorage 中的 dashboard_user。 +- 主要方法: + - 获取/设置/清除 Token。 + - 设置/获取/清除 用户信息。 + - 从 Token 解析用户信息(sub、username、is_super_admin)。 + - 判断 Token 是否过期(基于 exp)。 + - 清除认证信息并清空标签页缓存。 + - 判断是否超级管理员。 + +```mermaid +flowchart TD +GetToken["获取 Token"] --> HasToken{"存在 Token?"} +HasToken --> |否| NullUser["返回 null 或兜底解析"] +HasToken --> |是| ParseExp["解析 exp 时间戳"] +ParseExp --> Expired{"是否过期?"} +Expired --> |是| Clear["清除认证信息"] +Expired --> |否| ReturnUser["返回用户信息"] +Clear --> NullUser +``` + +图表来源 +- [frontend/src/utils/auth.js:4-99](file://frontend/src/utils/auth.js#L4-L99) + +章节来源 +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) + +### 后端认证路由与中间件 +- 登录接口: + - 校验必填参数,去空白用户名。 + - 查询用户并检查状态。 + - 使用 PBKDF2 验证密码。 + - 更新最近登录时间,签发 Access Token,返回用户信息与过期时间。 +- 获取当前用户接口:受认证中间件保护,返回用户字典。 +- 修改密码接口:校验旧密码与新密码长度,更新密码哈希。 +- 认证中间件: + - 校验 Authorization 头是否以 Bearer 开头。 + - 解码 JWT,注入 req.user(id、username、is_super_admin)。 + - 处理过期与无效 Token 场景。 + +```mermaid +sequenceDiagram +participant CL as "客户端" +participant AR as "认证路由" +participant DB as "数据库模型" +participant PW as "密码工具" +participant JW as "JWT 工具" +CL->>AR : POST /api/auth/login +AR->>DB : 查找用户 +AR->>PW : verifyPassword(password, hash) +PW-->>AR : 验证结果 +AR->>DB : 更新最近登录时间 +AR->>JW : createAccessToken(user) +JW-->>AR : 返回 access_token +AR-->>CL : 返回 {access_token,user,expires_in} +``` + +图表来源 +- [backend/src/routes/auth.js:24-64](file://backend/src/routes/auth.js#L24-L64) +- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34) +- [backend/src/utils/jwt.js:7-17](file://backend/src/utils/jwt.js#L7-L17) + +章节来源 +- [backend/src/routes/auth.js:24-112](file://backend/src/routes/auth.js#L24-L112) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) + +### 路由守卫与权限控制 +- 守卫逻辑: + - 需要认证的路由:若无 Token 或已过期,清除认证并跳转登录页,附带 redirect。 + - 超级管理员限制:当目标路由标记 requiresSuperAdmin 且当前用户非超级管理员时,重定向首页。 + - 已登录用户访问 /login:若 Token 有效则重定向首页。 +- 与认证工具配合:使用 isTokenExpired 与 isSuperAdmin 判断。 + +```mermaid +flowchart TD +Enter(["进入路由"]) --> NeedAuth{"需要认证?"} +NeedAuth --> |否| Next["放行"] +NeedAuth --> |是| HasToken{"有有效 Token?"} +HasToken --> |否| GoLogin["跳转登录并附带 redirect"] +HasToken --> |是| SuperReq{"需要超级管理员?"} +SuperReq --> |是| IsSuper{"当前用户是超级管理员?"} +IsSuper --> |否| Home["重定向首页"] +IsSuper --> |是| Next +GoLogin --> End(["结束"]) +Home --> End +Next --> End +``` + +图表来源 +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/utils/auth.js:73-75](file://frontend/src/utils/auth.js#L73-L75) + +章节来源 +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/utils/auth.js:73-75](file://frontend/src/utils/auth.js#L73-L75) + +### JWT 令牌机制 +- 签发: + - Payload 包含 sub、username、is_super_admin、iat、exp。 + - TTL 固定为 12 小时,exp 以秒计算。 +- 校验: + - 中间件使用 HS256 算法验证签名与过期时间。 + - 过期或无效时返回 401。 +- 前端解析: + - 从 Token 解析 exp 并转换为毫秒时间戳判断过期。 + - 支持从 Token 兜底解析用户信息(sub、username、is_super_admin)。 + +```mermaid +classDiagram +class JWTUtil { ++createAccessToken(user) ++decodeToken(token) ++getTokenTtlSeconds() +} +class AuthMW { ++authMiddleware(req,res,next) ++requireSuperAdmin(req,res,next) +} +class AuthUtils { ++getUserFromToken(token) ++getTokenExpiresAt(token) ++isTokenExpired(token) +} +AuthMW --> JWTUtil : "校验 Token" +AuthUtils --> JWTUtil : "解析 payload" +``` + +图表来源 +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [frontend/src/utils/auth.js:52-99](file://frontend/src/utils/auth.js#L52-L99) + +章节来源 +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [frontend/src/utils/auth.js:52-99](file://frontend/src/utils/auth.js#L52-L99) + +### 安全措施 +- 密码存储与校验: + - 使用 PBKDF2(迭代次数、盐、密钥长度、摘要算法)进行哈希。 + - 安全比对采用定时常量时间比较,降低侧信道攻击风险。 +- 传输安全: + - 所有非登录接口自动附加 Bearer Token,避免明文传输。 + - 建议在生产环境启用 HTTPS。 +- 会话管理: + - 前端仅保存 Token 与用户信息于 localStorage/sessionStorage。 + - 401 时自动清除认证信息并跳转登录。 + - 路由守卫在进入受保护路由前校验 Token 有效性。 +- 防暴力破解(建议): + - 后端可引入速率限制与账户锁定策略(当前实现未见显式限制逻辑)。 + +章节来源 +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [frontend/src/utils/request.js:44-59](file://frontend/src/utils/request.js#L44-L59) +- [frontend/src/router/index.js:68-73](file://frontend/src/router/index.js#L68-L73) + +### 错误处理与用户体验 +- 登录错误: + - 前端:表单校验失败提示;接口返回错误提示;异常捕获与日志输出。 + - 后端:参数缺失、用户不存在/禁用、密码错误、内部异常均返回统一结构。 +- 401 自动跳转: + - 响应拦截器检测 401,清除本地认证,跳转登录页并附带 redirect。 +- 403 权限不足: + - 弹出提示并阻止导航。 +- 加载态与交互: + - 登录按钮显示加载态,避免重复提交。 + - 提示文案统一使用 Element Plus 的消息组件。 + +章节来源 +- [frontend/src/views/login/index.vue:123-150](file://frontend/src/views/login/index.vue#L123-L150) +- [frontend/src/utils/request.js:27-69](file://frontend/src/utils/request.js#L27-L69) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +### 移动端适配 +- 视口与布局: + - 登录卡片最大宽度限制,保证在小屏设备上不拥挤。 + - 使用相对单位与弹性布局,确保在不同屏幕尺寸下保持良好体验。 +- 交互优化: + - 输入框自动聚焦与回车提交,减少移动端输入成本。 + - 按钮尺寸与间距适中,便于触摸点击。 + +章节来源 +- [frontend/src/views/login/index.vue:153-453](file://frontend/src/views/login/index.vue#L153-L453) + +## 依赖关系分析 +- 前端模块耦合: + - 登录视图依赖认证 API 与认证工具。 + - 认证 API 依赖请求封装。 + - 请求封装依赖认证工具(读取 Token)。 + - 路由守卫依赖认证工具与标签页工具。 +- 后端模块耦合: + - 认证路由依赖模型、密码工具、JWT 工具与响应封装。 + - 认证中间件依赖 JWT 工具。 +- 可能的循环依赖: + - 当前模块划分清晰,未发现循环依赖迹象。 + +```mermaid +graph LR +LV["登录视图"] --> API["认证 API"] +API --> REQ["请求封装"] +REQ --> AU["认证工具"] +RT["路由守卫"] --> AU +RT --> TU["标签页工具"] +AR["认证路由"] --> PW["密码工具"] +AR --> JW["JWT 工具"] +AR --> RU["响应封装"] +AR --> MW["认证中间件"] +``` + +图表来源 +- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151) +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [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) + +章节来源 +- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151) +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [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) + +## 性能考虑 +- Token TTL:12 小时,平衡安全性与用户体验。 +- 请求拦截器:避免重复设置 Authorization,减少不必要的网络开销。 +- 前端解析:仅在需要时解析 Token,避免频繁计算。 +- 建议优化: + - 对频繁访问的受保护接口,可在路由守卫中加入缓存策略(如短期缓存用户信息)。 + - 后端可引入登录失败计数与临时封禁策略,缓解暴力破解风险。 + +## 故障排除指南 +- 登录失败: + - 检查用户名/密码是否为空,确认后端返回的错误消息。 + - 确认数据库中用户状态正常且密码哈希正确。 +- 401 未授权: + - 检查请求头是否包含正确的 Bearer Token。 + - 确认 Token 未过期,必要时重新登录。 +- 403 无权限: + - 确认当前用户具备所需权限(超级管理员)。 +- 页面跳转异常: + - 检查路由守卫逻辑与 redirect 参数传递。 + - 确认标签页缓存清理是否成功。 + +章节来源 +- [frontend/src/utils/request.js:44-59](file://frontend/src/utils/request.js#L44-L59) +- [frontend/src/router/index.js:68-73](file://frontend/src/router/index.js#L68-L73) +- [backend/src/middleware/auth.js:21-25](file://backend/src/middleware/auth.js#L21-L25) + +## 结论 +该登录系统从前端表单到后端认证形成完整的闭环,具备良好的可维护性与扩展性。前端通过统一的请求封装与路由守卫保障了安全性与用户体验;后端通过 PBKDF2 哈希与 JWT 机制提供了可靠的认证基础。建议在生产环境中补充速率限制与 HTTPS 等安全措施,并持续监控与优化登录流程的性能与稳定性。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/页面组件/系统用户管理页面.md b/.qoder/repowiki/zh/content/前端组件/页面组件/系统用户管理页面.md new file mode 100644 index 0000000..07892c2 --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/页面组件/系统用户管理页面.md @@ -0,0 +1,462 @@ +# 系统用户管理页面 + + +**本文档引用的文件** +- [frontend/src/views/system/users/index.vue](file://frontend/src/views/system/users/index.vue) +- [frontend/src/api/user.js](file://frontend/src/api/user.js) +- [backend/src/routes/users.js](file://backend/src/routes/users.js) +- [backend/src/models/DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [frontend/src/utils/auth.js](file://frontend/src/utils/auth.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/services/userBootstrap.js](file://backend/src/services/userBootstrap.js) +- [backend/src/app.js](file://backend/src/app.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +系统用户管理页面是音频仪表板管理系统中的核心功能模块,负责管理后台系统的用户账户。该页面实现了完整的用户权限管理体系,包括用户列表展示、角色分配、权限控制和状态管理等功能。 + +本系统采用前后端分离架构,前端使用Vue 3 + Element Plus构建用户界面,后端使用Express.js提供RESTful API服务。系统支持超级管理员权限控制、用户密码管理、登录状态监控和安全审计功能。 + +## 项目结构 + +系统用户管理功能分布在前端和后端两个主要部分: + +```mermaid +graph TB +subgraph "前端层" +UI[用户界面组件] +API[API接口封装] +Router[路由管理] +Auth[认证工具] +end +subgraph "后端层" +Routes[用户路由] +Models[数据模型] +Middleware[中间件] +Utils[工具函数] +Services[业务服务] +end +subgraph "数据库层" +DB[(MySQL数据库)] +end +UI --> API +API --> Routes +Router --> Auth +Auth --> Routes +Routes --> Models +Routes --> Middleware +Routes --> Utils +Models --> DB +Services --> DB +``` + +**图表来源** +- [frontend/src/views/system/users/index.vue:1-428](file://frontend/src/views/system/users/index.vue#L1-L428) +- [backend/src/routes/users.js:1-180](file://backend/src/routes/users.js#L1-L180) + +**章节来源** +- [frontend/src/views/system/users/index.vue:1-428](file://frontend/src/views/system/users/index.vue#L1-L428) +- [backend/src/routes/users.js:1-180](file://backend/src/routes/users.js#L1-L180) + +## 核心组件 + +### 前端用户管理组件 + +用户管理页面采用Vue 3 Composition API编写,提供了完整的CRUD操作界面: + +- **用户列表展示**:支持分页显示、模糊搜索和状态标识 +- **用户操作功能**:创建、编辑、删除、启用/禁用、密码重置 +- **表单验证**:用户名长度验证、密码强度验证 +- **响应式设计**:适配不同屏幕尺寸的设备 + +### 后端用户管理服务 + +后端提供了完整的用户管理API,包含以下核心功能: + +- **用户认证中间件**:基于JWT的认证和授权 +- **超级管理员保护**:确保至少有一个超级管理员存在 +- **密码安全处理**:PBKDF2算法进行密码哈希 +- **数据验证**:输入参数的完整性和安全性检查 + +**章节来源** +- [frontend/src/views/system/users/index.vue:169-393](file://frontend/src/views/system/users/index.vue#L169-L393) +- [backend/src/routes/users.js:35-177](file://backend/src/routes/users.js#L35-L177) + +## 架构概览 + +系统采用分层架构设计,确保了良好的可维护性和扩展性: + +```mermaid +graph TB +subgraph "表现层" +UsersPage[用户管理页面] +Login[登录页面] +Home[首页] +end +subgraph "应用层" +UserAPI[用户API] +AuthAPI[认证API] +DashboardAPI[仪表板API] +end +subgraph "服务层" +UserRoutes[用户路由] +AuthRoutes[认证路由] +Middleware[中间件链] +end +subgraph "数据访问层" +UserModel[用户模型] +Database[(数据库)] +end +UsersPage --> UserAPI +Login --> AuthAPI +Home --> DashboardAPI +UserAPI --> UserRoutes +AuthAPI --> AuthRoutes +UserRoutes --> Middleware +AuthRoutes --> Middleware +Middleware --> UserModel +UserModel --> Database +``` + +**图表来源** +- [frontend/src/views/system/users/index.vue:173](file://frontend/src/views/system/users/index.vue#L173) +- [backend/src/routes/users.js:12-13](file://backend/src/routes/users.js#L12-L13) + +## 详细组件分析 + +### 用户管理页面组件 + +用户管理页面是一个完整的Vue组件,实现了以下功能模块: + +#### 数据表格组件 +- **列定义**:ID、用户名、超级管理员标识、状态、最近登录时间、创建时间 +- **状态显示**:使用标签组件直观显示用户状态 +- **操作按钮**:支持启用/禁用、密码修改、删除操作 + +#### 表单验证系统 +- **用户名验证**:1-64字符长度限制 +- **密码验证**:至少6位字符的安全要求 +- **表单重置**:提供完整的表单清理功能 + +#### 分页和搜索功能 +- **分页控制**:支持10、20、50、100条记录每页 +- **搜索功能**:基于用户名的模糊查询 +- **实时刷新**:操作完成后自动刷新数据 + +```mermaid +classDiagram +class UserManagementPage { ++loading : boolean ++tableData : Array ++searchForm : Object ++pagination : Object ++loadData() void ++handleSearch() void ++handleCreateSubmit() void ++handleChangePassword() void ++handleToggleStatus() void ++handleDelete() void +} +class UserAPI { ++getUsers(params) Promise ++createUser(data) Promise ++updateUser(id, data) Promise ++deleteUser(id) Promise +} +class ValidationRules { ++username : Array ++password : Array ++validateForm() boolean +} +UserManagementPage --> UserAPI : uses +UserManagementPage --> ValidationRules : validates +``` + +**图表来源** +- [frontend/src/views/system/users/index.vue:169-393](file://frontend/src/views/system/users/index.vue#L169-L393) +- [frontend/src/api/user.js:1-40](file://frontend/src/api/user.js#L1-L40) + +**章节来源** +- [frontend/src/views/system/users/index.vue:1-428](file://frontend/src/views/system/users/index.vue#L1-L428) + +### 用户路由和控制器 + +用户管理API提供了完整的RESTful接口: + +#### GET /api/users/ - 用户列表查询 +- **分页参数**:skip、limit、username +- **搜索功能**:支持用户名模糊匹配 +- **排序规则**:按ID升序排列 +- **数据格式**:标准化响应格式 + +#### POST /api/users/ - 创建用户 +- **必需字段**:username、password +- **权限要求**:超级管理员 +- **安全措施**:密码哈希存储 +- **唯一性约束**:用户名唯一 + +#### PUT /api/users/:user_id - 更新用户 +- **动态字段**:status、is_super_admin、password +- **权限保护**:超级管理员权限验证 +- **安全检查**:最后一个超级管理员保护 +- **审计日志**:操作记录 + +#### DELETE /api/users/:user_id - 删除用户 +- **自删除保护**:禁止删除当前登录用户 +- **超级管理员保护**:确保至少一个有效超级管理员 +- **级联删除**:关联数据的处理 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Auth as 认证中间件 +participant SuperAdmin as 超级管理员检查 +participant Controller as 用户控制器 +participant DB as 数据库 +Client->>Auth : 发送带令牌的请求 +Auth->>Auth : 验证JWT令牌 +Auth->>SuperAdmin : 检查超级管理员权限 +SuperAdmin->>Controller : 转发请求 +Controller->>Controller : 参数验证和业务逻辑 +Controller->>DB : 执行数据库操作 +DB-->>Controller : 返回操作结果 +Controller-->>Client : 标准化响应 +Note over Auth,DB : 包含密码哈希、权限验证等安全措施 +``` + +**图表来源** +- [backend/src/routes/users.js:35-177](file://backend/src/routes/users.js#L35-L177) +- [backend/src/middleware/auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) + +**章节来源** +- [backend/src/routes/users.js:35-177](file://backend/src/routes/users.js#L35-L177) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +### 数据模型设计 + +用户数据模型采用了标准化的设计原则: + +```mermaid +erDiagram +DASHBOARD_USER { +int id PK +string username UK +string password_hash +tinyint is_super_admin +tinyint status +datetime last_login_at +datetime create_at +datetime update_at +} +USER_ROLE { +int id PK +string role_name UK +text permissions +datetime created_at +datetime updated_at +} +USER_ROLE ||--o{ DASHBOARD_USER : "assigns" +``` + +**图表来源** +- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54) + +#### 字段说明 +- **id**: 自增主键,唯一标识用户 +- **username**: 用户名,唯一约束,最大64字符 +- **password_hash**: 密码哈希值,使用PBKDF2算法 +- **is_super_admin**: 是否为超级管理员,1表示是 +- **status**: 用户状态,1表示启用,0表示禁用 +- **last_login_at**: 最近登录时间 +- **create_at/update_at**: 记录创建和更新时间 + +**章节来源** +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) + +### 权限控制系统 + +系统实现了多层次的权限控制机制: + +#### 路由级别的权限控制 +- **requiresAuth**: 需要登录才能访问 +- **requiresSuperAdmin**: 需要超级管理员权限 +- **动态权限检查**: 在路由守卫中进行权限验证 + +#### API级别的权限控制 +- **JWT认证**: 基于令牌的身份验证 +- **超级管理员保护**: 关键操作的权限验证 +- **操作审计**: 记录所有重要操作 + +```mermaid +flowchart TD +Request[用户请求] --> CheckAuth{是否需要认证?} +CheckAuth --> |是| VerifyToken[验证JWT令牌] +CheckAuth --> |否| Access[直接访问] +VerifyToken --> TokenValid{令牌有效?} +TokenValid --> |否| Deny[拒绝访问] +TokenValid --> |是| CheckRole{是否需要特殊权限?} +CheckRole --> |是| VerifyRole[验证用户角色] +CheckRole --> |否| Access +VerifyRole --> RoleValid{权限验证通过?} +RoleValid --> |否| Deny +RoleValid --> |是| Access +Access --> Success[访问成功] +Deny --> Error[权限不足] +``` + +**图表来源** +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [backend/src/middleware/auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) + +**章节来源** +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/middleware/auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) + +### 密码安全管理 + +系统采用了业界标准的密码安全处理机制: + +#### PBKDF2算法实现 +- **迭代次数**: 310000次,确保足够的计算复杂度 +- **密钥长度**: 32字节,提供足够的熵值 +- **哈希算法**: SHA-256,选择安全的加密哈希 +- **随机盐值**: 每个密码生成独立的随机盐值 + +#### 密码验证流程 +```mermaid +flowchart TD +Input[用户输入密码] --> Hash[生成哈希值] +Hash --> Compare[与存储哈希比较] +Compare --> Match{匹配成功?} +Match --> |是| Success[验证通过] +Match --> |否| Fail[验证失败] +Hash --> Store[存储哈希值] +Store --> Salt[包含随机盐值] +``` + +**图表来源** +- [backend/src/utils/password.js:10-34](file://backend/src/utils/password.js#L10-L34) + +**章节来源** +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) + +## 依赖关系分析 + +系统各组件之间的依赖关系如下: + +```mermaid +graph TB +subgraph "前端依赖" +Vue[Vue 3] +ElementPlus[Element Plus] +Axios[Axios] +Router[Vue Router] +end +subgraph "后端依赖" +Express[Express.js] +Sequelize[Sequelize] +Winston[Winston] +Crypto[Node.js Crypto] +end +subgraph "数据库依赖" +MySQL[MySQL] +Redis[Redis(可选)] +end +UsersPage[用户管理页面] --> UserAPI[用户API] +UserAPI --> Express +Express --> Sequelize +Sequelize --> MySQL +Express --> Winston +Express --> Crypto +``` + +**图表来源** +- [frontend/src/views/system/users/index.vue:170-173](file://frontend/src/views/system/users/index.vue#L170-L173) +- [backend/src/app.js:6-12](file://backend/src/app.js#L6-L12) + +**章节来源** +- [frontend/src/views/system/users/index.vue:170-173](file://frontend/src/views/system/users/index.vue#L170-L173) +- [backend/src/app.js:6-12](file://backend/src/app.js#L6-L12) + +## 性能考虑 + +系统在设计时充分考虑了性能优化: + +### 前端性能优化 +- **懒加载**: 路由组件按需加载 +- **虚拟滚动**: 大数据量时的表格优化 +- **缓存策略**: 本地存储用户会话信息 +- **防抖处理**: 搜索框输入防抖 + +### 后端性能优化 +- **数据库索引**: 用户名字段建立索引 +- **查询优化**: 分页查询避免全表扫描 +- **连接池**: 数据库连接复用 +- **缓存机制**: Redis缓存热点数据 + +### 安全性能平衡 +- **密码哈希成本**: PBKDF2迭代次数平衡安全性和性能 +- **令牌过期**: JWT短有效期配合刷新机制 +- **速率限制**: 防止暴力破解攻击 + +## 故障排除指南 + +### 常见问题及解决方案 + +#### 登录认证问题 +- **问题**: 401未授权错误 +- **原因**: 令牌缺失或过期 +- **解决**: 检查localStorage中的令牌,重新登录 + +#### 权限访问问题 +- **问题**: 403权限不足 +- **原因**: 非超级管理员访问用户管理 +- **解决**: 使用超级管理员账户登录 + +#### 数据库连接问题 +- **问题**: 数据库连接失败 +- **原因**: 环境变量配置错误 +- **解决**: 检查DATABASE_URL配置 + +#### API调用失败 +- **问题**: HTTP 500服务器错误 +- **原因**: 服务器内部异常 +- **解决**: 查看后端日志文件 + +**章节来源** +- [backend/src/config/logger.js:10-26](file://backend/src/config/logger.js#L10-L26) +- [frontend/src/utils/auth.js:46-50](file://frontend/src/utils/auth.js#L46-L50) + +## 结论 + +系统用户管理页面是一个功能完整、安全可靠的用户权限管理解决方案。通过前后端分离架构、严格的权限控制和完善的错误处理机制,为用户提供了一个高效、安全的用户管理体验。 + +### 主要优势 +- **完整的CRUD功能**: 支持用户的所有基本操作 +- **严格的安全控制**: 多层次的权限验证和保护机制 +- **良好的用户体验**: 响应式设计和直观的操作界面 +- **可扩展的架构**: 清晰的分层设计便于功能扩展 + +### 技术特点 +- **现代化技术栈**: Vue 3 + Express.js + MySQL +- **安全最佳实践**: JWT认证、密码哈希、权限控制 +- **完整的开发流程**: 从设计到部署的完整解决方案 +- **详细的文档支持**: 清晰的代码注释和使用说明 + +该系统为音频仪表板管理提供了坚实的基础,可以根据具体需求进一步扩展功能,如添加批量操作、数据导出、操作日志等功能。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/页面组件/页面组件.md b/.qoder/repowiki/zh/content/前端组件/页面组件/页面组件.md new file mode 100644 index 0000000..bf822ac --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/页面组件/页面组件.md @@ -0,0 +1,527 @@ +# 页面组件 + + +**本文引用的文件** +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [frontend/src/views/home/index.vue](file://frontend/src/views/home/index.vue) +- [frontend/src/views/login/index.vue](file://frontend/src/views/login/index.vue) +- [frontend/src/views/brand/index.vue](file://frontend/src/views/brand/index.vue) +- [frontend/src/views/model/index.vue](file://frontend/src/views/model/index.vue) +- [frontend/src/views/ota/index.vue](file://frontend/src/views/ota/index.vue) +- [frontend/src/views/share-code/log.vue](file://frontend/src/views/share-code/log.vue) +- [frontend/src/views/system/users/index.vue](file://frontend/src/views/system/users/index.vue) +- [frontend/src/api/auth.js](file://frontend/src/api/auth.js) +- [frontend/src/api/brand.js](file://frontend/src/api/brand.js) +- [frontend/src/api/model.js](file://frontend/src/api/model.js) +- [frontend/src/api/ota.js](file://frontend/src/api/ota.js) +- [frontend/src/api/shareCodeLog.js](file://frontend/src/api/shareCodeLog.js) +- [frontend/src/api/user.js](file://frontend/src/api/user.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件面向前端页面组件,系统性梳理各功能页面的设计与实现,覆盖以下页面: +- 首页仪表板:数据概览与快捷入口 +- 登录页:身份认证与令牌管理 +- 品牌管理:品牌数据的增删改查 +- 型号管理:技术配置、推送搜索、查看 EQ 缓存与 CSV +- OTA 固件:版本控制与升级包上传 +- 分享码日志:数据追踪与 EQ 快照查看 +- 系统用户:账号管理与权限控制 + +文档重点阐述: +- 路由配置与鉴权守卫 +- 数据获取与分页策略 +- 表单验证与交互流程 +- 状态管理、错误处理与加载状态 +- 页面间导航与数据传递 + +## 项目结构 +前端采用 Vue 3 + Element Plus 架构,页面位于 views 下,路由集中于 router/index.js,API 层封装于 api 目录,通用工具位于 utils。 + +```mermaid +graph TB +subgraph "路由层" +R["router/index.js
定义路由与鉴权守卫"] +end +subgraph "视图层" +H["views/home/index.vue"] +L["views/login/index.vue"] +B["views/brand/index.vue"] +M["views/model/index.vue"] +O["views/ota/index.vue"] +S["views/share-code/log.vue"] +U["views/system/users/index.vue"] +end +subgraph "API 层" +A1["api/auth.js"] +A2["api/brand.js"] +A3["api/model.js"] +A4["api/ota.js"] +A5["api/shareCodeLog.js"] +A6["api/user.js"] +end +R --> H +R --> L +R --> B +R --> M +R --> O +R --> S +R --> U +H --> A1 +L --> A1 +B --> A2 +M --> A3 +O --> A4 +S --> A5 +U --> A6 +``` + +图表来源 +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/views/home/index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) +- [frontend/src/views/login/index.vue:1-453](file://frontend/src/views/login/index.vue#L1-L453) +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [frontend/src/views/model/index.vue:1-800](file://frontend/src/views/model/index.vue#L1-L800) +- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) +- [frontend/src/views/share-code/log.vue:1-353](file://frontend/src/views/share-code/log.vue#L1-L353) +- [frontend/src/views/system/users/index.vue:1-428](file://frontend/src/views/system/users/index.vue#L1-L428) +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [frontend/src/api/model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [frontend/src/api/ota.js:1-68](file://frontend/src/api/ota.js#L1-L68) +- [frontend/src/api/shareCodeLog.js:1-26](file://frontend/src/api/shareCodeLog.js#L1-L26) +- [frontend/src/api/user.js:1-40](file://frontend/src/api/user.js#L1-L40) + +章节来源 +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 核心组件 +- 路由与鉴权 + - 定义登录页与受保护页面,设置 requiresAuth 与 requiresSuperAdmin 元信息 + - beforeEach 守卫检查令牌有效性与超级管理员权限 +- 首页仪表板 + - 展示今日新增型号与 OTA 列表,支持点击快捷入口跳转 +- 登录页 + - 表单校验、调用登录 API、存储令牌与用户信息 +- 品牌管理 + - 搜索、分页、新增/编辑对话框、删除确认 +- 型号管理 + - 品牌联动、排序、批量推送搜索、查看 EQ 缓存与 CSV、上传频响文件 +- OTA 固件 + - 多条件筛选、开关控制、上传升级包并自动生成 MD5/URL +- 分享码日志 + - 时间范围筛选、动作过滤、查看 EQ 快照 +- 系统用户 + - 用户列表、启/禁用、改密、删除 + +章节来源 +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/views/home/index.vue:97-149](file://frontend/src/views/home/index.vue#L97-L149) +- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151) +- [frontend/src/views/brand/index.vue:109-276](file://frontend/src/views/brand/index.vue#L109-L276) +- [frontend/src/views/model/index.vue:460-800](file://frontend/src/views/model/index.vue#L460-L800) +- [frontend/src/views/ota/index.vue:249-580](file://frontend/src/views/ota/index.vue#L249-L580) +- [frontend/src/views/share-code/log.vue:148-278](file://frontend/src/views/share-code/log.vue#L148-L278) +- [frontend/src/views/system/users/index.vue:169-393](file://frontend/src/views/system/users/index.vue#L169-L393) + +## 架构总览 +页面组件通过 API 层与后端交互,统一使用 request 封装的 HTTP 客户端。路由守卫负责全局鉴权与权限拦截,页面内部通过响应式状态管理数据与 UI。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant V as "页面组件" +participant API as "API 模块" +participant S as "后端服务" +U->>V : 触发操作如登录/搜索/提交 +V->>API : 调用具体接口带参数 +API->>S : 发起 HTTP 请求 +S-->>API : 返回响应code/data/msg +API-->>V : 返回结果 +V->>V : 更新本地状态/显示消息 +``` + +图表来源 +- [frontend/src/views/login/index.vue:123-150](file://frontend/src/views/login/index.vue#L123-L150) +- [frontend/src/api/auth.js:3-12](file://frontend/src/api/auth.js#L3-L12) +- [frontend/src/views/brand/index.vue:146-168](file://frontend/src/views/brand/index.vue#L146-L168) +- [frontend/src/api/brand.js:10-16](file://frontend/src/api/brand.js#L10-L16) +- [frontend/src/views/model/index.vue:714-739](file://frontend/src/views/model/index.vue#L714-L739) +- [frontend/src/api/model.js:13-19](file://frontend/src/api/model.js#L13-L19) +- [frontend/src/views/ota/index.vue:420-449](file://frontend/src/views/ota/index.vue#L420-L449) +- [frontend/src/api/ota.js:13-19](file://frontend/src/api/ota.js#L13-L19) +- [frontend/src/views/share-code/log.vue:233-250](file://frontend/src/views/share-code/log.vue#L233-L250) +- [frontend/src/api/shareCodeLog.js:17-24](file://frontend/src/api/shareCodeLog.js#L17-L24) +- [frontend/src/views/system/users/index.vue:231-252](file://frontend/src/views/system/users/index.vue#L231-L252) +- [frontend/src/api/user.js:3-9](file://frontend/src/api/user.js#L3-L9) + +## 详细组件分析 + +### 首页仪表板(Home) +- 功能要点 + - 渲染欢迎语与快捷入口卡片,点击跳转至对应页面 + - 加载“今日新增”数据:型号与 OTA 列表,支持加载态与空态 + - 时间格式化工具函数 +- 数据流 + - 组件挂载时调用仪表板统计 API + - 成功后更新响应式状态,失败打印日志 +- 交互与状态 + - 使用 loading 状态控制加载指示 + - 使用数组长度判断空态 +- 错误处理 + - try/catch 包裹请求,finally 关闭加载态 +- 性能 + - 仅在首次进入时请求一次,避免重复请求 + +```mermaid +sequenceDiagram +participant C as "Home 组件" +participant API as "dashboard API" +participant S as "后端" +C->>C : onMounted() +C->>API : getTodayStats() +API->>S : GET /dashboard/stats +S-->>API : {code,data} +API-->>C : 结果 +alt code===1 +C->>C : 更新 todayModels/todayOtas +else 其他 +C->>C : 打印错误/保持空态 +end +``` + +图表来源 +- [frontend/src/views/home/index.vue:127-148](file://frontend/src/views/home/index.vue#L127-L148) +- [frontend/src/api/dashboard.js:1-200](file://frontend/src/api/dashboard.js#L1-L200) + +章节来源 +- [frontend/src/views/home/index.vue:97-149](file://frontend/src/views/home/index.vue#L97-L149) + +### 登录页(Login) +- 功能要点 + - 账号/密码输入与必填校验 + - 提交时调用登录 API,成功后写入令牌与用户信息,清空标签页缓存并跳转首页 +- 表单与校验 + - Element Plus 表单规则:账号与密码必填 +- 交互与状态 + - loading 控制按钮加载态 + - ElMessage 展示成功/失败提示 +- 错误处理 + - try/catch 捕获异常,finally 关闭加载态 +- 导航 + - 登录成功后 replace 到首页路径 + +```mermaid +sequenceDiagram +participant U as "用户" +participant L as "Login 组件" +participant API as "auth API" +participant S as "后端" +U->>L : 输入账号/密码并提交 +L->>L : validate() +alt 校验通过 +L->>API : login({username,password}) +API->>S : POST /auth/login +S-->>API : {code,data : {access_token,user}} +API-->>L : 结果 +alt code===1 +L->>L : setToken/setUser +L->>L : clearTabsStorage() +L->>L : router.replace(HOME_PATH) +else 其他 +L->>L : ElMessage.error() +end +else 校验失败 +L->>L : 停止提交 +end +``` + +图表来源 +- [frontend/src/views/login/index.vue:118-150](file://frontend/src/views/login/index.vue#L118-L150) +- [frontend/src/api/auth.js:3-12](file://frontend/src/api/auth.js#L3-L12) +- [frontend/src/router/index.js:82-85](file://frontend/src/router/index.js#L82-L85) + +章节来源 +- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151) + +### 品牌管理(Brand) +- 功能要点 + - 品牌名称搜索、分页(10/20/50/100) + - 新增/编辑对话框,表单必填校验(1-100字符) + - 删除前二次确认 +- 数据流 + - 搜索/重置/分页变更触发加载数据 + - 新增/编辑/删除调用对应 API +- 状态管理 + - loading 控制表格加载态 + - submitLoading 控制对话框提交按钮加载态 +- 错误处理 + - try/catch 包裹请求,失败提示并保持空数据 + +```mermaid +flowchart TD +Start(["进入页面"]) --> Load["加载数据
getBrands(skip,limit,name)"] +Load --> Render["渲染表格与分页"] +Render --> Action{"用户操作"} +Action --> |搜索| ResetPage["重置页码=1"] --> Load +Action --> |分页改变| Load +Action --> |新增/编辑| Dialog["打开对话框并校验"] --> Submit["提交表单"] --> Load +Action --> |删除| Confirm["确认删除"] --> DeleteReq["deleteBrand(id)"] --> Load +Action --> |关闭对话框| ResetForm["重置表单/字段"] +``` + +图表来源 +- [frontend/src/views/brand/index.vue:146-276](file://frontend/src/views/brand/index.vue#L146-L276) +- [frontend/src/api/brand.js:10-66](file://frontend/src/api/brand.js#L10-L66) + +章节来源 +- [frontend/src/views/brand/index.vue:109-276](file://frontend/src/views/brand/index.vue#L109-L276) + +### 型号管理(Model) +- 功能要点 + - 品牌/型号搜索、排序(id/create_at)、分页 + - 批量选择、推送搜索(校验+推送两步)、复制选中项 + - 更多操作:查看搜索、查看 EQ 缓存、查看 CSV(特定来源) + - 新增/编辑对话框:品牌下拉/可创建、文件上传、阻抗等字段 +- 数据流 + - 加载品牌选项与型号列表 + - 文件上传后自动填充来源与默认阻抗,并尝试解析品牌/型号 + - 推送搜索:先 validate,再 push,实时反馈步骤与进度 +- 状态管理 + - 多处 loading:表格、对话框、推送过程 + - pushSteps 控制推送步骤状态 + - selectedIds 记录勾选项 +- 错误处理 + - 各类请求失败统一提示 + - 文件上传失败清理列表并提示 + +```mermaid +sequenceDiagram +participant U as "用户" +participant M as "Model 组件" +participant API as "model API" +participant S as "后端" +U->>M : 选择若干型号并点击“推送搜索” +M->>API : validatePushToMeilisearch(ids) +API->>S : POST /models/push-to-search/validate +S-->>API : 校验结果 +API-->>M : 校验通过/失败列表 +alt 全部通过 +M->>API : pushToMeilisearch(ids) +API->>S : POST /models/push-to-search +S-->>API : 推送结果 +API-->>M : 成功数量/状态 +else 部分失败 +M->>M : 展示失败原因列表 +end +``` + +图表来源 +- [frontend/src/views/model/index.vue:494-506](file://frontend/src/views/model/index.vue#L494-L506) +- [frontend/src/api/model.js:128-150](file://frontend/src/api/model.js#L128-L150) + +章节来源 +- [frontend/src/views/model/index.vue:460-800](file://frontend/src/views/model/index.vue#L460-L800) + +### OTA 固件(OTA) +- 功能要点 + - 多条件筛选:版本名、设备型号、状态、版本号 + - 新增/编辑/复制/删除 + - 升级包上传(针对指定型号),自动生成 URL 与 MD5 + - 表单校验:版本号/名称/型号必填,MD5 32位十六进制 +- 数据流 + - 搜索/重置/分页变更触发加载 + - 上传文件后调用上传接口,回填 URL 与 MD5 +- 状态管理 + - loading 控制表格加载态 + - submitLoading 控制提交按钮 + - packageUploading 控制上传按钮 +- 错误处理 + - 上传失败清理文件列表并提示 + - 表单校验失败阻止提交 + +```mermaid +flowchart TD +Open(["打开新增/编辑对话框"]) --> Fill["填写基础字段"] +Fill --> ModelSel{"是否选择支持上传的型号?"} +ModelSel --> |是| Upload["选择文件并上传"] +Upload --> UploadOK{"上传成功?"} +UploadOK --> |是| AutoFill["自动填充URL/MD5并校验"] +UploadOK --> |否| Hint["提示失败并清理文件"] +ModelSel --> |否| Skip["跳过上传字段"] +AutoFill --> Submit["提交表单"] +Skip --> Submit +Submit --> Done["成功/失败提示并刷新列表"] +``` + +图表来源 +- [frontend/src/views/ota/index.vue:372-418](file://frontend/src/views/ota/index.vue#L372-L418) +- [frontend/src/api/ota.js:56-67](file://frontend/src/api/ota.js#L56-L67) + +章节来源 +- [frontend/src/views/ota/index.vue:249-580](file://frontend/src/views/ota/index.vue#L249-L580) + +### 分享码日志(ShareCodeLog) +- 功能要点 + - MAC/IP/动作/时间范围筛选 + - 查看 EQ 快照(JSON 可视化) +- 数据流 + - 构造查询参数(含时间范围),调用日志接口 + - 打开对话框时安全解析并展示 JSON +- 状态管理 + - loading 控制表格加载态 + - eqDialogVisible 控制弹窗 +- 错误处理 + - 请求失败统一提示 + +```mermaid +sequenceDiagram +participant U as "用户" +participant S as "ShareCodeLog 组件" +participant API as "shareCodeLog API" +participant B as "后端" +U->>S : 设置筛选条件并点击搜索 +S->>S : buildQueryParams() +S->>API : getShareCodeLogs(params) +API->>B : GET /share-code/logs +B-->>API : {code,data} +API-->>S : 结果 +S->>S : 渲染表格/分页 +U->>S : 点击某行“查看” +S->>S : safeParseJson(eq_data) +S->>S : 打开弹窗展示 +``` + +图表来源 +- [frontend/src/views/share-code/log.vue:214-250](file://frontend/src/views/share-code/log.vue#L214-L250) +- [frontend/src/api/shareCodeLog.js:17-24](file://frontend/src/api/shareCodeLog.js#L17-L24) + +章节来源 +- [frontend/src/views/share-code/log.vue:148-278](file://frontend/src/views/share-code/log.vue#L148-L278) + +### 系统用户(System Users) +- 功能要点 + - 用户名模糊搜索、分页 + - 启用/禁用、改密、删除 +- 数据流 + - 搜索/重置/分页变更触发加载 + - 新建账号、改密、启/禁用、删除分别调用对应 API +- 状态管理 + - loading 控制表格加载态 + - submitLoading 控制提交按钮 +- 错误处理 + - 统一提示与错误捕获 + +```mermaid +flowchart TD +Enter(["进入页面"]) --> Load["加载用户列表"] +Load --> Act{"用户操作"} +Act --> |新建| Create["打开新建对话框并校验"] --> CreateUser["createUser()"] --> Load +Act --> |改密| Change["打开改密对话框并校验"] --> UpdateUser["updateUser(pwd)"] --> Load +Act --> |启/禁用| Toggle["updateUser(status)"] --> Load +Act --> |删除| Del["确认删除"] --> DeleteUser["deleteUser(id)"] --> Load +``` + +图表来源 +- [frontend/src/views/system/users/index.vue:231-393](file://frontend/src/views/system/users/index.vue#L231-L393) +- [frontend/src/api/user.js:3-40](file://frontend/src/api/user.js#L3-L40) + +章节来源 +- [frontend/src/views/system/users/index.vue:169-393](file://frontend/src/views/system/users/index.vue#L169-L393) + +## 依赖分析 +- 路由与页面 + - 路由定义了页面路径、标题与图标,部分页面需要超级管理员权限 + - 鉴权守卫基于令牌与角色进行拦截 +- 页面与 API + - 各页面通过对应的 API 模块发起请求,遵循统一的参数与返回结构 +- 组件内聚与耦合 + - 页面组件内聚于自身状态与交互逻辑,API 层提供稳定接口契约 + - 低耦合:页面不直接依赖其他页面,仅通过路由与公共工具交互 + +```mermaid +graph LR +R["router/index.js"] --> H["views/home/index.vue"] +R --> L["views/login/index.vue"] +R --> B["views/brand/index.vue"] +R --> M["views/model/index.vue"] +R --> O["views/ota/index.vue"] +R --> S["views/share-code/log.vue"] +R --> U["views/system/users/index.vue"] +H --> A1["api/auth.js"] +L --> A1 +B --> A2["api/brand.js"] +M --> A3["api/model.js"] +O --> A4["api/ota.js"] +S --> A5["api/shareCodeLog.js"] +U --> A6["api/user.js"] +``` + +图表来源 +- [frontend/src/router/index.js:6-57](file://frontend/src/router/index.js#L6-L57) +- [frontend/src/views/home/index.vue:101-102](file://frontend/src/views/home/index.vue#L101-L102) +- [frontend/src/views/login/index.vue:105-106](file://frontend/src/views/login/index.vue#L105-L106) +- [frontend/src/views/brand/index.vue](file://frontend/src/views/brand/index.vue#L113) +- [frontend/src/views/model/index.vue:486-487](file://frontend/src/views/model/index.vue#L486-L487) +- [frontend/src/views/ota/index.vue](file://frontend/src/views/ota/index.vue#L253) +- [frontend/src/views/share-code/log.vue](file://frontend/src/views/share-code/log.vue#L154) +- [frontend/src/views/system/users/index.vue](file://frontend/src/views/system/users/index.vue#L173) + +章节来源 +- [frontend/src/router/index.js:6-57](file://frontend/src/router/index.js#L6-L57) + +## 性能考虑 +- 列表分页 + - 通过 skip/limit 控制每次请求的数据量,避免一次性加载过多 +- 加载态 + - 使用 v-loading 与局部 loading 状态,减少闪烁与无效渲染 +- 上传优化 + - OTA 升级包上传设置较长超时,避免短时中断 +- 事件节流 + - 搜索建议在输入完成后再触发请求(当前实现为即时触发,可根据需求增加防抖) + +## 故障排查指南 +- 登录失败 + - 检查网络与后端 /auth/login 接口连通性 + - 确认账号/密码正确,查看 ElMessage 提示 +- 数据为空 + - 检查筛选条件是否过于严格(如状态/型号/时间范围) + - 确认分页参数(page/pageSize)是否合理 +- 上传失败 + - 确认所选型号支持上传(非支持型号会清空上传字段) + - 检查文件类型与大小限制 +- 权限不足 + - 超级管理员页面访问被拦截时,确认当前用户角色 +- 推送搜索失败 + - 查看校验失败列表,修正问题型号后再重试 + +章节来源 +- [frontend/src/views/login/index.vue:144-149](file://frontend/src/views/login/index.vue#L144-L149) +- [frontend/src/views/ota/index.vue:384-418](file://frontend/src/views/ota/index.vue#L384-L418) +- [frontend/src/views/model/index.vue:494-506](file://frontend/src/views/model/index.vue#L494-L506) +- [frontend/src/router/index.js:75-79](file://frontend/src/router/index.js#L75-L79) + +## 结论 +本文档系统梳理了各功能页面的路由、数据获取、表单验证与交互流程,并结合状态管理、错误处理与加载状态给出实现参考。页面间通过路由与 API 进行解耦协作,整体具备良好的可维护性与扩展性。 + +## 附录 +- 路由元信息 + - requiresAuth:是否需要登录 + - requiresSuperAdmin:是否需要超级管理员 + - title/icon:菜单标题与图标 +- 常用工具 + - 时间格式化:formatTime/formatDateTime + - 消息提示:ElMessage + - 确认对话框:ElMessageBox \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/前端组件/页面组件/首页仪表板.md b/.qoder/repowiki/zh/content/前端组件/页面组件/首页仪表板.md new file mode 100644 index 0000000..3aa92a0 --- /dev/null +++ b/.qoder/repowiki/zh/content/前端组件/页面组件/首页仪表板.md @@ -0,0 +1,368 @@ +# 首页仪表板 + + +**本文引用的文件列表** +- [frontend/src/views/home/index.vue](file://frontend/src/views/home/index.vue) +- [frontend/src/api/dashboard.js](file://frontend/src/api/dashboard.js) +- [frontend/src/utils/request.js](file://frontend/src/utils/request.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [frontend/src/utils/auth.js](file://frontend/src/utils/auth.js) +- [frontend/src/utils/tabs.js](file://frontend/src/utils/tabs.js) +- [frontend/src/layout/index.vue](file://frontend/src/layout/index.vue) +- [frontend/src/components/TabsView.vue](file://frontend/src/components/TabsView.vue) +- [frontend/src/App.vue](file://frontend/src/App.vue) +- [backend/src/routes/dashboard.js](file://backend/src/routes/dashboard.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/models/Model.js](file://backend/src/models/Model.js) +- [backend/src/models/Ota.js](file://backend/src/models/Ota.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [组件详细分析](#组件详细分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件面向“首页仪表板”页面,系统性阐述其功能布局、数据展示机制、数据获取流程、响应式布局与样式定制、快捷入口配置与路由跳转、生命周期与错误处理、以及性能优化最佳实践。目标读者既包括前端开发者,也包括需要理解整体工作流的产品与运营人员。 + +## 项目结构 +首页位于前端单页应用中,采用 Vue 3 + Element Plus 组合,后端基于 Express + Sequelize 提供接口。首页通过 API 获取“今日新增”数据,并在页面上以卡片网格展示;同时提供快捷入口卡片,点击后通过路由跳转到相应功能模块。 + +```mermaid +graph TB +subgraph "前端" +A["App.vue
根组件"] +B["Layout/index.vue
布局容器"] +C["TabsView.vue
标签页视图"] +D["Home/index.vue
首页仪表板"] +E["api/dashboard.js
今日统计API封装"] +F["utils/request.js
HTTP拦截器"] +G["router/index.js
路由与鉴权守卫"] +H["utils/auth.js
鉴权工具"] +I["utils/tabs.js
标签页常量"] +end +subgraph "后端" +J["routes/dashboard.js
GET /api/dashboard/today"] +K["utils/response.js
统一响应结构"] +L["models/Model.js
型号模型"] +M["models/Ota.js
OTA模型"] +end +A --> B +B --> C +C --> D +D --> E +E --> F +F --> J +G --> H +J --> K +J --> L +J --> M +``` + +图表来源 +- [frontend/src/App.vue:1-30](file://frontend/src/App.vue#L1-L30) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/components/TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [frontend/src/views/home/index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) +- [frontend/src/api/dashboard.js:1-12](file://frontend/src/api/dashboard.js#L1-L12) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [frontend/src/utils/tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [backend/src/routes/dashboard.js:1-66](file://backend/src/routes/dashboard.js#L1-L66) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +章节来源 +- [frontend/src/views/home/index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/routes/dashboard.js:1-66](file://backend/src/routes/dashboard.js#L1-L66) + +## 核心组件 +- 首页仪表板组件:负责渲染欢迎信息、快捷入口卡片、今日新增统计区域,并在挂载时触发数据加载。 +- 今日统计 API 封装:封装 GET /api/dashboard/today 请求,返回 Promise。 +- HTTP 请求拦截器:统一设置 Authorization 头、处理 401/403/通用错误提示。 +- 路由与鉴权:全局前置守卫校验登录态与超级管理员权限,控制访问与重定向。 +- 布局与标签页:侧边栏导航、面包屑、用户下拉菜单、标签页持久化与缓存策略。 +- 后端路由与模型:按日期范围查询型号与 OTA 新增记录,统一响应结构。 + +章节来源 +- [frontend/src/views/home/index.vue:97-149](file://frontend/src/views/home/index.vue#L97-L149) +- [frontend/src/api/dashboard.js:1-12](file://frontend/src/api/dashboard.js#L1-L12) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/layout/index.vue:144-222](file://frontend/src/layout/index.vue#L144-L222) +- [frontend/src/components/TabsView.vue:55-287](file://frontend/src/components/TabsView.vue#L55-L287) +- [backend/src/routes/dashboard.js:19-63](file://backend/src/routes/dashboard.js#L19-L63) + +## 架构总览 +首页数据流自上而下:浏览器发起请求 -> 前端 Axios 拦截器 -> 后端路由 -> 数据库查询 -> 统一响应 -> 前端解析并渲染。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant V as "Home/index.vue" +participant A as "api/dashboard.js" +participant R as "utils/request.js" +participant S as "Express 路由" +participant DB as "数据库" +U->>V : 访问首页 +V->>V : onMounted 触发 +V->>A : 调用 getTodayStats() +A->>R : request({ url : '/dashboard/today', method : 'get' }) +R->>S : 发送带 Authorization 的 GET /api/dashboard/today +S->>DB : 查询今日新增型号/OTA +DB-->>S : 返回记录集 +S-->>R : ApiResponse.success({models, otas}) +R-->>A : 返回 {code,data} +A-->>V : 返回结果 +V->>V : 更新 todayModels/todayOtas +V-->>U : 渲染今日新增卡片 +``` + +图表来源 +- [frontend/src/views/home/index.vue:127-148](file://frontend/src/views/home/index.vue#L127-L148) +- [frontend/src/api/dashboard.js:6-11](file://frontend/src/api/dashboard.js#L6-L11) +- [frontend/src/utils/request.js:12-69](file://frontend/src/utils/request.js#L12-L69) +- [backend/src/routes/dashboard.js:19-63](file://backend/src/routes/dashboard.js#L19-L63) + +## 组件详细分析 + +### 首页仪表板组件(Home) +- 功能布局 + - 欢迎信息:根据本地存储的用户信息动态显示用户名。 + - 快捷入口卡片:支持点击跳转至品牌、型号、OTA、分享日志等模块。 + - 今日新增统计:分两列网格展示“新增型号”和“新增 OTA”,包含加载态、空态与列表项。 +- 数据绑定与状态 + - 使用响应式引用保存加载状态、今日新增列表。 + - 通过计算属性读取用户名,提升渲染效率。 +- 交互行为 + - 快捷入口卡片点击事件触发路由跳转。 + - 列表项 hover 效果增强可读性。 +- 样式与布局 + - 使用 CSS Grid 控制快捷入口与今日新增卡片布局。 + - 使用 :deep 选择器覆盖 Element Plus 卡片内部样式。 + - 响应式断点:快捷入口卡片自动换行,最大宽度限制。 +- 生命周期 + - 在 mounted 钩子中调用加载函数,保证 DOM 可见后再进行异步数据请求。 +- 错误处理 + - try/catch 包裹 API 调用,捕获异常并打印日志。 + - finally 中关闭加载态,避免 UI 长时间处于加载中。 +- 性能优化 + - 列表滚动容器设置最大高度并开启纵向滚动,避免长列表撑开页面。 + - 列表项 hover 仅做背景色过渡,减少复杂动画。 + +章节来源 +- [frontend/src/views/home/index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) + +### 今日统计 API 与数据格式 +- API 定义 + - 方法:GET + - 路径:/api/dashboard/today + - 返回:统一响应结构,包含 models 与 otas 数组。 +- 数据格式 + - models:包含 id、brand_name、name、create_at(ISO 字符串)。 + - otas:包含 id、verName、model、create_at(ISO 字符串)。 +- 前端解析 + - 校验响应 code 是否为成功标识,再将 data.models 与 data.otas 写入组件状态。 + - 时间字段通过格式化函数转换为 HH:mm 展示。 + +章节来源 +- [frontend/src/api/dashboard.js:1-12](file://frontend/src/api/dashboard.js#L1-L12) +- [backend/src/routes/dashboard.js:43-58](file://backend/src/routes/dashboard.js#L43-L58) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +### HTTP 请求拦截器与鉴权 +- 请求拦截 + - 自动注入 Authorization: Bearer token(除登录接口外)。 + - 统一 baseURL 为 /api。 +- 响应拦截 + - code 为 0 时视为业务错误,抛出错误并可选提示。 + - 401 强制清空鉴权信息并跳转登录页。 + - 403 提示权限不足。 + - 其他错误统一提示网络错误。 +- 鉴权工具 + - 令牌与用户信息存储于 localStorage。 + - 支持从 JWT 解析用户信息与过期时间判断。 + +章节来源 +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) + +### 路由与导航 +- 路由配置 + - 首页路径为 /home,作为 / 的子路由。 + - 所有子路由均需登录,部分路由需超级管理员权限。 +- 导航与面包屑 + - 侧边栏提供主要功能入口,支持折叠与高亮。 + - 标签页组件负责多页面切换与持久化。 +- 用户菜单 + - 支持修改密码、账号管理(超级管理员)、退出登录。 + +章节来源 +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/layout/index.vue:144-222](file://frontend/src/layout/index.vue#L144-L222) +- [frontend/src/components/TabsView.vue:55-287](file://frontend/src/components/TabsView.vue#L55-L287) + +### 后端路由与数据模型 +- 路由逻辑 + - 使用鉴权中间件保护接口。 + - 计算今日 00:00:00(UTC+8)作为起始时间。 + - 分别查询型号与 OTA 表中 create_at ≥ 今日起始时间的记录,按 id 降序。 + - 统一返回 ApiResponse.success 结构。 +- 数据模型 + - Model:包含品牌名、型号名、创建时间等字段。 + - Ota:包含版本号、版本名、URL、MD5、目标型号、创建时间等字段。 + +章节来源 +- [backend/src/routes/dashboard.js:19-63](file://backend/src/routes/dashboard.js#L19-L63) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +### 快捷入口配置与路由跳转 +- 配置方式 + - quickLinks 数组定义了四个入口项,每项包含 path、title、desc、icon。 + - 图标通过动态组件渲染,支持任意 Element Plus 图标。 +- 跳转机制 + - 点击卡片触发 go(path) 函数,内部使用 vue-router 的 push 实现导航。 + - 与侧边栏导航保持一致的路径约定,便于统一维护。 + +章节来源 +- [frontend/src/views/home/index.vue:113-144](file://frontend/src/views/home/index.vue#L113-L144) +- [frontend/src/router/index.js:26-54](file://frontend/src/router/index.js#L26-L54) + +### 生命周期管理与错误处理 +- 生命周期 + - onMounted 中触发 loadTodayStats,确保 DOM 初始化完成后再发起请求。 +- 错误处理 + - try/catch 捕获异常,finally 关闭 loading。 + - 响应拦截器对 401/403 做统一处理,避免页面卡死。 +- 用户体验 + - 加载态与空态分别渲染,避免白屏与闪烁。 + - hover 效果与时间格式化提升可读性。 + +章节来源 +- [frontend/src/views/home/index.vue:127-148](file://frontend/src/views/home/index.vue#L127-L148) +- [frontend/src/utils/request.js:28-69](file://frontend/src/utils/request.js#L28-L69) + +### 性能优化最佳实践 +- 列表渲染 + - 使用 v-for 渲染列表,合理设置 key,避免重复渲染。 + - 为长列表设置最大高度与滚动条,降低布局抖动。 +- 缓存与复用 + - 标签页组件使用 KeepAlive 对组件进行缓存,减少重复渲染。 + - sessionStorage 持久化标签页状态,刷新后恢复。 +- 网络请求 + - 统一 baseURL 与超时设置,避免请求堆积。 + - 401 自动跳转登录,避免无效请求占用资源。 + +章节来源 +- [frontend/src/components/TabsView.vue:47-50](file://frontend/src/components/TabsView.vue#L47-L50) +- [frontend/src/utils/request.js:6-9](file://frontend/src/utils/request.js#L6-L9) +- [frontend/src/views/home/index.vue:250-284](file://frontend/src/views/home/index.vue#L250-L284) + +## 依赖关系分析 +- 组件耦合 + - Home 依赖 api/dashboard.js 与 utils/request.js,形成清晰的职责分离。 + - 与路由层通过 go(path) 解耦,便于测试与替换。 +- 外部依赖 + - Element Plus 提供 UI 组件与图标。 + - Vue Router 提供导航能力。 + - Axios 提供 HTTP 能力与拦截器。 +- 数据一致性 + - 后端统一响应结构,前端按约定解析,降低耦合度。 + - 模型字段与接口返回字段一一对应,便于扩展。 + +```mermaid +classDiagram +class HomeIndexVue { ++username : ComputedRef ++todayLoading : Ref ++todayModels : Ref ++todayOtas : Ref ++quickLinks : any[] ++loadTodayStats() ++go(path) ++formatTime(isoStr) +} +class DashboardApi { ++getTodayStats() +} +class RequestUtil { ++interceptors.request ++interceptors.response +} +class RouterGuard { ++beforeEach(to, from, next) +} +class LayoutIndexVue { ++activeMenu ++handleUserMenuCommand() +} +HomeIndexVue --> DashboardApi : "调用" +DashboardApi --> RequestUtil : "封装请求" +LayoutIndexVue --> RouterGuard : "依赖" +``` + +图表来源 +- [frontend/src/views/home/index.vue:97-149](file://frontend/src/views/home/index.vue#L97-L149) +- [frontend/src/api/dashboard.js:6-11](file://frontend/src/api/dashboard.js#L6-L11) +- [frontend/src/utils/request.js:12-69](file://frontend/src/utils/request.js#L12-L69) +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/layout/index.vue:144-222](file://frontend/src/layout/index.vue#L144-L222) + +## 性能考量 +- 渲染层面 + - 长列表设置固定高度与滚动,避免频繁重排。 + - 使用 :deep 覆盖第三方组件样式,减少不必要的样式穿透。 +- 网络层面 + - 统一超时与 baseURL,减少请求失败带来的等待。 + - 401 自动清理鉴权信息并跳转,避免无效请求。 +- 缓存层面 + - 标签页 KeepAlive 与 sessionStorage 持久化,减少重复渲染与数据请求。 + +## 故障排查指南 +- 无法加载今日数据 + - 检查后端接口是否返回统一响应结构。 + - 确认前端解析逻辑是否正确处理 code 与 data。 +- 登录态失效 + - 查看响应拦截器对 401 的处理逻辑,确认是否被自动跳转登录。 + - 检查本地存储中的 token 是否存在且未过期。 +- 权限不足 + - 检查路由守卫是否正确识别超级管理员权限。 + - 确认用户角色与路由 meta.requiresSuperAdmin 的匹配。 +- 快捷入口不生效 + - 检查 quickLinks 的 path 是否与路由配置一致。 + - 确认 go(path) 调用是否正确触发路由跳转。 + +章节来源 +- [frontend/src/utils/request.js:28-69](file://frontend/src/utils/request.js#L28-L69) +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/views/home/index.vue:113-144](file://frontend/src/views/home/index.vue#L113-L144) + +## 结论 +首页仪表板通过清晰的组件划分、统一的 API 约定与完善的鉴权与拦截机制,实现了良好的用户体验与可维护性。建议后续在以下方面持续优化: +- 增加加载骨架屏与错误重试策略,进一步提升弱网体验。 +- 对今日新增列表增加分页或虚拟滚动,应对数据量增长。 +- 将快捷入口配置抽象为可配置文件,便于产品侧快速调整。 + +## 附录 +- 快捷入口卡片配置项 + - path:目标路由路径 + - title:卡片标题 + - desc:卡片描述 + - icon:Element Plus 图标组件 +- 标签页持久化键值 + - sessionStorage 中存储的键名用于恢复标签页状态 + +章节来源 +- [frontend/src/views/home/index.vue:113-118](file://frontend/src/views/home/index.vue#L113-L118) +- [frontend/src/utils/tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/后端API文档/OTA固件API.md b/.qoder/repowiki/zh/content/后端API文档/OTA固件API.md new file mode 100644 index 0000000..b8ace30 --- /dev/null +++ b/.qoder/repowiki/zh/content/后端API文档/OTA固件API.md @@ -0,0 +1,388 @@ +# OTA固件API + + +**本文引用的文件** +- [backend/src/routes/ota.js](file://backend/src/routes/ota.js) +- [backend/src/models/Ota.js](file://backend/src/models/Ota.js) +- [backend/src/services/otaStorage.js](file://backend/src/services/otaStorage.js) +- [backend/src/validators/ota.js](file://backend/src/validators/ota.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [frontend/src/api/ota.js](file://frontend/src/api/ota.js) +- [frontend/src/views/ota/index.vue](file://frontend/src/views/ota/index.vue) +- [backend/package.json](file://backend/package.json) +- [frontend/package.json](file://frontend/package.json) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件为OTA固件管理API的完整RESTful接口文档,涵盖固件版本管理的HTTP方法、URL模式、请求/响应格式以及文件上传处理流程。内容包括: +- 固件版本列表查询、详情获取、创建、更新、删除接口 +- 设备端“最新版本检查”接口 +- 文件上传(Luxsin-X8上传至S3,Luxsin-X9保存到本地目录) +- 存储服务配置与使用示例 +- 固件版本比较、强制更新策略与兼容性检查机制 +- 下载链接生成、版本升级通知与错误处理实现指南 + +## 项目结构 +后端采用Express + Sequelize + MySQL架构,前端基于Vue3 + Element Plus。OTA相关逻辑集中在路由、模型、服务层与验证器中,并通过统一响应封装返回。 + +```mermaid +graph TB +subgraph "前端" +FE_API["前端API模块
frontend/src/api/ota.js"] +FE_VIEW["OTA页面视图
frontend/src/views/ota/index.vue"] +end +subgraph "后端" +ROUTER["OTA路由
backend/src/routes/ota.js"] +AUTH["认证中间件
backend/src/middleware/auth.js"] +RESP["统一响应封装
backend/src/utils/response.js"] +VALID["参数校验
backend/src/validators/ota.js"] +MODEL["数据库模型
backend/src/models/Ota.js"] +STORE["存储服务
backend/src/services/otaStorage.js"] +ENV["环境配置
backend/src/config/env.js"] +end +FE_API --> ROUTER +FE_VIEW --> FE_API +ROUTER --> AUTH +ROUTER --> VALID +ROUTER --> MODEL +ROUTER --> STORE +ROUTER --> RESP +STORE --> ENV +``` + +图表来源 +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [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) + +章节来源 +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [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) + +## 核心组件 +- 路由层:定义所有OTA相关HTTP接口,包含设备端“最新版本检查”和后台管理接口。 +- 认证中间件:保护后台接口,要求Bearer Token。 +- 参数校验:使用Zod对创建/更新请求体进行严格校验。 +- 数据模型:Sequelize定义的OTA表结构,包含版本号、MD5、强制更新、定向灰度、时间窗口等字段。 +- 存储服务:根据设备型号选择不同存储路径(S3或本地),并生成公开下载链接。 +- 响应封装:统一封装成功/错误/无数据三类响应格式。 + +章节来源 +- [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/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 架构总览 +OTA接口分为两类: +- 设备端调用:无需登录,用于查询最新可升级版本。 +- 后台管理:需登录,用于维护OTA版本列表、上传升级包、查看/编辑/删除。 + +```mermaid +sequenceDiagram +participant Device as "设备端" +participant Router as "OTA路由" +participant Model as "数据库模型" +participant Logger as "日志" +Device->>Router : GET /api/ota/latest/check?currentVerCode&model&hw +Router->>Model : 查询 verCode > 当前版本且状态可用 +alt 找到更高版本 +Model-->>Router : 返回最高版本记录 +Router-->>Device : 成功响应含下载URL、MD5、是否强制等 +else 无更高版本 +Router-->>Device : 无数据响应 +end +Router->>Logger : 记录查询结果 +``` + +图表来源 +- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +## 详细组件分析 + +### 设备端“最新版本检查” +- 方法与路径:GET /api/ota/latest/check +- 请求参数: + - currentVerCode: 当前设备版本号(整数) + - model: 设备型号(如 Luxsin-X8/X9) + - hw: 可选硬件版本号(整数) +- 响应: + - 成功:返回最高可用版本记录(含URL、MD5、是否强制更新、定向/灰度等) + - 无数据:表示无更高可用版本 +- 兼容性与策略: + - 仅查询状态为可用且版本号大于当前版本的记录 + - 支持按硬件版本过滤 + - 强制更新字段用于客户端决定是否强制升级 + +章节来源 +- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102) + +### 后台管理接口(需登录) + +#### 获取OTA版本列表 +- 方法与路径:GET /api/ota/ +- 查询参数: + - skip: 跳过条数(默认0) + - limit: 每页数量(默认100,最大1000) + - verCode: 精确匹配版本号 + - verName: 模糊匹配版本名称 + - model: 模糊匹配设备型号 + - status: 状态(0/1) +- 响应:分页数据(items、total、skip、limit) + +章节来源 +- [backend/src/routes/ota.js:107-143](file://backend/src/routes/ota.js#L107-L143) + +#### 获取指定OTA详情 +- 方法与路径:GET /api/ota/:ota_id +- 路径参数:ota_id(整数) +- 响应:单条记录或无数据 + +章节来源 +- [backend/src/routes/ota.js:145-160](file://backend/src/routes/ota.js#L145-L160) + +#### 创建OTA版本 +- 方法与路径:POST /api/ota/ +- 请求体字段(必填/可选见校验规则): + - verCode: 整数(唯一性约束:同model下不可重复) + - verName: 字符串(1~20) + - url: 字符串(下载地址或上传后生成的URL) + - md5: 32位十六进制字符串 + - force: 0/1(默认0) + - desc: 描述(可空) + - model: 设备型号(可空) + - hw: 硬件版本号(默认0) + - target: 是否定向(0/1,默认0) + - beta: 是否灰度(0/1,默认0) + - startTime/endTime: 时间字符串(可空) + - status: 状态(0/1,默认1) +- 响应:创建成功的记录 + +章节来源 +- [backend/src/routes/ota.js:162-194](file://backend/src/routes/ota.js#L162-L194) +- [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) + +#### 更新OTA版本 +- 方法与路径:PUT /api/ota/:ota_id +- 请求体字段:同创建接口(部分字段可为空表示不更新) +- 响应:更新后的记录 +- 注意: + - 若更新版本号或设备型号,需保证新的组合在同model下唯一 + - 日期字段会自动转换为Date类型 + +章节来源 +- [backend/src/routes/ota.js:196-247](file://backend/src/routes/ota.js#L196-L247) +- [backend/src/validators/ota.js:19-33](file://backend/src/validators/ota.js#L19-L33) + +#### 删除OTA版本 +- 方法与路径:DELETE /api/ota/:ota_id +- 响应:删除成功消息 + +章节来源 +- [backend/src/routes/ota.js:249-268](file://backend/src/routes/ota.js#L249-L268) + +### 文件上传与存储 + +#### 接口:上传升级包 +- 方法与路径:POST /api/ota/upload-package +- 请求头:Content-Type: multipart/form-data +- 表单字段: + - package_file: 二进制文件 + - model: 设备型号(仅支持 Luxsin-X8 或 Luxsin-X9) +- 响应: + - 成功:返回md5、filename、url;X8同时返回s3_key + - 错误:返回错误信息(如未配置S3、上传失败、不支持的设备型号等) + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Router as "OTA路由" +participant Store as "存储服务" +participant S3 as "S3客户端" +participant FS as "本地文件系统" +Client->>Router : POST /api/ota/upload-package +Router->>Store : readUploadContentAndMd5(buffer) +alt model == Luxsin-X9 +Store->>FS : 写入本地文件并生成URL +FS-->>Store : 返回保存名与URL +else model == Luxsin-X8 +Store->>S3 : 上传对象并生成URL +S3-->>Store : 返回保存名、URL与S3 Key +end +Store-->>Router : {md5, filename, url[, s3_key]} +Router-->>Client : 成功响应 +``` + +图表来源 +- [backend/src/routes/ota.js:24-66](file://backend/src/routes/ota.js#L24-L66) +- [backend/src/services/otaStorage.js:46-103](file://backend/src/services/otaStorage.js#L46-L103) + +#### 存储策略与配置 +- 设备型号支持:Luxsin-X8、Luxsin-X9 +- 存储方式: + - X8:上传至S3,生成公开访问URL + - X9:写入本地目录,生成公开访问URL +- 关键环境变量(来自存储服务): + - OTA_UPLOAD_DIR:本地上传根目录(开发默认临时目录,生产默认/data/projects/source) + - AWS_REGION/AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY:S3区域与凭证(无凭证时走IAM角色) + - AWS_S3_OTA_BUCKET:S3存储桶名称 + - OTA_X8_PUBLIC_BASE:X8公开URL基础路径 + - OTA_X9_URL_BASE:X9公开URL基础路径 + +章节来源 +- [backend/src/services/otaStorage.js:12-25](file://backend/src/services/otaStorage.js#L12-L25) +- [backend/src/services/otaStorage.js:51-103](file://backend/src/services/otaStorage.js#L51-L103) + +### 前端集成与使用示例 +- 前端API模块提供: + - 列表、详情、创建、更新、删除、上传包等方法 +- OTA页面视图: + - 支持搜索(版本名、设备型号、状态、版本号) + - 分页与表格展示 + - 上传升级包(X8/X9)并回填URL与MD5 + - 表单校验与提交 + +章节来源 +- [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) + +## 依赖关系分析 + +```mermaid +classDiagram +class OtaRoute { ++GET "/api/ota/" ++GET "/api/ota/ : ota_id" ++POST "/api/ota/" ++PUT "/api/ota/ : ota_id" ++DELETE "/api/ota/ : ota_id" ++POST "/api/ota/upload-package" ++GET "/api/ota/latest/check" +} +class AuthMiddleware { ++authMiddleware() +} +class ApiResponse { ++success(data,msg) ++error(msg,code) ++noData(msg) +} +class OtaValidator { ++OtaCreateSchema ++OtaUpdateSchema +} +class OtaModel { ++verCode : int ++verName : string ++url : string ++md5 : string ++force : smallint ++desc : string ++model : string ++hw : int ++target : smallint ++beta : smallint ++startTime : date ++endTime : date ++status : smallint +} +class OtaStorage { ++readUploadContentAndMd5() ++saveX9PackageLocal() ++uploadX8PackageToS3() +} +OtaRoute --> AuthMiddleware : "保护后台接口" +OtaRoute --> OtaValidator : "参数校验" +OtaRoute --> OtaModel : "读写数据库" +OtaRoute --> OtaStorage : "文件上传" +OtaRoute --> ApiResponse : "统一响应" +``` + +图表来源 +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [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) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +## 性能考量 +- 列表查询限制每页最大1000条,避免一次性返回过多数据。 +- “最新版本检查”接口按verCode降序查询第一条,索引建议: + - 在verCode、model、status上建立复合索引以提升查询效率。 +- 文件上传使用内存存储(multer.memoryStorage),大文件可能影响内存占用,建议: + - 控制上传文件大小与超时时间(前端已设置较长超时)。 + - 对于X8大文件,优先考虑流式上传或分片上传策略(当前实现为一次性上传)。 + +[本节为通用性能建议,不直接分析具体文件] + +## 故障排查指南 +- 认证失败(401): + - 检查请求头Authorization是否为Bearer Token + - 确认Token未过期 +- 参数校验失败: + - 按照Zod校验规则修正请求体字段(长度、类型、取值范围) +- 版本冲突: + - 创建/更新时若verCode与model组合重复,会返回“该版本已存在” +- S3上传失败: + - 检查AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY与AWS_S3_OTA_BUCKET配置 + - 确认S3权限与存储桶存在 +- 无可用版本: + - 设备端查询不到更高版本时返回“无数据”,确认目标设备型号、硬件版本与状态 + +章节来源 +- [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/services/otaStorage.js:72-103](file://backend/src/services/otaStorage.js#L72-L103) + +## 结论 +本OTA固件API提供了完善的版本管理能力,支持设备端“最新版本检查”与后台管理功能,结合S3与本地存储策略满足不同设备型号的升级包分发需求。通过严格的参数校验与统一响应封装,提升了接口的稳定性与易用性。建议在生产环境中完善索引、优化大文件上传策略,并加强S3权限与监控告警。 + +[本节为总结性内容,不直接分析具体文件] + +## 附录 + +### 统一响应格式 +- 成功:code=1,msg为成功信息,data为返回数据 +- 错误:code=0,msg为错误信息,data=null +- 无数据:code=2,msg为提示信息,data=null + +章节来源 +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +### 设备端版本比较与强制更新策略 +- 版本比较:仅返回verCode大于当前版本且状态为可用的最高版本 +- 强制更新:由force字段控制,客户端据此决定是否强制升级 +- 定向/灰度:target/beta字段可用于控制发布范围 + +章节来源 +- [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) + +### 前端调用示例(参考) +- 列表查询:传入skip、limit、verName、model、status、verCode +- 上传包:构造FormData,包含package_file与model,设置Content-Type为multipart/form-data +- 提交表单:根据设备型号决定是否需要先上传包再填写URL/MD5 + +章节来源 +- [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) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/后端API文档/仪表板API.md b/.qoder/repowiki/zh/content/后端API文档/仪表板API.md new file mode 100644 index 0000000..7a21768 --- /dev/null +++ b/.qoder/repowiki/zh/content/后端API文档/仪表板API.md @@ -0,0 +1,418 @@ +# 仪表板API + + +**本文档引用的文件** +- [backend/src/routes/dashboard.js](file://backend/src/routes/dashboard.js) +- [backend/src/routes/models.js](file://backend/src/routes/models.js) +- [backend/src/models/Model.js](file://backend/src/models/Model.js) +- [backend/src/models/Ota.js](file://backend/src/models/Ota.js) +- [backend/src/models/DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [backend/src/services/measurementStorage.js](file://backend/src/services/measurementStorage.js) +- [frontend/src/api/dashboard.js](file://frontend/src/api/dashboard.js) +- [frontend/src/views/home/index.vue](file://frontend/src/views/home/index.vue) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件为“仪表板API”的RESTful接口文档,聚焦系统统计数据查询能力,覆盖以下指标与能力: +- 品牌数量统计:基于品牌模型的计数与唯一性约束,可用于统计品牌总数与活跃品牌数。 +- 型号分布情况:按品牌、形式、阻抗等维度进行分组统计与聚合展示。 +- OTA更新状态:按版本状态、目标范围、灰度/强升等维度进行筛选与聚合。 +- 用户活跃度:后台用户登录时间与状态,用于评估管理员活跃度。 +- 数据聚合查询:按日期、品牌、型号等维度进行分组统计。 +- 时间序列分析:以“今日新增”为代表的日粒度趋势数据。 +- 图表数据格式:统一返回结构与字段命名,便于前端可视化。 +- 缓存策略:Redis缓存EQ键值,降低后端压力。 +- 性能优化:数据库索引、查询条件、分页与轻量字段返回。 +- 实时数据更新机制:通过定时任务或事件触发刷新缓存。 +- 自定义统计维度与数据导出:通过查询参数扩展维度与导出CSV。 + +本项目采用前后端分离架构,后端基于Express,数据库使用Sequelize ORM,前端使用Vue 3 + Element Plus。 + +## 项目结构 +后端采用模块化路由组织,仪表板相关接口集中在dashboard路由中,并通过认证中间件保护。前端通过API封装调用后端接口。 + +```mermaid +graph TB +FE["前端应用
Vue 3 + Element Plus"] --> API["仪表板API
/api/dashboard/*"] +API --> AUTH["认证中间件
Bearer Token"] +API --> RESP["统一响应封装
ApiResponse/PageData"] +API --> MODELS["型号模型
Model"] +API --> OTA["OTA模型
Ota"] +API --> REDIS["Redis 缓存
EQ缓存"] +API --> S3["S3 存储
频响CSV"] +AUTH --> USER["后台用户模型
DashboardUser"] +``` + +图示来源 +- [backend/src/routes/dashboard.js:1-66](file://backend/src/routes/dashboard.js#L1-L66) +- [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/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +章节来源 +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) + +## 核心组件 +- 认证中间件:校验Authorization头中的Bearer Token,注入用户上下文。 +- 统一响应封装:提供成功/错误/无数据三种响应结构,便于前端处理。 +- 仪表板路由:提供“今日新增”接口,返回型号与OTA的当日增量数据。 +- 模型与OTA数据模型:定义品牌、型号、OTA等核心实体字段。 +- Redis缓存服务:提供EQ缓存键值读取与字段解析。 +- S3存储服务:提供频响CSV上传与读取能力,支持来源与佩戴方式等维度。 + +章节来源 +- [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/routes/dashboard.js:1-66](file://backend/src/routes/dashboard.js#L1-L66) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +## 架构总览 +后端启动时同步数据库表并挂载所有路由,根路径与健康检查接口无需认证,业务路由统一通过认证中间件保护。仪表板接口在路由层引入认证中间件,确保只有登录用户可访问。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant App as "Express 应用" +participant Router as "仪表板路由" +participant Auth as "认证中间件" +participant Resp as "统一响应" +participant DB as "数据库" +Client->>App : GET / +App-->>Client : {message, docs, redoc} +Client->>App : GET /health +App-->>Client : {status : "healthy"} +Client->>Router : GET /api/dashboard/today +Router->>Auth : 校验 Bearer Token +Auth-->>Router : 注入用户上下文 +Router->>DB : 查询今日新增型号与OTA +DB-->>Router : 返回结果 +Router->>Resp : 包装响应 +Resp-->>Client : {code,msg,data} +``` + +图示来源 +- [backend/src/app.js:22-38](file://backend/src/app.js#L22-L38) +- [backend/src/routes/dashboard.js:12-66](file://backend/src/routes/dashboard.js#L12-L66) +- [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) + +## 详细组件分析 + +### 仪表板路由与“今日新增”接口 +- 接口:GET /api/dashboard/today +- 认证:需登录(路由内挂载认证中间件) +- 功能:返回当日00:00起至当前的新增型号与OTA列表 +- 请求参数:无 +- 响应字段: + - models:数组,包含id、brand_name、name、create_at + - otas:数组,包含id、verName、model、create_at +- 时间范围:以服务器所在时区计算当日起点 +- 错误处理:捕获异常并返回统一错误响应 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant R as "仪表板路由" +participant A as "认证中间件" +participant M as "Model模型" +participant O as "Ota模型" +participant U as "统一响应" +C->>R : GET /api/dashboard/today +R->>A : 校验Token +A-->>R : 注入用户 +R->>M : 查询当日新增型号 +M-->>R : 型号列表 +R->>O : 查询当日新增OTA +O-->>R : OTA列表 +R->>U : 包装响应 +U-->>C : {code,msg,data} +``` + +图示来源 +- [backend/src/routes/dashboard.js:16-66](file://backend/src/routes/dashboard.js#L16-L66) +- [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/routes/dashboard.js:1-66](file://backend/src/routes/dashboard.js#L1-L66) + +### 型号与OTA数据模型 +- 型号模型(Model):包含品牌名、型号名、形式、阻抗、来源、EQ键、创建时间等字段,支持按品牌与型号组合唯一性约束。 +- OTA模型(Ota):包含版本号、版本名、升级包URL、MD5、是否强升、描述、对应型号、硬件版本、目标范围、灰度状态、起止时间、状态、创建时间等字段,支持按版本号与名称等维度筛选。 + +```mermaid +erDiagram +MODEL { +int id PK +string brand_name +string name +string form +string rig +string source +string eq_key +datetime create_at +} +OTA { +int id PK +int verCode +string verName +string url +string md5 +smallint force +string desc +string model +int hw +smallint target +smallint beta +datetime startTime +datetime endTime +smallint status +datetime create_at +} +``` + +图示来源 +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +章节来源 +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +### Redis缓存与EQ键值读取 +- 缓存键构建规则:{品牌名称} {型号名称} +- 接口: + - GET /api/models/:model_id/eq-cache:返回该型号的缓存键与字段列表(不含value,避免响应过大) + - GET /api/models/:model_id/eq-cache/field?key=:返回指定字段的值(自动JSON解析) +- 错误处理:字段不存在、Redis读取失败等场景返回统一错误响应 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant R as "型号路由" +participant S as "EQ缓存服务" +participant RC as "Redis客户端" +participant U as "统一响应" +C->>R : GET /api/models/ : model_id/eq-cache +R->>S : getEqCacheKeys(brand,name) +S->>RC : hkeys(redisKey) +RC-->>S : field_keys +S-->>R : {redis_key, field_keys} +R->>U : 包装响应 +U-->>C : {code,msg,data} +C->>R : GET /api/models/ : model_id/eq-cache/field?key=... +R->>S : getEqCacheField(brand,name,key) +S->>RC : hget(redisKey,key) +RC-->>S : raw_value +S-->>R : {redis_key,key,value} +R->>U : 包装响应 +U-->>C : {code,msg,data} +``` + +图示来源 +- [backend/src/routes/models.js:192-223](file://backend/src/routes/models.js#L192-L223) +- [backend/src/services/eqCacheStorage.js:24-66](file://backend/src/services/eqCacheStorage.js#L24-L66) +- [backend/src/config/redis.js:11-29](file://backend/src/config/redis.js#L11-L29) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +章节来源 +- [backend/src/routes/models.js:192-223](file://backend/src/routes/models.js#L192-L223) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) + +### S3频响CSV读取 +- 接口:GET /api/models/:model_id/measurement +- 适用来源:仅支持来源为“Eafonyoung”的型号 +- 依赖字段:型号必须包含佩戴方式(form),否则无法定位S3文件 +- 返回:S3 Key与CSV内容字符串 +- 错误处理:来源不符、缺少form、S3未找到等场景返回统一错误响应 + +```mermaid +flowchart TD +Start(["请求进入"]) --> CheckSource["校验来源是否为 Eafonyoung"] +CheckSource --> |否| ErrSource["返回错误:仅支持 Eafonyoung"] +CheckSource --> |是| CheckForm["校验是否存在佩戴方式(form)"] +CheckForm --> |否| ErrForm["返回错误:缺少佩戴方式"] +CheckForm --> |是| BuildKey["构建S3 Key"] +BuildKey --> ReadS3["从S3读取CSV内容"] +ReadS3 --> Found{"找到文件?"} +Found --> |否| ErrNotFound["返回错误:S3未找到文件"] +Found --> |是| ReturnOK["返回 {s3_key,content}"] +ErrSource --> End(["结束"]) +ErrForm --> End +ErrNotFound --> End +ReturnOK --> End +``` + +图示来源 +- [backend/src/routes/models.js:246-278](file://backend/src/routes/models.js#L246-L278) +- [backend/src/services/measurementStorage.js:87-108](file://backend/src/services/measurementStorage.js#L87-L108) + +章节来源 +- [backend/src/routes/models.js:246-278](file://backend/src/routes/models.js#L246-L278) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +### 前端集成与使用示例 +- 前端API封装:提供获取“今日新增”的方法,内部调用 /dashboard/today +- 前端页面:首页卡片展示今日新增型号与OTA数量与列表,支持时间格式化显示 + +```mermaid +sequenceDiagram +participant V as "首页视图" +participant A as "仪表板API" +participant S as "后端仪表板路由" +V->>A : getTodayStats() +A->>S : GET /dashboard/today +S-->>A : {code,msg,data : {models,otas}} +A-->>V : Promise.resolve(data) +V->>V : 渲染今日新增卡片 +``` + +图示来源 +- [frontend/src/api/dashboard.js:1-12](file://frontend/src/api/dashboard.js#L1-L12) +- [frontend/src/views/home/index.vue:127-140](file://frontend/src/views/home/index.vue#L127-L140) +- [backend/src/routes/dashboard.js:16-66](file://backend/src/routes/dashboard.js#L16-L66) + +章节来源 +- [frontend/src/api/dashboard.js:1-12](file://frontend/src/api/dashboard.js#L1-L12) +- [frontend/src/views/home/index.vue:1-200](file://frontend/src/views/home/index.vue#L1-L200) + +## 依赖关系分析 +- 路由汇总:后端将各模块路由集中注册,包括仪表板路由 +- 认证链路:所有仪表板接口均受认证中间件保护 +- 数据模型:仪表板接口依赖Model与Ota模型进行查询 +- 缓存链路:型号路由依赖EQ缓存服务与Redis客户端 +- 存储链路:型号路由依赖S3存储服务进行频响文件读取 + +```mermaid +graph LR +RoutesIndex["路由汇总"] --> DashboardRoute["仪表板路由"] +RoutesIndex --> ModelsRoute["型号路由"] +DashboardRoute --> AuthMW["认证中间件"] +ModelsRoute --> AuthMW +DashboardRoute --> ModelModel["Model模型"] +DashboardRoute --> OtaModel["Ota模型"] +ModelsRoute --> EqCache["EQ缓存服务"] +ModelsRoute --> S3Svc["S3存储服务"] +AuthMW --> User["DashboardUser模型"] +``` + +图示来源 +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/routes/dashboard.js:1-66](file://backend/src/routes/dashboard.js#L1-L66) +- [backend/src/routes/models.js:192-223](file://backend/src/routes/models.js#L192-L223) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +章节来源 +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 性能考虑 +- 查询优化 + - 使用精确时间范围过滤当日新增,避免全表扫描 + - 仅返回必要字段,减少网络传输 +- 缓存策略 + - Redis缓存EQ键值,避免频繁读取数据库 + - 字段列表与单字段读取分离,控制响应大小 +- 存储优化 + - S3文件按来源、佩戴方式、品牌首字母与型号组织,便于快速定位 +- 并发与超时 + - Redis连接设置最大重试次数与连接超时 + - 前端对EQ缓存读取设置较长超时,避免弱网失败 +- 分页与限制 + - 当前“今日新增”接口未分页,建议后续扩展分页参数以应对高并发 + +## 故障排查指南 +- 认证失败 + - 现象:返回未登录或缺少凭证、无效凭证、登录已过期 + - 排查:确认Authorization头格式为Bearer Token,检查Token有效期 +- Redis读取失败 + - 现象:返回Redis读取失败或字段不存在 + - 排查:确认Redis连接配置正确,检查缓存键是否存在 +- S3文件未找到 + - 现象:返回S3上未找到该型号的频响文件 + - 排查:确认来源为Eafonyoung且存在佩戴方式,检查S3 Key拼接逻辑 +- 统一错误响应 + - 现象:接口返回code=0或2,msg包含错误信息 + - 排查:根据msg提示定位具体问题,查看后端日志 + +章节来源 +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/services/eqCacheStorage.js:38-66](file://backend/src/services/eqCacheStorage.js#L38-L66) +- [backend/src/services/measurementStorage.js:100-108](file://backend/src/services/measurementStorage.js#L100-L108) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 结论 +本仪表板API围绕“今日新增”这一高频指标提供了简洁高效的查询接口,并通过Redis缓存与S3存储提升了整体性能与可扩展性。建议后续在以下方面持续优化: +- 扩展更多统计维度(品牌、型号、OTA状态等)与分页能力 +- 引入时间序列分析接口,支持多日趋势对比 +- 完善缓存失效与更新策略,保证数据一致性 +- 提供数据导出能力(如CSV),满足报表需求 + +## 附录 + +### API定义与使用示例 + +- 获取今日新增(型号 + OTA) + - 方法:GET + - URL:/api/dashboard/today + - 认证:是 + - 请求参数:无 + - 响应字段: + - models:数组,元素含id、brand_name、name、create_at + - otas:数组,元素含id、verName、model、create_at + - 示例调用:前端通过 getTodayStats() 封装调用 + +章节来源 +- [backend/src/routes/dashboard.js:16-66](file://backend/src/routes/dashboard.js#L16-L66) +- [frontend/src/api/dashboard.js:1-12](file://frontend/src/api/dashboard.js#L1-L12) +- [frontend/src/views/home/index.vue:127-140](file://frontend/src/views/home/index.vue#L127-L140) + +### 缓存与实时更新机制 +- 缓存键:{品牌名称} {型号名称} +- 读取策略: + - 列表:仅返回字段名列表,避免大响应 + - 单字段:按key读取并自动解析JSON +- 实时更新:建议通过定时任务或事件触发刷新Redis缓存,确保前端展示最新数据 + +章节来源 +- [backend/src/services/eqCacheStorage.js:24-66](file://backend/src/services/eqCacheStorage.js#L24-L66) +- [backend/src/config/redis.js:11-29](file://backend/src/config/redis.js#L11-L29) + +### 数据导出与图表数据格式 +- 导出建议:在现有接口基础上增加查询参数(如时间范围、维度、格式)以支持导出 +- 图表数据格式:统一使用统一响应结构,前端按需转换为折线图、柱状图等所需格式 + +章节来源 +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/后端API文档/分享码日志API.md b/.qoder/repowiki/zh/content/后端API文档/分享码日志API.md new file mode 100644 index 0000000..82b4625 --- /dev/null +++ b/.qoder/repowiki/zh/content/后端API文档/分享码日志API.md @@ -0,0 +1,421 @@ +# 分享码日志API + + +**本文档引用的文件** +- [ShareCodeLog.js](file://backend/src/models/ShareCodeLog.js) +- [shareCodeLogs.js](file://backend/src/routes/shareCodeLogs.js) +- [response.js](file://backend/src/utils/response.js) +- [auth.js](file://backend/src/middleware/auth.js) +- [database.js](file://backend/src/config/database.js) +- [index.js](file://backend/src/routes/index.js) +- [app.js](file://backend/src/app.js) +- [shareCodeLog.js](file://frontend/src/api/shareCodeLog.js) +- [log.vue](file://frontend/src/views/share-code/log.vue) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +分享码日志API是一个基于Express.js和Sequelize的RESTful API服务,专门用于管理和查询分享码使用记录。该系统提供了完整的日志查询、筛选和统计分析功能,支持设备MAC地址、分享码、操作类型、IP地址等多种维度的查询,并具备分页查询和排序能力。 + +该API采用MySQL作为数据存储,通过索引优化确保大数据量场景下的查询性能。前端界面提供了直观的日志查询和展示功能,支持时间范围查询、用户筛选和设备类型过滤。 + +## 项目结构 + +分享码日志API位于项目的后端目录中,采用典型的三层架构设计: + +```mermaid +graph TB +subgraph "前端层" +FE_API[前端API模块
shareCodeLog.js] +FE_VIEW[前端视图组件
log.vue] +end +subgraph "后端层" +ROUTES[路由层
shareCodeLogs.js] +MIDDLEWARE[中间件层
auth.js] +MODELS[模型层
ShareCodeLog.js] +UTILS[工具类
response.js] +end +subgraph "基础设施层" +CONFIG[配置层
database.js] +APP[应用入口
app.js] +ROUTE_INDEX[路由汇总
index.js] +end +FE_API --> FE_VIEW +FE_VIEW --> ROUTES +ROUTES --> MIDDLEWARE +ROUTES --> MODELS +ROUTES --> UTILS +MODELS --> CONFIG +ROUTES --> ROUTE_INDEX +ROUTE_INDEX --> APP +APP --> CONFIG +``` + +**图表来源** +- [shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) +- [ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [database.js:1-24](file://backend/src/config/database.js#L1-L24) + +**章节来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 核心组件 + +### 数据模型定义 + +分享码日志模型定义了完整的数据结构和约束条件: + +| 字段名 | 数据类型 | 约束条件 | 描述 | +|--------|----------|----------|------| +| id | INTEGER | 主键, 自增 | 日志记录唯一标识 | +| mac_addr | STRING(17) | 非空 | 设备MAC地址,格式如AA:BB:CC:DD:EE:FF | +| share_code | CHAR(5) | 非空 | 分享码,固定5位字符 | +| action | ENUM | 非空 | 操作类型:export=导出, import=导入 | +| ip_addr | STRING(45) | 非空, 默认'' | 用户IP地址,支持IPv4/IPv6 | +| eq_data | JSON | 非空 | EQ数据快照,JSON格式存储 | +| expire_at | DATE | 可空 | 分享码到期时间(导出时快照) | +| create_at | DATE | 非空, 默认当前时间 | 操作时间戳 | + +### 数据库索引策略 + +为了优化查询性能,系统建立了以下复合索引: +- `idx_mac_addr`: 基于MAC地址的索引 +- `idx_share_code`: 基于分享码的索引 +- `idx_create_at`: 基于创建时间的索引 + +**章节来源** +- [ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) + +## 架构概览 + +分享码日志API采用MVC架构模式,结合中间件机制实现认证授权和请求处理: + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Auth as 认证中间件 +participant Route as 路由处理器 +participant Model as 数据模型 +participant DB as MySQL数据库 +Client->>Auth : 发送带Bearer Token的请求 +Auth->>Auth : 验证JWT令牌有效性 +Auth->>Route : 通过认证,传递用户信息 +Route->>Route : 解析查询参数和过滤条件 +Route->>Model : 执行数据库查询 +Model->>DB : 发送SQL查询请求 +DB-->>Model : 返回查询结果 +Model-->>Route : 返回ORM对象数组 +Route->>Route : 处理数据格式化和分页 +Route-->>Client : 返回标准化响应 +Note over Client,DB : 支持多维度查询和分页 +``` + +**图表来源** +- [shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) +- [auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) + +**章节来源** +- [shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +## 详细组件分析 + +### API接口规范 + +#### GET /api/share-code/logs - 日志列表查询 + +**请求参数** + +| 参数名 | 类型 | 必填 | 默认值 | 描述 | +|--------|------|------|--------|------| +| skip | number | 否 | 0 | 跳过记录数,用于分页 | +| limit | number | 否 | 100 | 每页记录数,最大1000 | +| mac_addr | string | 否 | 无 | 设备MAC地址模糊查询 | +| share_code | string | 否 | 无 | 分享码模糊查询 | +| action | enum | 否 | 无 | 操作类型:export/import | +| ip_addr | string | 否 | 无 | IP地址模糊查询 | +| start_at | string | 否 | 无 | 开始时间(ISO格式) | +| end_at | string | 否 | 无 | 结束时间(ISO格式) | +| sort_by | enum | 否 | id | 排序字段:id/create_at | +| sort_order | enum | 否 | desc | 排序方式:asc/desc | + +**响应格式** + +```mermaid +classDiagram +class ApiResponse { ++number code ++string msg ++any data +} +class PageData { ++Item[] items ++number total ++number skip ++number limit +} +class Item { ++number id ++string mac_addr ++string share_code ++string action ++string ip_addr ++object eq_data ++string expire_at ++string create_at +} +ApiResponse --> PageData : "包含" +PageData --> Item : "包含多个" +``` + +**图表来源** +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +**响应示例** +```javascript +{ + "code": 1, + "msg": "success", + "data": { + "items": [ + { + "id": 1, + "mac_addr": "AA:BB:CC:DD:EE:FF", + "share_code": "ABCD1", + "action": "export", + "ip_addr": "192.168.1.100", + "eq_data": { /* JSON格式的EQ数据 */ }, + "expire_at": "2024-01-01T12:00:00Z", + "create_at": "2024-01-01T10:00:00Z" + } + ], + "total": 150, + "skip": 0, + "limit": 100 + } +} +``` + +**章节来源** +- [shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +### 查询过滤逻辑 + +系统实现了灵活的查询过滤机制,支持多种组合查询条件: + +```mermaid +flowchart TD +Start([开始查询]) --> ParseParams["解析查询参数"] +ParseParams --> BuildWhere["构建WHERE条件"] +BuildWhere --> CheckMac{"MAC地址存在?"} +CheckMac --> |是| AddMac["添加MAC模糊查询"] +CheckMac --> |否| CheckCode{"分享码存在?"} +AddMac --> CheckCode +CheckCode --> |是| AddCode["添加分享码模糊查询"] +CheckCode --> |否| CheckAction{"操作类型存在?"} +AddCode --> CheckAction +CheckAction --> |是| AddAction["添加操作类型过滤"] +CheckAction --> |否| CheckIP{"IP地址存在?"} +AddAction --> CheckIP +CheckIP --> |是| AddIP["添加IP模糊查询"] +CheckIP --> |否| CheckTime{"时间范围存在?"} +AddIP --> CheckTime +CheckTime --> |是| AddTime["添加时间范围查询"] +CheckTime --> |否| ExecuteQuery["执行查询"] +AddTime --> ExecuteQuery +ExecuteQuery --> CheckResult{"有结果?"} +CheckResult --> |是| FormatData["格式化返回数据"] +CheckResult --> |否| ReturnEmpty["返回空数据"] +FormatData --> ReturnSuccess["返回成功响应"] +ReturnEmpty --> ReturnNoData["返回无数据响应"] +ReturnSuccess --> End([结束]) +ReturnNoData --> End +``` + +**图表来源** +- [shareCodeLogs.js:15-84](file://backend/src/routes/shareCodeLogs.js#L15-L84) + +**章节来源** +- [shareCodeLogs.js:31-48](file://backend/src/routes/shareCodeLogs.js#L31-L48) + +### 前端集成 + +前端提供了完整的日志查询界面,支持实时数据展示和交互操作: + +```mermaid +sequenceDiagram +participant User as 用户 +participant View as 视图组件 +participant API as API模块 +participant Backend as 后端服务 +User->>View : 输入查询条件 +View->>View : 构建查询参数 +View->>API : 调用getShareCodeLogs() +API->>Backend : 发送HTTP请求 +Backend->>Backend : 处理查询逻辑 +Backend->>Backend : 应用过滤条件 +Backend->>Backend : 执行数据库查询 +Backend-->>API : 返回查询结果 +API-->>View : 返回响应数据 +View->>View : 更新表格显示 +View->>User : 展示查询结果 +Note over User,Backend : 支持分页、排序、筛选 +``` + +**图表来源** +- [log.vue:214-277](file://frontend/src/views/share-code/log.vue#L214-L277) +- [shareCodeLog.js:17-24](file://frontend/src/api/shareCodeLog.js#L17-L24) + +**章节来源** +- [log.vue:1-353](file://frontend/src/views/share-code/log.vue#L1-L353) +- [shareCodeLog.js:1-26](file://frontend/src/api/shareCodeLog.js#L1-L26) + +## 依赖关系分析 + +### 技术栈依赖 + +分享码日志API采用现代化的Node.js技术栈,各组件之间的依赖关系如下: + +```mermaid +graph LR +subgraph "核心框架" +Express[Express.js] +Sequelize[Sequelize ORM] +MySQL[MySQL驱动] +end +subgraph "认证授权" +JWT[JWT Token] +Auth[认证中间件] +end +subgraph "工具库" +CORS[CORS跨域] +Winston[Winston日志] +Dotenv[环境变量] +end +subgraph "前端集成" +ElementPlus[Element Plus UI] +Axios[Axios HTTP] +end +Express --> Sequelize +Sequelize --> MySQL +Express --> Auth +Auth --> JWT +Express --> CORS +Express --> Winston +Express --> Dotenv +ElementPlus --> Axios +``` + +**图表来源** +- [package.json:11-27](file://backend/package.json#L11-L27) + +### 组件耦合度分析 + +系统采用了低耦合的设计原则: + +1. **路由层与模型层分离**: 路由处理只负责请求接收和响应格式化 +2. **中间件独立性**: 认证中间件可复用到其他路由 +3. **配置集中管理**: 数据库连接和环境配置统一管理 +4. **工具类模块化**: 响应格式化等工具函数独立封装 + +**章节来源** +- [package.json:1-29](file://backend/package.json#L1-L29) + +## 性能考虑 + +### 查询优化策略 + +针对大数据量场景,系统采用了多项性能优化措施: + +1. **索引优化**: 为常用查询字段建立复合索引 +2. **分页限制**: 单次查询最大返回1000条记录 +3. **查询条件优化**: 支持多条件组合查询,避免全表扫描 +4. **时间范围查询**: 优先使用时间索引进行范围查询 + +### 缓存策略 + +虽然当前版本未实现专用缓存,但系统具备良好的扩展性: + +```mermaid +flowchart LR +Request[请求到达] --> CheckCache{检查缓存} +CheckCache --> |命中| ReturnCache[返回缓存数据] +CheckCache --> |未命中| QueryDB[查询数据库] +QueryDB --> FormatData[格式化数据] +FormatData --> StoreCache[存储到缓存] +StoreCache --> ReturnData[返回响应] +ReturnCache --> End[结束] +ReturnData --> End +``` + +### 大数据量处理 + +对于超大数据量的场景,建议采用以下策略: + +1. **时间分区**: 按月或按季度对日志表进行分区 +2. **归档策略**: 将历史数据迁移到归档表 +3. **异步处理**: 对复杂的统计分析采用异步任务队列 +4. **读写分离**: 主从复制实现读写分离 + +## 故障排除指南 + +### 常见错误及解决方案 + +| 错误类型 | 错误码 | 描述 | 解决方案 | +|----------|--------|------|----------| +| 认证失败 | 401 | 未登录或缺少凭证 | 检查Authorization头是否正确设置 | +| 权限不足 | 403 | 需要超级管理员权限 | 确认用户具有相应权限 | +| 参数错误 | 400 | 请求参数格式不正确 | 验证查询参数的格式和类型 | +| 数据库错误 | 500 | 数据库操作失败 | 检查数据库连接和SQL语句 | + +### 日志监控 + +系统内置了完善的日志记录机制: + +```mermaid +graph TD +subgraph "日志级别" +Info[Info日志] +Error[Error日志] +Warn[Warn日志] +end +subgraph "监控指标" +QueryCount[查询次数统计] +ErrorRate[错误率监控] +ResponseTime[响应时间] +DBConnection[数据库连接状态] +end +Info --> QueryCount +Error --> ErrorRate +Info --> ResponseTime +Info --> DBConnection +``` + +**章节来源** +- [shareCodeLogs.js:80-83](file://backend/src/routes/shareCodeLogs.js#L80-L83) +- [auth.js:21-25](file://backend/src/middleware/auth.js#L21-L25) + +## 结论 + +分享码日志API是一个功能完整、架构清晰的RESTful服务。它提供了: + +1. **完整的查询功能**: 支持多维度、多条件的灵活查询 +2. **高性能设计**: 通过索引优化和分页机制保证查询效率 +3. **安全可靠**: 基于JWT的认证授权机制确保系统安全 +4. **易于扩展**: 模块化的架构设计便于功能扩展和维护 + +该API为分享码使用情况的监控和分析提供了强有力的技术支撑,能够满足日常运营和数据分析的各种需求。随着业务的发展,可以在此基础上进一步完善统计分析、报表生成和趋势预测等功能。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/后端API文档/后端API文档.md b/.qoder/repowiki/zh/content/后端API文档/后端API文档.md new file mode 100644 index 0000000..3643570 --- /dev/null +++ b/.qoder/repowiki/zh/content/后端API文档/后端API文档.md @@ -0,0 +1,423 @@ +# 后端API文档 + + +**本文引用的文件** +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [backend/src/routes/auth.js](file://backend/src/routes/auth.js) +- [backend/src/routes/brands.js](file://backend/src/routes/brands.js) +- [backend/src/routes/models.js](file://backend/src/routes/models.js) +- [backend/src/routes/ota.js](file://backend/src/routes/ota.js) +- [backend/src/routes/shareCodeLogs.js](file://backend/src/routes/shareCodeLogs.js) +- [backend/src/routes/users.js](file://backend/src/routes/users.js) +- [backend/src/routes/dashboard.js](file://backend/src/routes/dashboard.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/models/index.js](file://backend/src/models/index.js) +- [backend/package.json](file://backend/package.json) +- [backend/README.md](file://backend/README.md) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本项目为“耳机品牌与型号管理平台”的后端 RESTful API,采用 Node.js + Express 构建,提供认证系统、品牌管理、型号管理、OTA 固件、用户管理以及分享码日志等完整能力。系统通过统一响应体封装、JWT 认证中间件、Sequelize 数据库访问层与多处外部服务集成(S3、Meilisearch、AWS SDK),形成模块化、可扩展的 API 体系。 + +- 版本信息:后端版本 1.0.0 +- 默认端口:8083(可通过环境变量覆盖) +- 健康检查:GET /health +- 在线文档:Swagger UI 与 ReDoc(根路径与健康检查接口提供文档入口) + +**章节来源** +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/README.md:61-66](file://backend/README.md#L61-L66) + +## 项目结构 +后端采用按功能域划分的路由组织方式,入口文件加载中间件、数据库与路由,随后启动服务并进行数据库同步与初始化任务。 + +```mermaid +graph TB +A["入口应用
backend/src/app.js"] --> B["CORS/BodyLimit 中间件"] +A --> C["路由注册
backend/src/routes/index.js"] +C --> D["认证路由
backend/src/routes/auth.js"] +C --> E["品牌路由
backend/src/routes/brands.js"] +C --> F["型号路由
backend/src/routes/models.js"] +C --> G["OTA 路由
backend/src/routes/ota.js"] +C --> H["分享码日志路由
backend/src/routes/shareCodeLogs.js"] +C --> I["用户路由
backend/src/routes/users.js"] +C --> J["仪表盘路由
backend/src/routes/dashboard.js"] +A --> K["数据库同步与启动"] +``` + +**图表来源** +- [backend/src/app.js:14-37](file://backend/src/app.js#L14-L37) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +**章节来源** +- [backend/src/app.js:14-37](file://backend/src/app.js#L14-L37) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 核心组件 +- 统一响应体封装:ApiResponse 提供 success/error/noData 三类标准响应,便于前端统一处理。 +- 认证中间件:基于 Bearer Token 的 JWT 校验,支持超级管理员权限拦截。 +- 密码处理:PBKDF2 加盐哈希,安全存储用户口令。 +- 数据库访问:Sequelize ORM,配合各模型完成 CRUD 与查询统计。 +- 外部服务集成:S3 存储频响文件、Meilisearch 搜索索引、AWS SDK、Redis 缓存等。 + +**章节来源** +- [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/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) + +## 架构总览 +系统整体交互流程如下: + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Auth as "认证路由" +participant JWT as "JWT 工具" +participant User as "用户模型" +participant Resp as "统一响应" +Client->>Auth : POST /api/auth/login +Auth->>User : 查询用户并校验状态 +Auth->>JWT : 生成访问令牌 +JWT-->>Auth : 访问令牌 +Auth-->>Resp : 包装响应 +Resp-->>Client : {code,msg,data} +Client->>Auth : GET /api/auth/me +Auth->>JWT : 解析并校验令牌 +JWT-->>Auth : 用户负载 +Auth->>User : 查询用户详情 +Auth-->>Resp : 包装响应 +Resp-->>Client : {code,msg,data} +``` + +**图表来源** +- [backend/src/routes/auth.js:24-77](file://backend/src/routes/auth.js#L24-L77) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/utils/jwt.js:7-21](file://backend/src/utils/jwt.js#L7-L21) + +## 详细组件分析 + +### 认证系统 API +- 登录 + - 方法与路径:POST /api/auth/login + - 请求体:username, password + - 成功响应:access_token, token_type, expires_in, user + - 错误:用户名或密码为空;用户不存在或状态异常;口令错误;内部错误 + - 安全:口令使用 PBKDF2 校验;登录成功更新最近登录时间 +- 当前用户 + - 方法与路径:GET /api/auth/me + - 认证:Bearer Token + - 成功响应:用户信息字典 + - 错误:未登录/凭证无效/账号不存在或禁用 +- 修改密码 + - 方法与路径:PUT /api/auth/password + - 认证:Bearer Token + - 请求体:old_password, new_password(≥6位) + - 成功响应:操作结果提示 + - 错误:缺少参数;原密码错误;内部错误 + +**章节来源** +- [backend/src/routes/auth.js:24-109](file://backend/src/routes/auth.js#L24-L109) +- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) + +### 品牌管理 API +- 列表查询 + - 方法与路径:GET /api/brands/ + - 查询参数:skip, limit(≤1000), name(模糊) + - 成功响应:items[{id,name}], total, skip, limit + - 错误:内部错误 +- 单条查询 + - 方法与路径:GET /api/brands/:brand_id + - 成功响应:{id,name} 或 noData + - 错误:内部错误 +- 新增 + - 方法与路径:POST /api/brands/ + - 请求体:name + - 成功响应:{id,name} + - 错误:名称为空;已存在;内部错误 +- 更新 + - 方法与路径:PUT /api/brands/:brand_id + - 请求体:name + - 成功响应:{id,name} + - 错误:名称为空;已存在;内部错误 +- 删除 + - 方法与路径:DELETE /api/brands/:brand_id + - 成功响应:删除结果 + - 错误:不存在;内部错误 + +**章节来源** +- [backend/src/routes/brands.js:14-144](file://backend/src/routes/brands.js#L14-L144) + +### 型号管理 API +- 列表查询 + - 方法与路径:GET /api/models/ + - 查询参数:skip, limit(≤1000), brand_name(模糊), name(模糊), sort_by(id/create_at), sort_order(asc/desc) + - 成功响应:items[{id,brand_name,name,form,rig,source,eq_key,create_at}], total, skip, limit + - 错误:内部错误 +- EQ 缓存键列表 + - 方法与路径:GET /api/models/:model_id/eq-cache + - 成功响应:{redis_key, field_keys} + - 错误:内部错误 +- EQ 缓存字段值 + - 方法与路径:GET /api/models/:model_id/eq-cache/field?key=... + - 查询参数:key + - 成功响应:字段值 + - 错误:缺少 key;内部错误 +- Meilisearch 推送状态 + - 方法与路径:GET /api/models/:model_id/meilisearch + - 成功响应:{pushed:boolean, document|null} + - 错误:内部错误 +- 频响 CSV 查看(仅 Eafonyoung) + - 方法与路径:GET /api/models/:model_id/measurement + - 成功响应:{s3_key,content} + - 错误:来源非 Eafonyoung;缺少佩戴方式;内部错误 +- 单条查询 + - 方法与路径:GET /api/models/:model_id + - 成功响应:{id,brand_name,name,form,rig,source,eq_key,create_at} + - 错误:不存在;内部错误 +- 新增(支持频响文件上传) + - 方法与路径:POST /api/models/ + - 请求体:multipart/form-data,字段包括 brand_name, name, form, rig, source, eq_key,以及 measurement_file(.csv/.txt/.json) + - 成功响应:新建型号对象 + - 错误:重复;格式不支持;S3 上传失败;内部错误 +- 更新(支持频响文件上传) + - 方法与路径:PUT /api/models/:model_id + - 请求体:multipart/form-data,字段包括 brand_name, name, form, rig, source, eq_key,以及 measurement_file + - 成功响应:更新后型号对象 + - 错误:重复;格式不支持;缺少来源/形式;S3 上传失败;内部错误 +- 删除 + - 方法与路径:DELETE /api/models/:model_id + - 成功响应:删除结果 + - 错误:不存在;Meilisearch 删除失败;内部错误 +- 推送到搜索(校验) + - 方法与路径:POST /api/models/push-to-search/validate + - 请求体:model_ids[] + - 成功响应:validated_count 或包含错误明细 + - 错误:内部错误 +- 推送到搜索 + - 方法与路径:POST /api/models/push-to-search + - 请求体:model_ids[] + - 成功响应:pushed_count, task_uid, models + - 错误:连接失败;内部错误 + +**章节来源** +- [backend/src/routes/models.js:133-566](file://backend/src/routes/models.js#L133-L566) + +### OTA 固件 API +- 设备端最新版本检查(无需登录) + - 方法与路径:GET /api/ota/latest/check + - 查询参数:currentVerCode, model, hw(可选) + - 成功响应:最新 OTA 对象或 noData + - 错误:内部错误 +- 列表查询(需登录) + - 方法与路径:GET /api/ota/ + - 查询参数:skip, limit(≤1000), verCode, verName(模糊), model, status + - 成功响应:items[], total, skip, limit + - 错误:内部错误 +- 单条查询(需登录) + - 方法与路径:GET /api/ota/:ota_id + - 成功响应:OTA 对象 + - 错误:不存在;内部错误 +- 新增(需登录) + - 方法与路径:POST /api/ota/ + - 请求体:verCode, verName, url, md5, force, desc, model, hw, target, beta, startTime, endTime, status + - 成功响应:创建后的 OTA 对象 + - 错误:版本已存在;字段校验失败;内部错误 +- 更新(需登录) + - 方法与路径:PUT /api/ota/:ota_id + - 请求体:同上(可部分字段) + - 成功响应:更新后的 OTA 对象 + - 错误:版本冲突;字段校验失败;内部错误 +- 删除(需登录) + - 方法与路径:DELETE /api/ota/:ota_id + - 成功响应:删除结果 + - 错误:不存在;内部错误 +- 升级包上传(需登录) + - 方法与路径:POST /api/ota/upload-package + - 请求体:multipart/form-data,字段 model(X8/X9),package_file + - 成功响应:md5, filename, url, s3_key(如适用) + - 错误:不支持的设备;文件缺失;S3 配置/上传失败;内部错误 + +**章节来源** +- [backend/src/routes/ota.js:68-268](file://backend/src/routes/ota.js#L68-L268) + +### 用户管理 API(超级管理员) +- 列表查询(需登录且超级管理员) + - 方法与路径:GET /api/users/ + - 查询参数:skip, limit(≤1000), username(模糊) + - 成功响应:items[], total, skip, limit + - 错误:内部错误 +- 新增(需登录且超级管理员) + - 方法与路径:POST /api/users/ + - 请求体:username(≤64), password(≥6), is_super_admin(布尔) + - 成功响应:用户对象 + - 错误:用户名为空/过长/已存在;密码过短;内部错误 +- 更新(需登录且超级管理员) + - 方法与路径:PUT /api/users/:user_id + - 请求体:status(0/1), is_super_admin(布尔), password(≥6可选) + - 成功响应:用户对象 + - 错误:状态非法;最后一位超级管理员不可降权/禁用;密码过短;内部错误 +- 删除(需登录且超级管理员) + - 方法与路径:DELETE /api/users/:user_id + - 成功响应:删除结果 + - 错误:不可删除当前登录账号;最后一位超级管理员不可删除;内部错误 + +**章节来源** +- [backend/src/routes/users.js:35-177](file://backend/src/routes/users.js#L35-L177) + +### 分享码日志 API(需登录) +- 查询 + - 方法与路径:GET /api/share-code/logs + - 查询参数:skip, limit(≤1000), mac_addr(模糊), share_code(模糊), action(import/export), ip_addr(模糊), start_at,end_at, sort_by(id/create_at), sort_order(asc/desc) + - 成功响应:items[{id,mac_addr,share_code,action,ip_addr,eq_data,expire_at,create_at}], total, skip, limit + - 错误:内部错误 + +**章节来源** +- [backend/src/routes/shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) + +### 仪表盘 API(需登录) +- 今日新增 + - 方法与路径:GET /api/dashboard/today + - 成功响应:models[], otas[](当日新增) + - 错误:内部错误 + +**章节来源** +- [backend/src/routes/dashboard.js:19-63](file://backend/src/routes/dashboard.js#L19-L63) + +## 依赖关系分析 +- 入口应用加载路由汇总并启动服务,路由按功能域拆分,降低耦合度。 +- 认证中间件贯穿多路由,统一鉴权;超级管理员中间件仅用于用户管理。 +- 响应封装统一返回结构,便于前端与监控系统消费。 +- 多处外部服务调用(S3、Meilisearch、AWS SDK、Redis)通过独立服务模块抽象,便于替换与测试。 + +```mermaid +graph LR +App["入口应用
app.js"] --> RIndex["路由汇总
routes/index.js"] +RIndex --> RAuth["认证路由"] +RIndex --> RBrands["品牌路由"] +RIndex --> RModels["型号路由"] +RIndex --> ROta["OTA 路由"] +RIndex --> RShare["分享码日志路由"] +RIndex --> RUsers["用户路由"] +RIndex --> RDash["仪表盘路由"] +RAuth --> JWT["JWT 工具"] +RAuth --> Pwd["密码工具"] +RAuth --> UResp["统一响应"] +RModels --> S3["S3 存储服务"] +RModels --> MS["Meilisearch"] +RModels --> Eq["EQ 缓存服务"] +ROta --> OtaStore["OTA 存储服务"] +ROta --> OtaVal["OTA 校验器"] +RUsers --> UResp +RBrands --> UResp +RShare --> UResp +RDash --> UResp +``` + +**图表来源** +- [backend/src/app.js:10-37](file://backend/src/app.js#L10-L37) +- [backend/src/routes/index.js:4-10](file://backend/src/routes/index.js#L4-L10) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +**章节来源** +- [backend/src/app.js:10-37](file://backend/src/app.js#L10-L37) +- [backend/src/routes/index.js:4-10](file://backend/src/routes/index.js#L4-L10) + +## 性能考量 +- 分页与上限:列表接口统一支持 skip/limit,最大限制为 1000,避免一次性返回过多数据。 +- 查询过滤:品牌/型号/OTA/日志均支持多字段模糊匹配与范围筛选,建议结合索引与分页使用。 +- 文件上传:型号频响文件采用内存存储(multer.memoryStorage),注意控制文件大小与并发量;S3 上传失败时需重试与告警。 +- 外部服务超时:Meilisearch 请求设置超时,避免阻塞主流程;OTA 最新版本检查对设备端开放,减少不必要的鉴权开销。 +- 缓存与索引:EQ 缓存与 Meilisearch 索引提升读取性能,写入时需保证一致性与幂等。 + +[本节为通用指导,不直接分析具体文件] + +## 故障排查指南 +- 认证失败 + - 现象:401 未登录/无效凭证/登录过期 + - 排查:确认 Authorization 头是否为 Bearer Token;检查 JWT_SECRET 是否正确;确认用户状态正常 +- 密码错误 + - 现象:登录/改密返回错误 + - 排查:确认旧密码正确;新密码长度≥6;PBKDF2 校验逻辑 +- 资源不存在 + - 现象:noData 或 404 类似响应 + - 排查:确认 ID/名称是否存在;品牌/型号/OTA/日志是否被删除 +- 外部服务异常 + - 现象:S3/Meilisearch/AWS SDK 调用失败 + - 排查:检查配置项(S3 凭证、Meilisearch 地址与密钥);网络连通性;超时与重试策略 +- 日志与监控 + - 建议:开启 Winston 日志输出;结合统一响应体与错误码定位问题;对高频接口增加指标埋点 + +**章节来源** +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34) +- [backend/src/routes/models.js:89-128](file://backend/src/routes/models.js#L89-L128) +- [backend/src/routes/ota.js:37-66](file://backend/src/routes/ota.js#L37-L66) + +## 结论 +本 API 体系以模块化路由为核心,结合统一响应体、JWT 认证与外部服务集成,提供了从认证到品牌/型号/OTA/用户/日志的完整能力。通过严格的参数校验、分页与上限控制、以及对外部服务的容错设计,系统具备良好的可维护性与扩展性。建议在生产环境中完善 CORS 限制、速率限制、审计日志与监控告警机制。 + +[本节为总结性内容,不直接分析具体文件] + +## 附录 + +### 认证与安全 +- 认证方式:Bearer Token(JWT) +- Token 有效期:12 小时 +- 密码策略:PBKDF2 加盐哈希,迭代次数与长度配置见密码工具 +- 权限控制:超级管理员仅限用户管理相关接口 + +**章节来源** +- [backend/src/utils/jwt.js:3-25](file://backend/src/utils/jwt.js#L3-L25) +- [backend/src/utils/password.js:6-34](file://backend/src/utils/password.js#L6-L34) +- [backend/src/middleware/auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) + +### 速率限制与版本 +- 速率限制:未内置全局限流中间件,建议在网关或反向代理层配置 +- 版本:后端版本 1.0.0 + +**章节来源** +- [backend/package.json:1-29](file://backend/package.json#L1-L29) + +### 常见用例与最佳实践 +- 品牌管理:先查询列表/模糊搜索,再执行新增/更新/删除 +- 型号管理:上传频响文件时同时提供 source 与 form 字段;使用校验接口预检后再推送至搜索 +- OTA 管理:先上传升级包并获取下载地址/MD5,再创建 OTA 记录;设备端通过最新版本检查接口获取可用升级 +- 用户管理:确保至少保留一位超级管理员;变更权限时注意最后一位管理员保护 + +[本节为通用指导,不直接分析具体文件] + +### 调试工具与监控 +- 在线文档:启动后访问根路径或健康检查接口查看 Swagger UI 与 ReDoc +- 日志:Winston 输出,建议接入集中式日志系统 +- 监控:对关键接口(登录、OTA 最新版本检查、型号上传)埋点与告警 + +**章节来源** +- [backend/src/app.js:23-34](file://backend/src/app.js#L23-L34) + +### 已弃用功能与迁移指南 +- 项目说明文档未提及明确的弃用接口;若后续出现弃用,请关注版本变更与迁移说明 +- 建议:在升级前备份数据库与外部服务数据,逐步替换服务模块并验证接口行为 + +**章节来源** +- [backend/README.md:1-99](file://backend/README.md#L1-L99) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/后端API文档/品牌管理API.md b/.qoder/repowiki/zh/content/后端API文档/品牌管理API.md new file mode 100644 index 0000000..6b95821 --- /dev/null +++ b/.qoder/repowiki/zh/content/后端API文档/品牌管理API.md @@ -0,0 +1,434 @@ +# 品牌管理API + + +**本文档引用的文件** +- [brands.js](file://backend/src/routes/brands.js) +- [Brand.js](file://backend/src/models/Brand.js) +- [brand.js](file://backend/src/validators/brand.js) +- [response.js](file://backend/src/utils/response.js) +- [app.js](file://backend/src/app.js) +- [index.js](file://backend/src/routes/index.js) +- [brand.js](file://frontend/src/api/brand.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +品牌管理API是一个基于Express.js和Sequelize的RESTful Web服务,用于管理音频设备品牌信息。该API提供了完整的企业级品牌CRUD操作,包括品牌列表查询、单个品牌获取、品牌创建、更新和删除功能。系统采用Zod进行数据验证,确保数据完整性和安全性。 + +## 项目结构 + +品牌管理API采用典型的三层架构设计: + +```mermaid +graph TB +subgraph "前端层" +FE_API[前端API模块
frontend/src/api/brand.js] +end +subgraph "应用层" +APP[应用入口
backend/src/app.js] +ROUTES[路由层
backend/src/routes/brands.js] +MIDDLEWARE[中间件
backend/src/middleware/auth.js] +end +subgraph "服务层" +VALIDATORS[Zod验证器
backend/src/validators/brand.js] +RESPONSE[响应格式化
backend/src/utils/response.js] +end +subgraph "数据层" +MODELS[模型定义
backend/src/models/Brand.js] +DATABASE[(MySQL数据库)] +end +FE_API --> APP +APP --> ROUTES +ROUTES --> MIDDLEWARE +ROUTES --> VALIDATORS +ROUTES --> RESPONSE +ROUTES --> MODELS +MODELS --> DATABASE +``` + +**图表来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +**章节来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 核心组件 + +### 数据模型 + +品牌模型定义了品牌实体的数据结构和约束条件: + +| 字段名 | 类型 | 约束 | 描述 | +|--------|------|------|------| +| id | INTEGER | 主键, 自增 | 品牌ID | +| name | STRING(100) | 唯一, 非空 | 品牌名称 | + +### 响应格式 + +所有API响应遵循统一的JSON格式: + +```mermaid +classDiagram +class ApiResponse { ++success(data, msg) Object ++error(msg, code) Object ++noData(msg) Object +} +class PageData { ++Array items ++number total ++number skip ++number limit ++constructor(items, total, skip, limit) +} +ApiResponse --> PageData : "返回分页数据" +``` + +**图表来源** +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +**章节来源** +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 架构概览 + +品牌管理API采用MVC架构模式,通过Express.js处理HTTP请求,Sequelize ORM管理数据库操作。 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant API as Express应用 +participant Auth as 认证中间件 +participant Route as 品牌路由 +participant Validator as Zod验证器 +participant Model as 品牌模型 +participant DB as MySQL数据库 +Client->>API : HTTP请求 +API->>Auth : 验证用户身份 +Auth-->>API : 认证通过 +API->>Route : 路由分发 +Route->>Validator : 数据验证 +Validator-->>Route : 验证结果 +Route->>Model : 数据库操作 +Model->>DB : SQL执行 +DB-->>Model : 查询结果 +Model-->>Route : 模型实例 +Route-->>Client : JSON响应 +``` + +**图表来源** +- [brands.js:14-147](file://backend/src/routes/brands.js#L14-L147) +- [brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) + +## 详细组件分析 + +### 品牌路由层 + +品牌路由实现了完整的CRUD操作,所有接口均需要认证。 + +#### GET /api/brands/ - 品牌列表查询 + +**请求参数:** +- `skip` (可选): 跳过记录数,默认0 +- `limit` (可选): 返回记录数,默认100,最大1000 +- `name` (可选): 品牌名称模糊查询 + +**响应数据:** +```javascript +{ + code: 1, + msg: "success", + data: { + items: [ + { id: number, name: string } + ], + total: number, + skip: number, + limit: number + } +} +``` + +#### GET /api/brands/:brand_id - 单个品牌获取 + +**路径参数:** +- `brand_id`: 品牌ID + +**响应数据:** +```javascript +{ + code: 1, + msg: "success", + data: { id: number, name: string } +} +``` + +#### POST /api/brands/ - 创建品牌 + +**请求体:** +```javascript +{ + name: string // 品牌名称,1-100字符 +} +``` + +**响应数据:** +```javascript +{ + code: 1, + msg: "品牌创建成功", + data: { id: number, name: string } +} +``` + +#### PUT /api/brands/:brand_id - 更新品牌 + +**路径参数:** +- `brand_id`: 品牌ID + +**请求体:** +```javascript +{ + name?: string // 品牌名称,1-100字符(可选) +} +``` + +**响应数据:** +```javascript +{ + code: 1, + msg: "品牌更新成功", + data: { id: number, name: string } +} +``` + +#### DELETE /api/brands/:brand_id - 删除品牌 + +**路径参数:** +- `brand_id`: 品牌ID + +**响应数据:** +```javascript +{ + code: 1, + msg: "删除成功", + data: null +} +``` + +**章节来源** +- [brands.js:14-147](file://backend/src/routes/brands.js#L14-L147) + +### 数据验证器 + +使用Zod进行类型安全的数据验证: + +```mermaid +classDiagram +class BrandCreateSchema { ++name : string(min=1, max=100) +} +class BrandUpdateSchema { ++name : string(min=1, max=100)? +} +class ZodValidator { ++safeParse(input) ValidationResult ++parse(input) ValidatedData +} +BrandCreateSchema --|> ZodValidator +BrandUpdateSchema --|> ZodValidator +``` + +**图表来源** +- [brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) + +**章节来源** +- [brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) + +### 前端集成 + +前端提供了完整的API调用封装: + +```mermaid +sequenceDiagram +participant Vue as Vue组件 +participant API as 品牌API +participant Backend as 后端服务 +participant DB as 数据库 +Vue->>API : getBrands(params) +API->>Backend : GET /brands/ +Backend->>DB : 查询品牌列表 +DB-->>Backend : 品牌数据 +Backend-->>API : JSON响应 +API-->>Vue : Promise结果 +Vue->>API : createBrand(data) +API->>Backend : POST /brands/ +Backend->>DB : 创建品牌 +DB-->>Backend : 新品牌ID +Backend-->>API : 成功响应 +API-->>Vue : Promise结果 +``` + +**图表来源** +- [brand.js:10-66](file://frontend/src/api/brand.js#L10-L66) + +**章节来源** +- [brand.js:10-66](file://frontend/src/api/brand.js#L10-L66) + +## 依赖关系分析 + +### 数据库约束关系 + +```mermaid +erDiagram +BRAND { +int id PK +varchar name UK +} +MODEL { +int id PK +varchar brand_name +varchar name +varchar form +varchar rig +varchar source +varchar eq_key +datetime create_at +} +BRAND ||--o{ MODEL : "一对一关联" +``` + +**图表来源** +- [Brand.js:4-20](file://backend/src/models/Brand.js#L4-L20) +- [Model.js:4-50](file://backend/src/models/Model.js#L4-L50) + +### 组件依赖图 + +```mermaid +graph LR +subgraph "外部依赖" +EXPRESS[Express.js] +SEQUELIZE[Sequelize ORM] +MYSQL[MySQL驱动] +ZOD[Zod验证库] +end +subgraph "内部模块" +ROUTES[品牌路由] +MODELS[品牌模型] +VALIDATORS[验证器] +RESPONSE[响应格式化] +AUTH[认证中间件] +end +EXPRESS --> ROUTES +SEQUELIZE --> MODELS +MYSQL --> SEQUELIZE +ZOD --> VALIDATORS +ROUTES --> MODELS +ROUTES --> VALIDATORS +ROUTES --> RESPONSE +ROUTES --> AUTH +``` + +**图表来源** +- [brands.js:1-10](file://backend/src/routes/brands.js#L1-L10) +- [Brand.js:1-2](file://backend/src/models/Brand.js#L1-L2) +- [brand.js:1-1](file://backend/src/validators/brand.js#L1-L1) + +**章节来源** +- [brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +## 性能考虑 + +### 分页优化 +- 最大限制:1000条记录 +- 默认限制:100条记录 +- 支持跳过机制避免全表扫描 + +### 数据库优化 +- 品牌名称字段建立唯一索引 +- 使用`findAndCountAll`进行高效分页查询 +- 条件查询支持模糊匹配 + +### 缓存策略 +- 建议在应用层添加Redis缓存 +- 对频繁访问的品牌数据进行缓存 +- 设置合理的TTL过期时间 + +## 故障排除指南 + +### 常见错误码 + +| 错误码 | 描述 | 可能原因 | 解决方案 | +|--------|------|----------|----------| +| 0 | error | 服务器内部错误 | 检查服务器日志,确认数据库连接 | +| 1 | success | 操作成功 | 正常响应,无需处理 | +| 2 | no data | 无数据 | 检查查询条件或数据是否存在 | + +### 错误处理流程 + +```mermaid +flowchart TD +Start([请求开始]) --> Validate[参数验证] +Validate --> Valid{验证通过?} +Valid --> |否| ReturnError[返回错误响应] +Valid --> |是| DBOperation[数据库操作] +DBOperation --> DBSuccess{操作成功?} +DBSuccess --> |否| HandleError[处理数据库错误] +DBSuccess --> |是| ReturnSuccess[返回成功响应] +HandleError --> ReturnError +ReturnError --> End([请求结束]) +ReturnSuccess --> End +``` + +**图表来源** +- [brands.js:36-81](file://backend/src/routes/brands.js#L36-L81) + +### 调试建议 +1. 检查认证中间件是否正确配置 +2. 验证数据库连接字符串 +3. 确认品牌表结构和约束 +4. 查看服务器日志输出 + +**章节来源** +- [brands.js:36-147](file://backend/src/routes/brands.js#L36-L147) + +## 结论 + +品牌管理API提供了完整的企业级品牌数据管理解决方案。系统具有以下特点: + +### 技术优势 +- **类型安全**: 使用Zod进行编译时类型检查 +- **数据完整性**: 数据库层面的唯一性约束 +- **响应标准化**: 统一的JSON响应格式 +- **错误处理**: 完善的异常捕获和错误响应 + +### 功能特性 +- **完整的CRUD操作**: 支持品牌的增删改查 +- **分页查询**: 高效的大数据量查询 +- **模糊搜索**: 支持品牌名称的模糊匹配 +- **认证保护**: 所有接口均需登录认证 + +### 扩展建议 +1. 添加品牌与型号的一对一关联关系 +2. 实现批量操作接口 +3. 添加排序和过滤选项 +4. 增加数据导入导出功能 +5. 实现审计日志记录 + +该API为音频设备管理系统提供了坚实的基础,可以作为企业级应用的可靠数据服务层。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/后端API文档/型号管理API.md b/.qoder/repowiki/zh/content/后端API文档/型号管理API.md new file mode 100644 index 0000000..7fcdcdc --- /dev/null +++ b/.qoder/repowiki/zh/content/后端API文档/型号管理API.md @@ -0,0 +1,347 @@ +# 型号管理API + + +**本文档引用的文件** +- [backend/src/routes/models.js](file://backend/src/routes/models.js) +- [backend/src/models/Model.js](file://backend/src/models/Model.js) +- [backend/src/validators/model.js](file://backend/src/validators/model.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [frontend/src/api/model.js](file://frontend/src/api/model.js) +- [backend/src/models/Ota.js](file://backend/src/models/Ota.js) +- [backend/src/routes/ota.js](file://backend/src/routes/ota.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文件为型号管理API的详细RESTful API文档,覆盖型号的CRUD操作、查询筛选与排序、数据验证规则,以及与OTA固件的一对多关联关系与级联操作。文档同时提供前端调用示例与后端实现细节,帮助开发者快速集成与维护。 + +## 项目结构 +型号管理API位于后端Express应用中,采用模块化设计: +- 路由层:集中于 models.js,提供型号的增删改查、搜索推送、频响文件处理等接口 +- 模型层:Model.js 定义数据库表结构 +- 验证层:model.js 使用Zod进行请求体验证 +- 工具层:response.js 统一响应格式 +- 中间件:auth.js 提供鉴权保护 +- 前端封装:frontend/src/api/model.js 提供HTTP调用封装 + +```mermaid +graph TB +FE["前端应用
frontend/src/api/model.js"] --> R["路由层
backend/src/routes/models.js"] +R --> M["模型层
backend/src/models/Model.js"] +R --> V["验证层
backend/src/validators/model.js"] +R --> U["工具层
backend/src/utils/response.js"] +R --> A["中间件
backend/src/middleware/auth.js"] +R -. 关联 .-> OTA["OTA模型
backend/src/models/Ota.js"] +``` + +图表来源 +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [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) +- [frontend/src/api/model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +章节来源 +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [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) +- [frontend/src/api/model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +## 核心组件 +- 路由控制器:models.js 提供型号的列表查询、详情获取、创建、更新、删除、搜索推送、频响文件上传与查询等接口 +- 数据模型:Model.js 定义型号字段及约束 +- 请求验证:model.js 使用Zod Schema进行创建/更新的输入校验 +- 统一响应:response.js 提供统一的响应结构 +- 鉴权中间件:auth.js 实现Bearer Token鉴权 +- 前端封装:frontend/src/api/model.js 提供HTTP调用封装 + +章节来源 +- [backend/src/routes/models.js:133-181](file://backend/src/routes/models.js#L133-L181) +- [backend/src/models/Model.js:4-50](file://backend/src/models/Model.js#L4-L50) +- [backend/src/validators/model.js:3-19](file://backend/src/validators/model.js#L3-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) +- [frontend/src/api/model.js:13-150](file://frontend/src/api/model.js#L13-L150) + +## 架构概览 +型号管理API采用分层架构,路由层负责HTTP协议与参数解析,模型层负责数据持久化,验证层确保输入合法性,工具层统一输出格式,中间件提供安全控制。 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant R as "路由(models.js)" +participant V as "验证(model.js)" +participant M as "模型(Model.js)" +participant U as "响应(response.js)" +participant A as "鉴权(auth.js)" +C->>R : "HTTP请求" +R->>A : "鉴权检查" +A-->>R : "通过/拒绝" +R->>V : "请求体验证" +V-->>R : "验证结果" +R->>M : "数据库操作" +M-->>R : "结果" +R->>U : "封装响应" +U-->>C : "统一响应" +``` + +图表来源 +- [backend/src/routes/models.js:307-361](file://backend/src/routes/models.js#L307-L361) +- [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/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) + +## 详细组件分析 + +### 型号数据模型 +型号实体包含以下字段: +- id:自增主键 +- brand_name:品牌名称(必填,最大100字符) +- name:型号名称(必填,最大100字符) +- form:佩戴方式(可选,最大100字符) +- rig:阻抗(可选,最大100字符) +- source:来源(可选,最大100字符) +- eq_key:EQ键(可选,最大255字符) +- create_at:创建时间(默认当前时间) + +```mermaid +erDiagram +MODEL { +int id PK +string brand_name +string name +string form +string rig +string source +string eq_key +datetime create_at +} +``` + +图表来源 +- [backend/src/models/Model.js:4-50](file://backend/src/models/Model.js#L4-L50) + +章节来源 +- [backend/src/models/Model.js:4-50](file://backend/src/models/Model.js#L4-L50) + +### 型号参数验证规则 +- 创建请求体验证: + - brand_name:字符串,长度1-100 + - name:字符串,长度1-100 + - form/rig/source/eq_key:字符串,最大长度分别为100、100、100、255,可为空 +- 更新请求体验证: + - 字段同上,但允许部分字段为空(表示不更新) + +章节来源 +- [backend/src/validators/model.js:3-19](file://backend/src/validators/model.js#L3-L19) + +### 型号CRUD接口 + +#### 1) 型号列表查询 +- 方法与路径:GET /api/models/ +- 认证:需要登录(Bearer Token) +- 查询参数: + - skip:跳过数量,默认0 + - limit:返回数量,默认100,上限1000 + - brand_name:品牌名称(模糊匹配) + - name:型号名称(模糊匹配) + - sort_by:排序字段,id 或 create_at,默认id + - sort_order:asc 或 desc,默认desc +- 成功响应:包含items、total、skip、limit的分页数据 +- 异常响应:统一错误码与消息 + +章节来源 +- [backend/src/routes/models.js:133-181](file://backend/src/routes/models.js#L133-L181) +- [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) + +#### 2) 型号详情获取 +- 方法与路径:GET /api/models/:model_id +- 认证:需要登录 +- 路径参数:model_id(整数) +- 成功响应:型号基础字段 +- 异常响应:未找到或通用错误 + +章节来源 +- [backend/src/routes/models.js:280-304](file://backend/src/routes/models.js#L280-L304) +- [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) + +#### 3) 型号创建 +- 方法与路径:POST /api/models/ +- 认证:需要登录 +- 内容类型:multipart/form-data +- 表单字段: + - measurement_file:频响文件(CSV/TXT/JSON),可选 + - brand_name、name、form、rig、source、eq_key +- 文件处理: + - TXT文件自动转换为CSV + - 仅允许.csv、.txt、.json + - 上传至S3,键值包含source、form、brand_name、name +- 成功响应:创建后的型号信息 +- 异常响应:重复、格式不支持、通用错误 + +章节来源 +- [backend/src/routes/models.js:306-361](file://backend/src/routes/models.js#L306-L361) +- [backend/src/validators/model.js:3-10](file://backend/src/validators/model.js#L3-L10) +- [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) + +#### 4) 型号更新 +- 方法与路径:PUT /api/models/:model_id +- 认证:需要登录 +- 内容类型:multipart/form-data +- 路径参数:model_id(整数) +- 表单字段:同创建,支持部分字段更新(传入'null'表示保持原值) +- 文件处理:同创建,若上传需提供source与form +- 成功响应:更新后的型号信息 +- 异常响应:未找到、重复、格式不支持、通用错误 + +章节来源 +- [backend/src/routes/models.js:363-436](file://backend/src/routes/models.js#L363-L436) +- [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) + +#### 5) 型号删除 +- 方法与路径:DELETE /api/models/:model_id +- 认证:需要登录 +- 路径参数:model_id(整数) +- 删除流程: + - 先从Meilisearch删除对应文档 + - 再删除数据库记录 +- 成功响应:删除成功 +- 异常响应:未找到、Meilisearch删除失败、通用错误 + +章节来源 +- [backend/src/routes/models.js:438-464](file://backend/src/routes/models.js#L438-L464) +- [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) + +### 型号搜索、过滤与排序 +- 支持按品牌名称与型号名称进行模糊过滤 +- 支持按id或create_at排序,升序/降序 +- 分页参数:skip、limit(上限1000) + +章节来源 +- [backend/src/routes/models.js:136-157](file://backend/src/routes/models.js#L136-L157) + +### 型号与OTA固件的一对多关联 +- 关联字段:OTA模型中的model字段用于标识对应设备型号 +- 查询示例:可通过OTA路由按model字段过滤 +- 级联建议:删除型号前应清理或迁移相关OTA记录,避免悬挂引用 + +```mermaid +erDiagram +MODEL ||--o{ OTA : "一对多" +MODEL { +int id PK +string brand_name +string name +} +OTA { +int id PK +int verCode +string verName +string model +} +``` + +图表来源 +- [backend/src/models/Model.js:4-50](file://backend/src/models/Model.js#L4-L50) +- [backend/src/models/Ota.js:44-48](file://backend/src/models/Ota.js#L44-L48) + +章节来源 +- [backend/src/models/Ota.js:44-48](file://backend/src/models/Ota.js#L44-L48) + +### Meilisearch搜索推送与校验 +- 校验接口:POST /api/models/push-to-search/validate + - 输入:model_ids数组 + - 输出:通过校验的型号数量或具体校验失败项 +- 推送接口:POST /api/models/push-to-search + - 输入:model_ids数组 + - 输出:推送成功数量、任务ID与推送数据 + +章节来源 +- [backend/src/routes/models.js:466-566](file://backend/src/routes/models.js#L466-L566) + +### 频响文件上传与查询 +- 上传:POST /api/models/(multipart/form-data),支持TXT自动转换为CSV +- 查询:GET /api/models/:model_id/measurement(仅Eafonyoung来源且存在form时可用) + +章节来源 +- [backend/src/routes/models.js:306-361](file://backend/src/routes/models.js#L306-L361) +- [backend/src/routes/models.js:246-278](file://backend/src/routes/models.js#L246-L278) + +### EQ缓存与Meilisearch文档查询 +- 获取Redis EQ缓存键:GET /api/models/:model_id/eq-cache +- 获取指定Hash Field:GET /api/models/:model_id/eq-cache/field?key=... +- 查询Meilisearch推送状态:GET /api/models/:model_id/meilisearch + +章节来源 +- [backend/src/routes/models.js:183-244](file://backend/src/routes/models.js#L183-L244) + +## 依赖分析 +- 路由依赖:models.js 依赖Model模型、Zod验证器、响应工具、鉴权中间件,并与Meilisearch、S3服务交互 +- 模型依赖:Model.js 依赖Sequelize ORM +- 前端依赖:frontend/src/api/model.js 依赖通用请求封装 + +```mermaid +graph LR +R["models.js"] --> M["Model.js"] +R --> V["model.js(Zod)"] +R --> U["response.js"] +R --> A["auth.js"] +R -. 外部 .-> MS["Meilisearch"] +R -. 外部 .-> S3["S3存储"] +``` + +图表来源 +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [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/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) + +## 性能考虑 +- 分页限制:列表查询limit上限为1000,避免一次性返回过多数据 +- Meilisearch超时:查询与删除文档设置超时,防止阻塞 +- 文件上传:内存存储multer,建议在高并发场景下优化为流式处理或外部对象存储直传 +- 验证前置:使用Zod在进入数据库操作前完成字段校验,减少无效请求 + +## 故障排除指南 +- 401 未登录/无效凭证:检查Authorization头是否为Bearer Token且有效 +- 403 需要超级管理员权限:确认用户角色 +- 404 未找到资源:确认model_id是否存在 +- 重复型号:创建/更新时如提示品牌+型号已存在,请调整参数 +- 文件格式不支持:仅允许.csv、.txt、.json,TXT会自动转换为CSV +- Meilisearch异常:检查服务连通性与API密钥 + +章节来源 +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/routes/models.js:314-317](file://backend/src/routes/models.js#L314-L317) +- [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) + +## 结论 +型号管理API提供了完善的CRUD能力、灵活的查询过滤与排序、严格的输入验证、以及与搜索与存储系统的集成。结合OTA模型的关联关系,可支撑从型号到固件升级的完整业务闭环。建议在生产环境中关注分页与超时配置、文件上传性能与安全策略,并在删除型号前做好OTA关联清理。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/后端API文档/用户管理API.md b/.qoder/repowiki/zh/content/后端API文档/用户管理API.md new file mode 100644 index 0000000..5be09b8 --- /dev/null +++ b/.qoder/repowiki/zh/content/后端API文档/用户管理API.md @@ -0,0 +1,460 @@ +# 用户管理API + + +**本文档引用的文件** +- [backend/src/routes/users.js](file://backend/src/routes/users.js) +- [backend/src/models/DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/routes/auth.js](file://backend/src/routes/auth.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/services/userBootstrap.js](file://backend/src/services/userBootstrap.js) +- [backend/src/app.js](file://backend/src/app.js) +- [frontend/src/api/user.js](file://frontend/src/api/user.js) +- [frontend/src/views/system/users/index.vue](file://frontend/src/views/system/users/index.vue) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件为系统“用户管理API”的详细RESTful接口文档,覆盖用户CRUD操作(列表查询、详情获取、创建、更新、删除)、权限控制与角色管理、状态控制、密码重置、账户激活以及批量操作与导入导出的实现指南。文档同时提供前后端交互流程图与最佳实践建议,帮助开发者快速集成与维护。 + +## 项目结构 +后端采用Express + Sequelize架构,前端基于Vue3 + Element Plus。用户管理API位于独立路由模块中,并通过认证中间件进行统一鉴权。 + +```mermaid +graph TB +subgraph "后端" +A["应用入口
backend/src/app.js"] +B["路由汇总
backend/src/routes/index.js"] +C["用户路由
backend/src/routes/users.js"] +D["认证中间件
backend/src/middleware/auth.js"] +E["用户模型
backend/src/models/DashboardUser.js"] +F["密码工具
backend/src/utils/password.js"] +G["响应封装
backend/src/utils/response.js"] +H["认证路由
backend/src/routes/auth.js"] +I["JWT 工具
backend/src/utils/jwt.js"] +J["引导服务
backend/src/services/userBootstrap.js"] +end +subgraph "前端" +K["用户API封装
frontend/src/api/user.js"] +L["用户管理页面
frontend/src/views/system/users/index.vue"] +end +A --> B --> C +C --> D +C --> E +C --> F +C --> G +H --> I +H --> F +J --> E +K --> C +L --> K +``` + +**图表来源** +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/routes/users.js:1-180](file://backend/src/routes/users.js#L1-L180) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) +- [frontend/src/api/user.js:1-40](file://frontend/src/api/user.js#L1-L40) +- [frontend/src/views/system/users/index.vue:1-428](file://frontend/src/views/system/users/index.vue#L1-L428) + +**章节来源** +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 核心组件 +- 用户路由模块:提供用户CRUD接口,内置分页、模糊查询、状态与角色变更校验。 +- 认证中间件:统一处理Bearer Token解析与超级管理员权限校验。 +- 密码工具:PBKDF2哈希与校验,确保密码安全存储。 +- 响应封装:统一封装成功/错误/无数据返回格式。 +- 用户模型:定义字段类型、默认值与注释,支撑权限与状态控制。 +- 引导服务:首次部署自动创建超级管理员账号。 + +**章节来源** +- [backend/src/routes/users.js:1-180](file://backend/src/routes/users.js#L1-L180) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) + +## 架构总览 +用户管理API遵循“路由-中间件-模型-工具”分层设计,所有用户管理接口均需通过认证中间件并具备超级管理员权限。 + +```mermaid +sequenceDiagram +participant FE as "前端" +participant API as "用户路由(users.js)" +participant AUTH as "认证中间件(auth.js)" +participant MODEL as "用户模型(DashboardUser)" +participant PWD as "密码工具(password.js)" +participant RESP as "响应封装(response.js)" +FE->>API : "调用受保护的用户管理接口" +API->>AUTH : "执行鉴权与超级管理员校验" +AUTH-->>API : "通过后注入用户上下文" +API->>MODEL : "读写数据库" +API->>PWD : "密码哈希/校验" +API->>RESP : "封装统一响应" +API-->>FE : "返回JSON响应" +``` + +**图表来源** +- [backend/src/routes/users.js:12-13](file://backend/src/routes/users.js#L12-L13) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/utils/password.js:10-34](file://backend/src/utils/password.js#L10-L34) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 详细组件分析 + +### 接口清单与规范 +- 基础路径:/api/users +- 认证方式:Authorization: Bearer +- 权限要求:仅超级管理员可访问 +- 分页参数:skip(起始偏移),limit(最大1000,默认100) +- 查询参数:username(模糊匹配) + +**章节来源** +- [backend/src/routes/users.js:35-61](file://backend/src/routes/users.js#L35-L61) +- [backend/src/middleware/auth.js:3-33](file://backend/src/middleware/auth.js#L3-L33) + +#### 列表查询 +- 方法:GET +- 路径:/api/users/ +- 请求参数: + - skip:数字,可选 + - limit:数字,范围[1,1000],默认100 + - username:字符串,模糊查询用户名 +- 成功响应:包含items、total、skip、limit的分页对象 +- 错误响应:空数据时返回“无数据”标识 + +```mermaid +sequenceDiagram +participant FE as "前端" +participant API as "GET /api/users/" +participant MODEL as "DashboardUser" +participant RESP as "ApiResponse" +FE->>API : "携带分页与查询参数" +API->>MODEL : "统计总数与分页查询" +MODEL-->>API : "返回用户列表" +API->>RESP : "封装分页结果" +API-->>FE : "返回统一响应" +``` + +**图表来源** +- [backend/src/routes/users.js:35-61](file://backend/src/routes/users.js#L35-L61) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +**章节来源** +- [backend/src/routes/users.js:35-61](file://backend/src/routes/users.js#L35-L61) + +#### 创建用户 +- 方法:POST +- 路径:/api/users/ +- 请求体字段: + - username:字符串,必填,长度<=64 + - password:字符串,必填,长度>=6 + - is_super_admin:布尔,可选,默认false +- 成功响应:返回创建的用户字典 +- 限制: + - 用户名唯一 + - 至少保留一个超级管理员(删除/降级时校验) + +```mermaid +flowchart TD +Start(["开始"]) --> Validate["校验用户名与密码长度"] +Validate --> Exists{"用户名已存在?"} +Exists --> |是| ErrExists["返回错误:用户名已存在"] +Exists --> |否| Hash["生成密码哈希"] +Hash --> Create["创建用户记录"] +Create --> Log["记录日志"] +Log --> Done(["结束"]) +ErrExists --> Done +``` + +**图表来源** +- [backend/src/routes/users.js:63-98](file://backend/src/routes/users.js#L63-L98) +- [backend/src/utils/password.js:10-14](file://backend/src/utils/password.js#L10-L14) + +**章节来源** +- [backend/src/routes/users.js:63-98](file://backend/src/routes/users.js#L63-L98) + +#### 更新用户 +- 方法:PUT +- 路径:/api/users/:user_id +- 请求体字段: + - status:0或1,可选 + - is_super_admin:布尔,可选 + - password:字符串,可选(若提供则长度>=6) +- 成功响应:返回更新后的用户字典 +- 限制: + - 不能禁用或降级最后一个超级管理员 + - 当前登录用户不可自我删除 + +```mermaid +flowchart TD +S(["开始"]) --> Load["按ID加载用户"] +Load --> Found{"用户是否存在?"} +Found --> |否| NoData["返回无数据"] +Found --> |是| Parse["解析status/is_super_admin/password"] +Parse --> SA{"是否涉及超级管理员变更?"} +SA --> |是| CountSA["统计其他有效超级管理员数量"] +CountSA --> LastSA{"是否为最后一位?"} +LastSA --> |是| Block["阻止:至少保留一位超级管理员"] +LastSA --> |否| Next +SA --> |否| Next["继续"] +Next --> Passwd{"是否提供新密码?"} +Passwd --> |是| Hash["生成新密码哈希并保存"] +Passwd --> |否| Save["直接保存状态与角色"] +Hash --> Save +Save --> Log["记录日志"] +Log --> OK(["结束"]) +Block --> OK +NoData --> OK +``` + +**图表来源** +- [backend/src/routes/users.js:100-147](file://backend/src/routes/users.js#L100-L147) +- [backend/src/utils/password.js:10-14](file://backend/src/utils/password.js#L10-L14) + +**章节来源** +- [backend/src/routes/users.js:100-147](file://backend/src/routes/users.js#L100-L147) + +#### 删除用户 +- 方法:DELETE +- 路径:/api/users/:user_id +- 限制: + - 不允许删除当前登录用户 + - 不允许删除最后一个超级管理员 + +```mermaid +sequenceDiagram +participant FE as "前端" +participant API as "DELETE /api/users/ : user_id" +participant MODEL as "DashboardUser" +participant COUNT as "计数器" +FE->>API : "提交删除请求" +API->>MODEL : "按ID查找用户" +MODEL-->>API : "返回用户或空" +API->>COUNT : "统计其他有效超级管理员" +COUNT-->>API : "返回数量" +API-->>FE : "返回统一响应" +``` + +**图表来源** +- [backend/src/routes/users.js:149-177](file://backend/src/routes/users.js#L149-L177) + +**章节来源** +- [backend/src/routes/users.js:149-177](file://backend/src/routes/users.js#L149-L177) + +### 权限控制与角色管理 +- 认证中间件: + - 解析Authorization头中的Bearer Token + - 解码并注入用户上下文(id、username、is_super_admin) + - 过期或无效令牌返回401 +- 超级管理员校验: + - 仅is_super_admin为真时放行 + - 否则返回403 +- 角色与状态: + - 字段is_super_admin与status均为TinyInt,1表示启用/是,0表示禁用/否 + - 默认status=1,is_super_admin=0 + +```mermaid +classDiagram +class AuthMiddleware { ++authMiddleware(req,res,next) ++requireSuperAdmin(req,res,next) +} +class DashboardUser { ++id : int ++username : string ++password_hash : string ++is_super_admin : int ++status : int ++last_login_at : date ++create_at : date ++update_at : date +} +AuthMiddleware --> DashboardUser : "读取用户状态" +``` + +**图表来源** +- [backend/src/middleware/auth.js:3-33](file://backend/src/middleware/auth.js#L3-L33) +- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54) + +**章节来源** +- [backend/src/middleware/auth.js:3-33](file://backend/src/middleware/auth.js#L3-L33) +- [backend/src/models/DashboardUser.js:22-33](file://backend/src/models/DashboardUser.js#L22-L33) + +### 密码重置与账户激活 +- 密码重置(当前用户): + - 路由:PUT /api/auth/password + - 参数:old_password、new_password(长度>=6) + - 流程:校验旧密码,通过后更新为新密码哈希 +- 账户激活: + - 用户状态由status字段控制,1为启用,0为禁用 + - 通过更新用户状态实现“激活/禁用” + +```mermaid +sequenceDiagram +participant FE as "前端" +participant AUTH as "PUT /api/auth/password" +participant MODEL as "DashboardUser" +participant PWD as "verifyPassword/hashPassword" +FE->>AUTH : "提交旧密码与新密码" +AUTH->>MODEL : "按ID加载用户" +MODEL-->>AUTH : "返回用户或空" +AUTH->>PWD : "校验旧密码" +PWD-->>AUTH : "返回校验结果" +AUTH->>PWD : "生成新密码哈希" +AUTH->>MODEL : "保存新密码哈希" +AUTH-->>FE : "返回成功消息" +``` + +**图表来源** +- [backend/src/routes/auth.js:79-109](file://backend/src/routes/auth.js#L79-L109) +- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34) + +**章节来源** +- [backend/src/routes/auth.js:79-109](file://backend/src/routes/auth.js#L79-L109) +- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34) + +### 批量操作与导入导出 +- 批量操作建议: + - 使用循环调用单条更新接口(如批量启用/禁用、批量改密) + - 在前端对用户ID集合进行分批处理,避免超时 +- 导入导出建议: + - 导出:后端提供CSV/Excel导出接口,读取用户列表并序列化 + - 导入:前端上传文件,后端解析后逐条调用创建接口;注意幂等性与重复用户名处理 + - 安全性:导入过程建议增加事务与回滚策略,失败时撤销已创建记录 + +[本节为通用实现建议,不直接对应具体源文件] + +### 前后端交互示例 +- 前端API封装: + - GET /users/:分页查询 + - POST /users/:创建用户 + - PUT /users/:id:更新用户 + - DELETE /users/:id:删除用户 +- 前端页面: + - 支持搜索、分页、启用/禁用切换、改密、删除 + - 通过Element Plus对话框与表格展示用户列表 + +```mermaid +sequenceDiagram +participant UI as "用户管理页面(index.vue)" +participant API as "API封装(user.js)" +participant USERS as "用户路由(users.js)" +UI->>API : "调用获取/创建/更新/删除" +API->>USERS : "转发HTTP请求" +USERS-->>API : "返回统一响应" +API-->>UI : "渲染结果" +``` + +**图表来源** +- [frontend/src/views/system/users/index.vue:173-392](file://frontend/src/views/system/users/index.vue#L173-L392) +- [frontend/src/api/user.js:1-40](file://frontend/src/api/user.js#L1-L40) +- [backend/src/routes/users.js:35-177](file://backend/src/routes/users.js#L35-L177) + +**章节来源** +- [frontend/src/api/user.js:1-40](file://frontend/src/api/user.js#L1-L40) +- [frontend/src/views/system/users/index.vue:173-392](file://frontend/src/views/system/users/index.vue#L173-L392) + +## 依赖关系分析 +- 路由依赖: + - users路由依赖auth中间件与DashboardUser模型 + - auth路由依赖jwt工具与password工具 +- 工具依赖: + - password工具依赖crypto与pbkdf2 + - response工具提供统一响应结构 +- 引导依赖: + - userBootstrap在应用启动时同步数据库并创建超级管理员 + +```mermaid +graph LR +USERS["users.js"] --> AUTHMW["auth.js"] +USERS --> MODEL["DashboardUser.js"] +USERS --> PWD["password.js"] +USERS --> RESP["response.js"] +AUTH["auth.js"] --> JWT["jwt.js"] +AUTH --> PWD +BOOT["userBootstrap.js"] --> MODEL +``` + +**图表来源** +- [backend/src/routes/users.js:1-180](file://backend/src/routes/users.js#L1-L180) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) + +**章节来源** +- [backend/src/routes/users.js:1-180](file://backend/src/routes/users.js#L1-L180) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) + +## 性能考虑 +- 分页与查询: + - 限制limit上限为1000,避免大结果集导致内存压力 + - username模糊查询使用索引优化(建议在数据库层面建立索引) +- 密码哈希: + - PBKDF2迭代次数较高,保证安全性的同时需关注CPU开销 +- 日志与错误: + - 统一使用logger记录错误堆栈,便于定位性能瓶颈 + +[本节提供通用指导,不直接分析具体文件] + +## 故障排除指南 +- 401 未登录或缺少凭证: + - 检查Authorization头格式是否为Bearer Token + - 核对JWT_SECRET配置与签名算法 +- 403 需要超级管理员权限: + - 确认当前用户is_super_admin为真 +- 404 账号不存在: + - 确认用户ID正确且未被删除 +- 422 数据校验失败: + - 用户名长度、密码长度、状态值范围不符合要求 +- 423 不能删除/禁用最后一个超级管理员: + - 至少保留一位有效超级管理员 + +**章节来源** +- [backend/src/middleware/auth.js:5-25](file://backend/src/middleware/auth.js#L5-L25) +- [backend/src/routes/users.js:105-128](file://backend/src/routes/users.js#L105-L128) +- [backend/src/routes/users.js:154-168](file://backend/src/routes/users.js#L154-L168) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 结论 +用户管理API以清晰的分层架构实现了完整的用户生命周期管理,结合严格的权限控制与安全的密码策略,满足后台管理系统对账号安全与合规性的需求。通过统一的响应封装与前端交互组件,提升了开发效率与用户体验。建议在生产环境中进一步完善批量导入导出、审计日志与速率限制等能力。 + +## 附录 +- 环境变量: + - JWT_SECRET:用于JWT签名的密钥 + - DASHBOARD_ADMIN_USERNAME / DASHBOARD_ADMIN_PASSWORD:引导创建超级管理员的默认凭据 +- 健康检查: + - GET /health 返回服务健康状态 + +**章节来源** +- [backend/src/utils/jwt.js:3-5](file://backend/src/utils/jwt.js#L3-L5) +- [backend/src/services/userBootstrap.js:9-22](file://backend/src/services/userBootstrap.js#L9-L22) +- [backend/src/app.js:31-34](file://backend/src/app.js#L31-L34) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/后端API文档/认证系统API.md b/.qoder/repowiki/zh/content/后端API文档/认证系统API.md new file mode 100644 index 0000000..ee76347 --- /dev/null +++ b/.qoder/repowiki/zh/content/后端API文档/认证系统API.md @@ -0,0 +1,426 @@ +# 认证系统API + + +**本文引用的文件** +- [backend/src/routes/auth.js](file://backend/src/routes/auth.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) +- [backend/src/models/DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/services/userBootstrap.js](file://backend/src/services/userBootstrap.js) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [frontend/src/api/auth.js](file://frontend/src/api/auth.js) +- [frontend/src/utils/auth.js](file://frontend/src/utils/auth.js) +- [frontend/src/views/login/index.vue](file://frontend/src/views/login/index.vue) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件为认证系统API的详细RESTful文档,覆盖用户登录、查询当前用户、修改密码等认证相关接口;说明JWT令牌生成、验证与过期处理机制;提供认证中间件使用示例与错误处理策略;记录密码加密方式、令牌有效期与安全最佳实践,并给出常见认证场景、客户端实现指南与调试技巧。 + +## 项目结构 +后端采用Express + Sequelize架构,前端基于Vue 3 + Element Plus。认证相关逻辑集中在后端路由、中间件与工具模块,前端提供登录页面与认证状态管理。 + +```mermaid +graph TB +subgraph "后端" +A["应用入口
app.js"] +B["路由汇总
routes/index.js"] +C["认证路由
routes/auth.js"] +D["认证中间件
middleware/auth.js"] +E["JWT 工具
utils/jwt.js"] +F["密码工具
utils/password.js"] +G["响应封装
utils/response.js"] +H["用户模型
models/DashboardUser.js"] +I["环境配置
config/env.js"] +J["数据库配置
config/database.js"] +K["引导服务
services/userBootstrap.js"] +end +subgraph "前端" +L["登录视图
frontend/views/login/index.vue"] +M["认证API封装
frontend/api/auth.js"] +N["认证状态工具
frontend/utils/auth.js"] +end +A --> B +B --> C +C --> D +C --> E +C --> F +C --> G +C --> H +A --> I +A --> J +A --> K +L --> M +M --> N +``` + +**图表来源** +- [backend/src/app.js:14-37](file://backend/src/app.js#L14-L37) +- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) +- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151) +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) + +**章节来源** +- [backend/src/app.js:14-37](file://backend/src/app.js#L14-L37) +- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12) + +## 核心组件 +- 认证路由:提供登录、查询当前用户、修改密码接口。 +- 认证中间件:校验Authorization头中的Bearer Token,解析并注入用户信息。 +- JWT工具:签发访问令牌、解码验证、计算过期秒数。 +- 密码工具:PBKDF2加盐哈希与安全比对。 +- 用户模型:存储用户名、密码哈希、状态、最后登录时间等。 +- 响应封装:统一返回格式(code/msg/data)。 +- 引导服务:首次启动自动创建超级管理员账号。 + +**章节来源** +- [backend/src/routes/auth.js:24-109](file://backend/src/routes/auth.js#L24-L109) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/utils/jwt.js:7-25](file://backend/src/utils/jwt.js#L7-L25) +- [backend/src/utils/password.js:10-34](file://backend/src/utils/password.js#L10-L34) +- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54) +- [backend/src/utils/response.js:1-13](file://backend/src/utils/response.js#L1-L13) +- [backend/src/services/userBootstrap.js:5-24](file://backend/src/services/userBootstrap.js#L5-L24) + +## 架构总览 +认证流程概览:客户端发起登录请求,后端验证凭据并签发JWT;后续请求携带Authorization: Bearer ,中间件解码并校验,注入用户上下文;支持查询当前用户与修改密码。 + +```mermaid +sequenceDiagram +participant FE as "前端" +participant API as "认证路由(auth.js)" +participant MW as "认证中间件(auth.js)" +participant JWT as "JWT工具(jwt.js)" +participant PWD as "密码工具(password.js)" +participant DB as "用户模型(DashboardUser)" +FE->>API : "POST /api/auth/login" +API->>DB : "按用户名查询用户" +API->>PWD : "verifyPassword(明文, 存储哈希)" +PWD-->>API : "验证结果" +API->>JWT : "createAccessToken(用户)" +JWT-->>API : "access_token" +API-->>FE : "返回 {access_token, token_type, expires_in, user}" +FE->>API : "GET /api/auth/me" +API->>MW : "authMiddleware" +MW->>JWT : "decodeToken" +JWT-->>MW : "payload" +MW-->>API : "注入 req.user" +API->>DB : "findByPk(req.user.id)" +DB-->>API : "用户信息" +API-->>FE : "返回当前用户" +FE->>API : "PUT /api/auth/password" +API->>MW : "authMiddleware" +MW-->>API : "注入 req.user" +API->>PWD : "verifyPassword(旧密码)" +PWD-->>API : "验证结果" +API->>DB : "更新 password_hash" +API-->>FE : "返回修改结果" +``` + +**图表来源** +- [backend/src/routes/auth.js:24-109](file://backend/src/routes/auth.js#L24-L109) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/utils/jwt.js:7-21](file://backend/src/utils/jwt.js#L7-L21) +- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34) +- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54) + +## 详细组件分析 + +### 接口定义与调用规范 + +- 登录接口 + - 方法与路径:POST /api/auth/login + - 请求体字段: + - username: string(必填,前后去空格) + - password: string(必填) + - 成功响应数据: + - access_token: string(JWT) + - token_type: string(固定为 bearer) + - expires_in: number(秒,令牌有效期) + - user: object(id, username, is_super_admin, status, last_login_at, create_at, update_at) + - 错误响应: + - 用户名或密码为空:返回错误 + - 用户不存在或状态非启用:返回错误 + - 密码错误:返回错误 + - 其他异常:返回登录失败 + +- 查询当前用户接口 + - 方法与路径:GET /api/auth/me + - 认证要求:必须携带 Authorization: Bearer + - 成功响应数据:当前用户对象(同上) + - 错误响应: + - 未登录/缺少凭证:401 + - 无效凭证/过期:401 + - 账号不存在或已禁用:401 + +- 修改密码接口 + - 方法与路径:PUT /api/auth/password + - 认证要求:必须携带 Authorization: Bearer + - 请求体字段: + - old_password: string(必填) + - new_password: string(必填,至少6位) + - 成功响应:返回操作成功消息 + - 错误响应: + - 参数缺失:返回错误 + - 新密码长度不足:返回错误 + - 旧密码错误:返回错误 + - 账号不存在或已禁用:401 + - 其他异常:返回修改失败 + +**章节来源** +- [backend/src/routes/auth.js:24-109](file://backend/src/routes/auth.js#L24-L109) +- [backend/src/utils/response.js:1-13](file://backend/src/utils/response.js#L1-L13) + +### JWT令牌机制 +- 生成: + - 使用HS256算法签名,密钥来自环境变量(默认开发值)。 + - 载荷包含:sub(用户ID)、username、is_super_admin、iat(签发时间)、exp(过期时间,12小时)。 +- 验证: + - 使用相同密钥与算法进行verify。 + - 若抛出TokenExpiredError,返回“登录已过期,请重新登录”。 +- 刷新: + - 当前实现不提供专用刷新接口;建议客户端在过期前重新登录以获取新令牌。 + +```mermaid +flowchart TD +Start(["开始"]) --> Gen["签发访问令牌
createAccessToken"] +Gen --> Payload["载荷: sub, username, is_super_admin, iat, exp"] +Payload --> Sign["HS256签名"] +Sign --> Token["返回 access_token"] +Token --> Verify["解码验证
decodeToken"] +Verify --> Expired{"是否过期?"} +Expired --> |是| ErrExp["返回 401: 登录已过期"] +Expired --> |否| OK["返回有效载荷"] +``` + +**图表来源** +- [backend/src/utils/jwt.js:7-25](file://backend/src/utils/jwt.js#L7-L25) +- [backend/src/middleware/auth.js:19-25](file://backend/src/middleware/auth.js#L19-L25) + +**章节来源** +- [backend/src/utils/jwt.js:3-25](file://backend/src/utils/jwt.js#L3-L25) +- [backend/src/middleware/auth.js:19-25](file://backend/src/middleware/auth.js#L19-L25) + +### 密码加密与校验 +- 加密: + - PBKDF2,迭代次数、密钥长度、摘要算法均固定。 + - 存储格式:前缀+摘要算法+迭代次数+盐+十六进制哈希。 +- 校验: + - 安全比对,避免时序攻击。 + - 不匹配或格式不合法直接返回false。 + +```mermaid +flowchart TD +A["输入明文密码"] --> B["解析存储格式"] +B --> C{"格式合法?"} +C --> |否| F["返回 false"] +C --> |是| D["提取 salt/迭代次数/摘要算法/期望哈希"] +D --> E["PBKDF2 计算哈希"] +E --> G["timingSafeEqual 安全比较"] +G --> H{"一致?"} +H --> |是| T["返回 true"] +H --> |否| F +``` + +**图表来源** +- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34) + +**章节来源** +- [backend/src/utils/password.js:10-34](file://backend/src/utils/password.js#L10-L34) +- [backend/src/models/DashboardUser.js:17-21](file://backend/src/models/DashboardUser.js#L17-L21) + +### 认证中间件与使用示例 +- 校验规则: + - 必须存在Authorization头且以Bearer开头。 + - 解码失败或载荷无sub则视为无效凭证。 + - 过期异常返回“登录已过期,请重新登录”。 +- 注入上下文: + - 成功后在req.user中注入:id、username、is_super_admin。 +- 超级管理员校验: + - 提供requireSuperAdmin中间件,用于需要超级管理员权限的路由。 + +```mermaid +flowchart TD +S["进入中间件"] --> H1["读取 Authorization 头"] +H1 --> Check{"以 Bearer 开头?"} +Check --> |否| R401["返回 401: 未登录或缺少凭证"] +Check --> |是| Decode["decodeToken"] +Decode --> Valid{"载荷有效且含 sub?"} +Valid --> |否| R401B["返回 401: 无效凭证"] +Valid --> |是| Inject["注入 req.user"] +Inject --> Next["放行 next()"] +``` + +**图表来源** +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) + +**章节来源** +- [backend/src/middleware/auth.js:3-33](file://backend/src/middleware/auth.js#L3-L33) + +### 数据模型与状态 +- 用户表字段要点: + - 主键、唯一用户名、密码哈希、是否超级管理员、状态(启用/禁用)、最后登录时间、创建/更新时间。 +- 登录成功后会更新last_login_at。 + +```mermaid +erDiagram +DASHBOARD_USER { +int id PK +string username UK +string password_hash +tinyint is_super_admin +tinyint status +datetime last_login_at +datetime create_at +datetime update_at +} +``` + +**图表来源** +- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54) + +**章节来源** +- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54) +- [backend/src/routes/auth.js:48-49](file://backend/src/routes/auth.js#L48-L49) + +### 客户端实现指南 +- 登录流程: + - 前端调用登录API,接收access_token与用户信息。 + - 将token存入localStorage并设置用户信息,跳转首页。 +- 携带令牌: + - 后续请求在请求头添加Authorization: Bearer 。 +- 令牌过期处理: + - 前端可解析token的exp判断过期,提示重新登录。 +- 修改密码: + - 调用修改密码接口,成功后提示并刷新用户信息。 + +```mermaid +sequenceDiagram +participant VUE as "登录页(index.vue)" +participant API as "API封装(auth.js)" +participant UTIL as "认证工具(auth.js)" +VUE->>API : "login({username,password})" +API-->>VUE : "返回 {code,data}" +VUE->>UTIL : "setToken(access_token)" +VUE->>UTIL : "setUser(user)" +VUE-->>VUE : "跳转首页" +``` + +**图表来源** +- [frontend/src/views/login/index.vue:123-150](file://frontend/src/views/login/index.vue#L123-L150) +- [frontend/src/api/auth.js:3-12](file://frontend/src/api/auth.js#L3-L12) +- [frontend/src/utils/auth.js:8-14](file://frontend/src/utils/auth.js#L8-L14) + +**章节来源** +- [frontend/src/views/login/index.vue:100-151](file://frontend/src/views/login/index.vue#L100-L151) +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) + +## 依赖关系分析 +- 路由依赖中间件与工具模块,统一返回格式。 +- 中间件依赖JWT工具进行解码。 +- 登录流程依赖密码工具与用户模型。 +- 应用入口加载路由、中间件与数据库初始化。 + +```mermaid +graph LR +Routes["routes/auth.js"] --> MW["middleware/auth.js"] +Routes --> JWT["utils/jwt.js"] +Routes --> PWD["utils/password.js"] +Routes --> RESP["utils/response.js"] +Routes --> MODEL["models/DashboardUser.js"] +APP["app.js"] --> ROUTESIDX["routes/index.js"] +ROUTESIDX --> Routes +APP --> ENV["config/env.js"] +APP --> DB["config/database.js"] +APP --> BOOT["services/userBootstrap.js"] +``` + +**图表来源** +- [backend/src/routes/auth.js:1-11](file://backend/src/routes/auth.js#L1-L11) +- [backend/src/middleware/auth.js:1-1](file://backend/src/middleware/auth.js#L1-L1) +- [backend/src/utils/jwt.js:1-1](file://backend/src/utils/jwt.js#L1-L1) +- [backend/src/utils/password.js:1-2](file://backend/src/utils/password.js#L1-L2) +- [backend/src/utils/response.js:1-2](file://backend/src/utils/response.js#L1-L2) +- [backend/src/models/DashboardUser.js:1-2](file://backend/src/models/DashboardUser.js#L1-L2) +- [backend/src/app.js:10-12](file://backend/src/app.js#L10-L12) +- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12) +- [backend/src/config/env.js:1-2](file://backend/src/config/env.js#L1-L2) +- [backend/src/config/database.js:1-2](file://backend/src/config/database.js#L1-L2) +- [backend/src/services/userBootstrap.js:1-3](file://backend/src/services/userBootstrap.js#L1-L3) + +**章节来源** +- [backend/src/app.js:10-12](file://backend/src/app.js#L10-L12) +- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12) + +## 性能考虑 +- 密码哈希迭代次数较高,确保安全性但会增加CPU开销;可在生产环境根据硬件能力评估。 +- JWT签发/验证为轻量操作,主要成本在数据库查询与密码校验。 +- 建议: + - 在高并发场景下,关注数据库连接池与索引(用户名唯一索引)。 + - 对登录失败进行日志记录但避免泄露敏感信息。 + +## 故障排查指南 +- 常见错误与定位: + - 401 未登录或缺少凭证:检查请求头Authorization是否正确。 + - 401 无效凭证:检查JWT密钥、算法与签名一致性。 + - 401 登录已过期:客户端需重新登录获取新令牌。 + - 用户名或密码错误:确认用户名大小写、空格与密码哈希。 + - 获取用户信息失败/修改密码失败:查看后端日志与数据库状态。 +- 前端调试: + - 检查localStorage中的token是否存在与格式正确。 + - 使用工具函数解析token的exp判断是否过期。 + - 登录页提示“登录状态有效期12小时”,过期后需重新登录。 + +**章节来源** +- [backend/src/middleware/auth.js:5-25](file://backend/src/middleware/auth.js#L5-L25) +- [backend/src/routes/auth.js:37-46](file://backend/src/routes/auth.js#L37-L46) +- [frontend/src/views/login/index.vue:93-93](file://frontend/src/views/login/index.vue#L93-L93) +- [frontend/src/utils/auth.js:78-92](file://frontend/src/utils/auth.js#L78-L92) + +## 结论 +该认证系统采用JWT作为会话载体,结合强密码哈希与严格的中间件校验,提供了基础而完整的认证能力。建议在生产环境中: +- 设置稳定的JWT_SECRET; +- 控制密码迭代次数与数据库性能; +- 在客户端实现令牌过期检测与自动重新登录; +- 对登录与修改密码接口增加限流与风控策略。 + +## 附录 + +### 环境变量与配置 +- JWT_SECRET:JWT签名密钥(生产环境务必自定义)。 +- DATABASE_*:数据库连接参数(名称、用户、密码、主机、端口)。 +- DASHBOARD_ADMIN_USERNAME / DASHBOARD_ADMIN_PASSWORD:首次引导创建超级管理员的默认值。 +- APP_ENV:环境标识(development/production)。 + +**章节来源** +- [backend/src/utils/jwt.js:3-3](file://backend/src/utils/jwt.js#L3-L3) +- [backend/src/config/database.js:4-21](file://backend/src/config/database.js#L4-L21) +- [backend/src/services/userBootstrap.js:9-10](file://backend/src/services/userBootstrap.js#L9-L10) +- [backend/src/config/env.js:7-10](file://backend/src/config/env.js#L7-L10) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/开发指南.md b/.qoder/repowiki/zh/content/开发指南.md new file mode 100644 index 0000000..2cdf8a3 --- /dev/null +++ b/.qoder/repowiki/zh/content/开发指南.md @@ -0,0 +1,399 @@ +# 开发指南 + + +**本文引用的文件** +- [README.md](file://README.md) +- [DEPLOY.md](file://DEPLOY.md) +- [docker-compose.yml](file://docker-compose.yml) +- [backend/package.json](file://backend/package.json) +- [frontend/package.json](file://frontend/package.json) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/config/loadEnv.js](file://backend/src/config/loadEnv.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/services/userBootstrap.js](file://backend/src/services/userBootstrap.js) +- [frontend/vite.config.js](file://frontend/vite.config.js) +- [frontend/src/main.js](file://frontend/src/main.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [scripts/upload.sh](file://scripts/upload.sh) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本开发指南面向参与“Audio Dashboard”项目的开发者,提供从环境搭建、代码规范、开发流程、测试策略到部署与运维的全流程指导。项目采用前后端分离架构:前端基于 Vue 3 + Vite,后端基于 Node.js + Express,通过 Docker Compose 进行编排,Nginx 提供静态资源与反向代理。 + +## 项目结构 +项目采用多模块组织方式,根目录包含后端、前端、脚本与部署编排文件。关键目录与职责如下: +- backend:后端 Node.js 应用,包含配置、中间件、模型、路由、服务、工具与验证器等。 +- frontend:前端 Vue 3 应用,包含 API 封装、组件、布局、路由、样式与视图。 +- scripts:部署与同步脚本,支持一键上传与预览模式。 +- docker-compose.yml:服务编排定义,包含后端 API 与前端 Nginx 服务。 +- DEPLOY.md:部署与运维指南,涵盖首次部署、更新部署、常见问题与本地开发。 + +```mermaid +graph TB +subgraph "根目录" +DC["docker-compose.yml"] +DEP["DEPLOY.md"] +SCR["scripts/upload.sh"] +end +subgraph "后端 backend" +BPJ["backend/package.json"] +APP["backend/src/app.js"] +CFG["backend/src/config/"] +MID["backend/src/middleware/"] +MOD["backend/src/models/"] +RT["backend/src/routes/"] +SVC["backend/src/services/"] +UTL["backend/src/utils/"] +VAL["backend/src/validators/"] +end +subgraph "前端 frontend" +FPJ["frontend/package.json"] +VCFG["frontend/vite.config.js"] +MAIN["frontend/src/main.js"] +ROUTER["frontend/src/router/index.js"] +API["frontend/src/api/"] +CMP["frontend/src/components/"] +LYT["frontend/src/layout/"] +VIEWS["frontend/src/views/"] +STY["frontend/src/styles/"] +end +DC --> APP +DC --> VCFG +APP --> RT +APP --> CFG +APP --> MID +APP --> SVC +RT --> MID +RT --> MOD +RT --> SVC +RT --> VAL +MAIN --> ROUTER +MAIN --> API +MAIN --> CMP +MAIN --> LYT +MAIN --> VIEWS +MAIN --> STY +``` + +图表来源 +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [frontend/vite.config.js:1-27](file://frontend/vite.config.js#L1-L27) +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +章节来源 +- [README.md:1-94](file://README.md#L1-L94) +- [DEPLOY.md:1-269](file://DEPLOY.md#L1-L269) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +## 核心组件 +- 后端入口与生命周期 + - 应用入口负责加载环境、初始化日志、同步数据库表、引导超级管理员,并启动 HTTP 服务。 + - 关键点:健康检查接口、根路径响应、统一 CORS 配置、请求体大小限制中间件。 +- 路由聚合 + - 路由按功能模块拆分并在入口集中注册,便于扩展与维护。 +- 认证中间件 + - 基于 Bearer Token 的鉴权,支持超级管理员权限校验。 +- 环境加载 + - 统一从项目根目录加载 .env,支持本地开发与 Docker 环境差异。 +- 前端应用与路由 + - 基于 Vue 3 + Element Plus,内置路由守卫实现登录态与权限控制。 + - Vite 开发服务器配置了 /api 代理到后端端口。 + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/vite.config.js:1-27](file://frontend/vite.config.js#L1-L27) + +## 架构总览 +系统采用前后端分离与容器化部署: +- 前端:Nginx 静态托管,通过 /api 代理转发至后端。 +- 后端:Node.js + Express,提供 REST API,连接数据库、缓存与对象存储。 +- 编排:Docker Compose 统一管理服务生命周期与网络。 +- 部署:提供本地构建 + 上传脚本与一键部署流程。 + +```mermaid +graph TB +Browser["浏览器"] --> Nginx["Nginx 前端服务
端口 8082 → 80"] +Nginx --> API["后端 API 服务
端口 8083 → 8000"] +subgraph "容器网络" +Nginx +API +end +API --> DB["MySQL 数据库"] +API --> REDIS["Redis 缓存"] +API --> S3["AWS S3 存储"] +API --> MEILI["Meilisearch 搜索引擎"] +``` + +图表来源 +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [DEPLOY.md:1-269](file://DEPLOY.md#L1-L269) + +## 详细组件分析 + +### 后端应用与启动流程 +- 加载环境变量:优先读取根目录 .env,确保开发与生产一致性。 +- 初始化日志、数据库与超级管理员引导。 +- 启动 HTTP 服务器,提供根路径与健康检查接口。 + +```mermaid +sequenceDiagram +participant Entrypoint as "入口(app.js)" +participant Env as "环境加载(loadEnv.js)" +participant DB as "数据库(sequelize)" +participant Boot as "引导(userBootstrap.js)" +participant Server as "HTTP 服务器" +Entrypoint->>Env : "加载根目录 .env" +Entrypoint->>DB : "同步数据库表" +Entrypoint->>Boot : "创建超级管理员" +Entrypoint->>Server : "监听端口并启动" +Server-->>Entrypoint : "返回运行状态" +``` + +图表来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) + +### 认证与权限控制 +- 鉴权中间件:解析 Authorization 头,校验 Bearer Token 有效性与过期时间。 +- 超级管理员校验:对特定路由进行权限拦截。 +- 前端路由守卫:根据登录态与角色重定向或拒绝访问。 + +```mermaid +flowchart TD +Start(["进入受保护路由"]) --> CheckAuth["检查是否需要登录"] +CheckAuth --> |否| Allow["放行"] +CheckAuth --> |是| HasToken{"是否存在有效 Token"} +HasToken --> |否| RedirectLogin["重定向到登录页"] +HasToken --> |是| NeedSA{"是否需要超级管理员"} +NeedSA --> |否| Allow +NeedSA --> |是| IsSA{"是否为超级管理员"} +IsSA --> |否| ToHome["重定向到首页"] +IsSA --> |是| Allow +Allow --> End(["继续导航"]) +RedirectLogin --> End +ToHome --> End +``` + +图表来源 +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +章节来源 +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +### 前端应用与开发体验 +- 应用入口:注册 Element Plus、路由、主题样式,完成首屏渲染控制。 +- 开发服务器:Vite 提供热更新与 /api 代理,便于联调后端。 +- 路由设计:菜单驱动的权限路由,支持超级管理员专属页面。 + +```mermaid +sequenceDiagram +participant Browser as "浏览器" +participant Vite as "Vite 开发服务器" +participant Proxy as "代理(/api)" +participant Backend as "后端 API" +Browser->>Vite : "访问 /" +Vite-->>Browser : "返回首页" +Browser->>Vite : "访问 /api/*" +Vite->>Proxy : "转发到 http : //localhost : 8083" +Proxy->>Backend : "请求后端接口" +Backend-->>Proxy : "返回数据" +Proxy-->>Vite : "透传响应" +Vite-->>Browser : "渲染页面" +``` + +图表来源 +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/vite.config.js:17-25](file://frontend/vite.config.js#L17-L25) + +章节来源 +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/vite.config.js:1-27](file://frontend/vite.config.js#L1-L27) + +### 部署与上传脚本 +- 支持按模块选择性上传:前端、后端、编排文件。 +- 支持虚拟执行预览同步结果,避免误操作。 +- 默认上传到服务器指定根目录,支持自定义 SSH 密钥与远端路径。 + +```mermaid +flowchart TD +CLI["命令行参数"] --> Resolve["解析预设/路径"] +Resolve --> BuildList["生成待同步列表"] +BuildList --> DryRun{"是否预览模式"} +DryRun --> |是| Preview["打印预览信息"] +DryRun --> |否| Sync["rsync 同步"] +Preview --> Done["完成"] +Sync --> Done +``` + +图表来源 +- [scripts/upload.sh:1-191](file://scripts/upload.sh#L1-L191) + +章节来源 +- [scripts/upload.sh:1-191](file://scripts/upload.sh#L1-L191) + +## 依赖分析 +- 后端依赖 + - Web 框架与工具:Express、CORS、Sequelize、MySQL2、Axios、Dotenv、Zod、Winston、IORedis。 + - 包管理:pnpm,锁定版本以保证一致性。 +- 前端依赖 + - 框架与 UI:Vue 3、Element Plus、Vue Router。 + - 构建与开发:Vite、@vitejs/plugin-vue。 +- 运行时与编排 + - Docker Compose 管理服务、网络与卷,Nginx 提供静态资源与代理。 + +```mermaid +graph LR +subgraph "后端" +BE_PKG["backend/package.json"] +BE_EXP["Express"] +BE_DB["Sequelize/MySQL2"] +BE_LOG["Winston 日志"] +BE_CACHE["IORedis"] +BE_S3["@aws-sdk/client-s3"] +end +subgraph "前端" +FE_PKG["frontend/package.json"] +FE_VUE["Vue 3"] +FE_ROUTER["Vue Router"] +FE_ELE["Element Plus"] +FE_VITE["Vite"] +end +BE_PKG --> BE_EXP +BE_PKG --> BE_DB +BE_PKG --> BE_LOG +BE_PKG --> BE_CACHE +BE_PKG --> BE_S3 +FE_PKG --> FE_VUE +FE_PKG --> FE_ROUTER +FE_PKG --> FE_ELE +FE_PKG --> FE_VITE +``` + +图表来源 +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) + +章节来源 +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) + +## 性能考虑 +- 服务端 + - 合理设置数据库连接池与查询索引,避免慢查询。 + - 使用缓存层(Redis)降低热点数据读取压力。 + - 控制日志级别与输出频率,避免 I/O 抖动。 +- 客户端 + - 按需加载组件与路由,减少首屏体积。 + - 图片与静态资源启用压缩与缓存策略。 +- 编排与部署 + - 使用只读挂载静态资源,避免不必要的写入。 + - 合理设置容器日志轮转,控制磁盘占用。 + +## 故障排查指南 +- 前端页面空白 + - 检查前端构建产物是否上传成功、Nginx 配置是否正确。 + - 查看前端容器日志定位问题。 +- API 请求失败 + - 确认后端服务状态、数据库/缓存/搜索引擎连接情况。 + - 核对 Nginx 代理目标与端口映射。 +- 后端构建失败(pnpm/Node 版本) + - 确认上传了 package.json 与 pnpm-lock.yaml。 + - 检查后端镜像基础版本与 Node 版本匹配。 +- 修改 .env 后不生效 + - 强制重建后端容器以重新注入环境变量。 +- 停止与重启 + - 使用 Compose 停止或重启相关服务。 + +章节来源 +- [DEPLOY.md:226-256](file://DEPLOY.md#L226-L256) + +## 结论 +本指南提供了从开发到部署的全链路实践建议。建议团队在日常工作中遵循统一的代码规范、版本与分支策略,并结合自动化测试与日志监控提升交付质量与稳定性。 + +## 附录 + +### 开发环境配置 +- 本地开发 + - 后端:根目录配置 .env,安装依赖后启动服务。 + - 前端:安装依赖后启动开发服务器,自动代理 /api 到后端端口。 +- Docker 开发 + - 使用 Compose 启动服务,注意端口映射与容器内端口一致性。 + +章节来源 +- [DEPLOY.md:259-269](file://DEPLOY.md#L259-L269) +- [frontend/vite.config.js:17-25](file://frontend/vite.config.js#L17-L25) +- [backend/src/app.js:40-56](file://backend/src/app.js#L40-L56) + +### Git 工作流与分支策略 +- 建议采用 Git Flow 或 GitHub Flow,主分支受保护,特性分支从 develop 拉取并合并回 develop,发布前打标签并合并到 main。 +- 合并请求(MR)必须通过代码审查与 CI 检查。 + +### 代码规范与命名约定 +- 文件与目录 + - 后端按功能分层(config/middleware/models/routes/services/utils/validators),统一小写与下划线。 + - 前端按功能域组织(api/components/layout/router/utils/views/styles),组件与页面使用 PascalCase。 +- 命名 + - 变量与函数使用驼峰命名;常量使用大写下划线;类与构造函数使用帕斯卡命名。 +- 文档 + - README 保持简洁,贡献者指南与变更日志独立维护。 + +### 测试策略 +- 单元测试 + - 后端:针对工具函数、验证器与服务层进行单元测试。 + - 前端:针对工具函数与组件逻辑进行单元测试。 +- 集成测试 + - 后端:集成数据库、缓存与外部服务的端到端接口测试。 +- 端到端测试 + - 使用自动化测试框架(如 Playwright/Cypress)覆盖关键用户路径。 + +### 依赖管理与版本控制 +- 包管理 + - 使用 pnpm 并锁定版本,确保团队一致性。 +- 版本发布 + - 语义化版本管理,变更记录与发布说明同步更新。 + +### 发布流程 +- 本地构建前端产物,使用上传脚本同步到服务器,随后在服务器执行 Compose 构建与启动。 +- 仅更新前端或后端时,可选择性上传并重启对应服务。 + +章节来源 +- [scripts/upload.sh:1-191](file://scripts/upload.sh#L1-L191) +- [DEPLOY.md:122-154](file://DEPLOY.md#L122-L154) + +### 团队协作与文档维护 +- 代码审查 + - 至少一名合作者审查并通过 CI 检查后方可合并。 +- 文档 + - 重要变更同步更新 README、DEPLOY.md 与内部 Wiki。 +- 沟通 + - 使用问题跟踪与每日站会保持进度透明。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/快速开始.md b/.qoder/repowiki/zh/content/快速开始.md new file mode 100644 index 0000000..1a36aba --- /dev/null +++ b/.qoder/repowiki/zh/content/快速开始.md @@ -0,0 +1,297 @@ +# 快速开始 + + +**本文引用的文件** +- [README.md](file://README.md) +- [DEPLOY.md](file://DEPLOY.md) +- [docker-compose.yml](file://docker-compose.yml) +- [backend/package.json](file://backend/package.json) +- [frontend/package.json](file://frontend/package.json) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/loadEnv.js](file://backend/src/config/loadEnv.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/Dockerfile](file://backend/Dockerfile) +- [frontend/Dockerfile](file://frontend/Dockerfile) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [backend/src/models/index.js](file://backend/src/models/index.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能注意事项](#性能注意事项) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本指南面向首次接触项目的开发者,帮助你在最短时间内完成环境准备、依赖安装、数据库初始化、环境变量配置以及本地或容器化启动。文档同时提供 Docker Compose 的完整部署流程,并给出常见问题的排查建议与基础使用示例,涵盖添加品牌、创建型号、进行 OTA 更新的关键操作路径。 + +## 项目结构 +项目采用前后端分离架构,后端为 Node.js + Express,前端为 Vue 3 + Vite,通过 Nginx 提供静态资源与反向代理。整体通过 Docker Compose 编排,后端容器暴露 8000 端口,前端容器暴露 80 端口并通过宿主端口映射对外提供服务。 + +```mermaid +graph TB +subgraph "宿主机" +FE_PORT["前端端口 8082 -> 80"] +BE_PORT["后端端口 8083 -> 8000"] +DATA_VOL["卷: /data/projects/source"] +end +subgraph "容器网络" +NET["bridge: audio-network"] +end +subgraph "后端服务" +BACKEND["dashboard-backend
Node.js 22 Alpine"] +DB["MySQL"] +REDIS["Redis"] +end +subgraph "前端服务" +FRONTEND["Nginx Alpine"] +end +FE_PORT --> FRONTEND +BE_PORT --> BACKEND +DATA_VOL -. 存储OTA升级包 .-> BACKEND +FRONTEND --> |"反向代理 /api"| BACKEND +BACKEND --> DB +BACKEND --> REDIS +NET --- BACKEND +NET --- FRONTEND +``` + +图表来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) +- [frontend/Dockerfile:1-32](file://frontend/Dockerfile#L1-L32) + +章节来源 +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) +- [frontend/Dockerfile:1-32](file://frontend/Dockerfile#L1-L32) + +## 核心组件 +- 后端入口与启动 + - 后端通过入口文件启动,内置健康检查与数据库同步逻辑,启动后自动尝试创建表并初始化超级管理员账户。 +- 环境与配置 + - 通过统一的环境加载模块从项目根目录加载 .env;支持开发/生产环境切换;数据库、Redis、日志等均通过环境变量配置。 +- 路由与模型 + - 路由集中注册,包含认证、品牌、型号、OTA、分享码日志、用户与仪表盘等模块;模型层定义了品牌、型号、OTA、分享码日志与系统用户等实体。 +- 日志与监控 + - 使用 winston 输出到控制台与文件;提供健康检查接口便于外部探活。 + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) + +## 架构总览 +下图展示了从浏览器到后端 API 的典型请求链路,以及后端与数据库、缓存之间的交互。 + +```mermaid +sequenceDiagram +participant U as "用户浏览器" +participant F as "Nginx 前端" +participant B as "Node.js 后端" +participant D as "MySQL" +participant R as "Redis" +U->>F : "访问前端页面" +F-->>U : "返回静态页面" +U->>F : "发起 /api 请求" +F->>B : "反向代理到 http : //backend : 8000" +B->>D : "查询/写入数据" +B->>R : "读取/写入缓存" +B-->>F : "返回 JSON 响应" +F-->>U : "返回响应" +``` + +图表来源 +- [docker-compose.yml:13-38](file://docker-compose.yml#L13-L38) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) + +## 详细组件分析 + +### 环境与依赖安装 +- 环境要求 + - Node.js:后端使用 Node.js 22(容器镜像已内置),前端使用 Node.js 18(构建阶段)。 + - 包管理器:项目使用 pnpm,版本在 package.json 中固定。 + - 数据库:MySQL(默认端口 3306),用于存储业务数据。 + - 缓存:Redis(默认端口 6379),用于 EQ 缓存等场景。 +- 本地安装(非容器) + - 后端:在 backend 目录安装依赖并启动。 + - 前端:在 frontend 目录安装依赖并启动,开发服务器默认端口为 3000,/api 代理至后端 8083。 +- 容器安装 + - 使用 Docker Compose 一键编排,后端镜像基于 node:22-alpine,前端镜像基于 nginx:alpine,构建完成后自动启动。 + +章节来源 +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) +- [frontend/Dockerfile:1-32](file://frontend/Dockerfile#L1-L32) +- [DEPLOY.md:259-269](file://DEPLOY.md#L259-L269) + +### 环境变量配置 +- 配置位置 + - 根目录 .env(与 docker-compose.yml 同级),本地开发与 Docker 部署均从此处读取。 +- 关键变量类别 + - 数据库:数据库主机、端口、名称、用户名、密码。 + - 应用:应用名、环境(development/production)。 + - 认证:JWT 密钥、后台管理员用户名与密码。 + - 搜索:Meilisearch 地址、密钥、索引。 + - S3:区域、OTA 与测量桶名称。 + - OTA:X8/X9 基础地址、上传目录。 + - Redis EQ:主机、端口、密码、数据库编号。 +- 加载机制 + - 后端启动前统一从根目录加载 .env;Docker 部署时由 compose env_file 注入,容器内不再读取本地 .env 文件。 + +章节来源 +- [DEPLOY.md:190-204](file://DEPLOY.md#L190-L204) +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) + +### 数据库初始化 +- 初始化流程 + - 启动时后端尝试同步数据库表结构;若失败则记录告警但不影响服务继续运行。 + - 同时会初始化超级管理员账户,确保首次可用。 +- 连接参数 + - 默认连接 localhost:3306,数据库名与凭据可通过环境变量覆盖。 + +章节来源 +- [backend/src/app.js:42-57](file://backend/src/app.js#L42-L57) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) + +### 缓存与日志 +- Redis + - 提供 EQ 缓存客户端工厂方法,支持密码、数据库选择与错误监听。 +- 日志 + - 控制台与文件双通道输出,日志目录位于后端 src 下 logs。 + +章节来源 +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +### 路由与模型 +- 路由 + - 路由集中注册,包含认证、品牌、型号、OTA、分享码日志、用户与仪表盘等模块。 +- 模型 + - 品牌、型号、OTA、分享码日志、系统用户等实体定义。 + +章节来源 +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) + +### 启动命令与健康检查 +- 本地开发 + - 后端:在 backend 目录执行启动脚本,默认监听 8083。 + - 前端:在 frontend 目录执行启动脚本,默认监听 3000,/api 代理至 8083。 +- 容器化 + - 使用 docker compose up -d 启动;前端通过 8082 访问,后端通过 8083 访问;健康检查接口 /health 返回健康状态。 +- 健康检查 + - 访问 http://localhost:8083/health 验证后端是否正常运行。 + +章节来源 +- [backend/src/app.js:22-38](file://backend/src/app.js#L22-L38) +- [DEPLOY.md:104-119](file://DEPLOY.md#L104-L119) + +### Docker 容器化部署流程 +- 本地构建前端 + - 在 frontend 目录执行构建,产物生成于 dist。 +- 上传到服务器 + - 使用上传脚本或手动 rsync 上传前端 dist、nginx.conf、后端源码与 docker-compose.yml。 +- 服务器构建与启动 + - 在服务器执行 docker compose build --no-cache backend 与 docker compose up -d。 +- 验证 + - 使用 docker compose ps 与 docker compose logs -f backend 检查状态与日志;使用 curl http://localhost:8083/health 进行健康检查。 + +章节来源 +- [DEPLOY.md:49-119](file://DEPLOY.md#L49-L119) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +### 基本使用示例 +- 添加第一个品牌 + - 通过品牌管理界面或后端接口创建品牌信息。 +- 创建型号 + - 在品牌下创建对应型号,填写必要字段并保存。 +- 进行 OTA 更新 + - 上传升级包至指定目录(由环境变量配置),在 OTA 页面关联型号并发布更新。 +- 注意事项 + - OTA 升级包存储目录需与后端容器挂载一致;S3 配置按需调整。 + +章节来源 +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [DEPLOY.md:206-223](file://DEPLOY.md#L206-L223) + +## 依赖关系分析 +后端应用的依赖关系如下所示: + +```mermaid +graph LR +APP["backend/src/app.js"] --> CFG_ENV["backend/src/config/env.js"] +APP --> CFG_DB["backend/src/config/database.js"] +APP --> CFG_REDIS["backend/src/config/redis.js"] +APP --> CFG_LOGGER["backend/src/config/logger.js"] +APP --> ROUTES["backend/src/routes/index.js"] +APP --> MODELS["backend/src/models/index.js"] +APP --> LOADENV["backend/src/config/loadEnv.js"] +``` + +图表来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) + +## 性能注意事项 +- 日志轮转:服务日志最大大小与保留文件数已在 compose 中配置,避免日志过大影响磁盘。 +- 端口映射:前端与后端端口映射需与 Nginx 代理配置保持一致,避免代理失败导致性能下降。 +- 缓存命中:合理设置 Redis 参数与数据库连接池,提升查询性能。 +- 构建优化:前端构建产物仅需上传,避免重复构建;后端镜像使用 pnpm 与只读依赖锁文件,保证构建一致性。 + +章节来源 +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [frontend/Dockerfile:1-32](file://frontend/Dockerfile#L1-L32) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) + +## 故障排除指南 +- 前端页面空白 + - 检查 dist 是否上传成功、路径是否正确;查看前端容器日志;确认 Nginx 配置。 +- API 请求失败 + - 确认后端容器处于 running 状态;查看后端日志中的数据库、Redis、Meilisearch 连接错误;核对 Nginx 代理目标。 +- 后端构建失败(pnpm/Node 版本) + - 确保上传了 package.json 与 pnpm-lock.yaml;后端镜像基于 node:22-alpine。 +- 修改 .env 后不生效 + - 重新创建后端容器以加载新环境变量。 +- 停止服务 + - 使用 docker compose down 停止所有服务。 + +章节来源 +- [DEPLOY.md:226-256](file://DEPLOY.md#L226-L256) + +## 结论 +通过本指南,你可以快速完成环境准备、依赖安装、数据库初始化与容器化部署,并掌握常见问题的排查方法。建议在正式环境中完善安全配置(如 JWT 密钥、管理员密码、S3 权限等),并结合日志与健康检查持续监控系统运行状态。 + +## 附录 +- 本地开发命令参考 + - 后端:在 backend 目录执行启动脚本,默认监听 8083。 + - 前端:在 frontend 目录执行启动脚本,默认监听 3000,/api 代理至 8083。 +- 健康检查 + - 访问 http://localhost:8083/health 获取后端健康状态。 + +章节来源 +- [DEPLOY.md:259-269](file://DEPLOY.md#L259-L269) +- [backend/src/app.js:31-38](file://backend/src/app.js#L31-L38) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/数据库设计/OTA固件模型.md b/.qoder/repowiki/zh/content/数据库设计/OTA固件模型.md new file mode 100644 index 0000000..79e312f --- /dev/null +++ b/.qoder/repowiki/zh/content/数据库设计/OTA固件模型.md @@ -0,0 +1,424 @@ +# OTA固件模型 + + +**本文档引用的文件** +- [backend/src/models/Ota.js](file://backend/src/models/Ota.js) +- [backend/src/routes/ota.js](file://backend/src/routes/ota.js) +- [backend/src/services/otaStorage.js](file://backend/src/services/otaStorage.js) +- [backend/src/validators/ota.js](file://backend/src/validators/ota.js) +- [frontend/src/views/ota/index.vue](file://frontend/src/views/ota/index.vue) +- [frontend/src/api/ota.js](file://frontend/src/api/ota.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [DEPLOY.md](file://DEPLOY.md) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +本文档详细介绍了OTA固件模型的设计与实现,包括固件版本管理、存储机制、发布策略以及升级流程。系统支持两种设备型号(Luxsin-X8和Luxsin-X9),提供强制更新和可选更新两种升级类型,并具备灰度发布和定向发布的功能。 + +## 项目结构 + +OTA系统采用前后端分离架构,主要由以下组件构成: + +```mermaid +graph TB +subgraph "前端层" +FE[Vue.js 前端界面] +API[API封装层] +end +subgraph "后端层" +ROUTES[路由层] +VALIDATORS[验证器] +MODELS[数据模型] +STORAGE[存储服务] +end +subgraph "基础设施" +DB[(数据库)] +S3[S3存储] +FS[文件系统] +end +FE --> API +API --> ROUTES +ROUTES --> VALIDATORS +ROUTES --> MODELS +MODELS --> DB +ROUTES --> STORAGE +STORAGE --> S3 +STORAGE --> FS +``` + +**图表来源** +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +**章节来源** +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +## 核心组件 + +### 数据模型设计 + +OTA固件模型定义了完整的固件版本管理结构,包含以下关键字段: + +| 字段名 | 类型 | 描述 | 默认值 | +|--------|------|------|--------| +| id | INTEGER | 主键ID | 自增 | +| verCode | INTEGER | 版本号(整数) | 必填 | +| verName | STRING(20) | 版本名称 | 必填 | +| url | STRING(255) | 升级包URL | 必填 | +| md5 | STRING(32) | 升级包MD5校验码 | 必填 | +| force | SMALLINT | 是否强制更新 | 0(否) | +| desc | STRING(255) | 描述信息 | NULL | +| model | STRING(100) | 对应设备型号 | NULL | +| hw | INTEGER | 硬件版本号 | 0 | +| target | SMALLINT | 是否定向发布 | 0(否) | +| beta | SMALLINT | 是否灰度发布 | 0(否) | +| startTime | DATE | 升级开始时间 | NULL | +| endTime | DATE | 升级结束时间 | NULL | +| status | SMALLINT | 发布状态 | 1(可用) | +| create_at | DATE | 创建时间 | 当前时间 | + +**章节来源** +- [backend/src/models/Ota.js:4-94](file://backend/src/models/Ota.js#L4-L94) + +### 存储策略 + +系统针对不同设备型号采用差异化的存储策略: + +```mermaid +flowchart TD +Start([上传请求]) --> CheckModel{检查设备型号} +CheckModel --> |Luxsin-X8| UploadS3[上传到S3存储] +CheckModel --> |Luxsin-X9| SaveLocal[保存到本地文件系统] +UploadS3 --> GenKey[生成S3 Key] +GenKey --> PutObject[写入S3对象] +PutObject --> BuildURL[构建公共URL] +SaveLocal --> CreateDir[创建目录结构] +CreateDir --> WriteFile[写入文件] +WriteFile --> BuildLocalURL[构建本地URL] +BuildURL --> Return[返回结果] +BuildLocalURL --> Return +``` + +**图表来源** +- [backend/src/services/otaStorage.js:72-103](file://backend/src/services/otaStorage.js#L72-L103) +- [backend/src/services/otaStorage.js:51-70](file://backend/src/services/otaStorage.js#L51-L70) + +**章节来源** +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +## 架构概览 + +OTA系统采用RESTful API设计,提供完整的CRUD操作和专门的升级包上传功能: + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Frontend as 前端界面 +participant Backend as 后端服务 +participant Storage as 存储服务 +participant Database as 数据库 +Client->>Frontend : 访问OTA管理界面 +Frontend->>Backend : 获取OTA列表 +Backend->>Database : 查询OTA记录 +Database-->>Backend : 返回OTA数据 +Backend-->>Frontend : 返回JSON响应 +Frontend->>Backend : 上传升级包 +Backend->>Storage : 处理文件上传 +Storage->>Storage : 计算MD5哈希 +Storage->>Storage : 保存文件 +Storage-->>Backend : 返回文件信息 +Backend-->>Frontend : 返回上传结果 +Frontend->>Backend : 创建OTA记录 +Backend->>Database : 插入新记录 +Database-->>Backend : 返回新ID +Backend-->>Frontend : 返回创建结果 +``` + +**图表来源** +- [frontend/src/views/ota/index.vue:420-449](file://frontend/src/views/ota/index.vue#L420-L449) +- [backend/src/routes/ota.js:24-66](file://backend/src/routes/ota.js#L24-L66) +- [backend/src/routes/ota.js:162-194](file://backend/src/routes/ota.js#L162-L194) + +## 详细组件分析 + +### 前端管理界面 + +前端采用Element Plus组件库构建,提供直观的OTA管理界面: + +```mermaid +classDiagram +class OtaManagement { ++searchForm : Object ++pagination : Object ++tableData : Array ++dialogVisible : Boolean ++formData : Object ++loadData() void ++handleSearch() void ++handleAdd() void ++handleEdit(row) void ++handleSubmit() void ++handleDelete(row) void +} +class FormValidation { ++verCode : Number ++verName : String ++model : String ++url : String ++md5 : String ++force : Number ++status : Number ++target : Number ++beta : Number ++hw : Number +} +class PackageUpload { ++packageFileList : Array ++packageUploading : Boolean ++handlePackageChange(file) Promise ++handlePackageRemove() void +} +OtaManagement --> FormValidation : "使用" +OtaManagement --> PackageUpload : "集成" +``` + +**图表来源** +- [frontend/src/views/ota/index.vue:249-580](file://frontend/src/views/ota/index.vue#L249-L580) + +前端界面特性: +- 支持按版本名称、设备型号、状态进行筛选 +- 提供分页功能,支持10-100条记录每页 +- 内置表单验证,确保数据完整性 +- 支持升级包自动上传和MD5校验 +- 提供复制现有版本的功能 + +**章节来源** +- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) + +### 后端API服务 + +后端提供完整的OTA管理API: + +#### 核心API接口 + +| 接口 | 方法 | 功能 | 权限要求 | +|------|------|------|----------| +| `/api/ota/upload-package` | POST | 上传升级包 | 登录用户 | +| `/api/ota/latest/check` | GET | 检查最新版本 | 无需登录 | +| `/api/ota/` | GET | 获取OTA列表 | 登录用户 | +| `/api/ota/:ota_id` | GET | 获取指定OTA | 登录用户 | +| `/api/ota/` | POST | 创建OTA记录 | 登录用户 | +| `/api/ota/:ota_id` | PUT | 更新OTA记录 | 登录用户 | +| `/api/ota/:ota_id` | DELETE | 删除OTA记录 | 登录用户 | + +#### 版本检查逻辑 + +设备端通过`/api/ota/latest/check`接口获取最新可用版本: + +```mermaid +flowchart TD +Request[设备请求] --> ParseParams[解析参数] +ParseParams --> CheckStatus{检查状态} +CheckStatus --> |不可用| NoData[返回空数据] +CheckStatus --> |可用| QueryDB[查询数据库] +QueryDB --> FilterByVersion{过滤更高版本} +FilterByVersion --> FilterByModel{按设备型号过滤} +FilterByModel --> FilterByHW{按硬件版本过滤} +FilterByHW --> OrderByVersion[按版本号降序排列] +OrderByVersion --> ReturnResult[返回最新版本] +NoData --> End([结束]) +ReturnResult --> End +``` + +**图表来源** +- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102) + +**章节来源** +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) + +### 存储服务实现 + +存储服务根据设备型号采用不同的存储策略: + +#### Luxsin-X8存储策略 +- 使用Amazon S3作为存储后端 +- 文件命名为`LUXSIN_X8.PKG` +- 生成S3 Key格式:`ota/{YYYYMM}/x8/{md5前5位}/LUXSIN_X8.PKG` +- 支持IAM角色认证和显式凭证两种模式 + +#### Luxsin-X9存储策略 +- 使用本地文件系统存储 +- 文件命名为`LUXSIN.PKG` +- 目录结构:`{OTA_UPLOAD_DIR}/ota/{YYYYMM}/x9/{md5前5位}/LUXSIN.PKG` +- 支持开发和生产环境的不同存储路径 + +**章节来源** +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +### 数据验证机制 + +系统采用Zod库实现严格的数据验证: + +```mermaid +flowchart TD +Input[用户输入] --> Schema[验证模式] +Schema --> Validate{验证通过?} +Validate --> |是| Process[处理数据] +Validate --> |否| Error[返回错误信息] +Process --> CreateRecord[创建数据库记录] +CreateRecord --> Success[返回成功响应] +Error --> End([结束]) +Success --> End +``` + +**图表来源** +- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) + +**章节来源** +- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) + +## 依赖关系分析 + +```mermaid +graph LR +subgraph "外部依赖" +ZOD[Zod验证库] +SEQUELIZE[Sequelize ORM] +MULTER[Multer文件上传] +S3_SDK[AWS S3 SDK] +end +subgraph "内部模块" +OtaModel[Ota模型] +OtaRoutes[OTA路由] +OtaStorage[存储服务] +OtaValidator[验证器] +ApiResponse[响应封装] +end +ZOD --> OtaValidator +SEQUELIZE --> OtaModel +MULTER --> OtaRoutes +S3_SDK --> OtaStorage +OtaRoutes --> OtaModel +OtaRoutes --> OtaStorage +OtaRoutes --> OtaValidator +OtaRoutes --> ApiResponse +``` + +**图表来源** +- [backend/src/routes/ota.js:1-20](file://backend/src/routes/ota.js#L1-L20) +- [backend/src/models/Ota.js:1-3](file://backend/src/models/Ota.js#L1-L3) +- [backend/src/services/otaStorage.js:1-10](file://backend/src/services/otaStorage.js#L1-L10) + +**章节来源** +- [backend/src/routes/ota.js:1-20](file://backend/src/routes/ota.js#L1-L20) +- [backend/src/models/Ota.js:1-3](file://backend/src/models/Ota.js#L1-L3) + +## 性能考虑 + +### 存储优化 +- **S3存储**:利用CDN加速全球访问,支持断点续传 +- **本地存储**:使用递归目录结构,避免单目录文件过多 +- **MD5校验**:上传即计算,确保文件完整性 + +### 数据库优化 +- **索引策略**:对`verCode`、`model`、`status`建立复合索引 +- **查询优化**:使用`LIMIT`限制返回数量,避免全表扫描 +- **缓存策略**:结合Redis实现热点数据缓存 + +### 前端性能 +- **懒加载**:表格数据按需加载 +- **分页机制**:支持大数据量场景下的分页显示 +- **防抖处理**:搜索框输入防抖,减少请求频率 + +## 故障排除指南 + +### 常见问题及解决方案 + +#### 1. S3上传失败 +**症状**:升级包上传到Luxsin-X8失败 +**原因**: +- AWS凭证配置错误 +- S3权限不足 +- 网络连接问题 + +**解决方案**: +- 检查`AWS_ACCESS_KEY_ID`和`AWS_SECRET_ACCESS_KEY`配置 +- 验证S3桶权限设置 +- 确认网络连通性 + +#### 2. 本地存储权限问题 +**症状**:升级包无法保存到Luxsin-X9 +**原因**: +- 目录权限不足 +- 磁盘空间不足 +- 路径不存在 + +**解决方案**: +- 确保`/data/projects/source`目录可写 +- 检查磁盘空间 +- 创建必要的目录结构 + +#### 3. 版本冲突 +**症状**:创建OTA记录时报版本已存在 +**原因**: +- 相同设备型号的版本号重复 +- 数据库约束冲突 + +**解决方案**: +- 修改版本号确保唯一性 +- 检查现有版本记录 + +#### 4. 前端上传异常 +**症状**:升级包上传界面无响应 +**原因**: +- 文件大小超限 +- 网络超时 +- 前端验证失败 + +**解决方案**: +- 检查文件大小限制(50MB) +- 确认网络连接稳定 +- 重新选择符合要求的文件 + +**章节来源** +- [backend/src/routes/ota.js:58-65](file://backend/src/routes/ota.js#L58-L65) +- [backend/src/services/otaStorage.js:95-98](file://backend/src/services/otaStorage.js#L95-L98) + +## 结论 + +OTA固件模型提供了完整的固件版本管理解决方案,具有以下特点: + +### 技术优势 +- **双存储策略**:针对不同设备型号采用最优存储方案 +- **严格验证**:前后端双重数据验证确保数据完整性 +- **灵活发布**:支持强制更新、可选更新、灰度发布等多种发布策略 +- **安全可靠**:MD5校验、权限控制、错误处理机制完善 + +### 扩展性 +- **模块化设计**:各组件职责清晰,易于维护和扩展 +- **环境适配**:支持开发、测试、生产多环境部署 +- **API标准化**:RESTful接口设计便于第三方集成 + +### 最佳实践建议 +1. **版本管理**:建立严格的版本号命名规范 +2. **测试流程**:在灰度环境中充分测试后再全量发布 +3. **监控告警**:建立OTA升级监控和异常告警机制 +4. **回滚策略**:制定完善的版本回滚预案 + +该系统为固件版本管理提供了可靠的基础设施,能够满足现代IoT设备的OTA升级需求。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/数据库设计/分享码日志模型.md b/.qoder/repowiki/zh/content/数据库设计/分享码日志模型.md new file mode 100644 index 0000000..9e04408 --- /dev/null +++ b/.qoder/repowiki/zh/content/数据库设计/分享码日志模型.md @@ -0,0 +1,323 @@ +# 分享码日志模型 + + +**本文档引用的文件** +- [ShareCodeLog.js](file://backend/src/models/ShareCodeLog.js) +- [shareCodeLogs.js](file://backend/src/routes/shareCodeLogs.js) +- [log.vue](file://frontend/src/views/share-code/log.vue) +- [shareCodeLog.js](file://frontend/src/api/shareCodeLog.js) +- [response.js](file://backend/src/utils/response.js) +- [database.js](file://backend/src/config/database.js) +- [logger.js](file://backend/src/config/logger.js) +- [env.js](file://backend/src/config/env.js) +- [app.js](file://backend/src/app.js) +- [index.js](file://backend/src/routes/index.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +分享码日志模型是音频管理系统中的重要组成部分,用于跟踪和记录设备分享码的生成、使用和管理过程。该系统通过记录设备MAC地址、分享码、操作类型、用户IP地址、EQ数据快照以及时间戳等关键信息,为音频设备的分享功能提供了完整的审计和追踪能力。 + +本系统采用前后端分离架构,后端基于Node.js和Express框架,前端使用Vue.js构建用户界面。数据存储采用MySQL数据库,通过Sequelize ORM进行对象关系映射。 + +## 项目结构 + +分享码日志功能涉及以下主要文件和模块: + +```mermaid +graph TB +subgraph "后端架构" +A[app.js 应用入口] --> B[routes/index.js 路由汇总] +B --> C[shareCodeLogs.js 分享码日志路由] +C --> D[ShareCodeLog.js 模型定义] +C --> E[response.js 响应处理] +C --> F[logger.js 日志配置] +D --> G[database.js 数据库配置] +end +subgraph "前端架构" +H[log.vue 视图组件] --> I[shareCodeLog.js API封装] +I --> J[请求拦截器] +end +K[MySQL数据库] <- --> G +L[浏览器] <- --> H +``` + +**图表来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) +- [ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) + +**章节来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 核心组件 + +### 数据模型设计 + +分享码日志模型采用Sequelize ORM定义,包含以下核心字段: + +| 字段名 | 类型 | 约束 | 描述 | +|--------|------|------|------| +| id | INTEGER | 主键, 自增 | 日志记录唯一标识符 | +| mac_addr | STRING(17) | 非空 | 设备MAC地址,格式如AA:BB:CC:DD:EE:FF | +| share_code | CHAR(5) | 非空 | 5位分享码 | +| action | ENUM | 非空 | 操作类型:export(导出)或import(导入) | +| ip_addr | STRING(45) | 非空, 默认空串 | 用户IP地址,支持IPv4/IPv6 | +| eq_data | JSON | 非空 | EQ数据快照,以JSON格式存储 | +| expire_at | DATE | 可空 | 分享码到期时间(仅导出时设置) | +| create_at | DATE | 非空, 默认当前时间 | 操作时间戳 | + +### 数据库索引优化 + +模型定义了三个关键索引以优化查询性能: +- `idx_mac_addr`: 基于MAC地址的索引,支持设备级别的快速检索 +- `idx_share_code`: 基于分享码的索引,支持分享码级别的快速检索 +- `idx_create_at`: 基于创建时间的索引,支持时间范围查询优化 + +**章节来源** +- [ShareCodeLog.js:4-56](file://backend/src/models/ShareCodeLog.js#L4-L56) + +## 架构概览 + +分享码日志系统的整体架构采用经典的三层架构模式: + +```mermaid +sequenceDiagram +participant Browser as 浏览器 +participant Frontend as 前端应用 +participant API as API服务器 +participant DB as MySQL数据库 +participant Logger as 日志系统 +Browser->>Frontend : 访问分享码日志页面 +Frontend->>API : GET /api/share-code/logs +API->>API : 验证用户身份 +API->>DB : 查询分享码日志数据 +DB-->>API : 返回查询结果 +API->>Logger : 记录查询日志 +API-->>Frontend : 返回JSON响应 +Frontend->>Browser : 渲染日志表格 +Note over Browser,DB : 用户可通过界面筛选和排序日志记录 +``` + +**图表来源** +- [shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) +- [log.vue:233-277](file://frontend/src/views/share-code/log.vue#L233-L277) + +## 详细组件分析 + +### 后端路由实现 + +后端路由层负责处理HTTP请求并返回标准化的响应格式: + +#### 查询参数处理 + +路由支持多种查询条件,包括: +- 设备过滤:MAC地址模糊匹配 +- 分享码过滤:分享码模糊匹配 +- 操作类型过滤:export或import精确匹配 +- IP地址过滤:IP地址模糊匹配 +- 时间范围过滤:基于create_at字段的时间区间查询 + +#### 分页和排序机制 + +系统实现了灵活的分页和排序功能: +- 分页参数:skip(偏移量)和limit(每页数量),限制最大1000条记录 +- 排序字段:支持按id和create_at排序 +- 排序方向:支持升序(asc)和降序(desc) + +#### 响应数据格式 + +所有API响应遵循统一的格式规范: +```javascript +{ + code: number, // 1成功, 2无数据, 0错误 + msg: string, // 响应消息 + data: object|null // 返回的数据或null +} +``` + +### 前端界面实现 + +前端采用Vue.js构建响应式用户界面,提供丰富的交互功能: + +#### 搜索功能 + +用户可以通过多种维度筛选日志记录: +- MAC地址输入框,支持标准MAC格式输入 +- 分享码输入框,限制最多5个字符 +- 操作类型下拉选择,提供导出/导入选项 +- IP地址输入框,支持IPv4/IPv6格式 +- 时间范围选择器,精确到秒级的时间区间 + +#### 数据展示 + +日志表格显示关键信息: +- ID:记录唯一标识 +- MAC:设备MAC地址 +- 分享码:5位分享码 +- 动作:导出或导入状态 +- IP:操作者IP地址 +- 到期时间:分享码过期时间 +- 操作时间:记录创建时间 +- EQ快照:查看详细的EQ数据 + +#### JSON数据可视化 + +系统提供专门的对话框展示EQ数据快照,支持: +- 树形结构展示JSON数据 +- 支持展开/折叠操作 +- 不同数据类型的彩色高亮显示 +- 滚动条支持大量数据浏览 + +**章节来源** +- [shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) +- [log.vue:1-353](file://frontend/src/views/share-code/log.vue#L1-L353) + +### 数据库配置和连接 + +系统使用MySQL作为数据存储,配置特点包括: +- UTF-8字符集支持,确保国际化兼容性 +- 开发环境下启用SQL日志输出,便于调试 +- 关闭自动时间戳字段,使用自定义create_at字段 +- 冻结表名,避免复数形式的表名变化 + +**章节来源** +- [database.js:1-24](file://backend/src/config/database.js#L1-L24) + +## 依赖关系分析 + +分享码日志系统的依赖关系呈现清晰的层次结构: + +```mermaid +graph TD +A[ShareCodeLog.js] --> B[database.js] +C[shareCodeLogs.js] --> A +C --> D[response.js] +C --> E[logger.js] +F[log.vue] --> G[shareCodeLog.js] +G --> H[request.js] +subgraph "外部依赖" +I[Sequelize ORM] +J[Express框架] +K[Winston日志] +L[Element Plus UI] +end +B --> I +C --> J +E --> K +F --> L +``` + +**图表来源** +- [ShareCodeLog.js:1-2](file://backend/src/models/ShareCodeLog.js#L1-L2) +- [shareCodeLogs.js:1-9](file://backend/src/routes/shareCodeLogs.js#L1-L9) + +### 外部依赖管理 + +系统对外部依赖的管理遵循以下原则: +- ORM框架:Sequelize提供数据库抽象层 +- Web框架:Express处理HTTP请求和响应 +- 日志系统:Winston提供结构化日志记录 +- 前端UI:Element Plus提供组件库支持 + +**章节来源** +- [ShareCodeLog.js:1-2](file://backend/src/models/ShareCodeLog.js#L1-L2) +- [shareCodeLogs.js:1-9](file://backend/src/routes/shareCodeLogs.js#L1-L9) + +## 性能考虑 + +### 查询优化策略 + +系统通过以下方式优化查询性能: + +1. **索引优化**:为高频查询字段建立专用索引 +2. **分页限制**:防止大数据量查询影响系统性能 +3. **条件过滤**:支持多维度精确过滤减少数据传输 +4. **时间范围优化**:利用create_at索引支持高效的时间范围查询 + +### 缓存策略 + +虽然当前实现未集成缓存层,但系统具备良好的扩展性: +- 可在路由层添加Redis缓存 +- 支持热点数据的短期缓存 +- 提供缓存失效策略 + +### 并发处理 + +系统采用异步处理模式: +- 所有数据库操作使用Promise +- 支持高并发请求处理 +- 错误处理采用统一的异常捕获机制 + +## 故障排除指南 + +### 常见问题诊断 + +#### 数据库连接问题 + +**症状**:应用启动时报数据库连接错误 +**解决方案**: +1. 检查数据库配置参数 +2. 验证数据库服务状态 +3. 确认网络连接正常 + +#### 权限认证问题 + +**症状**:访问API返回认证失败 +**解决方案**: +1. 检查用户登录状态 +2. 验证Token有效性 +3. 确认用户权限级别 + +#### 查询性能问题 + +**症状**:日志查询响应缓慢 +**解决方案**: +1. 检查数据库索引是否生效 +2. 优化查询条件组合 +3. 调整分页参数 + +### 日志分析 + +系统提供完善的日志记录机制: +- 请求级别的详细日志 +- 错误信息的结构化记录 +- 性能指标的监控日志 + +**章节来源** +- [logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [shareCodeLogs.js:62-82](file://backend/src/routes/shareCodeLogs.js#L62-L82) + +## 结论 + +分享码日志模型通过精心设计的数据结构和完整的功能实现,为音频设备分享功能提供了可靠的审计和追踪能力。系统采用现代化的技术栈,具有良好的可扩展性和维护性。 + +### 主要优势 + +1. **完整的数据追踪**:记录分享码生成、使用和管理的全过程 +2. **灵活的查询功能**:支持多维度条件筛选和排序 +3. **友好的用户界面**:提供直观的日志查看和数据分析功能 +4. **高性能设计**:通过索引优化和分页机制确保系统性能 +5. **完善的错误处理**:提供统一的错误处理和日志记录机制 + +### 发展建议 + +1. **增加分享码生命周期管理**:实现自动过期和清理机制 +2. **增强统计分析功能**:提供更丰富的数据报表和趋势分析 +3. **引入缓存机制**:提升高频查询的响应速度 +4. **扩展权限控制**:细化不同用户的访问权限 + +该系统为音频设备分享功能提供了坚实的技术基础,能够满足当前业务需求并为未来的功能扩展预留了充足的空间。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/数据库设计/品牌模型.md b/.qoder/repowiki/zh/content/数据库设计/品牌模型.md new file mode 100644 index 0000000..f7e3ef0 --- /dev/null +++ b/.qoder/repowiki/zh/content/数据库设计/品牌模型.md @@ -0,0 +1,411 @@ +# 品牌模型 + + +**本文档引用的文件** +- [Brand.js](file://backend/src/models/Brand.js) +- [brands.js](file://backend/src/routes/brands.js) +- [brand.js](file://backend/src/validators/brand.js) +- [index.vue](file://frontend/src/views/brand/index.vue) +- [brand.js](file://frontend/src/api/brand.js) +- [response.js](file://backend/src/utils/response.js) +- [auth.js](file://backend/src/middleware/auth.js) +- [index.js](file://backend/src/models/index.js) +- [Model.js](file://backend/src/models/Model.js) +- [index.js](file://backend/src/routes/index.js) +- [app.js](file://backend/src/app.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +品牌模型是音频设备管理系统中的核心实体之一,用于存储和管理耳机品牌信息。该模型采用简洁的设计理念,仅包含品牌标识符和品牌名称两个核心字段,为后续的型号管理和数据关联提供了基础支撑。 + +本系统采用前后端分离架构,后端基于Node.js和Express框架构建RESTful API,前端使用Vue.js和Element Plus实现用户界面。品牌功能通过完整的CRUD操作支持品牌信息的创建、查询、更新和删除。 + +## 项目结构 + +品牌模型在整个项目架构中位于以下层次结构中: + +```mermaid +graph TB +subgraph "前端层" +FE_API[品牌API模块] +FE_VIEW[品牌视图组件] +end +subgraph "后端层" +ROUTES[品牌路由] +VALIDATORS[品牌验证器] +MODELS[品牌模型] +UTILS[响应工具] +MIDDLEWARE[认证中间件] +end +subgraph "数据层" +DATABASE[(数据库)] +TABLE[品牌表] +end +FE_API --> FE_VIEW +FE_VIEW --> FE_API +FE_API --> ROUTES +ROUTES --> VALIDATORS +ROUTES --> MODELS +ROUTES --> UTILS +ROUTES --> MIDDLEWARE +MODELS --> DATABASE +DATABASE --> TABLE +``` + +**图表来源** +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [brand.js:1-311](file://frontend/src/views/brand/index.vue#L1-L311) + +**章节来源** +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [index.js:1-8](file://backend/src/models/index.js#L1-L8) + +## 核心组件 + +### 数据模型定义 + +品牌模型采用Sequelize ORM框架定义,具有以下核心特征: + +| 字段名 | 数据类型 | 约束条件 | 描述 | +|--------|----------|----------|------| +| id | INTEGER | 主键、自增 | 品牌唯一标识符 | +| name | STRING(100) | 非空、唯一 | 品牌名称,最大100字符 | + +### 验证规则 + +前端和后端均实现了双重验证机制: + +**前端验证规则:** +- 必填验证:品牌名称为必填项 +- 长度验证:1-100个字符限制 +- 实时反馈:输入时即时验证 + +**后端验证规则:** +- 空值检查:确保品牌名称非空 +- 唯一性检查:防止重复品牌名称 +- 长度限制:严格控制在100字符以内 + +**章节来源** +- [Brand.js:4-20](file://backend/src/models/Brand.js#L4-L20) +- [brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [index.vue:138-143](file://frontend/src/views/brand/index.vue#L138-L143) + +## 架构概览 + +品牌系统的整体架构采用分层设计模式,确保了良好的可维护性和扩展性: + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Frontend as 前端应用 +participant API as API网关 +participant Auth as 认证中间件 +participant Validator as 数据验证器 +participant Model as 品牌模型 +participant DB as 数据库 +Client->>Frontend : 用户操作请求 +Frontend->>API : 发送HTTP请求 +API->>Auth : 执行身份验证 +Auth->>Validator : 数据格式验证 +Validator->>Model : 业务逻辑处理 +Model->>DB : 数据持久化 +DB-->>Model : 返回结果 +Model-->>API : 处理完成 +API-->>Frontend : 响应数据 +Frontend-->>Client : 展示结果 +``` + +**图表来源** +- [brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) + +## 详细组件分析 + +### 品牌模型类图 + +```mermaid +classDiagram +class Brand { ++INTEGER id ++STRING name ++constructor() ++validateName() ++checkUniqueName() +} +class ApiResponse { ++success(data, msg) ++error(msg, code) ++noData(msg) +} +class BrandValidator { ++BrandCreateSchema ++BrandUpdateSchema ++validateCreate(data) ++validateUpdate(data) +} +class BrandController { ++getAllBrands(req, res) ++getBrandById(req, res) ++createBrand(req, res) ++updateBrand(req, res) ++deleteBrand(req, res) +} +Brand --> ApiResponse : 使用 +Brand --> BrandValidator : 验证 +BrandController --> Brand : 操作 +BrandController --> ApiResponse : 返回 +``` + +**图表来源** +- [Brand.js:4-20](file://backend/src/models/Brand.js#L4-L20) +- [brands.js:14-147](file://backend/src/routes/brands.js#L14-L147) +- [brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +### CRUD操作流程 + +#### 创建品牌流程 + +```mermaid +flowchart TD +Start([开始创建品牌]) --> ValidateInput["验证输入数据"] +ValidateInput --> CheckEmpty{"品牌名称是否为空"} +CheckEmpty --> |是| ReturnError["返回错误:品牌名称不能为空"] +CheckEmpty --> |否| CheckUnique["检查品牌名称唯一性"] +CheckUnique --> Exists{"品牌是否存在"} +Exists --> |是| ReturnExists["返回错误:品牌名称已存在"] +Exists --> |否| CreateBrand["创建新品牌记录"] +CreateBrand --> SaveToDB["保存到数据库"] +SaveToDB --> Success["返回成功响应"] +ReturnError --> End([结束]) +ReturnExists --> End +Success --> End +``` + +**图表来源** +- [brands.js:59-81](file://backend/src/routes/brands.js#L59-L81) + +#### 更新品牌流程 + +```mermaid +flowchart TD +Start([开始更新品牌]) --> LoadBrand["根据ID加载品牌"] +LoadBrand --> BrandExists{"品牌是否存在"} +BrandExists --> |否| ReturnNotFound["返回错误:品牌不存在"] +BrandExists --> |是| CheckName{"是否提供新名称"} +CheckName --> |否| ReturnSuccess["返回成功:无更改"] +CheckName --> |是| ValidateName["验证新名称"] +ValidateName --> NameEmpty{"新名称是否为空"} +NameEmpty --> |是| ReturnEmpty["返回错误:品牌名称不能为空"] +NameEmpty --> |否| CheckUnique["检查新名称唯一性"] +CheckUnique --> Duplicate{"新名称是否重复"} +Duplicate --> |是| ReturnDuplicate["返回错误:品牌名称已存在"] +Duplicate --> |否| UpdateBrand["更新品牌信息"] +UpdateBrand --> SaveDB["保存到数据库"] +SaveDB --> Success["返回成功响应"] +ReturnNotFound --> End([结束]) +ReturnSuccess --> End +ReturnEmpty --> End +ReturnDuplicate --> End +Success --> End +``` + +**图表来源** +- [brands.js:83-123](file://backend/src/routes/brands.js#L83-L123) + +### 前端交互组件 + +品牌管理界面采用现代化的Vue.js组件设计: + +```mermaid +graph LR +subgraph "品牌管理界面" +SearchForm[搜索表单] +DataTable[品牌表格] +Pagination[分页控件] +Dialog[编辑对话框] +end +subgraph "API调用" +GetBrands[获取品牌列表] +CreateBrand[创建品牌] +UpdateBrand[更新品牌] +DeleteBrand[删除品牌] +end +SearchForm --> GetBrands +DataTable --> GetBrands +Pagination --> GetBrands +DataTable --> Dialog +Dialog --> CreateBrand +Dialog --> UpdateBrand +DataTable --> DeleteBrand +``` + +**图表来源** +- [index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) + +**章节来源** +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) + +## 依赖关系分析 + +### 模型间关系 + +品牌模型与型号模型存在直接的关联关系: + +```mermaid +erDiagram +BRAND { +INTEGER id PK +STRING name UK +} +MODEL { +INTEGER id PK +STRING brand_name +STRING name +STRING form +STRING rig +STRING source +STRING eq_key +DATE create_at +} +BRAND ||--o{ MODEL : "包含多个" +``` + +**图表来源** +- [Brand.js:4-20](file://backend/src/models/Brand.js#L4-L20) +- [Model.js:4-53](file://backend/src/models/Model.js#L4-L53) + +### 组件依赖图 + +```mermaid +graph TB +subgraph "路由层" +BrandsRoute[品牌路由] +ModelsRoute[型号路由] +end +subgraph "验证层" +BrandValidator[品牌验证器] +ModelValidator[型号验证器] +end +subgraph "模型层" +BrandModel[品牌模型] +ModelModel[型号模型] +end +subgraph "工具层" +ApiResponse[响应工具] +AuthMiddleware[认证中间件] +end +BrandsRoute --> BrandValidator +BrandsRoute --> BrandModel +BrandsRoute --> ApiResponse +BrandsRoute --> AuthMiddleware +ModelsRoute --> ModelValidator +ModelsRoute --> ModelModel +ModelsRoute --> ApiResponse +BrandModel --> ModelModel +``` + +**图表来源** +- [brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +**章节来源** +- [index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 性能考虑 + +### 数据库优化策略 + +1. **索引设计**:品牌名称字段设置唯一索引,确保查询效率和数据完整性 +2. **查询优化**:支持模糊查询和分页功能,避免一次性加载大量数据 +3. **连接池管理**:合理配置数据库连接池大小,提高并发处理能力 + +### 缓存策略 + +虽然当前版本未实现缓存,但建议在未来版本中考虑: +- 品牌列表缓存:减少频繁查询数据库的压力 +- 品牌详情缓存:加速常用品牌的访问速度 +- 缓存失效策略:基于时间或事件的缓存更新机制 + +### 前端性能优化 + +1. **虚拟滚动**:对于大量品牌数据,考虑实现虚拟滚动提升渲染性能 +2. **懒加载**:按需加载品牌数据,减少初始页面加载时间 +3. **防抖处理**:对搜索功能实现防抖,避免频繁的API调用 + +## 故障排除指南 + +### 常见问题及解决方案 + +#### 认证失败 +**症状**:访问品牌API返回401状态码 +**原因**:缺少有效的认证令牌或令牌已过期 +**解决方法**: +1. 确认客户端已正确携带Authorization头 +2. 检查令牌格式是否为"Bearer token" +3. 验证令牌是否在有效期内 + +#### 数据验证错误 +**症状**:创建或更新品牌时返回验证错误 +**原因**:品牌名称为空或超出长度限制 +**解决方法**: +1. 确保品牌名称至少包含一个字符 +2. 检查品牌名称长度不超过100个字符 +3. 验证品牌名称是否包含特殊字符 + +#### 数据库约束冲突 +**症状**:创建品牌时提示"品牌名称已存在" +**原因**:数据库中已存在相同的品牌名称 +**解决方法**: +1. 检查现有品牌列表,确认名称唯一性 +2. 修改品牌名称或联系管理员处理重复数据 + +**章节来源** +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [brands.js:62-72](file://backend/src/routes/brands.js#L62-L72) +- [brands.js:99-112](file://backend/src/routes/brands.js#L99-L112) + +## 结论 + +品牌模型作为音频设备管理系统的基础实体,展现了现代Web应用开发的最佳实践。其简洁而强大的设计不仅满足了当前的功能需求,还为未来的扩展奠定了坚实的基础。 + +### 设计优势 + +1. **简洁性**:仅包含必要的字段,避免了过度设计 +2. **一致性**:前后端验证规则保持一致,确保数据质量 +3. **可扩展性**:清晰的架构设计便于添加新的功能特性 +4. **安全性**:完善的认证和授权机制保护系统安全 + +### 未来发展方向 + +1. **增强功能**:考虑添加品牌描述、logo图片等扩展字段 +2. **性能优化**:实现缓存机制和数据库索引优化 +3. **国际化支持**:添加多语言品牌名称支持 +4. **审计日志**:记录品牌数据的变更历史 + +该品牌模型为整个音频设备管理系统的稳定运行提供了重要支撑,其设计理念和实现方式值得在其他类似项目中借鉴和参考。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/数据库设计/型号模型.md b/.qoder/repowiki/zh/content/数据库设计/型号模型.md new file mode 100644 index 0000000..77aeb0f --- /dev/null +++ b/.qoder/repowiki/zh/content/数据库设计/型号模型.md @@ -0,0 +1,390 @@ +# 型号模型 + + +**本文档引用的文件** +- [Model.js](file://backend/src/models/Model.js) +- [Brand.js](file://backend/src/models/Brand.js) +- [model.js](file://backend/src/validators/model.js) +- [models.js](file://backend/src/routes/models.js) +- [index.js](file://backend/src/models/index.js) +- [response.js](file://backend/src/utils/response.js) +- [model.js](file://frontend/src/api/model.js) +- [index.vue](file://frontend/src/views/model/index.vue) +- [Ota.js](file://backend/src/models/Ota.js) +- [ota.js](file://backend/src/routes/ota.js) +- [otaStorage.js](file://backend/src/services/otaStorage.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文档详细介绍了型号模型(Model)的设计与实现,涵盖型号基本信息、技术规格、参数配置等字段定义,以及型号与品牌的关联关系和数据验证规则。文档还阐述了型号的完整生命周期管理(创建、更新、删除),提供了型号数据结构示例和实际应用场景,并解释了型号模型在OTA升级和固件管理中的作用。 + +## 项目结构 +型号模型位于后端的ORM层,采用Sequelize框架进行数据库映射。前端通过API接口与后端交互,实现型号的增删改查功能。 + +```mermaid +graph TB +subgraph "前端" +FE_API[前端API模块] +FE_View[型号视图组件] +end +subgraph "后端" +Routes[路由层] +Validators[验证器] +Models[模型层] +Services[服务层] +end +subgraph "数据库" +ModelTable[model表] +BrandTable[brand表] +OtaTable[ota表] +end +FE_API --> Routes +FE_View --> FE_API +Routes --> Validators +Routes --> Models +Models --> ModelTable +Models --> BrandTable +Models --> OtaTable +Services --> OtaTable +``` + +**图表来源** +- [models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +**章节来源** +- [models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +## 核心组件 +型号模型包含以下核心字段: + +### 基础信息字段 +- **id**: 自增主键,唯一标识型号 +- **brand_name**: 品牌名称,必填,最大100字符 +- **name**: 型号名称,必填,最大100字符 +- **create_at**: 创建时间,默认当前时间 + +### 技术规格字段 +- **form**: 佩戴方式,如in-ear、over-ear、earbud +- **rig**: 阻抗值,如32Ω +- **source**: 数据来源标识 + +### 高级配置字段 +- **eq_key**: EQ缓存键,用于音频均衡器配置 + +**章节来源** +- [Model.js:4-50](file://backend/src/models/Model.js#L4-L50) +- [model.js:3-19](file://backend/src/validators/model.js#L3-L19) + +## 架构概览 +型号模型采用MVC架构模式,前后端分离设计: + +```mermaid +sequenceDiagram +participant Client as 前端客户端 +participant API as API网关 +participant Route as 路由处理器 +participant Validator as 数据验证器 +participant Model as ORM模型 +participant DB as 数据库 +Client->>API : 发起HTTP请求 +API->>Route : 路由分发 +Route->>Validator : 数据验证 +Validator-->>Route : 验证结果 +Route->>Model : 数据库操作 +Model->>DB : SQL执行 +DB-->>Model : 查询结果 +Model-->>Route : 模型实例 +Route-->>API : 响应数据 +API-->>Client : 返回结果 +``` + +**图表来源** +- [models.js:134-181](file://backend/src/routes/models.js#L134-L181) +- [model.js:1-22](file://backend/src/validators/model.js#L1-L22) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) + +## 详细组件分析 + +### 数据模型设计 +型号模型采用关系型数据库设计,具有明确的数据类型和约束: + +```mermaid +erDiagram +MODEL { +int id PK +string brand_name +string name +string form +string rig +string source +string eq_key +datetime create_at +} +BRAND { +int id PK +string name UK +} +OTA { +int id PK +int verCode +string verName +string url +string md5 +smallint force +string desc +string model +int hw +smallint target +smallint beta +datetime startTime +datetime endTime +smallint status +datetime create_at +} +MODEL ||--|| BRAND : "属于" +MODEL ||--o{ OTA : "关联" +``` + +**图表来源** +- [Model.js:4-50](file://backend/src/models/Model.js#L4-L50) +- [Brand.js:4-20](file://backend/src/models/Brand.js#L4-L20) +- [Ota.js:4-94](file://backend/src/models/Ota.js#L4-L94) + +### 数据验证规则 +前端和后端都实现了严格的数据验证: + +#### 前端验证(Zod Schema) +- 品牌名称:1-100字符,必填 +- 型号名称:1-100字符,必填 +- 其他字段:最大长度限制,可选 + +#### 后端验证(Express中间件) +- 品牌唯一性检查 +- 文件格式验证(CSV/TXT/JSON) +- 字段长度和类型约束 + +**章节来源** +- [model.js:3-19](file://backend/src/validators/model.js#L3-L19) +- [models.js:307-361](file://backend/src/routes/models.js#L307-L361) + +### 生命周期管理 + +#### 创建流程 +```mermaid +flowchart TD +Start([开始创建]) --> Validate["验证输入数据"] +Validate --> CheckExist{"检查重复"} +CheckExist --> |存在| ReturnError["返回错误"] +CheckExist --> |不存在| ProcessFile["处理频响文件"] +ProcessFile --> SaveModel["保存型号记录"] +SaveModel --> ReturnSuccess["返回成功响应"] +ReturnError --> End([结束]) +ReturnSuccess --> End +``` + +**图表来源** +- [models.js:307-361](file://backend/src/routes/models.js#L307-L361) + +#### 更新流程 +```mermaid +flowchart TD +Start([开始更新]) --> LoadModel["加载现有型号"] +LoadModel --> CheckExist{"检查新组合"} +CheckExist --> |存在| ReturnError["返回错误"] +CheckExist --> |不存在| ProcessFile["处理文件更新"] +ProcessFile --> UpdateFields["更新字段"] +UpdateFields --> SaveChanges["保存更改"] +SaveChanges --> ReturnSuccess["返回成功"] +ReturnError --> End([结束]) +ReturnSuccess --> End +``` + +**图表来源** +- [models.js:364-436](file://backend/src/routes/models.js#L364-L436) + +#### 删除流程 +```mermaid +flowchart TD +Start([开始删除]) --> LoadModel["加载型号"] +LoadModel --> DeleteSearch["从搜索引擎删除"] +DeleteSearch --> DeleteRecord["删除数据库记录"] +DeleteRecord --> ReturnSuccess["返回成功"] +ReturnSuccess --> End([结束]) +``` + +**图表来源** +- [models.js:439-464](file://backend/src/routes/models.js#L439-L464) + +### 品牌关联关系 +型号与品牌采用松耦合设计: + +```mermaid +classDiagram +class Brand { ++int id ++string name +} +class Model { ++int id ++string brand_name ++string name ++string form ++string rig ++string source ++string eq_key ++datetime create_at +} +class ApiResponse { ++int code ++string msg ++any data +} +Model --> Brand : "引用品牌名称" +ApiResponse --> Model : "封装响应" +``` + +**图表来源** +- [Brand.js:4-20](file://backend/src/models/Brand.js#L4-L20) +- [Model.js:4-50](file://backend/src/models/Model.js#L4-L50) +- [response.js:1-13](file://backend/src/utils/response.js#L1-L13) + +**章节来源** +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) + +### OTA升级集成 +型号模型与OTA升级系统深度集成: + +```mermaid +sequenceDiagram +participant Model as 型号模型 +participant OTA as OTA升级 +participant Storage as 存储服务 +participant Device as 设备端 +Model->>OTA : 关联设备型号 +OTA->>Storage : 上传升级包 +Storage-->>OTA : 返回访问URL +OTA->>Device : 提供升级信息 +Device->>OTA : 检查最新版本 +OTA-->>Device : 返回升级包信息 +``` + +**图表来源** +- [Ota.js:44-48](file://backend/src/models/Ota.js#L44-L48) +- [ota.js:24-66](file://backend/src/routes/ota.js#L24-L66) +- [otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +**章节来源** +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +## 依赖分析 +型号模型的依赖关系清晰,遵循单一职责原则: + +```mermaid +graph LR +subgraph "外部依赖" +Sequelize[Sequelize ORM] +Zod[Zod验证库] +Express[Express框架] +end +subgraph "内部模块" +Model[Model模型] +Brand[Brand模型] +Validator[验证器] +Route[路由处理器] +Service[服务层] +end +Sequelize --> Model +Sequelize --> Brand +Zod --> Validator +Express --> Route +Model --> Route +Brand --> Route +Validator --> Route +Service --> Route +``` + +**图表来源** +- [index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [models.js:1-569](file://backend/src/routes/models.js#L1-L569) + +**章节来源** +- [index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [models.js:1-569](file://backend/src/routes/models.js#L1-L569) + +## 性能考虑 +- **数据库索引优化**:建议为brand_name和name字段建立复合索引 +- **查询优化**:使用分页机制限制单次查询数量 +- **缓存策略**:利用Redis缓存频繁访问的EQ配置 +- **文件存储**:频响文件采用S3存储,支持CDN加速 + +## 故障排除指南 + +### 常见问题及解决方案 +1. **型号重复创建** + - 检查品牌名称和型号名称的组合唯一性 + - 使用现有的型号记录而非重复创建 + +2. **文件上传失败** + - 验证文件格式(CSV/TXT/JSON) + - 检查文件大小限制 + - 确认S3存储权限配置 + +3. **搜索功能异常** + - 检查Meilisearch服务状态 + - 验证索引配置和同步状态 + +**章节来源** +- [models.js:312-317](file://backend/src/routes/models.js#L312-L317) +- [models.js:320-325](file://backend/src/routes/models.js#L320-L325) + +## 结论 +型号模型设计合理,功能完整,能够满足音频设备型号管理的需求。通过严格的验证机制、完善的生命周期管理和与OTA系统的深度集成,为后续的功能扩展奠定了良好的基础。建议在未来版本中进一步优化数据库查询性能,并增强错误处理和监控能力。 + +## 附录 + +### API接口规范 +- **GET /api/models/**: 获取型号列表 +- **GET /api/models/:id**: 获取单个型号详情 +- **POST /api/models/**: 创建新型号 +- **PUT /api/models/:id**: 更新型号信息 +- **DELETE /api/models/:id**: 删除型号 + +### 数据结构示例 +```javascript +// 型号对象示例 +{ + id: 1, + brand_name: "Sony", + name: "WH-1000XM4", + form: "over-ear", + rig: "300Ω", + source: "Eafonyoung", + eq_key: "sony_wh1000xm4_eq", + create_at: "2024-01-15T10:30:00Z" +} +``` + +### 实际应用场景 +- **音频设备管理**:统一管理不同品牌和型号的耳机设备 +- **OTA升级推送**:基于型号信息进行定向升级推送 +- **频响数据分析**:通过CSV文件进行音频性能分析 +- **搜索功能集成**:支持基于型号的快速检索和过滤 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/数据库设计/实体关系设计.md b/.qoder/repowiki/zh/content/数据库设计/实体关系设计.md new file mode 100644 index 0000000..c78ab39 --- /dev/null +++ b/.qoder/repowiki/zh/content/数据库设计/实体关系设计.md @@ -0,0 +1,434 @@ +# 实体关系设计 + + +**本文档引用的文件** +- [Brand.js](file://backend/src/models/Brand.js) +- [Model.js](file://backend/src/models/Model.js) +- [Ota.js](file://backend/src/models/Ota.js) +- [index.js](file://backend/src/models/index.js) +- [database.js](file://backend/src/config/database.js) +- [brands.js](file://backend/src/routes/brands.js) +- [models.js](file://backend/src/routes/models.js) +- [ota.js](file://backend/src/routes/ota.js) +- [app.js](file://backend/src/app.js) +- [index.js](file://backend/src/routes/index.js) +- [ota.js](file://backend/src/validators/ota.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +本文件详细阐述了Audio Dashboard系统中Brand(品牌)、Model(型号)、Ota(OTA升级版本)三个核心实体之间的关系设计。该系统采用MySQL数据库和Sequelize ORM框架,实现了清晰的一对一和一对多关系映射,确保数据完整性和查询效率。 + +## 项目结构 + +系统采用典型的三层架构设计,重点关注数据模型层的设计和实现: + +```mermaid +graph TB +subgraph "前端层" +FE[Vue.js 前端应用] +end +subgraph "后端层" +API[Express.js API服务] +ROUTES[路由层
brands.js, models.js, ota.js] +MODELS[模型层
Brand.js, Model.js, Ota.js] +VALIDATORS[验证器
ota.js] +end +subgraph "数据层" +DB[(MySQL数据库)] +TABLES[表结构
brand, model, ota] +end +FE --> API +API --> ROUTES +ROUTES --> MODELS +MODELS --> DB +DB --> TABLES +``` + +**图表来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +**章节来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 核心组件 + +### 数据库配置 + +系统使用Sequelize ORM进行数据库操作,配置特点如下: + +- **数据库类型**: MySQL +- **字符集**: utf8mb4 +- **时间戳**: 关闭自动时间戳管理 +- **表名冻结**: 冻结表名,不使用复数形式 +- **日志级别**: 开发环境启用SQL日志 + +**章节来源** +- [database.js:1-24](file://backend/src/config/database.js#L1-L24) + +### 实体定义 + +#### Brand实体(品牌) + +```mermaid +erDiagram +BRAND { +int id PK +varchar name UK +} +MODEL { +int id PK +varchar brand_name +varchar name +varchar form +varchar rig +varchar source +varchar eq_key +datetime create_at +} +OTA { +int id PK +int verCode +varchar verName +varchar url +varchar md5 +smallint force +varchar desc +varchar model +int hw +smallint target +smallint beta +datetime startTime +datetime endTime +smallint status +datetime create_at +} +BRAND ||--o{ MODEL : "拥有" +MODEL ||--o{ OTA : "对应" +``` + +**图表来源** +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +#### Model实体(型号) + +Model实体包含丰富的音频相关属性: +- **基础信息**: 品牌名称、型号名称、佩戴形式、阻抗 +- **来源信息**: 数据来源标识 +- **EQ缓存**: EQ键值用于缓存管理 +- **时间戳**: 创建时间记录 + +#### Ota实体(OTA升级) + +Ota实体设计用于管理设备固件升级: +- **版本控制**: 版本号(整数)、版本名称 +- **文件管理**: 下载URL、MD5校验码 +- **发布策略**: 强制升级、定向发布、灰度发布 +- **时间窗口**: 生效时间和失效时间 +- **状态管理**: 可用性状态 + +**章节来源** +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +## 架构概览 + +系统采用RESTful API设计模式,每个实体都有完整的CRUD操作: + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant API as API网关 +participant Route as 路由处理器 +participant Model as Sequelize模型 +participant DB as MySQL数据库 +Client->>API : HTTP请求 +API->>Route : 路由分发 +Route->>Model : 数据库操作 +Model->>DB : SQL执行 +DB-->>Model : 查询结果 +Model-->>Route : 数据对象 +Route-->>API : 响应数据 +API-->>Client : JSON响应 +``` + +**图表来源** +- [brands.js:14-40](file://backend/src/routes/brands.js#L14-L40) +- [models.js:133-181](file://backend/src/routes/models.js#L133-L181) +- [ota.js:107-143](file://backend/src/routes/ota.js#L107-L143) + +## 详细组件分析 + +### 关系映射策略 + +#### 当前实现状态 + +经过深入分析,发现当前代码库中**Brand与Model之间没有建立显式的Sequelize关联关系**。这种设计选择有其合理性: + +1. **简化设计**: 避免复杂的外键约束 +2. **灵活性**: 允许跨品牌的数据迁移 +3. **性能考虑**: 减少JOIN操作的开销 + +#### 推荐的关系设计 + +基于业务需求,建议实现以下关系映射: + +```mermaid +classDiagram +class Brand { ++int id ++string name ++hasMany(Model) +} +class Model { ++int id ++string brand_name ++string name ++string form ++string rig ++string source ++string eq_key ++datetime create_at ++belongsTo(Brand) ++hasMany(Ota) +} +class Ota { ++int id ++int verCode ++string verName ++string url ++string md5 ++smallint force ++string desc ++string model ++int hw ++smallint target ++smallint beta ++datetime startTime ++datetime endTime ++smallint status ++datetime create_at ++belongsTo(Model) +} +Brand --> Model : "一对多" +Model --> Ota : "一对多" +``` + +**图表来源** +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +### 关系查询最佳实践 + +#### 基础查询模式 + +```mermaid +flowchart TD +Start([查询开始]) --> CheckType{"查询类型"} +CheckType --> |单表查询| DirectQuery["直接查询表"] +CheckType --> |关联查询| BuildJoin["构建JOIN语句"] +CheckType --> |聚合查询| AggQuery["使用聚合函数"] +DirectQuery --> Limit["限制结果数量"] +BuildJoin --> SelectCols["选择必要列"] +AggQuery --> GroupBy["按条件分组"] +Limit --> Return["返回结果"] +SelectCols --> Return +GroupBy --> Return +Return --> End([查询结束]) +``` + +#### 性能优化策略 + +1. **索引设计**: 在常用查询字段上建立索引 +2. **投影优化**: 只选择需要的字段 +3. **分页处理**: 使用LIMIT和OFFSET进行分页 +4. **批量操作**: 使用批量插入和更新 + +### 数据完整性保证 + +#### 约束策略 + +虽然当前未实现外键约束,但通过以下机制保证数据完整性: + +1. **业务层验证**: 在路由层进行数据验证 +2. **唯一性约束**: 品牌名称的唯一性保证 +3. **枚举值限制**: 状态字段的取值范围控制 + +#### 级联操作 + +由于缺乏外键约束,级联操作通过业务逻辑实现: + +```mermaid +flowchart TD +DeleteBrand["删除品牌"] --> CheckModels["检查型号关联"] +CheckModels --> HasModels{"是否有型号关联?"} +HasModels --> |是| BlockDelete["阻止删除"] +HasModels --> |否| ProceedDelete["允许删除"] +BlockDelete --> LogWarn["记录警告日志"] +ProceedDelete --> CascadeOps["执行级联操作"] +CascadeOps --> UpdateOta["更新OTA关联"] +UpdateOta --> Complete["完成删除"] +``` + +**图表来源** +- [brands.js:125-144](file://backend/src/routes/brands.js#L125-L144) + +**章节来源** +- [brands.js:14-144](file://backend/src/routes/brands.js#L14-L144) +- [models.js:133-464](file://backend/src/routes/models.js#L133-L464) +- [ota.js:107-268](file://backend/src/routes/ota.js#L107-L268) + +## 依赖关系分析 + +### 模块依赖图 + +```mermaid +graph LR +subgraph "核心模块" +APP[app.js] +DB[database.js] +MODELS_INDEX[models/index.js] +end +subgraph "模型层" +BRAND[Brand.js] +MODEL[Model.js] +OTA[Ota.js] +end +subgraph "路由层" +BRAND_ROUTE[brands.js] +MODEL_ROUTE[models.js] +OTA_ROUTE[ota.js] +end +subgraph "验证层" +OTA_VALIDATOR[validators/ota.js] +end +APP --> DB +APP --> MODELS_INDEX +MODELS_INDEX --> BRAND +MODELS_INDEX --> MODEL +MODELS_INDEX --> OTA +BRAND_ROUTE --> BRAND +MODEL_ROUTE --> MODEL +OTA_ROUTE --> OTA +OTA_ROUTE --> OTA_VALIDATOR +``` + +**图表来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [brands.js:1-10](file://backend/src/routes/brands.js#L1-L10) +- [models.js:1-16](file://backend/src/routes/models.js#L1-L16) +- [ota.js:1-20](file://backend/src/routes/ota.js#L1-L20) + +### 外部依赖 + +系统依赖的关键外部库: + +- **Sequelize**: ORM框架,提供数据库抽象层 +- **Express.js**: Web框架,处理HTTP请求 +- **Multer**: 文件上传中间件 +- **Zod**: 数据验证库 +- **Axios**: HTTP客户端 + +**章节来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [models.js:1-16](file://backend/src/routes/models.js#L1-L16) +- [ota.js:1-20](file://backend/src/routes/ota.js#L1-L20) + +## 性能考虑 + +### 查询优化策略 + +#### 索引设计建议 + +1. **主键索引**: 自动为所有表的主键创建索引 +2. **唯一索引**: 为品牌名称创建唯一索引 +3. **复合索引**: 为常用查询组合创建复合索引 +4. **全文索引**: 为搜索功能考虑全文索引 + +#### 分页查询优化 + +```mermaid +flowchart TD +QueryStart["查询开始"] --> CountTotal["统计总数"] +CountTotal --> CheckPage["检查页码范围"] +CheckPage --> ValidPage{"页码有效?"} +ValidPage --> |否| Error["返回错误"] +ValidPage --> |是| CalcOffset["计算偏移量"] +CalcOffset --> ApplyLimit["应用LIMIT"] +ApplyLimit --> ExecuteQuery["执行查询"] +ExecuteQuery --> ReturnResults["返回结果"] +Error --> End["结束"] +ReturnResults --> End +``` + +#### 批量操作优化 + +1. **批量插入**: 使用批量插入减少数据库往返 +2. **事务处理**: 对复杂操作使用事务保证一致性 +3. **连接池**: 合理配置数据库连接池大小 + +## 故障排除指南 + +### 常见问题及解决方案 + +#### 数据库连接问题 + +**症状**: 应用启动时数据库连接失败 +**原因**: 环境变量配置错误或数据库服务不可用 +**解决方案**: +1. 检查DATABASE_HOST、DATABASE_PORT、DATABASE_NAME等环境变量 +2. 确认MySQL服务正在运行 +3. 验证用户名和密码正确性 + +#### 数据验证错误 + +**症状**: API请求返回验证错误 +**原因**: 请求数据不符合验证规则 +**解决方案**: +1. 检查请求数据格式 +2. 确认必填字段完整 +3. 验证数据类型和长度限制 + +#### 查询性能问题 + +**症状**: 查询响应时间过长 +**原因**: 缺少适当的索引或查询条件不当 +**解决方案**: +1. 分析慢查询日志 +2. 添加必要的索引 +3. 优化查询条件 +4. 实施分页策略 + +**章节来源** +- [brands.js:36-39](file://backend/src/routes/brands.js#L36-L39) +- [models.js:177-180](file://backend/src/routes/models.js#L177-L180) +- [ota.js:139-142](file://backend/src/routes/ota.js#L139-L142) + +## 结论 + +本实体关系设计文档详细阐述了Brand、Model、Ota三个核心实体的设计理念和实现方案。当前系统采用简化的无外键设计,在灵活性和性能之间取得了平衡。建议在未来版本中: + +1. **实现显式关联**: 添加Sequelize关联定义 +2. **完善约束**: 建立外键约束确保数据完整性 +3. **优化查询**: 实现更高效的关联查询 +4. **增强监控**: 添加数据库性能监控 + +通过这些改进,可以在保持系统灵活性的同时,进一步提升数据一致性和查询性能。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/数据库设计/数据库设计.md b/.qoder/repowiki/zh/content/数据库设计/数据库设计.md new file mode 100644 index 0000000..4308aa4 --- /dev/null +++ b/.qoder/repowiki/zh/content/数据库设计/数据库设计.md @@ -0,0 +1,505 @@ +# 数据库设计 + + +**本文引用的文件** +- [backend/src/models/Brand.js](file://backend/src/models/Brand.js) +- [backend/src/models/Model.js](file://backend/src/models/Model.js) +- [backend/src/models/Ota.js](file://backend/src/models/Ota.js) +- [backend/src/models/DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [backend/src/models/ShareCodeLog.js](file://backend/src/models/ShareCodeLog.js) +- [backend/src/models/index.js](file://backend/src/models/index.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/validators/brand.js](file://backend/src/validators/brand.js) +- [backend/src/validators/model.js](file://backend/src/validators/model.js) +- [backend/src/validators/ota.js](file://backend/src/validators/ota.js) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [backend/src/services/otaStorage.js](file://backend/src/services/otaStorage.js) +- [backend/src/routes/brands.js](file://backend/src/routes/brands.js) +- [backend/src/routes/models.js](file://backend/src/routes/models.js) +- [backend/src/routes/ota.js](file://backend/src/routes/ota.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件系统性梳理后端数据库模型与相关数据访问模式,覆盖实体关系、字段定义、数据类型、主键/外键、索引与约束、数据验证与业务规则,并给出数据库模式图、示例数据、缓存策略、性能优化建议、数据生命周期与归档策略、迁移与版本管理思路,以及数据安全与访问控制要点。重点实体包括 Brand、Model、Ota、DashboardUser、ShareCodeLog。 + +## 项目结构 +- 数据模型采用 Sequelize ORM 定义,位于 backend/src/models,统一通过 backend/src/models/index.js 暴露。 +- 数据库连接在 backend/src/config/database.js 中配置,使用 MySQL,关闭默认时间戳与表名冻结,便于与现有表结构对齐。 +- 校验层使用 Zod 在 backend/src/validators 下定义,确保入参合法性。 +- 业务访问通过 Express 路由在 backend/src/routes 下实现,结合服务层完成复杂流程(如 OTA 包上传、S3 存储、Redis 缓存读取等)。 + +```mermaid +graph TB +subgraph "模型层" +M_Brand["Brand
品牌"] +M_Model["Model
型号"] +M_Ota["Ota
OTA 版本"] +M_User["DashboardUser
后台用户"] +M_Share["ShareCodeLog
分享码日志"] +end +subgraph "配置与入口" +C_DB["database.js
MySQL 连接"] +I_Index["models/index.js
模型导出"] +end +subgraph "校验层" +V_Brand["validators/brand.js"] +V_Model["validators/model.js"] +V_Ota["validators/ota.js"] +end +subgraph "服务层" +S_Eq["eqCacheStorage.js
Redis EQ 缓存"] +S_Ota["otaStorage.js
OTA 存储(S3/本地)"] +end +subgraph "路由层" +R_Brand["routes/brands.js"] +R_Model["routes/models.js"] +R_Ota["routes/ota.js"] +end +C_DB --> M_Brand +C_DB --> M_Model +C_DB --> M_Ota +C_DB --> M_User +C_DB --> M_Share +I_Index --> M_Brand +I_Index --> M_Model +I_Index --> M_Ota +I_Index --> M_User +I_Index --> M_Share +V_Brand --> R_Brand +V_Model --> R_Model +V_Ota --> R_Ota +R_Model --> S_Eq +R_Ota --> S_Ota +``` + +图表来源 +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/models/ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [backend/src/validators/model.js:1-22](file://backend/src/validators/model.js#L1-L22) +- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [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/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) + +## 核心组件 +本节聚焦五个核心实体的字段、类型、约束与业务含义。 + +- 品牌 Brand + - 字段与类型:id(INTEGER, 主键, 自增)、name(STRING(100), 唯一, 非空) + - 约束:唯一索引(name) + - 业务规则:品牌名称唯一;用于型号归属 + - 参考路径:[Brand 模型定义:1-23](file://backend/src/models/Brand.js#L1-L23) + +- 型号 Model + - 字段与类型:id(INTEGER, 主键, 自增)、brand_name(STRING(100), 非空)、name(STRING(100), 非空)、form(STRING(100))、rig(STRING(100))、source(STRING(100))、eq_key(STRING(255))、create_at(DATE, 默认 NOW) + - 约束:无显式外键;但业务上以 brand_name 关联品牌 + - 业务规则:同一品牌下型号名称唯一;create_at 默认当前时间 + - 参考路径:[Model 模型定义:1-53](file://backend/src/models/Model.js#L1-L53) + +- OTA 版本 Ota + - 字段与类型:id(INTEGER, 主键, 自增)、verCode(INTEGER, 非空)、verName(STRING(20), 非空)、url(STRING(255), 非空)、md5(STRING(32), 非空)、force(SMALLINT, 默认0)、desc(STRING(255))、model(STRING(100))、hw(INTEGER, 默认0)、target(SMALLINT, 默认0)、beta(SMALLINT, 默认0)、startTime/endTime(DATE)、status(SMALLINT, 默认1)、create_at(DATE, 默认 NOW) + - 约束:verCode+model 组合唯一(业务逻辑保证) + - 业务规则:verCode 必须大于当前设备版本才视为可用升级;target/beta 控制定向/灰度;status=1 表示可用 + - 参考路径:[Ota 模型定义:1-97](file://backend/src/models/Ota.js#L1-L97) + +- 后台用户 DashboardUser + - 字段与类型:id(INTEGER, 主键, 自增)、username(STRING(64), 唯一, 非空)、password_hash(STRING(255), 非空)、is_super_admin(TINYINT, 默认0)、status(TINYINT, 默认1)、last_login_at(DATE)、create_at/update_at(DATE, 默认 NOW) + - 约束:username 唯一 + - 业务规则:is_super_admin=1 表示超级管理员;status=1 启用 + - 参考路径:[DashboardUser 模型定义:1-58](file://backend/src/models/DashboardUser.js#L1-L58) + +- 分享码日志 ShareCodeLog + - 字段与类型:id(INTEGER, 主键, 自增)、mac_addr(STRING(17), 非空)、share_code(CHAR(5), 非空)、action(ENUM('export','import'), 非空)、ip_addr(STRING(45), 默认'')、eq_data(JSON, 非空)、expire_at(DATE)、create_at(DATE, 默认 NOW) + - 索引:idx_mac_addr、idx_share_code、idx_create_at + - 业务规则:记录导出/导入分享码的操作明细;expire_at 与导出快照关联 + - 参考路径:[ShareCodeLog 模型定义:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) + +章节来源 +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/models/ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) + +## 架构总览 +数据库层采用 MySQL,ORM 层为 Sequelize。路由层负责请求接入与参数校验,服务层封装外部存储(S3、本地文件系统、Redis)与业务逻辑。核心实体间的关系如下: + +```mermaid +erDiagram +BRAND { +int id PK +varchar name UK +} +MODEL { +int id PK +varchar brand_name +varchar name +varchar form +varchar rig +varchar source +varchar eq_key +datetime create_at +} +OTA { +int id PK +int verCode +varchar verName +varchar url +char md5 +smallint force +varchar desc +varchar model +int hw +smallint target +smallint beta +datetime startTime +datetime endTime +smallint status +datetime create_at +} +DASHBOARD_USER { +int id PK +varchar username UK +varchar password_hash +tinyint is_super_admin +tinyint status +datetime last_login_at +datetime create_at +datetime update_at +} +SHARE_CODE_LOG { +int id PK +varchar mac_addr +char share_code +enum action +varchar ip_addr +json eq_data +datetime expire_at +datetime create_at +} +MODEL }o--|| BRAND : "brand_name 关联" +OTA ||--o{ OTA : "同 model 的多版本" +DASHBOARD_USER ||--o{ SHARE_CODE_LOG : "操作记录" +``` + +图表来源 +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/models/ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) + +## 详细组件分析 + +### 品牌 Brand +- 设计理念:最小化品牌实体,仅保留 id 与 name,确保品牌唯一性,降低跨表关联复杂度。 +- 关系映射:被 Model 以 brand_name 文本字段引用,业务上保持一致性。 +- 索引与约束:name 唯一;无外键约束(文本引用)。 +- 参考路径:[Brand 模型定义:1-23](file://backend/src/models/Brand.js#L1-L23) + +章节来源 +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +### 型号 Model +- 设计理念:集中存储型号元信息与 EQ 快照键,便于搜索与展示;频响文件通过外部存储(S3/本地)管理。 +- 关系映射:与 Brand 通过 brand_name 文本关联;与 EQ 缓存通过 eq_key 或 Redis key 约定关联。 +- 索引与约束:无外键;同一品牌内型号名称唯一(业务约束)。 +- 数据访问模式: + - 列表/详情:路由层提供分页、排序、过滤与详情查询。 + - EQ 缓存:通过服务层读取 Redis Hash 字段列表与具体值。 + - 测量文件:仅允许特定来源与佩戴方式,且通过 S3 获取 CSV 内容。 +- 参考路径: + - [Model 模型定义:1-53](file://backend/src/models/Model.js#L1-L53) + - [models 路由:133-569](file://backend/src/routes/models.js#L133-L569) + - [eqCacheStorage 服务:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Route as "models 路由" +participant Model as "Model 模型" +participant EqSvc as "eqCacheStorage 服务" +participant Redis as "Redis" +Client->>Route : "GET /api/models/ : model_id/eq-cache" +Route->>Model : "findByPk(modelId)" +Model-->>Route : "型号对象" +Route->>EqSvc : "getEqCacheKeys(brand_name, name)" +EqSvc->>Redis : "hkeys(redisKey)" +Redis-->>EqSvc : "field_keys" +EqSvc-->>Route : "{redis_key, field_keys}" +Route-->>Client : "返回字段列表" +``` + +图表来源 +- [backend/src/routes/models.js:183-201](file://backend/src/routes/models.js#L183-L201) +- [backend/src/services/eqCacheStorage.js:24-42](file://backend/src/services/eqCacheStorage.js#L24-L42) + +章节来源 +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/routes/models.js:133-569](file://backend/src/routes/models.js#L133-L569) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +### OTA 版本 Ota +- 设计理念:以 verCode 为主键语义(实际仍由数据库自增 id 保证唯一),verCode+model 组合唯一,确保按版本与设备维度的幂等管理。 +- 关系映射:无外键;通过 model 字段标识目标设备型号。 +- 数据访问模式: + - 上传升级包:根据设备型号选择 S3 或本地存储,计算 MD5 并生成下载地址。 + - 查询最新可用版本:按 currentVerCode、model、hw 过滤,取最大 verCode。 +- 参考路径: + - [Ota 模型定义:1-97](file://backend/src/models/Ota.js#L1-L97) + - [ota 路由:1-292](file://backend/src/routes/ota.js#L1-L292) + - [otaStorage 服务:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +```mermaid +sequenceDiagram +participant Device as "设备端" +participant Route as "ota 路由" +participant Ota as "Ota 模型" +participant Store as "otaStorage 服务" +Device->>Route : "GET /api/ota/latest/check?currentVerCode&model&hw" +Route->>Ota : "findOne({status=1, verCode>current, model, hw})" +Ota-->>Route : "最新 OTA 记录" +Route-->>Device : "返回升级信息" +``` + +图表来源 +- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +章节来源 +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +### 后台用户 DashboardUser +- 设计理念:集中管理后台账号,支持超级管理员与启用/禁用状态,记录最近登录时间。 +- 访问控制:所有品牌/型号/OTA 接口均需登录中间件保护。 +- 参考路径: + - [DashboardUser 模型定义:1-58](file://backend/src/models/DashboardUser.js#L1-L58) + - [brands 路由:11-147](file://backend/src/routes/brands.js#L11-L147) + - [models 路由:70-569](file://backend/src/routes/models.js#L70-L569) + - [ota 路由:21-292](file://backend/src/routes/ota.js#L21-L292) + +章节来源 +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/routes/brands.js:11-147](file://backend/src/routes/brands.js#L11-L147) +- [backend/src/routes/models.js:70-569](file://backend/src/routes/models.js#L70-L569) +- [backend/src/routes/ota.js:21-292](file://backend/src/routes/ota.js#L21-L292) + +### 分享码日志 ShareCodeLog +- 设计理念:记录分享码导出/导入行为,包含 MAC、分享码、操作类型、IP、EQ 快照与过期时间。 +- 索引策略:针对高频查询字段建立索引,提升筛选效率。 +- 参考路径: + - [ShareCodeLog 模型定义:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) + +章节来源 +- [backend/src/models/ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) + +## 依赖分析 +- 模型依赖:各模型通过 Sequelize 连接 MySQL;models/index.js 统一导出,供路由层引用。 +- 校验依赖:路由层在写入操作前使用 Zod Schema 校验请求体,减少脏数据进入数据库。 +- 服务依赖:路由层调用服务层完成外部存储与缓存交互,解耦业务逻辑与基础设施。 +- 外部依赖:S3 SDK、Redis 客户端、Meilisearch HTTP 客户端。 + +```mermaid +graph LR +R_B["brands.js"] --> M_B["Brand.js"] +R_M["models.js"] --> M_M["Model.js"] +R_O["ota.js"] --> M_O["Ota.js"] +R_M --> S_Eq["eqCacheStorage.js"] +R_O --> S_Ota["otaStorage.js"] +V_B["validators/brand.js"] --> R_B +V_Mod["validators/model.js"] --> R_M +V_O["validators/ota.js"] --> R_O +``` + +图表来源 +- [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/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [backend/src/validators/model.js:1-22](file://backend/src/validators/model.js#L1-L22) +- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +章节来源 +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) + +## 性能考量 +- 查询性能 + - Model 列表:支持按 brand_name/name 过滤与按 id/create_at 排序,建议在相应列建立索引以优化分页查询。 + - ShareCodeLog:已建立 idx_mac_addr、idx_share_code、idx_create_at,满足常见筛选场景。 +- 缓存策略 + - EQ 缓存:使用 Redis Hash 存储型号 EQ 数据,提供字段列表与单字段读取接口,避免一次性传输大体积 JSON。 + - OTA 包:X8 使用 S3,X9 使用本地目录,结合 MD5 前缀组织目录,便于快速定位与去重。 +- IO 与网络 + - 测量文件与 OTA 包上传/下载涉及大量 IO 与网络,建议: + - 限制上传文件大小与格式; + - 使用内存存储配合流式处理; + - 对热点数据进行本地缓存或 CDN 加速。 +- 时间字段 + - create_at/update_at 默认使用数据库时间,注意时区与同步问题。 + +章节来源 +- [backend/src/models/ShareCodeLog.js:51-56](file://backend/src/models/ShareCodeLog.js#L51-L56) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [backend/src/routes/models.js:133-181](file://backend/src/routes/models.js#L133-L181) +- [backend/src/routes/ota.js:107-143](file://backend/src/routes/ota.js#L107-L143) + +## 故障排查指南 +- 品牌/型号重复 + - 现象:创建/更新时报“已存在”。 + - 排查:确认品牌名称或型号组合是否已在数据库中存在。 + - 参考路径: + - [brands 路由重复校验:68-72](file://backend/src/routes/brands.js#L68-L72) + - [models 路由重复校验:313-317](file://backend/src/routes/models.js#L313-L317) +- OTA 版本冲突 + - 现象:创建/更新时报“该版本已存在”。 + - 排查:verCode+model 组合唯一,检查是否已有相同版本。 + - 参考路径: + - [ota 路由重复校验:175-181](file://backend/src/routes/ota.js#L175-L181) + - [ota 路由更新冲突检查:221-228](file://backend/src/routes/ota.js#L221-L228) +- Redis 缓存异常 + - 现象:读取 EQ 缓存报错或字段不存在。 + - 排查:确认 Redis 连接、key 是否存在、字段是否正确。 + - 参考路径: + - [eqCacheStorage 异常处理:38-66](file://backend/src/services/eqCacheStorage.js#L38-L66) +- S3 上传失败 + - 现象:OTA 包上传到 S3 失败。 + - 排查:检查 AWS 凭证、Bucket 权限、区域设置。 + - 参考路径: + - [otaStorage S3 上传:72-103](file://backend/src/services/otaStorage.js#L72-L103) +- 登录态缺失 + - 现象:访问受保护接口返回错误。 + - 排查:确认鉴权中间件是否生效、Token 是否有效。 + - 参考路径: + - [brands/ota/models 路由中间件:12-12](file://backend/src/routes/brands.js#L12-L12) + - [backend/src/routes/ota.js#L105-L105:105-105](file://backend/src/routes/ota.js#L105-L105) + - [backend/src/routes/models.js:71-71](file://backend/src/routes/models.js#L71-L71) + +章节来源 +- [backend/src/routes/brands.js:68-72](file://backend/src/routes/brands.js#L68-L72) +- [backend/src/routes/models.js:313-317](file://backend/src/routes/models.js#L313-L317) +- [backend/src/routes/ota.js:175-181](file://backend/src/routes/ota.js#L175-L181) +- [backend/src/routes/ota.js:221-228](file://backend/src/routes/ota.js#L221-L228) +- [backend/src/services/eqCacheStorage.js:38-66](file://backend/src/services/eqCacheStorage.js#L38-L66) +- [backend/src/services/otaStorage.js:95-98](file://backend/src/services/otaStorage.js#L95-L98) +- [backend/src/routes/brands.js:12-12](file://backend/src/routes/brands.js#L12-L12) +- [backend/src/routes/ota.js:105-105](file://backend/src/routes/ota.js#L105-L105) +- [backend/src/routes/models.js:71-71](file://backend/src/routes/models.js#L71-L71) + +## 结论 +本数据库设计以简洁的实体与清晰的业务边界为核心,通过校验层与服务层实现输入约束与外部集成解耦。Model 与 Brand 通过文本字段关联,Ota 以 verCode+model 组合唯一,ShareCodeLog 提供完整审计轨迹。建议后续完善外键约束、补充索引与分区策略,并制定数据生命周期与归档规范。 + +## 附录 + +### 数据验证与业务规则摘要 +- 品牌 + - 名称必填且唯一 + - 参考路径:[品牌校验:1-12](file://backend/src/validators/brand.js#L1-L12) +- 型号 + - 品牌名、型号名必填;同一品牌下型号名唯一 + - 参考路径:[型号校验:1-22](file://backend/src/validators/model.js#L1-L22) +- OTA + - verCode 整数;verName、url、md5 长度限制;force/target/beta/status 0/1 限定 + - 参考路径:[OTA 校验:1-36](file://backend/src/validators/ota.js#L1-L36) + +章节来源 +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [backend/src/validators/model.js:1-22](file://backend/src/validators/model.js#L1-L22) +- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) + +### 示例数据 +- 品牌 Brand + - id: 1, name: "Luxsin" +- 型号 Model + - id: 1, brand_name: "Luxsin", name: "X8", form: "in-ear", rig: "32Ω", source: "Eafonyoung", eq_key: "luxsin_x8_eq", create_at: "2025-01-01 12:00:00" +- OTA 版本 Ota + - id: 1, verCode: 101, verName: "v1.0.1", url: "http://.../LUXSIN_X8.PKG", md5: "d41d8cd98f00b204e9800998ecf8427e", force: 1, model: "Luxsin-X8", hw: 1, target: 0, beta: 0, status: 1, create_at: "2025-01-01 12:00:00" +- 后台用户 DashboardUser + - id: 1, username: "admin", password_hash: "$2b$...", is_super_admin: 1, status: 1, create_at: "2025-01-01 12:00:00", update_at: "2025-01-01 12:00:00" +- 分享码日志 ShareCodeLog + - id: 1, mac_addr: "AA:BB:CC:DD:EE:FF", share_code: "ABCDE", action: "export", ip_addr: "::ffff:127.0.0.1", eq_data: "{}", create_at: "2025-01-01 12:00:00" + +### 数据访问模式与缓存策略 +- Model + - 列表/详情:分页、过滤、排序 + - EQ 缓存:字段列表与单字段读取 + - 参考路径:[models 路由:133-569](file://backend/src/routes/models.js#L133-L569), [eqCacheStorage:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- OTA + - 上传包:S3 或本地存储,返回下载地址 + - 最新版本查询:按 verCode 与 hw 过滤 + - 参考路径:[ota 路由:24-102](file://backend/src/routes/ota.js#L24-L102), [otaStorage:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +章节来源 +- [backend/src/routes/models.js:133-569](file://backend/src/routes/models.js#L133-L569) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/routes/ota.js:24-102](file://backend/src/routes/ota.js#L24-L102) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +### 数据生命周期、保留策略与归档规则 +- 建议 + - ShareCodeLog:按月清理历史日志,保留必要审计周期(如 90 天)。 + - OTA:旧版本保留 3-6 个月或按产品策略归档;S3/本地定期清理过期包。 + - Model:测量文件与 EQ 缓存按访问频率与容量阈值进行轮转。 +- 实施要点 + - 为 ShareCodeLog 增加 expire_at 字段与自动清理任务。 + - 为 OTA 增加归档标记与版本保留策略。 + - 对 S3/本地存储建立配额与过期清理机制。 + +[本节为通用建议,不直接分析具体文件] + +### 数据迁移路径与版本管理 +- 建议 + - 使用数据库迁移工具(如 Sequelize CLI)管理结构变更。 + - 新增字段采用非空默认值或分阶段上线,避免影响在线服务。 + - 对于索引与约束,先添加再回填数据,最后替换为严格约束。 +- 参考路径 + - [database.js 定义:1-24](file://backend/src/config/database.js#L1-L24) + +章节来源 +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) + +### 数据安全、隐私与访问控制 +- 访问控制 + - 所有受保护接口均需登录中间件;超级管理员具备更高权限。 + - 参考路径:[brands/ota/models 路由中间件:12-12](file://backend/src/routes/brands.js#L12-L12), [backend/src/routes/ota.js#L105-L105:105-105](file://backend/src/routes/ota.js#L105-L105), [backend/src/routes/models.js:71-71](file://backend/src/routes/models.js#L71-L71) +- 数据脱敏 + - 日志中避免输出敏感字段(如密码哈希);对外接口仅返回必要字段。 +- 合规 + - 对用户数据与操作日志遵循最小化原则,遵守隐私政策与数据保留期限。 + +章节来源 +- [backend/src/routes/brands.js:12-12](file://backend/src/routes/brands.js#L12-L12) +- [backend/src/routes/ota.js:105-105](file://backend/src/routes/ota.js#L105-L105) +- [backend/src/routes/models.js:71-71](file://backend/src/routes/models.js#L71-L71) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/数据库设计/用户模型.md b/.qoder/repowiki/zh/content/数据库设计/用户模型.md new file mode 100644 index 0000000..ce585c7 --- /dev/null +++ b/.qoder/repowiki/zh/content/数据库设计/用户模型.md @@ -0,0 +1,369 @@ +# 用户模型 + + +**本文档引用的文件** +- [DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [auth.js](file://backend/src/middleware/auth.js) +- [password.js](file://backend/src/utils/password.js) +- [jwt.js](file://backend/src/utils/jwt.js) +- [users.js](file://backend/src/routes/users.js) +- [auth.js](file://backend/src/routes/auth.js) +- [response.js](file://backend/src/utils/response.js) +- [index.js](file://backend/src/models/index.js) +- [userBootstrap.js](file://backend/src/services/userBootstrap.js) +- [auth.js](file://frontend/src/utils/auth.js) +- [auth.js](file://frontend/src/api/auth.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +DashboardUser 模型是本系统用户身份管理的核心数据结构,负责存储和管理后台系统的用户账户信息。该模型实现了完整的用户认证和授权机制,包括密码加密、JWT 令牌管理、会话控制以及基于角色的权限管理。 + +系统采用基于角色的访问控制(RBAC)模型,支持超级管理员和普通用户的权限区分,确保了系统的安全性和可维护性。 + +## 项目结构 + +用户管理系统在前后端分离架构中分布如下: + +```mermaid +graph TB +subgraph "后端架构" +A[DashboardUser 模型] --> B[认证中间件] +B --> C[用户管理路由] +B --> D[认证路由] +E[密码工具] --> A +F[JWT 工具] --> B +G[响应格式化] --> C +G --> D +end +subgraph "前端架构" +H[认证工具] --> I[请求封装] +I --> J[登录接口] +K[用户信息存储] --> H +end +subgraph "数据库层" +L[(MySQL 数据库)] +M[dashboard_user 表] +end +A --> L +L --> M +``` + +**图表来源** +- [DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [users.js:1-180](file://backend/src/routes/users.js#L1-L180) + +**章节来源** +- [DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [users.js:1-180](file://backend/src/routes/users.js#L1-L180) + +## 核心组件 + +### DashboardUser 模型定义 + +DashboardUser 模型使用 Sequelize ORM 定义,包含以下核心字段: + +| 字段名 | 类型 | 约束 | 描述 | +|--------|------|------|------| +| id | INTEGER | 主键, 自增 | 用户唯一标识符 | +| username | STRING(64) | 非空, 唯一 | 登录用户名 | +| password_hash | STRING(255) | 非空 | 密码哈希值 | +| is_super_admin | TINYINT | 非空, 默认0 | 是否为超级管理员 | +| status | TINYINT | 非空, 默认1 | 用户状态(1=启用, 0=禁用) | +| last_login_at | DATE | 可空 | 最近登录时间 | +| create_at | DATE | 非空, 默认当前时间 | 创建时间 | +| update_at | DATE | 非空, 默认当前时间 | 更新时间 | + +**章节来源** +- [DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54) + +### 权限管理机制 + +系统实现了两级权限控制: +- **超级管理员权限**:拥有系统所有功能的操作权限 +- **普通用户权限**:仅能进行基本的用户操作 + +权限验证通过中间件实现,确保只有具备相应权限的用户才能访问特定资源。 + +**章节来源** +- [auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) +- [users.js:12-13](file://backend/src/routes/users.js#L12-L13) + +## 架构概览 + +用户认证和授权系统采用分层架构设计,确保了安全性、可扩展性和易维护性: + +```mermaid +sequenceDiagram +participant Client as 客户端应用 +participant AuthRoute as 认证路由 +participant UserModel as 用户模型 +participant PasswordUtil as 密码工具 +participant JWTUtil as JWT工具 +participant UserRoute as 用户管理路由 +Client->>AuthRoute : POST /api/auth/login +AuthRoute->>UserModel : 查询用户信息 +UserModel-->>AuthRoute : 返回用户记录 +AuthRoute->>PasswordUtil : 验证密码 +PasswordUtil-->>AuthRoute : 返回验证结果 +AuthRoute->>UserModel : 更新最后登录时间 +AuthRoute->>JWTUtil : 创建访问令牌 +JWTUtil-->>AuthRoute : 返回JWT令牌 +AuthRoute-->>Client : 返回认证响应 +Client->>UserRoute : 访问受保护资源 +UserRoute->>JWTUtil : 解析JWT令牌 +JWTUtil-->>UserRoute : 返回用户信息 +UserRoute->>UserRoute : 验证权限级别 +UserRoute-->>Client : 返回资源数据 +``` + +**图表来源** +- [auth.js:24-64](file://backend/src/routes/auth.js#L24-L64) +- [auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [jwt.js:7-21](file://backend/src/utils/jwt.js#L7-L21) + +## 详细组件分析 + +### 密码加密与验证 + +系统采用 PBKDF2 算法进行密码加密,确保密码存储的安全性: + +```mermaid +flowchart TD +Start([开始密码处理]) --> Hash["生成随机盐值
PBKDF2 加密"] +Hash --> Store["存储格式:
pbkdf2:算法:迭代次数:盐值:哈希值"] +Store --> Verify["验证流程:
解析存储格式
提取参数
重新计算哈希值
安全比较"] +Verify --> Result{"验证结果"} +Result --> |匹配| Success["验证通过"] +Result --> |不匹配| Fail["验证失败"] +Success --> End([结束]) +Fail --> End +``` + +**图表来源** +- [password.js:10-34](file://backend/src/utils/password.js#L10-L34) + +密码加密特性: +- 使用 PBKDF2 算法,迭代次数为 310000 +- 随机生成 16 字节盐值 +- 输出十六进制格式的哈希值 +- 采用定时安全比较防止时序攻击 + +**章节来源** +- [password.js:1-37](file://backend/src/utils/password.js#L1-L37) + +### JWT 令牌管理 + +系统使用 JSON Web Token 进行无状态认证,令牌包含必要的用户信息: + +```mermaid +classDiagram +class AccessToken { ++sub : number ++username : string ++is_super_admin : boolean ++iat : number ++exp : number ++createAccessToken(user) : string ++decodeToken(token) : object ++getTokenTtlSeconds() : number +} +class User { ++id : number ++username : string ++is_super_admin : boolean ++status : number +} +class AuthMiddleware { ++authMiddleware(req, res, next) ++requireSuperAdmin(req, res, next) +} +AccessToken --> User : "包含用户信息" +AuthMiddleware --> AccessToken : "验证令牌" +AuthMiddleware --> User : "设置用户上下文" +``` + +**图表来源** +- [jwt.js:7-21](file://backend/src/utils/jwt.js#L7-L21) +- [auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) + +JWT 令牌配置: +- 算法:HS256 +- 有效期:12 小时 +- 包含字段:用户ID、用户名、是否超级管理员、签发时间、过期时间 + +**章节来源** +- [jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +### 用户管理操作流程 + +系统提供了完整的用户生命周期管理: + +```mermaid +flowchart TD +subgraph "用户管理流程" +A[创建用户] --> B[输入验证] +B --> C{用户名唯一性检查} +C --> |已存在| D[返回错误] +C --> |不存在| E[密码加密] +E --> F[创建用户记录] +F --> G[记录创建日志] +H[更新用户] --> I[权限验证] +I --> J[状态变更检查] +J --> K{超级管理员数量检查} +K --> |最后一个超级管理员| L[阻止操作] +K --> |正常| M[更新用户信息] +N[删除用户] --> O[权限验证] +O --> P{目标用户检查} +P --> |自己| Q[阻止删除] +P --> |其他用户| R{超级管理员检查} +R --> |最后一个超级管理员| S[阻止删除] +R --> |正常| T[删除用户] +end +``` + +**图表来源** +- [users.js:63-98](file://backend/src/routes/users.js#L63-L98) +- [users.js:100-147](file://backend/src/routes/users.js#L100-L147) +- [users.js:149-177](file://backend/src/routes/users.js#L149-L177) + +**章节来源** +- [users.js:1-180](file://backend/src/routes/users.js#L1-L180) + +### 前端认证集成 + +前端使用本地存储管理认证状态,实现了完整的用户会话管理: + +```mermaid +sequenceDiagram +participant UI as 用户界面 +participant AuthUtil as 认证工具 +participant LocalStorage as 本地存储 +participant API as 后端API +UI->>AuthUtil : 登录操作 +AuthUtil->>API : 发送登录请求 +API-->>AuthUtil : 返回JWT令牌 +AuthUtil->>LocalStorage : 存储令牌 +AuthUtil->>LocalStorage : 存储用户信息 +UI->>AuthUtil : 获取用户信息 +AuthUtil->>LocalStorage : 读取令牌 +AuthUtil->>AuthUtil : 解析JWT载荷 +AuthUtil-->>UI : 返回用户信息 +UI->>AuthUtil : 退出登录 +AuthUtil->>LocalStorage : 清除令牌和用户信息 +``` + +**图表来源** +- [auth.js:4-50](file://frontend/src/utils/auth.js#L4-L50) +- [auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) + +**章节来源** +- [auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) + +## 依赖关系分析 + +用户系统各组件之间的依赖关系如下: + +```mermaid +graph TD +subgraph "核心依赖" +A[DashboardUser 模型] --> B[Sequelize ORM] +C[认证中间件] --> D[JWT 工具] +C --> E[用户模型] +F[用户管理路由] --> G[密码工具] +F --> H[响应格式化] +I[认证路由] --> J[密码工具] +I --> K[JWT 工具] +end +subgraph "外部依赖" +L[jsonwebtoken] --> D +M[bcrypt] --> G +N[mysql2] --> B +O[sequelize] --> B +end +subgraph "前端依赖" +P[localStorage API] --> Q[认证工具] +R[fetch API] --> S[请求封装] +S --> I +end +``` + +**图表来源** +- [DashboardUser.js:1-2](file://backend/src/models/DashboardUser.js#L1-L2) +- [auth.js:1](file://backend/src/middleware/auth.js#L1) +- [password.js:1](file://backend/src/utils/password.js#L1) +- [jwt.js:1](file://backend/src/utils/jwt.js#L1) + +**章节来源** +- [index.js:1-8](file://backend/src/models/index.js#L1-L8) + +## 性能考虑 + +### 密码哈希性能 + +系统采用 PBKDF2 算法,迭代次数为 310000,提供了良好的安全性和性能平衡: + +- **安全性**:高迭代次数有效防止暴力破解 +- **性能**:单次验证耗时约几十毫秒,对用户体验影响最小 +- **扩展性**:可根据硬件性能调整迭代次数 + +### 数据库优化 + +- **索引策略**:用户名字段建立唯一索引,提高查询效率 +- **查询优化**:用户列表查询支持分页和模糊搜索 +- **缓存策略**:JWT 令牌无状态存储,减少数据库压力 + +### 并发控制 + +- **事务管理**:关键操作使用数据库事务确保数据一致性 +- **并发限制**:超级管理员数量检查避免竞态条件 +- **锁机制**:用户状态变更时的原子性操作 + +## 故障排除指南 + +### 常见问题及解决方案 + +| 问题类型 | 症状 | 可能原因 | 解决方案 | +|----------|------|----------|----------| +| 登录失败 | 返回"用户名或密码错误" | 用户名不存在或密码错误 | 检查用户名大小写和密码长度 | +| 权限不足 | 返回"需要超级管理员权限" | 当前用户权限不够 | 确认用户角色设置 | +| 令牌过期 | 返回"登录已过期" | JWT 令牌超过12小时有效期 | 重新登录获取新令牌 | +| 用户被禁用 | 返回"账号不存在或已禁用" | 用户状态为0 | 联系管理员启用账户 | +| 密码修改失败 | 返回"原密码错误" | 旧密码验证失败 | 确认输入的旧密码正确 | + +### 调试建议 + +1. **查看服务器日志**:关注认证相关的错误信息 +2. **检查环境变量**:确认 JWT_SECRET 和数据库连接配置 +3. **验证数据库连接**:确保 dashboard_user 表存在且可访问 +4. **测试密码加密**:使用系统提供的密码验证功能 + +**章节来源** +- [auth.js:5-25](file://backend/src/middleware/auth.js#L5-L25) +- [auth.js:38-46](file://backend/src/routes/auth.js#L38-L46) + +## 结论 + +DashboardUser 模型及其相关组件构成了一个完整、安全、高效的用户身份管理系统。系统通过以下特点确保了良好的用户体验和安全性: + +- **安全性**:采用 PBKDF2 密码加密和 JWT 令牌认证 +- **可扩展性**:基于 RBAC 的权限模型支持灵活的角色管理 +- **易用性**:前后端分离的架构提供了清晰的 API 接口 +- **可靠性**:完善的错误处理和日志记录机制 + +该系统为后续的功能扩展和维护奠定了坚实的基础,能够满足现代 Web 应用对用户管理的各种需求。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/核心功能模块/OTA固件管理.md b/.qoder/repowiki/zh/content/核心功能模块/OTA固件管理.md new file mode 100644 index 0000000..cba0835 --- /dev/null +++ b/.qoder/repowiki/zh/content/核心功能模块/OTA固件管理.md @@ -0,0 +1,476 @@ +# OTA固件管理 + + +**本文档引用的文件** +- [backend/src/models/Ota.js](file://backend/src/models/Ota.js) +- [backend/src/routes/ota.js](file://backend/src/routes/ota.js) +- [backend/src/services/otaStorage.js](file://backend/src/services/otaStorage.js) +- [backend/src/validators/ota.js](file://backend/src/validators/ota.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [frontend/src/views/ota/index.vue](file://frontend/src/views/ota/index.vue) +- [frontend/src/api/ota.js](file://frontend/src/api/ota.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本项目提供完整的OTA固件管理能力,涵盖固件版本管理、文件上传下载、强制更新配置以及设备端版本检查。系统支持两种设备型号:Luxsin-X8与Luxsin-X9,采用不同的存储策略: +- Luxsin-X8:通过S3对象存储进行分发 +- Luxsin-X9:保存到本地文件系统 + +系统还提供了完善的前端管理界面,支持版本列表查询、新增/编辑/删除、文件上传、强制更新策略配置等功能。 + +## 项目结构 +后端采用Express + Sequelize架构,前端基于Vue3 + Element Plus构建。整体结构清晰,职责分离明确。 + +```mermaid +graph TB +subgraph "前端" +FE_View["OTA视图
frontend/src/views/ota/index.vue"] +FE_API["OTA API封装
frontend/src/api/ota.js"] +end +subgraph "后端" +BE_Router["OTA路由
backend/src/routes/ota.js"] +BE_Model["OTA模型
backend/src/models/Ota.js"] +BE_Validator["OTA校验器
backend/src/validators/ota.js"] +BE_Storage["OTA存储服务
backend/src/services/otaStorage.js"] +BE_Utils["响应工具
backend/src/utils/response.js"] +BE_DB["数据库配置
backend/src/config/database.js"] +BE_ENV["环境配置
backend/src/config/env.js"] +end +FE_View --> FE_API +FE_API --> BE_Router +BE_Router --> BE_Model +BE_Router --> BE_Validator +BE_Router --> BE_Storage +BE_Router --> BE_Utils +BE_Model --> BE_DB +BE_Storage --> BE_ENV +``` + +**图表来源** +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) + +**章节来源** +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) + +## 核心组件 +系统的核心组件包括: +- **OTA模型**:定义固件版本的数据结构和约束 +- **OTA路由**:提供RESTful API接口 +- **OTA存储服务**:处理不同设备型号的文件存储策略 +- **OTA校验器**:使用Zod进行数据验证 +- **前端管理界面**:提供可视化操作界面 + +**章节来源** +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) +- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) + +## 架构总览 +系统采用分层架构设计,前后端分离,职责清晰: + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Frontend as "前端界面" +participant Backend as "后端API" +participant Storage as "存储服务" +participant DB as "数据库" +Client->>Frontend : 访问OTA管理页面 +Frontend->>Backend : 获取OTA版本列表 +Backend->>DB : 查询版本记录 +DB-->>Backend : 返回版本数据 +Backend-->>Frontend : 响应JSON数据 +Frontend->>Backend : 上传升级包(Luxsin-X8/X9) +Backend->>Storage : 保存文件 +Storage-->>Backend : 返回访问URL +Backend-->>Frontend : 响应上传结果 +Frontend->>Backend : 创建/更新OTA版本 +Backend->>DB : 持久化数据 +DB-->>Backend : 确认写入 +Backend-->>Frontend : 响应操作结果 +``` + +**图表来源** +- [backend/src/routes/ota.js:24-66](file://backend/src/routes/ota.js#L24-L66) +- [backend/src/services/otaStorage.js:46-103](file://backend/src/services/otaStorage.js#L46-L103) +- [frontend/src/views/ota/index.vue:384-412](file://frontend/src/views/ota/index.vue#L384-L412) + +## 详细组件分析 + +### OTA模型设计 +OTA模型定义了完整的固件版本数据结构,包含版本标识、文件信息、更新策略等关键字段。 + +```mermaid +erDiagram +OTA { +int id PK +int verCode +varchar verName +varchar url +char md5 +smallint force +varchar desc +varchar model +int hw +smallint target +smallint beta +datetime startTime +datetime endTime +smallint status +datetime create_at +} +MODEL { +int id PK +varchar brand_name +varchar name +varchar form +varchar rig +varchar source +varchar eq_key +datetime create_at +} +OTA ||--|| MODEL : "对应型号" +``` + +**图表来源** +- [backend/src/models/Ota.js:4-94](file://backend/src/models/Ota.js#L4-L94) +- [backend/src/models/Model.js:4-50](file://backend/src/models/Model.js#L4-L50) + +**字段说明**: +- `verCode`:版本号(整数),用于排序和比较 +- `verName`:版本名称,最多20字符 +- `url`:升级包下载URL +- `md5`:文件MD5校验值,32位十六进制 +- `force`:是否强制更新(0-否,1-是) +- `model`:对应的设备型号 +- `hw`:硬件版本号 +- `target`:是否定向发布(0-全量,1-定向) +- `beta`:是否灰度发布(0-否,1-是) +- `status`:状态(0-停用,1-可用) + +**章节来源** +- [backend/src/models/Ota.js:1-97](file://backend/src/models/Ota.js#L1-L97) + +### 文件上传与存储策略 +系统针对不同设备型号采用差异化的存储策略: + +```mermaid +flowchart TD +Start([开始上传]) --> CheckModel["检查设备型号"] +CheckModel --> IsX8{"是否Luxsin-X8?"} +IsX8 --> |是| UploadS3["上传到S3"] +IsX8 --> |否| CheckX9{"是否Luxsin-X9?"} +CheckX9 --> |是| SaveLocal["保存到本地"] +CheckX9 --> |否| Error["不支持的型号"] +UploadS3 --> GenS3Key["生成S3 Key"] +GenS3Key --> UploadOK{"上传成功?"} +UploadOK --> |是| BuildUrlS3["构建公共URL"] +UploadOK --> |否| S3Error["S3上传失败"] +SaveLocal --> GenDir["生成目录结构"] +GenDir --> WriteFile["写入文件"] +WriteFile --> BuildUrlLocal["构建本地URL"] +BuildUrlS3 --> Success([返回结果]) +BuildUrlLocal --> Success +S3Error --> Error +Error --> End([结束]) +``` + +**图表来源** +- [backend/src/routes/ota.js:24-66](file://backend/src/routes/ota.js#L24-L66) +- [backend/src/services/otaStorage.js:72-103](file://backend/src/services/otaStorage.js#L72-L103) + +**存储策略详情**: +- **Luxsin-X8(S3存储)**: + - 文件名固定:`LUXSIN_X8.PKG` + - 存储路径:`ota/{YYYYMM}/x8/{md5前5位}/LUXSIN_X8.PKG` + - 访问URL:基于S3 Bucket的公共域名 + - 凭证配置:支持显式凭证或IAM角色 + +- **Luxsin-X9(本地存储)**: + - 文件名固定:`LUXSIN.PKG` + - 存储路径:`ota/{YYYYMM}/x9/{md5前5位}/LUXSIN.PKG` + - 访问URL:基于配置的基础URL + - 环境区分:开发环境使用临时目录,生产环境使用/data/projects/source + +**章节来源** +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +### OTA版本检查流程 +设备端通过`/api/ota/latest/check`接口获取最新可用版本: + +```mermaid +sequenceDiagram +participant Device as "设备端" +participant API as "OTA检查接口" +participant DB as "数据库" +Device->>API : GET /api/ota/latest/check?currentVerCode&model&hw +API->>API : 解析查询参数 +API->>DB : 查询verCode > currentVerCode且status=1 +DB-->>API : 返回匹配记录 +API->>API : 按verCode降序排序 +API->>Device : 返回最高版本信息 +Note over Device,API : 未找到可用版本时返回空数据 +``` + +**图表来源** +- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102) + +**查询逻辑**: +- 必须满足:`status=1`(可用)、`verCode > 当前版本号` +- 支持按`model`和`hw`(硬件版本)过滤 +- 返回最高版本的完整信息 + +**章节来源** +- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102) + +### 数据验证与安全 +系统使用Zod进行严格的输入验证,确保数据完整性: + +```mermaid +classDiagram +class OtaCreateSchema { ++verCode : number ++verName : string ++url : string ++md5 : string ++force : number ++desc : string ++model : string ++hw : number ++target : number ++beta : number ++startTime : string ++endTime : string ++status : number +} +class OtaUpdateSchema { ++verCode : number? ++verName : string? ++url : string? ++md5 : string? ++force : number? ++desc : string? ++model : string? ++hw : number? ++target : number? ++beta : number? ++startTime : string? ++endTime : string? ++status : number? +} +class ApiResponse { ++success(data, msg) ++error(msg, code) ++noData(msg) +} +OtaCreateSchema --> ApiResponse : "验证失败时返回错误" +OtaUpdateSchema --> ApiResponse : "验证失败时返回错误" +``` + +**图表来源** +- [backend/src/validators/ota.js:3-35](file://backend/src/validators/ota.js#L3-L35) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +**验证规则**: +- 版本号必须为整数 +- 版本名称长度1-20字符 +- URL最长255字符 +- MD5必须为32位十六进制 +- 数值字段范围0-1(布尔型) +- 可选字段支持null值 + +**章节来源** +- [backend/src/validators/ota.js:1-36](file://backend/src/validators/ota.js#L1-L36) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +### 前端管理界面 +前端提供完整的OTA管理界面,支持多种操作: + +```mermaid +flowchart TD +PageLoad[页面加载] --> LoadData[加载OTA列表] +LoadData --> RenderTable[渲染表格] +AddBtn[新增按钮] --> OpenDialog[打开新增对话框] +EditBtn[编辑按钮] --> OpenDialog +CopyBtn[复制按钮] --> OpenDialog +OpenDialog --> FormInit[初始化表单] +FormInit --> CheckModel[检查设备型号] +CheckModel --> UploadMode{"是否支持上传?"} +UploadMode --> |是| EnableUpload[启用文件上传] +UploadMode --> |否| DisableUpload[禁用文件上传] +EnableUpload --> UploadFile[选择并上传文件] +UploadFile --> SaveInfo[自动填充URL和MD5] +SaveBtn[保存按钮] --> ValidateForm[表单验证] +ValidateForm --> SubmitAPI[提交到后端] +SubmitAPI --> RefreshList[刷新列表] +``` + +**图表来源** +- [frontend/src/views/ota/index.vue:420-579](file://frontend/src/views/ota/index.vue#L420-L579) + +**主要功能**: +- 版本列表查询(支持按版本名、型号、状态、版本号筛选) +- 分页加载(每页最多100条记录) +- 新增/编辑/删除OTA版本 +- 文件上传(支持Luxsin-X8/X9) +- 强制更新策略配置(强制更新、定向发布、灰度发布) +- 状态管理(可用/停用) + +**章节来源** +- [frontend/src/views/ota/index.vue:1-628](file://frontend/src/views/ota/index.vue#L1-L628) +- [frontend/src/api/ota.js:1-68](file://frontend/src/api/ota.js#L1-L68) + +## 依赖关系分析 + +```mermaid +graph LR +subgraph "外部依赖" +Express["Express框架"] +Sequelize["Sequelize ORM"] +Zod["Zod数据验证"] +S3["@aws-sdk/client-s3"] +Multer["Multer文件上传"] +end +subgraph "内部模块" +OtaRoute["OTA路由"] +OtaModel["OTA模型"] +OtaValidator["OTA校验器"] +OtaStorage["OTA存储服务"] +ResponseUtil["响应工具"] +EnvConfig["环境配置"] +DBConfig["数据库配置"] +end +Express --> OtaRoute +Sequelize --> OtaModel +Zod --> OtaValidator +S3 --> OtaStorage +Multer --> OtaRoute +OtaRoute --> OtaModel +OtaRoute --> OtaValidator +OtaRoute --> OtaStorage +OtaRoute --> ResponseUtil +OtaStorage --> EnvConfig +OtaModel --> DBConfig +``` + +**图表来源** +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [backend/package.json:11-24](file://backend/package.json#L11-L24) + +**依赖特点**: +- **轻量级**:仅使用必要的核心依赖 +- **可扩展**:模块化设计便于功能扩展 +- **环境适配**:支持开发/生产环境差异化配置 +- **安全性**:内置输入验证和错误处理 + +**章节来源** +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) + +## 性能考虑 +系统在设计时充分考虑了性能优化: + +### 数据库优化 +- 使用索引字段:`verCode`、`model`、`status` +- 分页查询限制:最大每页1000条记录 +- 条件查询优化:支持多字段组合查询 + +### 存储优化 +- **S3存储**:利用CDN加速,支持断点续传 +- **本地存储**:采用目录分片,避免单目录文件过多 +- **MD5前缀分片**:按MD5前5位组织文件结构 + +### 接口优化 +- **缓存友好**:查询参数明确,便于缓存 +- **批量操作**:支持分页批量获取 +- **错误快速返回**:验证失败立即返回 + +## 故障排除指南 + +### 常见问题及解决方案 + +**1. S3上传失败** +- 检查AWS凭证配置 +- 验证Bucket权限设置 +- 确认网络连接正常 + +**2. 版本冲突错误** +- 确保`verCode`+`model`组合唯一 +- 检查是否存在重复版本号 +- 避免在同一型号下使用相同版本号 + +**3. 文件完整性验证失败** +- 确认MD5计算正确 +- 检查文件传输完整性 +- 验证存储路径正确性 + +**4. 前端上传异常** +- 检查文件类型和大小限制 +- 确认跨域配置正确 +- 验证API接口可达性 + +**章节来源** +- [backend/src/routes/ota.js:174-181](file://backend/src/routes/ota.js#L174-L181) +- [backend/src/services/otaStorage.js:95-98](file://backend/src/services/otaStorage.js#L95-L98) + +## 结论 +本OTA固件管理系统具有以下优势: +- **架构清晰**:前后端分离,职责明确 +- **功能完整**:覆盖从版本管理到文件分发的全流程 +- **扩展性强**:模块化设计便于功能扩展 +- **安全可靠**:完善的输入验证和错误处理机制 +- **性能优化**:合理的存储策略和查询优化 + +系统特别适合需要管理多型号设备固件更新的企业应用场景,为设备厂商提供了完整的OTA解决方案。 + +## 附录 + +### API接口规范 + +**版本检查接口** +- 方法:GET +- 路径:`/api/ota/latest/check` +- 参数: + - `currentVerCode`:当前版本号(必填) + - `model`:设备型号(必填) + - `hw`:硬件版本(可选) + +**版本管理接口** +- 列表查询:GET `/api/ota/` +- 获取详情:GET `/api/ota/:ota_id` +- 创建版本:POST `/api/ota/` +- 更新版本:PUT `/api/ota/:ota_id` +- 删除版本:DELETE `/api/ota/:ota_id` + +**文件上传接口** +- 上传包:POST `/api/ota/upload-package` +- 支持格式:`.pkg`、`.bin`、`.zip` +- 超时时间:5分钟 + +### 环境配置 +- 数据库:MySQL(UTF8MB4字符集) +- 存储:S3或本地文件系统 +- 环境变量: + - `DATABASE_*`:数据库连接配置 + - `AWS_*`:S3存储配置 + - `OTA_*`:OTA存储路径和URL配置 + - `APP_ENV`:应用环境(development/production) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/核心功能模块/分享码日志管理.md b/.qoder/repowiki/zh/content/核心功能模块/分享码日志管理.md new file mode 100644 index 0000000..1cc6b7b --- /dev/null +++ b/.qoder/repowiki/zh/content/核心功能模块/分享码日志管理.md @@ -0,0 +1,345 @@ +# 分享码日志管理 + + +**本文档引用的文件** +- [ShareCodeLog.js](file://backend/src/models/ShareCodeLog.js) +- [shareCodeLogs.js](file://backend/src/routes/shareCodeLogs.js) +- [response.js](file://backend/src/utils/response.js) +- [database.js](file://backend/src/config/database.js) +- [log.vue](file://frontend/src/views/share-code/log.vue) +- [shareCodeLog.js](file://frontend/src/api/shareCodeLog.js) +- [index.js](file://frontend/src/router/index.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +分享码日志管理功能是一个完整的日志追踪系统,用于记录和查询分享码的使用情况。该系统实现了设备MAC地址、分享码、操作类型、IP地址等关键信息的完整记录,并提供了强大的查询统计功能。 + +系统采用前后端分离架构,后端基于Node.js + Express + Sequelize,前端使用Vue.js + Element Plus构建用户界面。日志数据存储在MySQL数据库中,通过索引优化确保查询性能。 + +## 项目结构 + +分享码日志管理功能主要分布在以下目录结构中: + +```mermaid +graph TB +subgraph "后端架构" +A[models/ShareCodeLog.js
日志模型定义] +B[routes/shareCodeLogs.js
日志路由处理] +C[utils/response.js
响应格式化] +D[config/database.js
数据库配置] +end +subgraph "前端架构" +E[views/share-code/log.vue
日志页面组件] +F[api/shareCodeLog.js
API请求封装] +G[router/index.js
路由配置] +end +subgraph "数据库层" +H[(MySQL 数据库)] +I[share_code_log 表] +end +A --> H +B --> A +E --> F +F --> G +B --> D +E --> G +``` + +**图表来源** +- [ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) +- [shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) +- [log.vue:1-353](file://frontend/src/views/share-code/log.vue#L1-L353) + +**章节来源** +- [ShareCodeLog.js:1-60](file://backend/src/models/ShareCodeLog.js#L1-L60) +- [shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) +- [log.vue:1-353](file://frontend/src/views/share-code/log.vue#L1-L353) + +## 核心组件 + +### 日志模型定义 + +分享码日志模型是整个系统的数据基础,定义了完整的字段结构和约束条件: + +| 字段名 | 类型 | 约束 | 描述 | +|--------|------|------|------| +| id | INTEGER | 主键, 自增 | 日志记录唯一标识 | +| mac_addr | STRING(17) | 非空 | 设备MAC地址,格式AA:BB:CC:DD:EE:FF | +| share_code | CHAR(5) | 非空 | 分享码,5位字符 | +| action | ENUM | 非空 | 操作类型:export=导出, import=导入 | +| ip_addr | STRING(45) | 非空, 默认'' | 用户IP地址,支持IPv4/IPv6 | +| eq_data | JSON | 非空 | EQ数据快照(JSON格式) | +| expire_at | DATE | 可空 | 分享码到期时间(导出时快照) | +| create_at | DATE | 非空, 默认NOW | 操作时间 | + +### 查询路由实现 + +后端路由提供了完整的日志查询接口,支持多种过滤条件和排序方式: + +**查询参数支持**: +- 分页参数:skip(跳过数量)、limit(每页条数,最大1000) +- 过滤条件:mac_addr、share_code、action、ip_addr +- 时间范围:start_at、end_at +- 排序参数:sort_by(id、create_at)、sort_order(asc、desc) + +**章节来源** +- [ShareCodeLog.js:4-56](file://backend/src/models/ShareCodeLog.js#L4-L56) +- [shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) + +## 架构概览 + +分享码日志管理系统的整体架构采用经典的三层架构设计: + +```mermaid +sequenceDiagram +participant User as 用户界面 +participant Frontend as 前端应用 +participant Backend as 后端服务 +participant Database as MySQL数据库 +participant Logger as 日志系统 +User->>Frontend : 访问分享码日志页面 +Frontend->>Backend : GET /api/share-code/logs +Backend->>Logger : 记录查询日志 +Backend->>Database : 执行查询带过滤条件 +Database-->>Backend : 返回查询结果 +Backend->>Backend : 格式化响应数据 +Backend-->>Frontend : 返回JSON响应 +Frontend->>User : 展示日志表格 +Note over User,Database : 完整的日志查询流程 +``` + +**图表来源** +- [shareCodeLogs.js:15-84](file://backend/src/routes/shareCodeLogs.js#L15-L84) +- [log.vue:233-277](file://frontend/src/views/share-code/log.vue#L233-L277) + +系统的关键特性包括: +- **实时查询**:支持多维度过滤和排序 +- **分页加载**:避免大量数据一次性传输 +- **响应式设计**:适配不同屏幕尺寸 +- **错误处理**:完善的异常捕获和用户提示 + +## 详细组件分析 + +### 后端路由处理流程 + +后端路由实现了完整的日志查询逻辑,包括参数验证、查询构建、结果处理等步骤: + +```mermaid +flowchart TD +Start([请求进入]) --> ParseParams["解析查询参数"] +ParseParams --> ValidateFilters["验证过滤条件"] +ValidateFilters --> BuildWhere["构建WHERE条件"] +BuildWhere --> CheckTimeRange{"是否设置时间范围?"} +CheckTimeRange --> |是| AddTimeRange["添加时间范围条件"] +CheckTimeRange --> |否| CountQuery["执行COUNT查询"] +AddTimeRange --> CountQuery +CountQuery --> BuildOrder["构建排序条件"] +BuildOrder --> PaginateQuery["执行分页查询"] +PaginateQuery --> FormatResponse["格式化响应数据"] +FormatResponse --> ReturnSuccess["返回成功响应"] +ReturnSuccess --> End([请求结束]) +CountQuery --> ErrorHandle["异常处理"] +ErrorHandle --> ReturnError["返回错误响应"] +ReturnError --> End +``` + +**图表来源** +- [shareCodeLogs.js:15-84](file://backend/src/routes/shareCodeLogs.js#L15-L84) + +### 前端页面交互流程 + +前端页面提供了直观的用户界面和完整的交互功能: + +```mermaid +sequenceDiagram +participant User as 用户 +participant SearchForm as 搜索表单 +participant Table as 数据表格 +participant Pagination as 分页控件 +participant API as API接口 +User->>SearchForm : 输入搜索条件 +SearchForm->>API : 发送查询请求 +API-->>SearchForm : 返回查询结果 +SearchForm->>Table : 更新表格数据 +User->>Pagination : 切换页码/页大小 +Pagination->>API : 发送新的分页请求 +API-->>Pagination : 返回分页数据 +Pagination->>Table : 更新表格显示 +Note over User,API : 用户驱动的数据查询流程 +``` + +**图表来源** +- [log.vue:214-277](file://frontend/src/views/share-code/log.vue#L214-L277) + +### 数据模型类图 + +```mermaid +classDiagram +class ShareCodeLog { ++number id ++string mac_addr ++string share_code ++string action ++string ip_addr ++object eq_data ++date expire_at ++date create_at +} +class ApiResponse { ++success(data, msg) Object ++error(msg, code) Object ++noData(msg) Object +} +class PageData { ++items array ++total number ++skip number ++limit number +} +class ShareCodeLogRoute { ++GET /api/share-code/logs ++parseQueryParams() Object ++buildWhereClause() Object ++formatResponse() Object +} +ShareCodeLogRoute --> ShareCodeLog : "查询" +ShareCodeLogRoute --> ApiResponse : "使用" +ShareCodeLogRoute --> PageData : "封装" +``` + +**图表来源** +- [ShareCodeLog.js:4-56](file://backend/src/models/ShareCodeLog.js#L4-L56) +- [shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +**章节来源** +- [log.vue:148-278](file://frontend/src/views/share-code/log.vue#L148-L278) +- [shareCodeLogs.js:15-84](file://backend/src/routes/shareCodeLogs.js#L15-L84) + +## 依赖关系分析 + +系统各组件之间的依赖关系清晰明确: + +```mermaid +graph LR +subgraph "前端依赖" +A[log.vue] --> B[shareCodeLog.js] +B --> C[request.js] +A --> D[Element Plus] +A --> E[VueJsonPretty] +end +subgraph "后端依赖" +F[shareCodeLogs.js] --> G[ShareCodeLog.js] +F --> H[response.js] +F --> I[logger.js] +G --> J[database.js] +end +subgraph "数据库依赖" +K[MySQL] <- --> J +L[share_code_log] <- --> G +end +A -.-> F +F -.-> K +``` + +**图表来源** +- [log.vue:154-154](file://frontend/src/views/share-code/log.vue#L154-L154) +- [shareCodeLogs.js:6-8](file://backend/src/routes/shareCodeLogs.js#L6-L8) +- [ShareCodeLog.js:2-2](file://backend/src/models/ShareCodeLog.js#L2-L2) + +**章节来源** +- [database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [index.js:43-47](file://frontend/src/router/index.js#L43-L47) + +## 性能考虑 + +### 数据库索引优化 + +系统在日志表上建立了三个关键索引以提升查询性能: + +| 索引名称 | 字段 | 用途 | 性能影响 | +|----------|------|------|----------| +| idx_mac_addr | mac_addr | 设备查询 | 显著提升MAC地址过滤速度 | +| idx_share_code | share_code | 分享码查询 | 提升分享码匹配效率 | +| idx_create_at | create_at | 时间排序 | 优化时间范围查询 | + +### 查询性能优化策略 + +1. **分页查询**:默认每页50条,最大限制1000条,避免大数据量传输 +2. **条件过滤**:仅在提供有效条件时添加WHERE子句 +3. **索引利用**:合理使用已建立的复合索引 +4. **数据类型优化**:使用合适的字段长度和数据类型 + +### 前端性能优化 + +1. **虚拟滚动**:对于大量数据时可考虑实现虚拟滚动 +2. **缓存机制**:对常用查询结果进行缓存 +3. **防抖处理**:搜索输入时添加防抖机制 +4. **懒加载**:对话框等组件按需加载 + +## 故障排除指南 + +### 常见问题及解决方案 + +**问题1:查询结果为空** +- 检查查询条件是否过于严格 +- 验证时间范围设置是否正确 +- 确认用户权限是否足够 + +**问题2:性能问题** +- 检查数据库连接配置 +- 验证索引是否正常工作 +- 考虑优化查询条件 + +**问题3:前端显示异常** +- 检查网络请求状态 +- 验证JSON数据格式 +- 确认Element Plus版本兼容性 + +### 错误处理机制 + +系统实现了多层次的错误处理: + +```mermaid +flowchart TD +Request[请求处理] --> TryBlock["try块执行"] +TryBlock --> Success["成功处理"] +TryBlock --> CatchBlock["catch异常捕获"] +CatchBlock --> LogError["记录错误日志"] +LogError --> ReturnError["返回错误响应"] +Success --> ReturnSuccess["返回成功响应"] +ReturnError --> ApiResponse["ApiResponse.error()"] +ReturnSuccess --> ApiResponse2["ApiResponse.success()"] +``` + +**图表来源** +- [shareCodeLogs.js:80-83](file://backend/src/routes/shareCodeLogs.js#L80-L83) +- [response.js:6-12](file://backend/src/utils/response.js#L6-L12) + +**章节来源** +- [shareCodeLogs.js:80-83](file://backend/src/routes/shareCodeLogs.js#L80-L83) +- [response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 结论 + +分享码日志管理功能是一个设计完善、实现优雅的日志追踪系统。它通过合理的数据模型设计、高效的查询实现和友好的用户界面,为用户提供了一个完整的分享码使用记录管理解决方案。 + +系统的主要优势包括: +- **完整的功能覆盖**:从数据记录到查询统计的全流程支持 +- **良好的扩展性**:模块化设计便于功能扩展和维护 +- **优秀的用户体验**:响应式界面和流畅的交互体验 +- **可靠的性能表现**:通过索引优化和分页机制保证查询效率 + +未来可以考虑的功能增强包括:数据导出功能、更丰富的统计图表、高级搜索条件、数据清理策略等,这些都将进一步提升系统的实用性和价值。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/核心功能模块/品牌管理.md b/.qoder/repowiki/zh/content/核心功能模块/品牌管理.md new file mode 100644 index 0000000..5873836 --- /dev/null +++ b/.qoder/repowiki/zh/content/核心功能模块/品牌管理.md @@ -0,0 +1,362 @@ +# 品牌管理 + + +**本文引用的文件** +- [backend/src/models/Brand.js](file://backend/src/models/Brand.js) +- [backend/src/models/Model.js](file://backend/src/models/Model.js) +- [backend/src/routes/brands.js](file://backend/src/routes/brands.js) +- [backend/src/validators/brand.js](file://backend/src/validators/brand.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [frontend/src/views/brand/index.vue](file://frontend/src/views/brand/index.vue) +- [frontend/src/api/brand.js](file://frontend/src/api/brand.js) +- [frontend/src/views/model/index.vue](file://frontend/src/views/model/index.vue) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本章节面向“品牌管理”功能,系统性阐述品牌 CRUD 操作、数据验证规则、与型号模型的关联关系以及缓存策略的实现细节。文档通过后端路由、模型定义、前端视图与 API 调用的联动,结合错误处理与日志记录,帮助初学者快速上手,同时为有经验的开发者提供足够的技术深度。 + +## 项目结构 +品牌管理功能涉及前后端协作:前端负责用户交互与分页搜索;后端提供认证中间件、统一响应格式、品牌路由与模型持久化;型号模型与品牌存在逻辑上的关联;此外还包含 EQ 缓存服务用于读取型号 EQ 数据。 + +```mermaid +graph TB +subgraph "前端" +FE_View["品牌视图
frontend/src/views/brand/index.vue"] +FE_API["品牌 API 封装
frontend/src/api/brand.js"] +end +subgraph "后端" +APP["应用入口
backend/src/app.js"] +ROUTES_IDX["路由汇总
backend/src/routes/index.js"] +AUTH_MW["认证中间件
backend/src/middleware/auth.js"] +BRAND_ROUTE["品牌路由
backend/src/routes/brands.js"] +BRAND_MODEL["品牌模型
backend/src/models/Brand.js"] +MODEL_MODEL["型号模型
backend/src/models/Model.js"] +RESP_UTIL["统一响应工具
backend/src/utils/response.js"] +EQ_CACHE["EQ 缓存服务
backend/src/services/eqCacheStorage.js"] +end +FE_View --> FE_API +FE_API --> BRAND_ROUTE +APP --> ROUTES_IDX --> BRAND_ROUTE +BRAND_ROUTE --> AUTH_MW +BRAND_ROUTE --> BRAND_MODEL +BRAND_ROUTE --> RESP_UTIL +MODEL_MODEL -. 关联 .-> BRAND_MODEL +EQ_CACHE -. 使用 .-> BRAND_MODEL +``` + +**图表来源** +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +**章节来源** +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) + +## 核心组件 +- 品牌模型:定义品牌表结构,包含唯一约束的品牌名称,确保全局唯一性。 +- 品牌路由:提供品牌列表查询、详情查询、新增、更新、删除接口,并内置登录态校验。 +- 品牌验证器:基于 Zod 定义创建与更新时的字段校验规则。 +- 统一响应工具:封装标准响应结构,便于前后端约定一致的数据格式。 +- 认证中间件:拦截请求,校验 Bearer Token 并注入用户信息。 +- 前端视图与 API:提供品牌列表、搜索、分页、新增/编辑弹窗、删除确认等交互能力。 +- 型号模型:与品牌存在逻辑关联(品牌名称字段),用于型号层面的品牌归属。 +- EQ 缓存服务:为型号 EQ 数据提供 Redis Hash 读取能力,键名由品牌与型号组合生成。 + +**章节来源** +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [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) +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +## 架构总览 +品牌管理采用前后端分离架构:前端通过 API 发起请求,后端经认证中间件、路由处理、模型持久化与日志记录,最终返回统一格式的响应。型号模型与品牌存在逻辑关联,前端在创建新型号时可自动确保品牌存在。 + +```mermaid +sequenceDiagram +participant FE as "前端视图
brand/index.vue" +participant API as "前端 API
brand.js" +participant APP as "应用入口
app.js" +participant MW as "认证中间件
auth.js" +participant RT as "品牌路由
brands.js" +participant MD as "品牌模型
Brand.js" +participant UT as "响应工具
response.js" +FE->>API : 调用 getBrands()/createBrand()/updateBrand()/deleteBrand() +API->>APP : 发送 HTTP 请求 +APP->>MW : 应用认证中间件 +MW-->>RT : 放行并注入用户信息 +RT->>MD : 读写数据库查询/新增/更新/删除 +MD-->>RT : 返回结果 +RT->>UT : 包装统一响应 +UT-->>API : 返回 {code,msg,data} +API-->>FE : 呈现结果 +``` + +**图表来源** +- [frontend/src/views/brand/index.vue:145-275](file://frontend/src/views/brand/index.vue#L145-L275) +- [frontend/src/api/brand.js:10-65](file://frontend/src/api/brand.js#L10-L65) +- [backend/src/app.js:36-37](file://backend/src/app.js#L36-L37) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/routes/brands.js:14-144](file://backend/src/routes/brands.js#L14-L144) +- [backend/src/models/Brand.js:4-22](file://backend/src/models/Brand.js#L4-L22) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 详细组件分析 + +### 品牌模型与数据库约束 +- 字段设计:主键自增 ID、唯一且非空的品牌名称,表名为 brand。 +- 约束意义:保证品牌名称全局唯一,避免重复品牌导致的歧义与业务冲突。 +- 与型号的关联:型号模型包含品牌名称字段,用于在型号层面标识所属品牌。 + +```mermaid +erDiagram +BRAND { +int id PK +string name UK +} +MODEL { +int id PK +string brand_name +string name +string form +string rig +string source +string eq_key +datetime create_at +} +BRAND ||--o{ MODEL : "通过 brand_name 关联" +``` + +**图表来源** +- [backend/src/models/Brand.js:4-20](file://backend/src/models/Brand.js#L4-L20) +- [backend/src/models/Model.js:4-50](file://backend/src/models/Model.js#L4-L50) + +**章节来源** +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) + +### 品牌路由与 CRUD 实现 +- 登录态要求:所有品牌接口均受认证中间件保护,需携带 Bearer Token。 +- 列表查询:支持分页 skip/limit 与名称模糊查询 name,最大限制 1000 条。 +- 详情查询:按主键查询,不存在时返回无数据响应。 +- 新增:去除空白后校验必填,检查名称是否已存在,存在则拒绝重复。 +- 更新:允许仅传入 id 不传 name 触发“无变更即成功”的语义;当传入新名称时,校验非空并检查与其他品牌的唯一性。 +- 删除:按主键查找并销毁,不存在时提示“品牌不存在”。 + +```mermaid +flowchart TD +Start(["进入路由处理"]) --> Method{"HTTP 方法"} +Method --> |GET /api/brands/| List["分页+模糊查询"] +Method --> |GET /api/brands/:id| Detail["按ID查询"] +Method --> |POST /api/brands/| Create["校验名称+去空白+查重+创建"] +Method --> |PUT /api/brands/:id| Update["校验名称+去空白+查重(排除自身)+保存"] +Method --> |DELETE /api/brands/:id| Delete["按ID查找+销毁"] +List --> Resp["统一响应封装"] +Detail --> Resp +Create --> Resp +Update --> Resp +Delete --> Resp +Resp --> End(["返回给客户端"]) +``` + +**图表来源** +- [backend/src/routes/brands.js:14-144](file://backend/src/routes/brands.js#L14-L144) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-25) + +**章节来源** +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [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) + +### 品牌验证器(Zod Schema) +- 创建校验:name 必填、字符串、最大长度 100。 +- 更新校验:name 可选、字符串、最大长度 100。 +- 配置要点:通过 optional() 控制更新时可不传 name,从而支持“仅查询/无变更即成功”的语义。 + +```mermaid +classDiagram +class BrandCreateSchema { ++name : string(1..100) +} +class BrandUpdateSchema { ++name : string(1..100)? +} +``` + +**图表来源** +- [backend/src/validators/brand.js:3-9](file://backend/src/validators/brand.js#L3-L9) + +**章节来源** +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) + +### 前端交互与 API 调用 +- 品牌视图:提供搜索、分页、新增/编辑弹窗、删除确认;调用封装好的 API。 +- API 封装:统一 GET/POST/PUT/DELETE 品牌接口,参数包括分页与过滤条件。 +- 与型号的联动:在创建新型号时,若品牌不存在会尝试自动创建品牌,确保后续型号能正确关联。 + +```mermaid +sequenceDiagram +participant View as "品牌视图
index.vue" +participant API as "品牌 API
brand.js" +participant ModelView as "型号视图
model/index.vue" +View->>API : getBrands({skip,limit,name}) +View->>API : createBrand({name}) / updateBrand({id,name}) / deleteBrand(id) +ModelView->>API : ensureBrandExistsForNewModel(name) +API-->>View : 返回统一响应 +API-->>ModelView : 返回统一响应 +``` + +**图表来源** +- [frontend/src/views/brand/index.vue:145-275](file://frontend/src/views/brand/index.vue#L145-L275) +- [frontend/src/api/brand.js:10-65](file://frontend/src/api/brand.js#L10-L65) +- [frontend/src/views/model/index.vue:677-693](file://frontend/src/views/model/index.vue#L677-L693) + +**章节来源** +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [frontend/src/views/model/index.vue:677-693](file://frontend/src/views/model/index.vue#L677-L693) + +### 缓存策略与 EQ 缓存服务 +- 缓存键构建:使用“品牌名称 型号名称”作为 Redis Hash 的键,便于按型号维度读取 EQ 字段。 +- 读取策略: + - 获取字段键集合:避免一次性读取全部哈希值,降低响应体积。 + - 读取单个字段:按字段名获取值,解析 JSON 或回退原始值。 +- 异常处理:对 Redis 读取失败进行统一错误抛出与日志记录。 + +```mermaid +flowchart TD +BuildKey["构建 Redis Key
品牌名称+空格+型号名称"] --> Exists{"Key 是否存在?"} +Exists --> |否| NotFound["记录日志并返回空字段"] +Exists --> |是| GetKeys["hkeys 获取字段键集合"] +GetKeys --> ReturnKeys["返回 {redis_key, field_keys}"] +BuildKey --> GetField["hget 读取单个字段"] +GetField --> Parse["JSON 解析或回退原始值"] +Parse --> ReturnField["返回 {redis_key,key,value}"] +``` + +**图表来源** +- [backend/src/services/eqCacheStorage.js:7-72](file://backend/src/services/eqCacheStorage.js#L7-L72) + +**章节来源** +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +## 依赖分析 +- 路由注册:应用启动时加载路由汇总,品牌路由独立于其他模块。 +- 认证依赖:品牌路由统一使用认证中间件,确保接口安全。 +- 模型依赖:品牌路由直接依赖品牌模型;型号模型与品牌存在逻辑关联。 +- 响应依赖:路由层统一使用响应工具封装返回体。 +- 前后端依赖:前端视图依赖 API 封装;型号视图在创建新型号时依赖品牌 API。 + +```mermaid +graph LR +APP["app.js"] --> ROUTES_IDX["routes/index.js"] +ROUTES_IDX --> BRAND_ROUTE["brands.js"] +BRAND_ROUTE --> AUTH_MW["auth.js"] +BRAND_ROUTE --> BRAND_MODEL["Brand.js"] +BRAND_ROUTE --> RESP_UTIL["response.js"] +MODEL_MODEL["Model.js"] -. 关联 .-> BRAND_MODEL +FE_VIEW["brand/index.vue"] --> FE_API["brand.js"] +FE_API --> BRAND_ROUTE +EQ_CACHE["eqCacheStorage.js"] -. 使用 .-> BRAND_MODEL +``` + +**图表来源** +- [backend/src/app.js:36-37](file://backend/src/app.js#L36-L37) +- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/routes/brands.js:12-12](file://backend/src/routes/brands.js#L12-L12) +- [backend/src/models/Brand.js:4-22](file://backend/src/models/Brand.js#L4-L22) +- [backend/src/models/Model.js:4-50](file://backend/src/models/Model.js#L4-L50) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [frontend/src/views/brand/index.vue:113-113](file://frontend/src/views/brand/index.vue#L113-L113) +- [frontend/src/api/brand.js:10-65](file://frontend/src/api/brand.js#L10-L65) +- [backend/src/services/eqCacheStorage.js:7-72](file://backend/src/services/eqCacheStorage.js#L7-L72) + +**章节来源** +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [frontend/src/views/brand/index.vue:1-311](file://frontend/src/views/brand/index.vue#L1-L311) +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) + +## 性能考虑 +- 分页与上限:列表查询默认每页 100 条,最大限制 1000 条,避免一次性返回过多数据。 +- 去空白与查重:新增/更新前对名称去空白并查重,减少无效写入与数据库压力。 +- 缓存键拆分:EQ 缓存仅读取字段键集合,避免大体积哈希值传输,提升响应速度。 +- 日志与异常:统一错误包装与日志记录,便于定位性能瓶颈与异常原因。 + +[本节为通用性能建议,不直接分析具体文件,故无“章节来源”] + +## 故障排查指南 +- 重复品牌名称 + - 现象:新增/更新时报“品牌名称已存在”。 + - 排查:检查数据库唯一索引与路由中的查重逻辑;确认名称去空白后是否仍与现有品牌相同。 + - 参考路径:[backend/src/routes/brands.js:68-72](file://backend/src/routes/brands.js#L68-L72)、[backend/src/routes/brands.js:106-112](file://backend/src/routes/brands.js#L106-L112) +- 品牌不存在 + - 现象:查询/更新/删除时返回“品牌不存在”。 + - 排查:确认传入的 ID 是否正确;检查数据库是否存在该记录。 + - 参考路径:[backend/src/routes/brands.js:47-51](file://backend/src/routes/brands.js#L47-L51)、[backend/src/routes/brands.js:89-93](file://backend/src/routes/brands.js#L89-L93)、[backend/src/routes/brands.js:131-135](file://backend/src/routes/brands.js#L131-L135) +- 未登录或 Token 失效 + - 现象:返回 401 未授权或“登录已过期”。 + - 排查:确认请求头 Authorization 是否为 Bearer Token;检查 Token 是否过期。 + - 参考路径:[backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- Redis 读取失败 + - 现象:EQ 缓存读取报错。 + - 排查:检查 Redis 连接状态与键是否存在;确认字段值是否为合法 JSON。 + - 参考路径:[backend/src/services/eqCacheStorage.js:28-42](file://backend/src/services/eqCacheStorage.js#L28-L42)、[backend/src/services/eqCacheStorage.js:51-66](file://backend/src/services/eqCacheStorage.js#L51-L66) + +**章节来源** +- [backend/src/routes/brands.js:47-51](file://backend/src/routes/brands.js#L47-L51) +- [backend/src/routes/brands.js:68-72](file://backend/src/routes/brands.js#L68-L72) +- [backend/src/routes/brands.js:89-93](file://backend/src/routes/brands.js#L89-L93) +- [backend/src/routes/brands.js:106-112](file://backend/src/routes/brands.js#L106-L112) +- [backend/src/routes/brands.js:131-135](file://backend/src/routes/brands.js#L131-L135) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/services/eqCacheStorage.js:28-42](file://backend/src/services/eqCacheStorage.js#L28-L42) +- [backend/src/services/eqCacheStorage.js:51-66](file://backend/src/services/eqCacheStorage.js#L51-L66) + +## 结论 +品牌管理功能通过清晰的模型定义、严格的验证规则、统一的响应格式与完善的日志记录,实现了稳定可靠的 CRUD 能力。前端与后端的职责边界明确,配合认证中间件与缓存策略,既保障了安全性也兼顾了性能。在型号层面的品牌关联与自动创建机制,进一步提升了业务流程的连贯性与易用性。 + +[本节为总结性内容,不直接分析具体文件,故无“章节来源”] + +## 附录 +- 常见问题速查 + - 如何批量导入品牌?建议通过后端脚本或数据库迁移工具,避免重复名称与并发冲突。 + - 如何清理无效品牌?先检查型号表中是否仍有引用,再执行删除;注意外键约束与业务影响。 + - 如何优化列表查询性能?合理设置分页参数与过滤条件,避免全量扫描。 +- 最佳实践 + - 在新增/更新前统一做名称去空白与长度校验。 + - 对关键操作增加日志埋点,便于审计与排障。 + - 对 Redis 缓存读取失败进行降级处理,保证核心功能可用。 + +[本节为通用建议,不直接分析具体文件,故无“章节来源”] \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/核心功能模块/型号管理.md b/.qoder/repowiki/zh/content/核心功能模块/型号管理.md new file mode 100644 index 0000000..dea90a8 --- /dev/null +++ b/.qoder/repowiki/zh/content/核心功能模块/型号管理.md @@ -0,0 +1,382 @@ +# 型号管理 + + +**本文引用的文件** +- [Model.js](file://backend/src/models/Model.js) +- [Brand.js](file://backend/src/models/Brand.js) +- [model.js](file://backend/src/validators/model.js) +- [models.js](file://backend/src/routes/models.js) +- [measurementStorage.js](file://backend/src/services/measurementStorage.js) +- [eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [curveClient.js](file://backend/src/services/curveClient.js) +- [index.vue](file://frontend/src/views/model/index.vue) +- [model.js](file://frontend/src/api/model.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件围绕“型号管理”功能进行系统性说明,涵盖型号的 CRUD 操作、技术规格管理、测量数据存储与检索、以及与品牌模型的一对一关联关系。文档基于实际代码库实现,提供接口调用流程、数据验证规则、存储策略与常见问题的解决方案,并给出面向初学者与高级开发者的分层解读。 + +## 项目结构 +型号管理功能由前端视图、API 客户端与后端路由/模型/服务共同组成,形成“前端交互—HTTP 请求—后端路由—数据模型—外部存储”的完整链路。 + +```mermaid +graph TB +FE["前端视图
frontend/src/views/model/index.vue"] --> API["API 客户端
frontend/src/api/model.js"] +API --> ROUTER["后端路由
backend/src/routes/models.js"] +ROUTER --> MODEL["型号模型
backend/src/models/Model.js"] +ROUTER --> VALIDATOR["型号验证器
backend/src/validators/model.js"] +ROUTER --> MSVC["频响存储服务
backend/src/services/measurementStorage.js"] +ROUTER --> ESVC["EQ 缓存服务
backend/src/services/eqCacheStorage.js"] +ROUTER --> CSVC["曲线校验服务
backend/src/services/curveClient.js"] +ROUTER --> BRAND["品牌模型
backend/src/models/Brand.js"] +``` + +图表来源 +- [index.vue:1-1226](file://frontend/src/views/model/index.vue#L1-L1226) +- [model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [model.js:1-22](file://backend/src/validators/model.js#L1-L22) +- [measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [curveClient.js:1-147](file://backend/src/services/curveClient.js#L1-L147) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +章节来源 +- [index.vue:1-1226](file://frontend/src/views/model/index.vue#L1-L1226) +- [model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [model.js:1-22](file://backend/src/validators/model.js#L1-L22) +- [measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [curveClient.js:1-147](file://backend/src/services/curveClient.js#L1-L147) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +## 核心组件 +- 型号模型:定义型号的数据结构与约束,包括品牌名称、型号名称、形式、阻抗、来源、EQ 键等字段。 +- 品牌模型:与型号存在一对一关联,型号通过品牌名称进行关联。 +- 型号验证器:使用 Zod 对创建/更新请求体进行严格校验。 +- 型号路由:提供列表查询、详情查看、新增、更新、删除、搜索推送、频响 CSV 查看、EQ 缓存查看等接口。 +- 测量存储服务:负责将频响 CSV/文本文件上传至 S3,并支持按路径键读取。 +- EQ 缓存服务:通过 Redis 提供型号 EQ 数据的哈希字段列表与具体值读取。 +- 曲线校验服务:对接外部曲线 API,校验型号的 parametric_eq 数据有效性。 + +章节来源 +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [model.js:1-22](file://backend/src/validators/model.js#L1-L22) +- [models.js:133-566](file://backend/src/routes/models.js#L133-L566) +- [measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [curveClient.js:1-147](file://backend/src/services/curveClient.js#L1-L147) + +## 架构总览 +型号管理的端到端流程如下: +- 前端通过 API 客户端发起请求,后端路由接收并进行鉴权与参数校验。 +- 路由根据业务逻辑调用模型层与服务层,完成数据库读写、外部存储交互与第三方校验。 +- 前端渲染结果,支持批量推送至搜索引擎、查看频响 CSV、查看 EQ 缓存等。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant FE as "前端视图" +participant API as "API 客户端" +participant RT as "后端路由(models.js)" +participant MD as "型号模型(Model.js)" +participant MS as "频响存储(measurementStorage.js)" +participant ES as "EQ 缓存(eqCacheStorage.js)" +participant CS as "曲线校验(curveClient.js)" +U->>FE : 打开型号页面 +FE->>API : 发起列表/详情/新增/更新/删除请求 +API->>RT : HTTP 请求 +alt 查询列表/详情 +RT->>MD : 读取数据库 +MD-->>RT : 返回数据 +else 新增/更新 +RT->>MD : 写入数据库 +MD-->>RT : 返回新记录 +opt 上传频响文件 +RT->>MS : 上传CSV/文本至S3 +MS-->>RT : 返回S3 Key +end +else 删除 +RT->>ES : 从搜索引擎删除文档 +RT->>MD : 删除数据库记录 +end +RT-->>API : 返回响应 +API-->>FE : 渲染结果 +``` + +图表来源 +- [models.js:133-566](file://backend/src/routes/models.js#L133-L566) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [measurementStorage.js:61-108](file://backend/src/services/measurementStorage.js#L61-L108) +- [eqCacheStorage.js:24-66](file://backend/src/services/eqCacheStorage.js#L24-L66) +- [curveClient.js:81-138](file://backend/src/services/curveClient.js#L81-L138) +- [index.vue:714-1063](file://frontend/src/views/model/index.vue#L714-L1063) +- [model.js:13-151](file://frontend/src/api/model.js#L13-L151) + +## 详细组件分析 + +### 型号数据模型与品牌关联 +- 型号模型包含主键、品牌名称、型号名称、形式、阻抗、来源、EQ 键、创建时间等字段。 +- 品牌模型包含主键与唯一约束的品牌名称。 +- 关联关系:前端在新增型号时会检查品牌是否存在,若不存在则自动创建;后端在新增/更新时也通过品牌名称进行一致性校验。 + +```mermaid +erDiagram +BRAND { +int id PK +string name UK +} +MODEL { +int id PK +string brand_name +string name +string form +string rig +string source +string eq_key +datetime create_at +} +BRAND ||--o{ MODEL : "拥有多个型号" +``` + +图表来源 +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) + +章节来源 +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) + +### 型号验证器与参数规范 +- 创建验证器:要求品牌名称与型号名称非空且长度不超过 100;其他字段可选且可为空。 +- 更新验证器:允许部分字段可选更新,其余规则与创建一致。 +- 返回值:验证通过后进入业务流程,失败则返回错误信息。 + +章节来源 +- [model.js:1-22](file://backend/src/validators/model.js#L1-L22) + +### 型号 CRUD 与查询接口 +- 列表查询:支持按品牌名称、型号名称模糊过滤,支持按 id 或创建时间排序,支持分页与跳过。 +- 详情查看:按 id 获取单条型号信息。 +- 新增:支持上传频响文件(CSV/TXT/JSON),自动转换 TXT 为 CSV;若存在同品牌同型号则拒绝重复创建。 +- 更新:支持部分字段更新;若上传新文件,需提供来源与形式字段;更新后写入数据库并可重新上传频响文件。 +- 删除:删除前尝试从搜索引擎删除文档,再删除数据库记录。 + +章节来源 +- [models.js:133-566](file://backend/src/routes/models.js#L133-L566) + +### 技术规格管理 +- 形式字段:支持入耳式、头戴式、耳塞式等枚举值映射。 +- 阻抗字段:用于记录典型阻抗值。 +- 来源字段:标识型号数据来源(如 Eafonyoung)。 +- EQ 键字段:用于关联 EQ 缓存的键名。 + +章节来源 +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [index.vue:226-250](file://frontend/src/views/model/index.vue#L226-L250) + +### 测量数据存储与检索 +- 文件类型:支持 CSV、TXT、JSON;TXT 将被转换为 CSV。 +- 上传流程:后端接收 multipart/form-data,校验扩展名,必要时转换格式,然后上传至 S3。 +- 下载流程:仅对特定来源(如 Eafonyoung)开放,需具备形式字段以定位 S3 Key。 +- S3 Key 构造规则:按来源、形式、品牌首字母与品牌+型号文件名组织路径。 + +```mermaid +flowchart TD +Start(["上传入口"]) --> CheckExt["校验文件扩展名"] +CheckExt --> ExtOK{"扩展名有效?"} +ExtOK --> |否| ErrExt["返回错误:不支持的文件格式"] +ExtOK --> |是| Convert["如为TXT则转换为CSV"] +Convert --> BuildKey["构建S3 Key"] +BuildKey --> Put["上传至S3"] +Put --> Done(["完成"]) +ErrExt --> Done +``` + +图表来源 +- [models.js:59-68](file://backend/src/routes/models.js#L59-L68) +- [models.js:307-335](file://backend/src/routes/models.js#L307-L335) +- [measurementStorage.js:48-79](file://backend/src/services/measurementStorage.js#L48-L79) + +章节来源 +- [models.js:59-68](file://backend/src/routes/models.js#L59-L68) +- [models.js:307-335](file://backend/src/routes/models.js#L307-L335) +- [measurementStorage.js:48-79](file://backend/src/services/measurementStorage.js#L48-L79) + +### EQ 缓存与频响 CSV 查看 +- EQ 缓存:通过 Redis 哈希存储型号的 EQ 数据,提供字段列表与单字段值读取。 +- 频响 CSV:仅对特定来源开放,按来源、形式、品牌、型号拼接 S3 Key 并读取内容。 + +章节来源 +- [models.js:183-278](file://backend/src/routes/models.js#L183-L278) +- [eqCacheStorage.js:24-66](file://backend/src/services/eqCacheStorage.js#L24-L66) +- [measurementStorage.js:87-108](file://backend/src/services/measurementStorage.js#L87-L108) + +### 搜索引擎推送与校验 +- 校验:对选中型号调用曲线校验服务,确保 parametric_eq 结构有效。 +- 推送:将型号文档推送到搜索引擎,支持批量与进度反馈。 + +```mermaid +sequenceDiagram +participant FE as "前端" +participant API as "API 客户端" +participant RT as "后端路由(models.js)" +participant CS as "曲线校验(curveClient.js)" +FE->>API : 选择型号并点击推送 +API->>RT : POST /models/push-to-search/validate +loop 对每个型号 +RT->>CS : fetchAndValidateCurve(brand,name,form) +CS-->>RT : [ok, reason] +end +alt 全部通过 +API->>RT : POST /models/push-to-search +RT-->>API : 返回推送结果 +else 部分失败 +RT-->>API : 返回错误列表 +end +``` + +图表来源 +- [models.js:466-514](file://backend/src/routes/models.js#L466-L514) +- [models.js:516-566](file://backend/src/routes/models.js#L516-L566) +- [curveClient.js:81-138](file://backend/src/services/curveClient.js#L81-L138) +- [index.vue:1117-1220](file://frontend/src/views/model/index.vue#L1117-L1220) + +章节来源 +- [models.js:466-514](file://backend/src/routes/models.js#L466-L514) +- [models.js:516-566](file://backend/src/routes/models.js#L516-L566) +- [curveClient.js:81-138](file://backend/src/services/curveClient.js#L81-L138) +- [index.vue:1117-1220](file://frontend/src/views/model/index.vue#L1117-L1220) + +### 前端交互与使用示例 +- 列表查询:支持品牌名称与型号名称模糊搜索、排序与分页。 +- 详情查看:点击更多操作可查看推送状态、EQ 缓存、CSV 内容。 +- 参数配置:新增/编辑对话框支持品牌选择、型号输入、形式、阻抗、来源与频响文件上传。 +- 批量推送:勾选多条后执行推送流程,包含校验与进度提示。 + +章节来源 +- [index.vue:1-1226](file://frontend/src/views/model/index.vue#L1-L1226) +- [model.js:1-151](file://frontend/src/api/model.js#L1-L151) + +## 依赖关系分析 +- 前端依赖:Element Plus 组件库、Vue 3、axios 请求封装。 +- 后端依赖:Express 路由、Sequelize ORM、Zod 验证、Multer 文件上传、Axios 第三方调用、AWS SDK S3 访问、Redis 客户端。 +- 外部服务:Meilisearch(搜索引擎)、Luxsin 曲线 API、S3 存储。 + +```mermaid +graph LR +FE["前端(index.vue)"] --> API["API(model.js)"] +API --> RT["路由(models.js)"] +RT --> MD["模型(Model.js)"] +RT --> VAL["验证器(model.js)"] +RT --> MS["S3(measurementStorage.js)"] +RT --> ES["Redis(eqCacheStorage.js)"] +RT --> CS["曲线(curveClient.js)"] +RT --> BR["品牌(Brand.js)"] +``` + +图表来源 +- [index.vue:1-1226](file://frontend/src/views/model/index.vue#L1-L1226) +- [model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [model.js:1-22](file://backend/src/validators/model.js#L1-L22) +- [measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [curveClient.js:1-147](file://backend/src/services/curveClient.js#L1-L147) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +章节来源 +- [index.vue:1-1226](file://frontend/src/views/model/index.vue#L1-L1226) +- [model.js:1-151](file://frontend/src/api/model.js#L1-L151) +- [models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [Model.js:1-53](file://backend/src/models/Model.js#L1-L53) +- [model.js:1-22](file://backend/src/validators/model.js#L1-L22) +- [measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [curveClient.js:1-147](file://backend/src/services/curveClient.js#L1-L147) +- [Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +## 性能考虑 +- 分页与排序:列表查询支持分页与排序,建议前端设置合理页大小与排序字段,避免一次性加载过多数据。 +- 文件上传:上传 TXT 时会进行转换,建议控制文件大小与格式,减少不必要的转换开销。 +- 搜索推送:批量推送包含校验步骤,建议分批处理并监控进度,避免超时。 +- 缓存与存储:EQ 缓存通过 Redis 快速读取字段列表,避免大对象传输;S3 读取采用流式读取,注意网络抖动与超时配置。 + +## 故障排查指南 +- 参数验证失败 + - 现象:创建/更新返回参数错误。 + - 排查:检查品牌名称与型号名称长度、必填字段是否缺失;确认前端表单规则与后端验证器一致。 + - 参考 + - [model.js:3-19](file://backend/src/validators/model.js#L3-L19) + - [models.js:307-361](file://backend/src/routes/models.js#L307-L361) +- 重复型号 + - 现象:新增时报“该品牌下型号名称已存在”。 + - 排查:确认数据库中是否已存在相同品牌+型号组合;更新时注意品牌与型号变更后的冲突检测。 + - 参考 + - [models.js:312-317](file://backend/src/routes/models.js#L312-L317) + - [models.js:380-388](file://backend/src/routes/models.js#L380-L388) +- 不支持的文件格式 + - 现象:上传文件返回“不支持的文件格式”。 + - 排查:确认扩展名为 CSV/TXT/JSON;TXT 会被转换为 CSV。 + - 参考 + - [models.js:320-325](file://backend/src/routes/models.js#L320-L325) + - [models.js:59-68](file://backend/src/routes/models.js#L59-L68) +- S3 读取失败 + - 现象:查看 CSV 时提示“S3 上未找到该型号的频响文件”或读取失败。 + - 排查:确认来源为 Eafonyoung、具备形式字段、S3 Key 构造正确;检查桶权限与区域配置。 + - 参考 + - [models.js:255-258](file://backend/src/routes/models.js#L255-L258) + - [measurementStorage.js:87-108](file://backend/src/services/measurementStorage.js#L87-L108) +- 推送失败 + - 现象:推送至搜索引擎失败或校验未通过。 + - 排查:检查型号的佩戴方式是否为入耳式或头戴式;确认曲线接口可用与响应格式正确。 + - 参考 + - [models.js:466-514](file://backend/src/routes/models.js#L466-L514) + - [curveClient.js:81-138](file://backend/src/services/curveClient.js#L81-L138) + +章节来源 +- [model.js:3-19](file://backend/src/validators/model.js#L3-L19) +- [models.js:312-317](file://backend/src/routes/models.js#L312-L317) +- [models.js:320-325](file://backend/src/routes/models.js#L320-L325) +- [models.js:255-258](file://backend/src/routes/models.js#L255-L258) +- [measurementStorage.js:87-108](file://backend/src/services/measurementStorage.js#L87-L108) +- [models.js:466-514](file://backend/src/routes/models.js#L466-L514) +- [curveClient.js:81-138](file://backend/src/services/curveClient.js#L81-L138) + +## 结论 +型号管理功能通过清晰的前后端职责划分与严格的参数验证,实现了从基础 CRUD 到技术规格管理、测量数据存储与搜索引擎推送的完整闭环。借助 Redis 与 S3 的高效读写能力,以及第三方曲线校验服务,系统在保证数据一致性的同时提升了用户体验与可维护性。建议在生产环境中进一步完善日志与监控,优化批量推送的并发与重试策略,并持续关注外部依赖的稳定性。 + +## 附录 +- 常用接口清单 + - 列表查询:GET /api/models/ + - 详情查看:GET /api/models/:id + - 新增:POST /api/models/ + - 更新:PUT /api/models/:id + - 删除:DELETE /api/models/:id + - 查看 EQ 缓存:GET /api/models/:id/eq-cache + - 查看 EQ 缓存字段:GET /api/models/:id/eq-cache/field?key=... + - 查看搜索引擎推送:GET /api/models/:id/meilisearch + - 查看频响 CSV:GET /api/models/:id/measurement + - 校验推送:POST /api/models/push-to-search/validate + - 推送:POST /api/models/push-to-search + +章节来源 +- [models.js:133-566](file://backend/src/routes/models.js#L133-L566) +- [model.js:13-151](file://frontend/src/api/model.js#L13-L151) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/核心功能模块/核心功能模块.md b/.qoder/repowiki/zh/content/核心功能模块/核心功能模块.md new file mode 100644 index 0000000..c9470f1 --- /dev/null +++ b/.qoder/repowiki/zh/content/核心功能模块/核心功能模块.md @@ -0,0 +1,476 @@ +# 核心功能模块 + + +**本文引用的文件** +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) +- [backend/src/models/index.js](file://backend/src/models/index.js) +- [backend/src/models/DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [backend/src/models/Brand.js](file://backend/src/models/Brand.js) +- [backend/src/models/Model.js](file://backend/src/models/Model.js) +- [backend/src/models/Ota.js](file://backend/src/models/Ota.js) +- [backend/src/models/ShareCodeLog.js](file://backend/src/models/ShareCodeLog.js) +- [backend/src/routes/auth.js](file://backend/src/routes/auth.js) +- [backend/src/routes/brands.js](file://backend/src/routes/brands.js) +- [backend/src/routes/models.js](file://backend/src/routes/models.js) +- [backend/src/routes/ota.js](file://backend/src/routes/ota.js) +- [backend/src/routes/shareCodeLogs.js](file://backend/src/routes/shareCodeLogs.js) +- [backend/src/services/curveClient.js](file://backend/src/services/curveClient.js) +- [backend/src/services/measurementStorage.js](file://backend/src/services/measurementStorage.js) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [backend/src/services/otaStorage.js](file://backend/src/services/otaStorage.js) +- [backend/src/validators/ota.js](file://backend/src/validators/ota.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [frontend/src/utils/auth.js](file://frontend/src/utils/auth.js) +- [frontend/src/views/brand/index.vue](file://frontend/src/views/brand/index.vue) +- [frontend/src/views/model/index.vue](file://frontend/src/views/model/index.vue) +- [frontend/src/views/ota/index.vue](file://frontend/src/views/ota/index.vue) +- [frontend/src/views/share-code/log.vue](file://frontend/src/views/share-code/log.vue) +- [frontend/src/views/system/users/index.vue](file://frontend/src/views/system/users/index.vue) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件聚焦于 Dashboard 后端与前端的核心功能模块,系统性阐述用户认证、品牌管理、型号管理、OTA 固件管理、用户权限管理以及分享码日志管理的实现原理、调用关系、接口定义、领域模型与使用模式。文档同时给出配置项、参数与返回值说明,解释前后端交互与各模块间的耦合关系,并提供常见问题与排障建议。 + +## 项目结构 +后端采用 Express + Sequelize 架构,路由按功能域拆分,中间件统一处理鉴权与请求体限制,模型定义集中在 models 目录并通过入口聚合导出。前端基于 Vue Router 实现页面级权限控制与导航。 + +```mermaid +graph TB +subgraph "后端" +APP["应用入口
backend/src/app.js"] +ROUTES_IDX["路由汇总
backend/src/routes/index.js"] +AUTH_MW["鉴权中间件
backend/src/middleware/auth.js"] +MODELS_IDX["模型聚合
backend/src/models/index.js"] +MODELS["模型定义
Brand/Model/Ota/ShareCodeLog/DashboardUser"] +ROUTERS["功能路由
auth/brands/models/ota/shareCodeLogs"] +SERVICES["服务层
curveClient/measurementStorage/eqCacheStorage/otaStorage"] +VALIDATORS["参数校验
backend/src/validators/ota.js"] +end +subgraph "前端" +ROUTER["路由配置
frontend/src/router/index.js"] +VIEWS["页面视图
brand/model/ota/share-code/system/users"] +UTILS_AUTH["前端鉴权工具
frontend/src/utils/auth.js"] +end +APP --> ROUTES_IDX --> ROUTERS +ROUTERS --> AUTH_MW +ROUTERS --> MODELS +ROUTERS --> SERVICES +ROUTERS --> VALIDATORS +MODELS --> MODELS_IDX +ROUTER --> VIEWS +ROUTER --> UTILS_AUTH +``` + +图表来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 核心组件 +- 用户认证与权限 + - 后端通过 JWT 进行身份签发与校验,提供登录、获取当前用户、修改密码接口,并在路由层统一挂载鉴权中间件。 + - 前端路由守卫根据 Token 与角色(超级管理员)决定页面访问权限。 +- 品牌管理 + - 提供品牌列表、详情、创建、更新、删除接口,支持模糊搜索与分页。 +- 型号管理 + - 支持型号增删改查、频响文件上传(CSV/TXT/JSON)、S3 存储、Meilisearch 推送与校验、Redis EQ 缓存读取。 +- OTA 固件管理 + - 支持 X8/X9 设备固件包上传(S3 或本地),设备端“最新版本检查”接口,后台管理列表与编辑。 +- 分享码日志管理 + - 提供分享码导出/导入日志的查询接口,支持多维过滤与排序。 +- 权限模型 + - DashboardUser 模型包含用户名、密码哈希、超级管理员标识与状态;路由中间件提供 requireSuperAdmin 守卫。 + +章节来源 +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [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/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) + +## 架构总览 +后端启动流程:加载环境变量 → 初始化 Express 应用 → 注册 CORS、JSON 解析、Body 限制中间件 → 注册路由 → 同步数据库并创建超级管理员 → 启动 HTTP 服务。前端路由守卫在进入受保护页面前校验 Token 与角色。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Front as "前端路由" +participant AuthAPI as "后端认证路由" +participant JWT as "JWT 工具" +participant DB as "数据库" +Client->>Front : 访问受保护页面 +Front->>Front : 校验 Token 与角色 +alt Token 缺失/过期 +Front-->>Client : 重定向到登录页 +else 已登录 +Front->>AuthAPI : 请求 /api/auth/me +AuthAPI->>DB : 查询用户信息 +DB-->>AuthAPI : 返回用户记录 +AuthAPI-->>Front : 返回用户信息 +Front-->>Client : 渲染目标页面 +end +``` + +图表来源 +- [backend/src/routes/auth.js:66-77](file://backend/src/routes/auth.js#L66-L77) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) + +章节来源 +- [backend/src/app.js:42-59](file://backend/src/app.js#L42-L59) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 详细组件分析 + +### 用户认证系统 +- 登录流程 + - 前端提交用户名与密码,后端校验账号是否存在且启用,验证密码哈希,更新最近登录时间,签发 Access Token 并返回用户信息。 +- 当前用户 + - 需携带有效 Token 调用“获取当前用户”,后端返回用户基础信息。 +- 修改密码 + - 需携带有效 Token,校验旧密码,长度不少于 6 位,成功后更新密码哈希。 +- 鉴权中间件 + - 从 Authorization 头解析 Bearer Token,解码后注入 req.user(包含 id、username、is_super_admin),异常时返回 401/403。 +- 前端路由守卫 + - 在进入受保护路由前检查 Token 是否存在与未过期;若目标页面要求超级管理员,则进一步校验角色。 + +```mermaid +sequenceDiagram +participant FE as "前端" +participant AuthR as "认证路由" +participant MW as "鉴权中间件" +participant JWTU as "JWT 工具" +participant PWD as "密码工具" +participant DB as "数据库" +FE->>AuthR : POST /api/auth/login +AuthR->>DB : 查询用户 +DB-->>AuthR : 用户记录 +AuthR->>PWD : 校验密码 +PWD-->>AuthR : 校验结果 +AuthR->>JWTU : 生成 Access Token +JWTU-->>AuthR : Token +AuthR-->>FE : {access_token, user} +FE->>AuthR : GET /api/auth/me (携带 Token) +AuthR->>MW : 中间件校验 +MW->>JWTU : 解码 Token +JWTU-->>MW : Payload +MW-->>AuthR : 注入 req.user +AuthR->>DB : 查询用户 +DB-->>AuthR : 用户信息 +AuthR-->>FE : 用户信息 +``` + +图表来源 +- [backend/src/routes/auth.js:24-77](file://backend/src/routes/auth.js#L24-L77) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) + +章节来源 +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) + +### 品牌管理 +- 功能点 + - 列表查询:支持按名称模糊搜索、分页(skip/limit,最大 1000)。 + - 详情查询:按 ID 获取品牌。 + - 创建:名称必填且唯一。 + - 更新:名称必填且唯一(排除自身 ID)。 + - 删除:级联删除。 +- 关键参数 + - 查询:name、skip、limit。 + - 新增/更新:name。 +- 返回值 + - 统一 ApiResponse 包裹,成功时返回 items/total/skip/limit 或单项数据。 + +```mermaid +flowchart TD +Start(["发起请求"]) --> Parse["解析查询参数
name/skip/limit"] +Parse --> BuildWhere["构建查询条件"] +BuildWhere --> Find["findAndCountAll/findByPk"] +Find --> Found{"是否找到数据?"} +Found -- 否 --> NoData["返回 noData(empty)"] +Found -- 是 --> Map["映射为 {id,name}"] +Map --> Success["返回 success(items,total,skip,limit)"] +NoData --> End(["结束"]) +Success --> End +``` + +图表来源 +- [backend/src/routes/brands.js:14-40](file://backend/src/routes/brands.js#L14-L40) +- [backend/src/routes/brands.js:42-57](file://backend/src/routes/brands.js#L42-L57) +- [backend/src/routes/brands.js:59-81](file://backend/src/routes/brands.js#L59-L81) +- [backend/src/routes/brands.js:83-123](file://backend/src/routes/brands.js#L83-L123) +- [backend/src/routes/brands.js:125-144](file://backend/src/routes/brands.js#L125-L144) + +章节来源 +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) + +### 型号管理 +- 功能点 + - 列表查询:支持按品牌名/型号名模糊搜索、排序(id/create_at asc/desc)。 + - 详情查询:按 ID 获取型号。 + - 创建:支持上传频响文件(CSV/TXT/JSON),TXT 自动转换为 CSV;S3 保存;写入数据库。 + - 更新:支持上传新频响文件;字段可部分更新;名称组合唯一性校验。 + - 删除:先从 Meilisearch 删除文档,再删除数据库记录。 + - Meilisearch 集成:提供校验与推送接口,支持批量校验与推送。 + - EQ 缓存:读取 Redis 中指定型号的缓存键与字段值。 + - 测量数据:仅允许查看来源为特定值的型号的 S3 CSV 内容。 +- 关键参数 + - 查询:brand_name、name、sort_by、sort_order、skip、limit。 + - 创建/更新:brand_name、name、form、rig、source、eq_key、measurement_file。 + - Meilisearch:model_id。 + - EQ 缓存:model_id、key。 + - S3:model_id。 +- 返回值 + - 统一 ApiResponse 包裹,成功时返回 items/total/skip/limit、单条记录或任务信息。 + +```mermaid +sequenceDiagram +participant FE as "前端" +participant ModelR as "型号路由" +participant S3 as "测量存储服务" +participant MS as "Meilisearch" +participant EC as "EQ 缓存服务" +participant DB as "数据库" +FE->>ModelR : POST /api/models/ (multipart/form-data) +ModelR->>S3 : 上传频响文件至 S3 +S3-->>ModelR : 返回 S3 Key +ModelR->>DB : 写入型号记录 +DB-->>ModelR : 返回新建记录 +ModelR-->>FE : 返回新建型号信息 +FE->>ModelR : GET /api/models/ : model_id/meilisearch +ModelR->>MS : 查询文档 +MS-->>ModelR : 文档或 404 +ModelR-->>FE : 返回 pushed/document +FE->>ModelR : GET /api/models/ : model_id/eq-cache/field?key=... +ModelR->>EC : 读取字段值 +EC-->>ModelR : 字段值 +ModelR-->>FE : 返回字段值 +``` + +图表来源 +- [backend/src/routes/models.js:307-361](file://backend/src/routes/models.js#L307-L361) +- [backend/src/routes/models.js:225-244](file://backend/src/routes/models.js#L225-L244) +- [backend/src/routes/models.js:183-223](file://backend/src/routes/models.js#L183-L223) +- [backend/src/services/measurementStorage.js](file://backend/src/services/measurementStorage.js) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [backend/src/services/curveClient.js](file://backend/src/services/curveClient.js) + +章节来源 +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) + +### OTA 固件管理 +- 功能点 + - 设备端“最新版本检查”:无需登录,按当前版本号、设备型号与硬件版本筛选可用升级包。 + - 后台上传固件包:支持 X8(S3)、X9(本地);自动计算 MD5,返回下载地址与存储键。 + - 后台管理:列表查询、详情、创建、更新(版本号+型号唯一性校验)、删除。 +- 关键参数 + - 最新版本检查:currentVerCode、model、hw。 + - 上传:model、package_file。 + - 列表:verCode、verName、model、status、skip、limit。 + - 创建/更新:verCode、verName、url、md5、force、desc、model、hw、target、beta、startTime、endTime、status。 +- 返回值 + - 统一 ApiResponse 包裹,成功时返回列表、单条记录或上传结果。 + +```mermaid +sequenceDiagram +participant Device as "设备端" +participant OTAR as "OTA 路由" +participant DB as "数据库" +participant OtaSvc as "OTA 存储服务" +Device->>OTAR : GET /api/ota/latest/check?currentVerCode&model&hw +OTAR->>DB : 查询可用升级包 +DB-->>OTAR : 返回最新记录 +OTAR-->>Device : 返回升级包信息 +Admin->>OTAR : POST /api/ota/upload-package +OTAR->>OtaSvc : 校验并保存升级包 +OtaSvc-->>OTAR : 返回 md5/filename/url/s3_key +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/services/otaStorage.js](file://backend/src/services/otaStorage.js) + +章节来源 +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) + +### 用户权限管理 +- 角色模型 + - DashboardUser 模型包含 is_super_admin 字段用于区分超级管理员。 +- 路由守卫 + - authMiddleware:校验 Token 并注入用户信息。 + - requireSuperAdmin:仅超级管理员可访问。 +- 前端页面守卫 + - 路由 meta.requiresSuperAdmin 控制页面是否仅超级管理员可见。 + +```mermaid +flowchart TD +Enter["进入受保护路由"] --> CheckAuth{"是否需要登录?"} +CheckAuth -- 是 --> TokenCheck["校验 Token 与过期"] +TokenCheck --> RoleCheck{"是否需要超级管理员?"} +RoleCheck -- 是 --> SuperAdminCheck["校验 is_super_admin"] +SuperAdminCheck --> Allowed["放行"] +RoleCheck -- 否 --> Allowed +TokenCheck --> |失败| Redirect["重定向到登录页"] +CheckAuth -- 否 --> Allowed +``` + +图表来源 +- [backend/src/middleware/auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) +- [frontend/src/router/index.js:75-79](file://frontend/src/router/index.js#L75-L79) + +章节来源 +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +### 分享码日志管理 +- 功能点 + - 列表查询:支持按 MAC 地址、分享码、操作类型(export/import)、IP 地址、时间范围过滤与排序。 +- 关键参数 + - 查询:mac_addr、share_code、action、ip_addr、start_at、end_at、sort_by、sort_order、skip、limit。 +- 返回值 + - 统一 ApiResponse 包裹,成功时返回 items/total/skip/limit。 + +```mermaid +flowchart TD +Start(["发起请求"]) --> Parse["解析查询参数
mac_addr/share_code/action/ip_addr/start_at/end_at"] +Parse --> BuildWhere["构建 where 条件"] +BuildWhere --> Sort["设置排序字段与方向"] +Sort --> Paginate["分页 skip/limit"] +Paginate --> Query["查询总数与列表"] +Query --> Found{"是否有数据?"} +Found -- 否 --> NoData["返回 noData(empty)"] +Found -- 是 --> Map["映射字段"] +Map --> Success["返回 success(items,total,skip,limit)"] +NoData --> End(["结束"]) +Success --> End +``` + +图表来源 +- [backend/src/routes/shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) + +章节来源 +- [backend/src/routes/shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) + +## 依赖分析 +- 组件耦合 + - 路由层依赖中间件(鉴权)、模型(Sequelize)、服务层(存储/缓存/外部服务)、验证器(Zod)与响应封装。 + - 前端路由依赖鉴权工具与页面视图,页面视图通过 API 适配器与后端交互。 +- 外部依赖 + - 数据库:MySQL/PostgreSQL(通过 Sequelize)。 + - 存储:S3(对象存储)、本地文件系统(X9 包)。 + - 搜索:Meilisearch。 + - 缓存:Redis(EQ 缓存)。 +- 循环依赖 + - 未见明显循环依赖;路由通过中间件与模型解耦。 + +```mermaid +graph LR +Routes["路由层"] --> MW["鉴权中间件"] +Routes --> Models["模型层"] +Routes --> Services["服务层"] +Routes --> Validators["验证器"] +FrontRoutes["前端路由"] --> Views["页面视图"] +Views --> APIs["API 适配器"] +Services --> Storage["S3/本地"] +Services --> Search["Meilisearch"] +Services --> Cache["Redis"] +``` + +图表来源 +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +章节来源 +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 性能考虑 +- 分页与限制 + - 列表接口统一限制每页最大数量,避免一次性返回过多数据。 +- 查询优化 + - 型号与分享码日志模型建立索引(如 mac_addr、share_code、create_at),提升过滤查询性能。 +- 外部服务超时 + - Meilisearch 请求设置超时,防止阻塞。 +- 缓存利用 + - EQ 缓存通过 Redis 减少重复计算与数据库压力。 +- 文件上传 + - 使用内存存储配合 Multer,大文件场景建议调整策略或引入流式处理。 + +## 故障排查指南 +- 登录失败 + - 检查用户名/密码是否为空、账号是否存在且启用、密码哈希是否匹配。 +- Token 相关 + - 401 未登录/无效凭证:确认 Authorization 头格式与签名有效性;检查过期时间。 + - 403 需要超级管理员权限:确认 is_super_admin 标记。 +- 品牌/型号操作 + - 名称唯一性冲突:确保品牌名或型号组合唯一。 + - 文件格式不支持:仅允许 CSV/TXT/JSON,TXT 将被自动转换为 CSV。 +- OTA 上传 + - 仅支持指定设备型号;S3 未配置或上传失败会返回明确错误。 +- Meilisearch 集成 + - 推送/删除失败:检查服务可达性与 API Key;关注返回的任务 UID。 +- 分享码日志 + - 时间范围查询:确保传入合法日期字符串。 + +章节来源 +- [backend/src/routes/auth.js:24-64](file://backend/src/routes/auth.js#L24-L64) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [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/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、校验与外部集成能力,适合在生产环境中稳定运行。建议持续完善监控与告警、日志分级与外部服务降级策略,以进一步提升稳定性与可观测性。 + +## 附录 +- 前端页面与路由对应关系 + - 品牌管理:/brand → [frontend/src/views/brand/index.vue](file://frontend/src/views/brand/index.vue) + - 型号管理:/model → [frontend/src/views/model/index.vue](file://frontend/src/views/model/index.vue) + - OTA 管理:/ota → [frontend/src/views/ota/index.vue](file://frontend/src/views/ota/index.vue) + - 分享日志:/share-code/log → [frontend/src/views/share-code/log.vue](file://frontend/src/views/share-code/log.vue) + - 账号管理(超级管理员):/system/users → [frontend/src/views/system/users/index.vue](file://frontend/src/views/system/users/index.vue) + +章节来源 +- [frontend/src/router/index.js:26-54](file://frontend/src/router/index.js#L26-L54) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/核心功能模块/用户权限管理.md b/.qoder/repowiki/zh/content/核心功能模块/用户权限管理.md new file mode 100644 index 0000000..a24c71e --- /dev/null +++ b/.qoder/repowiki/zh/content/核心功能模块/用户权限管理.md @@ -0,0 +1,462 @@ +# 用户权限管理 + + +**本文档引用的文件** +- [DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [users.js](file://backend/src/routes/users.js) +- [auth.js](file://backend/src/middleware/auth.js) +- [userBootstrap.js](file://backend/src/services/userBootstrap.js) +- [index.vue](file://frontend/src/views/system/users/index.vue) +- [user.js](file://frontend/src/api/user.js) +- [auth.js](file://frontend/src/utils/auth.js) +- [jwt.js](file://backend/src/utils/jwt.js) +- [password.js](file://backend/src/utils/password.js) +- [response.js](file://backend/src/utils/response.js) +- [app.js](file://backend/src/app.js) +- [env.js](file://backend/src/config/env.js) +- [database.js](file://backend/src/config/database.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +本项目是一个基于 Node.js 和 Vue.js 的仪表板管理系统,专注于用户权限管理功能。系统实现了完整的用户生命周期管理,包括用户创建、权限分配、状态控制等功能,并提供了超级管理员权限验证机制。 + +系统采用前后端分离架构,后端使用 Express.js 提供 RESTful API,前端使用 Vue.js 构建用户界面。用户权限管理功能通过 JWT 令牌进行身份验证和授权控制,确保只有具备相应权限的用户才能访问特定资源。 + +## 项目结构 + +系统采用模块化的项目结构,主要分为以下层次: + +```mermaid +graph TB +subgraph "前端层" +FE_API[API 层] +FE_VIEW[视图层] +FE_UTILS[工具层] +end +subgraph "后端层" +BE_APP[应用入口] +BE_ROUTES[路由层] +BE_MIDDLEWARE[中间件层] +BE_MODELS[数据模型层] +BE_SERVICES[服务层] +BE_UTILS[工具层] +end +subgraph "基础设施" +DB[(MySQL 数据库)] +CONFIG[配置管理] +end +FE_API --> BE_ROUTES +FE_VIEW --> FE_API +FE_UTILS --> FE_API +BE_APP --> BE_ROUTES +BE_ROUTES --> BE_MIDDLEWARE +BE_ROUTES --> BE_MODELS +BE_MIDDLEWARE --> BE_MODELS +BE_SERVICES --> BE_MODELS +BE_UTILS --> BE_MODELS +BE_MODELS --> DB +BE_APP --> CONFIG +``` + +**图表来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [users.js:1-180](file://backend/src/routes/users.js#L1-L180) + +**章节来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) +- [env.js:1-13](file://backend/src/config/env.js#L1-L13) + +## 核心组件 + +### 用户模型设计 + +系统的核心是 `DashboardUser` 模型,定义了用户的基本属性和约束条件: + +```mermaid +classDiagram +class DashboardUser { ++Integer id ++String username ++String password_hash ++TinyInt is_super_admin ++TinyInt status ++Date last_login_at ++Date create_at ++Date update_at +} +class UserModelConstraints { ++UNIQUE(username) ++DEFAULT(is_super_admin) = 0 ++DEFAULT(status) = 1 ++DEFAULT(create_at) = NOW() ++DEFAULT(update_at) = NOW() +} +DashboardUser --> UserModelConstraints : "遵循" +``` + +**图表来源** +- [DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54) + +### 权限验证机制 + +系统实现了两级权限验证机制: + +1. **基础认证中间件**:验证 JWT 令牌的有效性 +2. **超级管理员权限**:额外的权限检查 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant AuthMW as 认证中间件 +participant SuperAdminMW as 超级管理员中间件 +participant Controller as 控制器 +Client->>AuthMW : 发送带 Authorization 头的请求 +AuthMW->>AuthMW : 验证 JWT 令牌格式 +AuthMW->>AuthMW : 解码令牌负载 +AuthMW->>SuperAdminMW : 传递用户上下文 +SuperAdminMW->>SuperAdminMW : 检查 is_super_admin 标志 +SuperAdminMW->>Controller : 验证通过,继续执行 +Controller-->>Client : 返回响应 +``` + +**图表来源** +- [auth.js:3-33](file://backend/src/middleware/auth.js#L3-L33) + +**章节来源** +- [DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +## 架构概览 + +系统采用分层架构设计,确保关注点分离和代码可维护性: + +```mermaid +graph TD +subgraph "表现层" +UI[Vue.js 前端界面] +API[HTTP API 调用] +end +subgraph "应用层" +AUTH[认证服务] +USER[用户管理服务] +ROUTES[路由处理] +end +subgraph "数据层" +MODEL[用户模型] +DB[(MySQL 数据库)] +end +subgraph "基础设施" +JWT[JWT 令牌] +PASS[密码加密] +RESP[响应格式] +end +UI --> API +API --> ROUTES +ROUTES --> AUTH +ROUTES --> USER +AUTH --> JWT +USER --> PASS +USER --> MODEL +MODEL --> DB +AUTH --> RESP +USER --> RESP +``` + +**图表来源** +- [app.js:14-57](file://backend/src/app.js#L14-L57) +- [users.js:1-180](file://backend/src/routes/users.js#L1-L180) + +## 详细组件分析 + +### 用户管理路由系统 + +用户管理功能通过专门的路由模块实现,支持完整的 CRUD 操作: + +```mermaid +flowchart TD +Start([请求进入]) --> AuthCheck[认证中间件] +AuthCheck --> SuperAdminCheck[超级管理员检查] +SuperAdminCheck --> RouteType{路由类型} +RouteType --> |GET| ListUsers[获取用户列表] +RouteType --> |POST| CreateUser[创建用户] +RouteType --> |PUT| UpdateUser[更新用户] +RouteType --> |DELETE| DeleteUser[删除用户] +ListUsers --> ValidateParams[验证查询参数] +ValidateParams --> QueryDB[查询数据库] +QueryDB --> FormatResponse[格式化响应] +CreateUser --> ValidateCreate[验证创建参数] +ValidateCreate --> CheckDuplicate[检查重复用户名] +CheckDuplicate --> HashPassword[密码哈希] +HashPassword --> SaveUser[保存用户] +SaveUser --> FormatResponse +UpdateUser --> ValidateUpdate[验证更新参数] +ValidateUpdate --> CheckSuperAdmin[检查超级管理员限制] +CheckSuperAdmin --> UpdateDB[更新数据库] +UpdateDB --> FormatResponse +DeleteUser --> ValidateDelete[验证删除参数] +ValidateDelete --> CheckSuperAdminDel[检查最后超级管理员] +CheckSuperAdminDel --> DestroyUser[删除用户] +DestroyUser --> FormatResponse +FormatResponse --> End([返回响应]) +``` + +**图表来源** +- [users.js:35-177](file://backend/src/routes/users.js#L35-L177) + +#### 用户列表管理 + +用户列表功能支持分页查询、模糊搜索和状态过滤: + +**章节来源** +- [users.js:35-61](file://backend/src/routes/users.js#L35-L61) + +#### 权限分配机制 + +系统实现了灵活的权限分配机制,支持超级管理员角色的动态分配: + +**章节来源** +- [users.js:100-147](file://backend/src/routes/users.js#L100-L147) + +#### 用户状态控制 + +用户状态控制确保系统安全性和完整性: + +**章节来源** +- [users.js:149-177](file://backend/src/routes/users.js#L149-L177) + +### 前端用户界面 + +前端使用 Element Plus 组件库构建用户管理界面: + +```mermaid +graph LR +subgraph "用户界面组件" +Search[搜索表单] +Table[用户表格] +Pagination[分页控件] +Dialog[对话框] +end +subgraph "交互流程" +LoadData[加载数据] +SearchAction[搜索操作] +CreateAction[创建操作] +UpdateAction[更新操作] +DeleteAction[删除操作] +end +Search --> LoadData +Table --> Pagination +Table --> Dialog +Dialog --> CreateAction +Dialog --> UpdateAction +Dialog --> DeleteAction +SearchAction --> LoadData +CreateAction --> LoadData +UpdateAction --> LoadData +DeleteAction --> LoadData +``` + +**图表来源** +- [index.vue:1-428](file://frontend/src/views/system/users/index.vue#L1-L428) + +**章节来源** +- [index.vue:1-428](file://frontend/src/views/system/users/index.vue#L1-L428) + +### 超级管理员权限验证 + +系统实现了严格的超级管理员权限控制,防止权限滥用: + +```mermaid +sequenceDiagram +participant Admin as 超级管理员 +participant System as 系统 +participant DB as 数据库 +Admin->>System : 尝试执行敏感操作 +System->>DB : 查询其他超级管理员数量 +DB-->>System : 返回超级管理员数量 +alt 最后一个超级管理员 +System-->>Admin : 拒绝操作 +else 存在其他超级管理员 +System->>DB : 执行操作 +DB-->>System : 操作成功 +System-->>Admin : 返回成功响应 +end +``` + +**图表来源** +- [users.js:123-128](file://backend/src/routes/users.js#L123-L128) + +**章节来源** +- [users.js:27-33](file://backend/src/routes/users.js#L27-L33) + +### 用户引导初始化 + +系统提供了自动化的用户引导初始化功能: + +**章节来源** +- [userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) + +## 依赖关系分析 + +系统各组件之间的依赖关系如下: + +```mermaid +graph TB +subgraph "外部依赖" +JWT[jwt-nodejs] +SEQUELIZE[sequelize] +EXPRESS[express] +MYSQL[mysql2] +end +subgraph "内部模块" +AUTH_MW[auth.js] +USER_MODEL[DashboardUser.js] +USER_ROUTE[users.js] +PASSWORD_UTIL[password.js] +RESPONSE_UTIL[response.js] +JWT_UTIL[jwt.js] +BOOTSTRAP[userBootstrap.js] +end +AUTH_MW --> JWT_UTIL +USER_ROUTE --> AUTH_MW +USER_ROUTE --> USER_MODEL +USER_ROUTE --> PASSWORD_UTIL +USER_ROUTE --> RESPONSE_UTIL +BOOTSTRAP --> USER_MODEL +BOOTSTRAP --> PASSWORD_UTIL +USER_MODEL --> SEQUELIZE +SEQUELIZE --> MYSQL +AUTH_MW --> JWT +USER_ROUTE --> EXPRESS +``` + +**图表来源** +- [auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [users.js:1-12](file://backend/src/routes/users.js#L1-L12) + +**章节来源** +- [app.js:1-60](file://backend/src/app.js#L1-L60) + +## 性能考虑 + +### 数据库优化 + +系统在数据库层面采用了多项优化策略: + +1. **索引设计**:用户名字段设置唯一索引,提高查询效率 +2. **分页查询**:默认限制每页最大记录数,防止内存溢出 +3. **批量操作**:支持批量用户状态更新 + +### 缓存策略 + +虽然当前版本未实现缓存,但系统设计支持后续添加缓存层: + +```mermaid +flowchart TD +Request[用户请求] --> CacheCheck{缓存命中?} +CacheCheck --> |是| ReturnCache[返回缓存数据] +CacheCheck --> |否| QueryDB[查询数据库] +QueryDB --> UpdateCache[更新缓存] +UpdateCache --> ReturnData[返回数据] +ReturnCache --> End([完成]) +ReturnData --> End +``` + +### 安全优化 + +1. **密码存储**:使用 PBKDF2 算法进行密码哈希 +2. **令牌管理**:JWT 令牌设置合理的过期时间 +3. **输入验证**:严格的参数验证和长度限制 + +## 故障排除指南 + +### 常见问题及解决方案 + +#### 1. 用户名重复错误 + +**问题描述**:创建用户时提示用户名已存在 + +**解决方案**: +- 检查用户名是否已被其他用户使用 +- 确保用户名唯一性约束 + +**章节来源** +- [users.js:80-83](file://backend/src/routes/users.js#L80-L83) + +#### 2. 密码长度验证失败 + +**问题描述**:密码长度不足 6 位 + +**解决方案**: +- 确保新密码至少 6 位字符 +- 检查密码强度要求 + +**章节来源** +- [users.js:76-78](file://backend/src/routes/users.js#L76-L78) + +#### 3. 超级管理员权限限制 + +**问题描述**:无法禁用或删除最后一个超级管理员 + +**解决方案**: +- 确保系统始终至少有一个超级管理员 +- 先提升其他用户的权限,再执行操作 + +**章节来源** +- [users.js:123-128](file://backend/src/routes/users.js#L123-L128) + +#### 4. 认证失败 + +**问题描述**:登录或 API 请求返回认证错误 + +**解决方案**: +- 检查 JWT 令牌格式和有效期 +- 验证用户状态是否为启用状态 + +**章节来源** +- [auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) + +### 调试技巧 + +1. **日志分析**:查看后端日志中的错误信息 +2. **网络监控**:使用浏览器开发者工具检查 API 响应 +3. **数据库检查**:验证用户表的数据完整性 + +## 结论 + +本用户权限管理系统提供了完整的企业级用户管理功能,具有以下特点: + +### 技术优势 + +1. **安全性**:采用 JWT 令牌认证和 PBKDF2 密码哈希 +2. **可扩展性**:模块化设计支持功能扩展 +3. **易用性**:直观的前端界面和清晰的 API 设计 +4. **可靠性**:完善的错误处理和数据验证机制 + +### 功能特性 + +- 完整的用户生命周期管理 +- 灵活的权限分配机制 +- 严格的状态控制和审计 +- 自动化的用户引导初始化 +- 响应式的前端界面 + +### 改进建议 + +1. **添加权限继承机制**:支持基于角色的权限继承 +2. **实现操作审计日志**:记录所有用户管理操作 +3. **增加多因素认证**:提升账户安全性 +4. **优化前端性能**:实现虚拟滚动和懒加载 + +该系统为类似的企业管理平台提供了良好的技术基础,可以根据具体需求进行定制和扩展。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/核心功能模块/用户认证系统.md b/.qoder/repowiki/zh/content/核心功能模块/用户认证系统.md new file mode 100644 index 0000000..706e549 --- /dev/null +++ b/.qoder/repowiki/zh/content/核心功能模块/用户认证系统.md @@ -0,0 +1,520 @@ +# 用户认证系统 + + +**本文档引用的文件** +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) +- [backend/src/routes/auth.js](file://backend/src/routes/auth.js) +- [backend/src/models/DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/services/userBootstrap.js](file://backend/src/services/userBootstrap.js) +- [frontend/src/utils/auth.js](file://frontend/src/utils/auth.js) +- [frontend/src/utils/request.js](file://frontend/src/utils/request.js) +- [frontend/src/api/auth.js](file://frontend/src/api/auth.js) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 + +本项目是一个基于JWT(JSON Web Token)的用户认证系统,采用前后端分离架构设计。系统实现了完整的用户登录、令牌生成、权限验证和超级管理员权限检查功能。该认证系统具有以下特点: + +- **JWT认证机制**:使用HS256算法进行令牌签名,支持12小时有效期 +- **密码安全存储**:采用PBKDF2算法进行密码哈希,防止明文存储 +- **中间件验证**:提供通用认证中间件和超级管理员权限检查中间件 +- **前后端协作**:前端通过localStorage管理令牌,后端通过Authorization头验证 +- **错误处理**:完善的错误处理机制,支持令牌过期、权限不足等场景 + +## 项目结构 + +认证系统主要分布在后端和前端两个部分: + +```mermaid +graph TB +subgraph "后端架构" +A[Express 应用] --> B[认证路由] +A --> C[JWT工具] +A --> D[密码工具] +A --> E[认证中间件] +A --> F[用户模型] +A --> G[响应格式化] +end +subgraph "前端架构" +H[Axios请求] --> I[认证工具] +H --> J[API封装] +I --> K[本地存储] +I --> L[令牌解析] +end +subgraph "数据库" +M[DashboardUser表] +end +B --> M +E --> C +D --> M +``` + +**图表来源** +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) + +**章节来源** +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) + +## 核心组件 + +### JWT认证工具 + +JWT工具负责令牌的创建、解码和配置管理: + +```mermaid +classDiagram +class JWT工具 { ++JWT_SECRET : string ++JWT_ALGORITHM : string ++TOKEN_TTL_HOURS : number ++createAccessToken(user) : string ++decodeToken(token) : object ++getTokenTtlSeconds() : number +} +class 用户对象 { ++id : number ++username : string ++is_super_admin : boolean ++password_hash : string ++status : number +} +JWT工具 --> 用户对象 : "创建令牌时使用" +``` + +**图表来源** +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) + +### 密码加密工具 + +密码加密工具实现了PBKDF2算法的安全密码存储: + +```mermaid +flowchart TD +A[输入密码] --> B[生成随机盐值] +B --> C[PBKDF2哈希计算] +C --> D[组合存储格式] +D --> E[pbkdf2:digest:iterations:salt:hash] +F[验证密码] --> G[解析存储格式] +G --> H[提取参数] +H --> I[PBKDF2重新计算] +I --> J[安全比较] +J --> K{匹配?} +K --> |是| L[返回true] +K --> |否| M[返回false] +``` + +**图表来源** +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) + +### 认证中间件 + +认证中间件提供了统一的请求验证机制: + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Middleware as 认证中间件 +participant JWT as JWT工具 +participant Next as 下一个中间件 +Client->>Middleware : 发送带Authorization头的请求 +Middleware->>Middleware : 检查Authorization头格式 +Middleware->>JWT : decodeToken(token) +JWT-->>Middleware : 返回用户负载 +Middleware->>Middleware : 验证用户ID存在性 +Middleware->>Next : 设置req.user并继续 +Next-->>Client : 处理后续逻辑 +``` + +**图表来源** +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/jwt.js:19-21](file://backend/src/utils/jwt.js#L19-L21) + +**章节来源** +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/utils/password.js:1-37](file://backend/src/utils/password.js#L1-L37) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +## 架构概览 + +系统采用分层架构设计,前后端分离: + +```mermaid +graph TB +subgraph "前端层" +A[Vue应用] --> B[API封装] +B --> C[Axios请求] +C --> D[认证工具] +end +subgraph "网络层" +E[HTTP请求] +end +subgraph "后端层" +F[Express服务器] --> G[路由层] +G --> H[认证中间件] +G --> I[业务逻辑] +I --> J[数据库访问] +end +subgraph "数据层" +K[MySQL数据库] +end +A --> E +E --> F +F --> K +``` + +**图表来源** +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) + +## 详细组件分析 + +### 登录认证流程 + +登录流程是整个认证系统的核心: + +```mermaid +sequenceDiagram +participant User as 用户 +participant Frontend as 前端 +participant Backend as 后端 +participant DB as 数据库 +participant JWT as JWT工具 +User->>Frontend : 输入用户名密码 +Frontend->>Backend : POST /api/auth/login +Backend->>DB : 查询用户信息 +DB-->>Backend : 返回用户数据 +Backend->>Backend : 验证密码 +Backend->>JWT : createAccessToken(user) +JWT-->>Backend : 返回JWT令牌 +Backend-->>Frontend : 返回令牌和用户信息 +Frontend->>Frontend : 存储令牌到localStorage +``` + +**图表来源** +- [backend/src/routes/auth.js:24-64](file://backend/src/routes/auth.js#L24-L64) +- [backend/src/utils/jwt.js:7-17](file://backend/src/utils/jwt.js#L7-L17) +- [frontend/src/api/auth.js:1-24](file://frontend/src/api/auth.js#L1-L24) + +#### 登录接口实现要点 + +1. **输入验证**:检查用户名和密码是否为空 +2. **用户查询**:通过用户名查找用户,确保账户状态为启用 +3. **密码验证**:使用PBKDF2算法验证密码 +4. **最后登录时间更新**:成功登录后更新last_login_at字段 +5. **令牌生成**:为用户创建JWT访问令牌 +6. **响应格式化**:使用统一的ApiResponse格式返回 + +**章节来源** +- [backend/src/routes/auth.js:24-64](file://backend/src/routes/auth.js#L24-L64) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +### 权限验证中间件 + +系统提供了两层权限控制: + +```mermaid +flowchart TD +A[请求到达] --> B{是否有Authorization头} +B --> |否| C[返回401未登录] +B --> |是| D[提取JWT令牌] +D --> E[解码JWT令牌] +E --> F{令牌是否有效} +F --> |否| G[返回401无效凭证] +F --> |是| H[验证用户ID存在] +H --> I{用户是否存在且启用} +I --> |否| J[返回401账号不存在或已禁用] +I --> |是| K[设置req.user并继续] +subgraph "超级管理员检查" +L[调用requireSuperAdmin] --> M{是否超级管理员} +M --> |否| N[返回403权限不足] +M --> |是| O[继续执行] +end +``` + +**图表来源** +- [backend/src/middleware/auth.js:3-33](file://backend/src/middleware/auth.js#L3-L33) + +#### 中间件配置选项 + +| 参数 | 类型 | 默认值 | 描述 | +|------|------|--------|------| +| Authorization头 | String | 必填 | 格式为"Bearer {token}" | +| JWT_SECRET | String | 'dev-only-change-me-for-production' | 令牌签名密钥 | +| JWT_ALGORITHM | String | 'HS256' | 加密算法 | +| TOKEN_TTL_HOURS | Number | 12 | 令牌有效期(小时) | + +**章节来源** +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) + +### 超级管理员权限检查 + +超级管理员权限检查是系统的重要安全特性: + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant AuthMW as 认证中间件 +participant SuperMW as 超级管理员中间件 +participant Handler as 处理函数 +Client->>AuthMW : 带令牌的请求 +AuthMW->>AuthMW : 验证令牌有效性 +AuthMW->>SuperMW : 设置req.user +SuperMW->>SuperMW : 检查is_super_admin标志 +SuperMW->>Handler : 权限验证通过 +Handler-->>Client : 执行业务逻辑 +``` + +**图表来源** +- [backend/src/middleware/auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) + +**章节来源** +- [backend/src/middleware/auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) + +### 前端认证状态管理 + +前端通过localStorage管理认证状态: + +```mermaid +classDiagram +class 认证工具 { ++getToken() : string ++setToken(token : string) : void ++clearToken() : void ++getUser() : object ++setUser(user : object) : void ++clearUser() : void ++clearAuth() : void ++getUserFromToken(token? : string) : object ++isSuperAdmin(user? : object) : boolean ++getTokenExpiresAt(token? : string) : number ++isTokenExpired(token? : string) : boolean +} +class 本地存储 { ++setItem(key : string, value : string) : void ++getItem(key : string) : string ++removeItem(key : string) : void +} +class JWT解析 { ++base64解码 : string ++JSON解析 : object ++提取payload : object +} +认证工具 --> 本地存储 : "使用localStorage" +认证工具 --> JWT解析 : "解析令牌" +``` + +**图表来源** +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) + +**章节来源** +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) + +### 错误处理机制 + +系统实现了完善的错误处理: + +```mermaid +flowchart TD +A[请求处理] --> B{异常类型} +B --> |401未登录| C[清除认证状态] +B --> |403权限不足| D[显示权限不足消息] +B --> |其他错误| E[显示通用错误消息] +C --> F[重定向到登录页] +D --> G[阻止继续操作] +E --> H[记录日志并提示] +subgraph "前端处理" +I[请求拦截器] --> J[添加Authorization头] +K[响应拦截器] --> L[处理401/403状态] +end +``` + +**图表来源** +- [frontend/src/utils/request.js:46-68](file://frontend/src/utils/request.js#L46-L68) + +**章节来源** +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) + +## 依赖关系分析 + +### 技术栈依赖 + +```mermaid +graph TB +subgraph "后端依赖" +A[Express] --> B[JWT认证] +A --> C[数据库ORM] +D[Sequelize] --> E[MySQL驱动] +F[jsonwebtoken] --> G[HS256算法] +H[crypto] --> I[PBKDF2算法] +end +subgraph "前端依赖" +J[Axios] --> K[HTTP客户端] +L[Element Plus] --> M[UI组件] +N[Vue 3] --> O[响应式框架] +end +subgraph "开发工具" +P[Nodemon] --> Q[热重载] +R[Vite] --> S[构建工具] +end +``` + +**图表来源** +- [backend/package.json:11-28](file://backend/package.json#L11-L28) +- [frontend/package.json:10-24](file://frontend/package.json#L10-L24) + +### 数据模型关系 + +```mermaid +erDiagram +DASHBOARD_USER { +int id PK +string username UK +string password_hash +tinyint is_super_admin +tinyint status +datetime last_login_at +datetime create_at +datetime update_at +} +JWT_PAYLOAD { +string sub +string username +boolean is_super_admin +integer iat +integer exp +} +DASHBOARD_USER ||--o{ JWT_PAYLOAD : "生成令牌" +``` + +**图表来源** +- [backend/src/models/DashboardUser.js:4-54](file://backend/src/models/DashboardUser.js#L4-L54) +- [backend/src/utils/jwt.js:9-16](file://backend/src/utils/jwt.js#L9-L16) + +**章节来源** +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) + +## 性能考虑 + +### JWT令牌优化 + +1. **令牌大小控制**:JWT负载仅包含必要信息(用户ID、用户名、权限标志) +2. **有效期设置**:12小时有效期平衡安全性与用户体验 +3. **算法选择**:使用HS256算法确保性能和安全性 + +### 密码哈希优化 + +1. **迭代次数**:310000次迭代提供良好安全性 +2. **密钥长度**:32字节输出确保足够强度 +3. **随机盐值**:每次哈希使用不同盐值 + +### 缓存策略 + +```mermaid +flowchart LR +A[用户登录] --> B[生成JWT令牌] +B --> C[浏览器缓存] +C --> D[后续请求复用] +D --> E[减少服务器验证开销] +F[令牌过期] --> G[自动刷新机制] +G --> H[重新登录流程] +``` + +## 故障排除指南 + +### 常见认证问题及解决方案 + +#### 令牌过期问题 + +**问题现象**: +- 前端收到401状态码 +- 页面自动跳转到登录页 +- 控制台显示"登录已过期" + +**解决方案**: +1. 检查JWT_SECRET配置是否正确 +2. 验证系统时间同步 +3. 确认TOKEN_TTL_HOURS设置合理 + +**章节来源** +- [frontend/src/utils/request.js:46-58](file://frontend/src/utils/request.js#L46-L58) + +#### 权限不足问题 + +**问题现象**: +- 403状态码返回"需要超级管理员权限" +- 特定管理功能无法访问 + +**解决方案**: +1. 确认用户是否为超级管理员 +2. 检查数据库中is_super_admin字段 +3. 验证权限中间件是否正确配置 + +**章节来源** +- [backend/src/middleware/auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) + +#### 密码验证失败 + +**问题现象**: +- 登录时提示用户名或密码错误 +- 密码哈希存储格式不正确 + +**解决方案**: +1. 检查密码哈希存储格式 +2. 验证PBKDF2参数配置 +3. 确认密码比较算法正确性 + +**章节来源** +- [backend/src/utils/password.js:16-34](file://backend/src/utils/password.js#L16-L34) + +#### 前端认证状态异常 + +**问题现象**: +- 令牌存储损坏 +- 用户信息解析失败 +- 自动登出问题 + +**解决方案**: +1. 清除localStorage中的认证数据 +2. 检查令牌格式是否正确 +3. 验证JWT负载结构 + +**章节来源** +- [frontend/src/utils/auth.js:46-50](file://frontend/src/utils/auth.js#L46-L50) + +## 结论 + +本用户认证系统采用了现代Web应用的标准实践,实现了安全、可靠的用户认证机制。系统的主要优势包括: + +1. **安全性**:采用JWT令牌和PBKDF2密码哈希,提供多层安全保障 +2. **易用性**:前后端分离设计,提供清晰的API接口和错误处理 +3. **可维护性**:模块化架构,便于扩展和维护 +4. **性能**:合理的令牌配置和密码哈希参数,平衡安全性和性能 + +建议在生产环境中进一步完善的方面: +- 实现令牌刷新机制 +- 添加多因素认证支持 +- 增强日志审计功能 +- 实施更严格的密码策略 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/系统架构/前端架构.md b/.qoder/repowiki/zh/content/系统架构/前端架构.md new file mode 100644 index 0000000..aa396ac --- /dev/null +++ b/.qoder/repowiki/zh/content/系统架构/前端架构.md @@ -0,0 +1,375 @@ +# 前端架构 + + +**本文引用的文件** +- [frontend/package.json](file://frontend/package.json) +- [frontend/vite.config.js](file://frontend/vite.config.js) +- [frontend/src/main.js](file://frontend/src/main.js) +- [frontend/src/App.vue](file://frontend/src/App.vue) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [frontend/src/layout/index.vue](file://frontend/src/layout/index.vue) +- [frontend/src/components/TabsView.vue](file://frontend/src/components/TabsView.vue) +- [frontend/src/utils/request.js](file://frontend/src/utils/request.js) +- [frontend/src/utils/auth.js](file://frontend/src/utils/auth.js) +- [frontend/src/utils/tabs.js](file://frontend/src/utils/tabs.js) +- [frontend/src/views/home/index.vue](file://frontend/src/views/home/index.vue) +- [frontend/src/views/login/index.vue](file://frontend/src/views/login/index.vue) +- [frontend/src/components/ChangePasswordDialog.vue](file://frontend/src/components/ChangePasswordDialog.vue) +- [frontend/src/styles/lux-theme.css](file://frontend/src/styles/lux-theme.css) +- [frontend/src/api/dashboard.js](file://frontend/src/api/dashboard.js) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [组件详解](#组件详解) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 引言 +本文件面向前端工程团队与技术管理者,系统性阐述该 Vue 3 单页应用的前端架构设计与实现要点。重点覆盖 Composition API 使用模式、组件层次结构、路由配置与鉴权策略、状态管理策略(以 Tabs 视图与会话存储为核心)、Vite 构建与开发服务器配置、前后端交互模式与错误处理机制、性能优化策略、组件通信方式、依赖管理与打包部署流程,以及开发环境配置与调试指南。 + +## 项目结构 +前端采用基于目录的功能分层组织: +- 应用入口与全局配置:main.js、App.vue、router、utils、styles +- 页面视图:views 下按业务模块划分 +- 可复用组件:components 下抽取通用 UI 组件 +- API 层:api 下按领域模块封装请求方法 +- 构建与运行:vite.config.js、package.json + +```mermaid +graph TB +A["main.js
应用启动"] --> B["App.vue
根组件"] +B --> C["router/index.js
路由配置"] +C --> D["layout/index.vue
布局容器"] +D --> E["components/TabsView.vue
多页签视图"] +E --> F["views/*
业务页面"] +A --> G["utils/request.js
HTTP 客户端"] +G --> H["api/*
接口封装"] +A --> I["styles/lux-theme.css
主题样式"] +``` + +图表来源 +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/App.vue:1-30](file://frontend/src/App.vue#L1-L30) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/components/TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +章节来源 +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/App.vue:1-30](file://frontend/src/App.vue#L1-L30) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/components/TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 核心组件 +- 应用启动与插件注册:在入口中挂载 Element Plus、路由与主题样式,随后进行首屏可见性控制。 +- 根组件:最外层容器,承载路由出口。 +- 布局容器:提供侧边导航、面包屑、头部用户菜单与 Tabs 视图。 +- 多页签视图:集中管理页面标签、上下文菜单与 KeepAlive 缓存。 +- 登录页:表单校验、登录请求与令牌持久化。 +- 今日统计页:演示 Composition API 数据加载与模板渲染。 +- HTTP 客户端:统一请求头注入、响应拦截与错误处理。 +- 鉴权工具:本地令牌与用户信息读取、过期判断与清理。 +- 主题样式:深色宇宙风主题变量与组件态样式覆盖。 + +章节来源 +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/App.vue:1-30](file://frontend/src/App.vue#L1-L30) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/components/TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [frontend/src/views/login/index.vue:1-453](file://frontend/src/views/login/index.vue#L1-L453) +- [frontend/src/views/home/index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 架构总览 +应用采用“布局容器 + 多页签 + 业务视图”的结构,路由守卫负责鉴权与跳转,HTTP 层统一处理认证头与错误提示,主题样式通过 CSS 变量与组件作用域样式实现一致性视觉。 + +```mermaid +graph TB +subgraph "运行时" +M["main.js"] --> APP["App.vue"] +APP --> ROUTER["router/index.js"] +ROUTER --> LAYOUT["layout/index.vue"] +LAYOUT --> TABS["components/TabsView.vue"] +TABS --> VIEWS["views/*"] +M --> UTILS["utils/request.js"] +UTILS --> API["api/*"] +M --> THEME["styles/lux-theme.css"] +end +subgraph "开发/构建" +VITE["vite.config.js"] --> BUILD["Vite 打包/预览"] +end +ROUTER -.-> AUTH["utils/auth.js"] +TABS -.-> TABSUTIL["utils/tabs.js"] +``` + +图表来源 +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/App.vue:1-30](file://frontend/src/App.vue#L1-L30) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) +- [frontend/src/components/TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [frontend/src/utils/tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) +- [frontend/vite.config.js:1-27](file://frontend/vite.config.js#L1-L27) + +## 组件详解 + +### 路由与鉴权 +- 路由定义:登录页无需鉴权;其余页面默认 require 鉴权;部分系统管理页面要求超级管理员。 +- 导航守卫:检查令牌是否存在与未过期;对超级管理员页面进行角色校验;防止已登录用户访问登录页;自动重定向到首页。 +- 令牌与用户信息:本地存储令牌与用户信息;支持从 JWT 解析用户信息与过期时间;提供清理鉴权信息的工具函数。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant R as "路由守卫" +participant A as "鉴权工具(auth.js)" +participant S as "服务端" +U->>R : 访问受保护路由 +R->>A : 读取令牌/校验过期 +alt 未登录或已过期 +R->>U : 重定向至登录页(携带redirect) +else 已登录 +R->>A : 校验是否超级管理员 +alt 非超级管理员访问超级管理页面 +R->>U : 重定向至首页 +else 正常放行 +R-->>U : 放行 +end +end +``` + +图表来源 +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) + +章节来源 +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) + +### 多页签与缓存 +- 功能点:根据路由动态增删标签、点击切换、右键上下文菜单(关闭、关闭其他、关闭全部)、持久化到 sessionStorage。 +- KeepAlive:根据激活页签名称集合动态 include,减少重复渲染开销。 +- 默认首页:始终保留首页标签且不可关闭。 + +```mermaid +flowchart TD +Start(["进入页面"]) --> Restore["恢复标签状态(sessionStorage)"] +Restore --> Upsert["根据路由更新/插入标签"] +Upsert --> Persist["监听标签变化并持久化"] +Persist --> TabClick{"点击标签?"} +TabClick --> |是| Activate["激活并导航到对应路由"] +TabClick --> |否| Wait["等待事件"] +Wait --> Remove{"右键菜单-关闭?"} +Remove --> |是| DoRemove["移除标签并处理激活项"] +Remove --> |否| Others{"关闭其他/全部?"} +Others --> |是| CloseGroup["清理非首页标签"] +Others --> |否| End(["结束"]) +DoRemove --> End +CloseGroup --> End +``` + +图表来源 +- [frontend/src/components/TabsView.vue:120-287](file://frontend/src/components/TabsView.vue#L120-L287) +- [frontend/src/utils/tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) + +章节来源 +- [frontend/src/components/TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [frontend/src/utils/tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) + +### 布局容器与用户交互 +- 侧边栏:折叠/展开逻辑;根据当前路由自动展开对应菜单组;面包屑标题与分区联动。 +- 头部:用户下拉菜单(修改密码、账号管理、退出登录);根据用户角色显示不同菜单项。 +- 页签:与 TabsView 协作,承载具体业务视图。 + +章节来源 +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) + +### 登录流程 +- 表单校验:账号与密码必填。 +- 登录请求:调用登录 API,成功后写入令牌与用户信息,清空标签缓存并跳转首页。 +- 错误处理:统一提示与异常捕获。 + +```mermaid +sequenceDiagram +participant U as "用户" +participant L as "登录页(login/index.vue)" +participant API as "api/auth.js" +participant R as "路由(router)" +participant T as "tabs工具(utils/tabs)" +U->>L : 提交登录表单 +L->>L : 校验必填字段 +L->>API : 发起登录请求 +API-->>L : 返回结果(code/data) +alt 成功 +L->>L : 写入令牌/用户信息 +L->>T : 清空标签缓存 +L->>R : 跳转首页 +else 失败 +L-->>U : 提示错误 +end +``` + +图表来源 +- [frontend/src/views/login/index.vue:123-150](file://frontend/src/views/login/index.vue#L123-L150) +- [frontend/src/utils/tabs.js:4-8](file://frontend/src/utils/tabs.js#L4-L8) + +章节来源 +- [frontend/src/views/login/index.vue:1-453](file://frontend/src/views/login/index.vue#L1-L453) + +### 首页与今日统计 +- 首页卡片:欢迎语、快捷入口、今日新增型号与 OTA 列表。 +- 数据加载:进入页面时异步获取统计数据,展示加载态与空态。 +- 时间格式化:本地格式化时间字符串。 + +章节来源 +- [frontend/src/views/home/index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) +- [frontend/src/api/dashboard.js:1-12](file://frontend/src/api/dashboard.js#L1-L12) + +### HTTP 客户端与错误处理 +- 基础配置:baseURL 指向 /api;超时 10 秒。 +- 请求拦截:自动注入 Bearer 令牌(除登录接口)。 +- 响应拦截:统一处理业务错误(code=0)、401 清理鉴权并跳转登录、403 提示权限不足、其他网络错误统一提示。 +- 与路由守卫协作:401 场景下路由守卫配合跳转。 + +章节来源 +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/router/index.js:46-58](file://frontend/src/router/index.js#L46-L58) + +### 主题与样式 +- 全站主题:深色背景、卡片与玻璃体效果、青紫主色调。 +- CSS 变量:集中定义字体、颜色、背景等变量,便于主题切换与维护。 +- 组件级样式:通过 scoped 与深度选择器覆盖 Element Plus 组件态。 + +章节来源 +- [frontend/src/styles/lux-theme.css:1-471](file://frontend/src/styles/lux-theme.css#L1-L471) + +## 依赖关系分析 +- 运行时依赖:Vue 3、Element Plus、Vue Router、Axios。 +- 开发依赖:Vite、@vitejs/plugin-vue。 +- 项目内依赖:utils/request 作为 HTTP 客户端被 api/* 使用;api/* 被各页面调用;layout 与 TabsView 联动;路由守卫依赖鉴权工具。 + +```mermaid +graph LR +P["package.json"] --> VUE["vue"] +P --> ROUTER["vue-router"] +P --> AXIOS["axios"] +P --> EP["element-plus"] +MAIN["main.js"] --> VUE +MAIN --> ROUTER +MAIN --> EP +MAIN --> THEME["lux-theme.css"] +ROUTERIDX["router/index.js"] --> AUTH["utils/auth.js"] +TABSVIEW["components/TabsView.vue"] --> TABSUTIL["utils/tabs.js"] +REQUEST["utils/request.js"] --> API["api/*"] +LOGIN["views/login/index.vue"] --> API +HOME["views/home/index.vue"] --> API +LAYOUT["layout/index.vue"] --> TABSVIEW +``` + +图表来源 +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [frontend/src/utils/tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [frontend/src/components/TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [frontend/src/views/login/index.vue:1-453](file://frontend/src/views/login/index.vue#L1-L453) +- [frontend/src/views/home/index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) + +章节来源 +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [frontend/src/utils/auth.js:1-99](file://frontend/src/utils/auth.js#L1-L99) +- [frontend/src/utils/tabs.js:1-9](file://frontend/src/utils/tabs.js#L1-L9) +- [frontend/src/components/TabsView.vue:1-351](file://frontend/src/components/TabsView.vue#L1-L351) +- [frontend/src/views/login/index.vue:1-453](file://frontend/src/views/login/index.vue#L1-L453) +- [frontend/src/views/home/index.vue:1-327](file://frontend/src/views/home/index.vue#L1-L327) +- [frontend/src/layout/index.vue:1-338](file://frontend/src/layout/index.vue#L1-L338) + +## 性能考量 +- 组件缓存:TabsView 结合 KeepAlive,按页签名称 include,减少重复渲染与请求。 +- 路由懒加载:路由组件使用动态导入,降低首屏体积。 +- 图标按需:Element Plus 图标通过动态组件按需渲染。 +- 样式隔离:scoped 与深度选择器避免全局污染,提升样式计算效率。 +- 构建优化:Vite 默认启用按需编译与热更新;可通过插件扩展压缩与分析。 + +章节来源 +- [frontend/src/components/TabsView.vue:47-49](file://frontend/src/components/TabsView.vue#L47-L49) +- [frontend/src/router/index.js:10-11](file://frontend/src/router/index.js#L10-L11) +- [frontend/src/layout/index.vue:34-36](file://frontend/src/layout/index.vue#L34-L36) +- [frontend/vite.config.js:1-27](file://frontend/vite.config.js#L1-L27) + +## 故障排查指南 +- 登录失败 + - 检查表单校验规则与必填项。 + - 查看响应拦截器返回的错误消息与业务码。 +- 401 未授权 + - 检查请求拦截器是否正确注入 Authorization。 + - 确认路由守卫是否触发清理鉴权与跳转登录。 +- 403 权限不足 + - 检查用户角色与页面 meta.requiresSuperAdmin。 +- 网络错误 + - 查看响应拦截器统一错误提示与控制台日志。 +- 标签页异常 + - 检查 sessionStorage 是否被清理或损坏。 + - 确认 TabsView 的持久化与恢复逻辑。 + +章节来源 +- [frontend/src/views/login/index.vue:123-150](file://frontend/src/views/login/index.vue#L123-L150) +- [frontend/src/utils/request.js:27-69](file://frontend/src/utils/request.js#L27-L69) +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [frontend/src/utils/tabs.js:4-8](file://frontend/src/utils/tabs.js#L4-L8) +- [frontend/src/components/TabsView.vue:125-174](file://frontend/src/components/TabsView.vue#L125-L174) + +## 结论 +该前端架构以 Vue 3 Composition API 为核心,结合 Element Plus 与自研 HTTP 客户端,形成清晰的路由鉴权、多页签缓存与主题体系。通过路由懒加载与 KeepAlive 降低首屏与切换成本,借助 Vite 提供高效的开发体验。建议后续在大型页面引入 Pinia 或基于 provide/inject 的轻量状态管理,以进一步提升复杂场景下的可维护性。 + +## 附录 + +### Vite 配置与优化要点 +- 插件:启用 @vitejs/plugin-vue。 +- 全局常量:开启 Options API、关闭生产 devtools 与水合不匹配详情。 +- 路径别名:@ 指向 src。 +- 开发服务器:端口 3000,代理 /api 到后端服务地址。 +- 可选优化:按需引入 polyfill、压缩图片与静态资源、分析包体积。 + +章节来源 +- [frontend/vite.config.js:1-27](file://frontend/vite.config.js#L1-L27) + +### 依赖管理与脚本 +- 依赖:Vue、Element Plus、Vue Router、Axios。 +- 开发依赖:Vite、@vitejs/plugin-vue。 +- 脚本:dev、build、preview。 + +章节来源 +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) + +### 开发环境配置与调试 +- 启动:使用 dev 脚本启动 Vite 开发服务器。 +- 调试:利用浏览器断点与 Vue DevTools;关注请求拦截器与路由守卫日志。 +- 代理:开发阶段通过 /api 代理到后端,避免跨域问题。 + +章节来源 +- [frontend/package.json:5-9](file://frontend/package.json#L5-L9) +- [frontend/vite.config.js:17-25](file://frontend/vite.config.js#L17-L25) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/系统架构/后端架构.md b/.qoder/repowiki/zh/content/系统架构/后端架构.md new file mode 100644 index 0000000..cc5357e --- /dev/null +++ b/.qoder/repowiki/zh/content/系统架构/后端架构.md @@ -0,0 +1,581 @@ +# 后端架构 + + +**本文引用的文件** +- [backend/src/app.js](file://backend/src/app.js) +- [backend/package.json](file://backend/package.json) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/middleware/bodyLimit.js](file://backend/src/middleware/bodyLimit.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/routes/auth.js](file://backend/src/routes/auth.js) +- [backend/src/services/userBootstrap.js](file://backend/src/services/userBootstrap.js) +- [backend/src/models/DashboardUser.js](file://backend/src/models/DashboardUser.js) +- [backend/src/models/index.js](file://backend/src/models/index.js) +- [backend/src/services/curveClient.js](file://backend/src/services/curveClient.js) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [backend/src/services/measurementStorage.js](file://backend/src/services/measurementStorage.js) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 引言 +本文件面向后端架构与实现,围绕 Express 应用展开,系统性阐述 MVC 模式落地、中间件体系、路由组织、数据库连接、Redis 缓存、日志系统、认证授权、错误处理、请求限制、API 版本管理、安全防护与性能优化、启动流程、健康检查与监控配置等主题。文档同时提供可视化图示帮助读者快速把握代码结构与交互流程。 + +## 项目结构 +后端采用模块化分层组织: +- 配置层:环境变量、数据库、Redis、日志 +- 中间件层:认证、请求体大小限制 +- 路由层:按功能域划分的子路由集合 +- 服务层:业务逻辑封装(曲线拉取、EQ 缓存、频响存储等) +- 工具层:JWT、密码、统一响应包装 +- 模型层:基于 Sequelize 的数据模型 +- 入口:应用启动与监听 + +```mermaid +graph TB +subgraph "入口" +APP["app.js
启动与中间件注册"] +end +subgraph "配置" +ENV["env.js
环境标识"] +DB["database.js
Sequelize 实例"] +REDIS["redis.js
Redis 客户端"] +LOG["logger.js
Winston 日志"] +end +subgraph "中间件" +AUTHMW["auth.js
认证/鉴权"] +BODYLIMIT["bodyLimit.js
请求体大小限制"] +end +subgraph "路由" +ROUTESIDX["routes/index.js
路由聚合"] +ROUTE_AUTH["routes/auth.js
认证相关"] +end +subgraph "服务" +BOOTSTRAP["userBootstrap.js
超级管理员初始化"] +CURVE["curveClient.js
曲线拉取与校验"] +EQ["eqCacheStorage.js
EQ 缓存读取"] +MEAS["measurementStorage.js
频响文件 S3 存取"] +end +subgraph "模型" +MODELSIDX["models/index.js
模型导出"] +MODEL_USER["DashboardUser.js
用户模型"] +end +subgraph "工具" +JWT["jwt.js
JWT 生成/解析"] +RESP["response.js
统一响应包装"] +end +APP --> ENV +APP --> DB +APP --> REDIS +APP --> LOG +APP --> ROUTESIDX +APP --> AUTHMW +APP --> BODYLIMIT +ROUTESIDX --> ROUTE_AUTH +ROUTE_AUTH --> MODEL_USER +BOOTSTRAP --> MODEL_USER +EQ --> REDIS +MEAS --> DB +CURVE --> LOG +EQ --> LOG +MEAS --> LOG +JWT --> LOG +``` + +图表来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/middleware/bodyLimit.js:1-12](file://backend/src/middleware/bodyLimit.js#L1-L12) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [backend/src/services/curveClient.js:1-147](file://backend/src/services/curveClient.js#L1-L147) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 核心组件 +- 应用入口与中间件 + - 注册 CORS、JSON 解析、URL 编码解析、请求体大小限制中间件 + - 提供根路径与健康检查接口 + - 聚合并挂载各业务路由 +- 数据库连接 + - 基于 Sequelize 连接 MySQL,开发环境开启 SQL 日志输出 + - 应用启动时尝试同步数据库表结构 +- Redis 缓存 + - 单例客户端,支持密码、超时、重试次数配置 + - EQ 缓存采用 Redis Hash 结构,提供字段级读取与键列表查询 +- 日志系统 + - Winston 控制台与文件双通道输出,统一时间戳与格式化 +- 认证与授权 + - Bearer Token 解析与校验,支持超级管理员强制校验 +- 请求限制 + - 基于 Content-Length 的请求体大小限制(默认 8MB) + +章节来源 +- [backend/src/app.js:14-59](file://backend/src/app.js#L14-L59) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/middleware/bodyLimit.js:1-12](file://backend/src/middleware/bodyLimit.js#L1-L12) + +## 架构总览 +下图展示从请求进入至业务处理的关键流程,包括认证、路由分发、模型访问与外部服务调用。 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant A as "Express 应用(app.js)" +participant M1 as "认证中间件(auth.js)" +participant R as "路由(auth.js)" +participant U as "工具(jwt.js/response.js)" +participant DB as "数据库(Sequelize)" +participant L as "日志(Winston)" +C->>A : "HTTP 请求" +A->>M1 : "执行认证中间件" +M1-->>A : "通过/拒绝" +A->>R : "路由分发" +R->>U : "生成响应/解析令牌" +R->>DB : "查询/更新用户" +DB-->>R : "结果" +R-->>C : "统一响应" +R->>L : "记录日志" +``` + +图表来源 +- [backend/src/app.js:16-37](file://backend/src/app.js#L16-L37) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +## 详细组件分析 + +### MVC 模式实现 +- 视图层 + - 本项目为 API 服务,无传统视图层;统一以 JSON 响应输出 +- 模型层 + - 使用 Sequelize 定义数据模型,集中于 models 目录,导出统一索引 + - 示例:DashboardUser 模型定义了用户字段、注释与表名 +- 控制器层 + - Express 路由作为控制器,负责接收请求、调用服务/模型、返回响应 + - 示例:认证路由处理登录、获取当前用户、修改密码 + +```mermaid +classDiagram +class DashboardUser { ++id : number ++username : string ++password_hash : string ++is_super_admin : number ++status : number ++last_login_at : date ++create_at : date ++update_at : date +} +class AuthRoute { ++login() ++getCurrentUser() ++changePassword() +} +AuthRoute --> DashboardUser : "读写" +``` + +图表来源 +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) + +章节来源 +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) + +### 中间件体系 +- 认证中间件 + - 从 Authorization 头提取 Bearer Token,解码并注入用户上下文 + - 支持超级管理员强制校验 +- 请求体大小限制 + - 基于 Content-Length 校验,超过阈值返回 413 + +```mermaid +flowchart TD +Start(["进入中间件"]) --> CheckAuth["检查 Authorization 头"] +CheckAuth --> HasToken{"存在 Bearer Token?"} +HasToken --> |否| Reject401["返回 401 未登录"] +HasToken --> |是| Verify["验证 Token"] +Verify --> Valid{"有效?"} +Valid --> |否| Reject401 +Valid --> |是| InjectUser["注入用户上下文"] +InjectUser --> Next["放行"] +Reject401 --> End(["结束"]) +Next --> End +``` + +图表来源 +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +章节来源 +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/middleware/bodyLimit.js:1-12](file://backend/src/middleware/bodyLimit.js#L1-L12) + +### 路由组织结构 +- 路由聚合 + - routes/index.js 导出所有业务路由数组,入口统一挂载 +- 认证路由 + - 登录:校验凭据、更新最近登录时间、签发访问令牌 + - 获取当前用户:基于已认证用户 ID 查询 + - 修改密码:旧密码校验、新密码长度校验、更新哈希 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant R as "认证路由(auth.js)" +participant DB as "数据库" +participant JWT as "JWT 工具" +participant RESP as "响应包装" +C->>R : "POST /api/auth/login" +R->>DB : "按用户名查询用户" +DB-->>R : "用户记录" +R->>R : "校验密码/状态" +R->>DB : "更新最近登录时间" +R->>JWT : "签发访问令牌" +R->>RESP : "构造成功响应" +R-->>C : "返回 access_token 与用户信息" +``` + +图表来源 +- [backend/src/routes/auth.js:24-64](file://backend/src/routes/auth.js#L24-L64) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +章节来源 +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/routes/auth.js:1-112](file://backend/src/routes/auth.js#L1-L112) + +### 数据库连接管理 +- 连接配置 + - 通过环境变量配置主机、端口、用户名、密码、数据库名 + - 开发环境启用 SQL 日志,生产关闭 +- 启动同步 + - 应用启动时尝试同步表结构,失败记录告警但不阻断启动 +- 用户模型 + - 字段覆盖登录账号、密码哈希、状态、超级管理员标记、时间戳 + +```mermaid +flowchart TD +Boot(["应用启动"]) --> Sync["sequelize.sync()"] +Sync --> Ok{"同步成功?"} +Ok --> |是| Ready["记录成功日志"] +Ok --> |否| Warn["记录错误日志并继续"] +Ready --> Listen["监听端口"] +Warn --> Listen +``` + +图表来源 +- [backend/src/app.js:42-56](file://backend/src/app.js#L42-L56) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) + +章节来源 +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/app.js:42-56](file://backend/src/app.js#L42-L56) +- [backend/src/models/DashboardUser.js:1-58](file://backend/src/models/DashboardUser.js#L1-L58) + +### Redis 缓存策略 +- 客户端 + - 单例懒加载,支持密码、超时、重试次数 +- EQ 缓存 + - 使用 Redis Hash 存储型号的 EQ 字段 + - 提供字段键列表查询与单字段读取 + - 读取失败统一抛错并记录日志 + +```mermaid +sequenceDiagram +participant S as "服务(eqCacheStorage.js)" +participant RC as "Redis 客户端(redis.js)" +participant L as "日志(logger.js)" +S->>RC : "hkeys(key)/hget(key, field)" +alt "键存在" +RC-->>S : "字段列表/字段值" +S-->>S : "解析 JSON 或原始值" +else "键不存在/读取异常" +RC-->>S : "null 或抛错" +S->>L : "记录错误日志" +S-->>S : "抛出统一错误" +end +``` + +图表来源 +- [backend/src/services/eqCacheStorage.js:24-66](file://backend/src/services/eqCacheStorage.js#L24-L66) +- [backend/src/config/redis.js:11-29](file://backend/src/config/redis.js#L11-L29) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +章节来源 +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +### 日志系统配置 +- 输出目标 + - 控制台与文件双通道 +- 格式化 + - 时间戳、级别、消息、附加元数据 +- 目录 + - 自动创建 logs 目录 + +章节来源 +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +### 认证授权机制 +- 令牌签发 + - 基于 HS256 算法,有效期 12 小时 +- 令牌解析 + - 校验失败按类型返回不同错误 +- 授权 + - 超级管理员强制校验,非管理员返回 403 + +```mermaid +flowchart TD +A["收到请求"] --> B["解析 Authorization 头"] +B --> C{"Bearer Token 存在?"} +C --> |否| E["返回 401 未登录"] +C --> |是| D["jwt.verify 校验"] +D --> F{"有效?"} +F --> |否| G["返回 401 无效凭证/过期"] +F --> |是| H["注入用户上下文"] +H --> I{"是否超级管理员?"} +I --> |否| J["返回 403"] +I --> |是| K["放行"] +``` + +图表来源 +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) + +章节来源 +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +### 错误处理与统一响应 +- 统一响应包装 + - 成功/错误/无数据三类包装对象 +- 路由层错误捕获 + - 认证路由对异常进行日志记录并返回统一错误响应 +- 外部服务错误 + - S3/曲线服务捕获异常并记录日志,抛出统一错误 + +章节来源 +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/routes/auth.js:60-64](file://backend/src/routes/auth.js#L60-L64) +- [backend/src/services/measurementStorage.js:76-108](file://backend/src/services/measurementStorage.js#L76-L108) +- [backend/src/services/curveClient.js:94-138](file://backend/src/services/curveClient.js#L94-L138) + +### 请求限制策略 +- 限制规则 + - 基于 Content-Length,超过 8MB 返回 413 +- 生效范围 + - 全局中间件,适用于所有路由 + +章节来源 +- [backend/src/middleware/bodyLimit.js:1-12](file://backend/src/middleware/bodyLimit.js#L1-L12) +- [backend/src/app.js:17-20](file://backend/src/app.js#L17-L20) + +### API 版本管理 +- 当前实现 + - 路由路径采用 /api/{resource} 形态,未显式引入版本前缀 +- 建议 + - 可在入口处增加 /api/v1 前缀,后续迁移至 v2 时保持向后兼容 + +章节来源 +- [backend/src/routes/auth.js:24-77](file://backend/src/routes/auth.js#L24-L77) + +### 安全防护 +- CORS + - 允许任意来源与凭据 +- 认证 + - Bearer Token,建议配合 HTTPS 与短令牌有效期 +- 密码 + - 使用哈希存储,路由层对新密码长度进行约束 +- 请求限制 + - 8MB 限制,防止恶意大包 + +章节来源 +- [backend/src/app.js:17-18](file://backend/src/app.js#L17-L18) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) +- [backend/src/middleware/bodyLimit.js:1-12](file://backend/src/middleware/bodyLimit.js#L1-L12) + +### 性能优化方案 +- 数据库 + - 生产关闭 SQL 日志,减少 IO + - 合理索引与查询条件,避免 N+1 +- 缓存 + - Redis Hash 结构降低网络往返 + - 字段键列表查询避免一次性传输大量数据 +- 外部服务 + - S3 与曲线接口设置合理超时与错误重试 +- 日志 + - 控制台与文件双通道,避免过多 info 级日志影响性能 + +章节来源 +- [backend/src/config/database.js:15-15](file://backend/src/config/database.js#L15-L15) +- [backend/src/services/eqCacheStorage.js:24-42](file://backend/src/services/eqCacheStorage.js#L24-L42) +- [backend/src/services/measurementStorage.js:18-27](file://backend/src/services/measurementStorage.js#L18-L27) +- [backend/src/services/curveClient.js:94-100](file://backend/src/services/curveClient.js#L94-L100) +- [backend/src/config/logger.js:19-26](file://backend/src/config/logger.js#L19-L26) + +### 启动流程、健康检查与监控 +- 启动流程 + - 加载环境变量 → 初始化数据库 → 创建超级管理员 → 启动 HTTP 服务器 +- 健康检查 + - /health 返回健康状态 +- 监控建议 + - 结合日志与外部 APM 工具,关注慢查询、缓存命中率与外部接口延迟 + +```mermaid +sequenceDiagram +participant Boot as "启动脚本" +participant App as "app.js" +participant DB as "database.js" +participant Redis as "redis.js" +participant Logger as "logger.js" +Boot->>App : "node src/app.js" +App->>DB : "sequelize.sync()" +App->>App : "ensureBootstrapSuperAdmin()" +App->>Redis : "初始化客户端" +App->>Logger : "记录启动日志" +App->>App : "listen(PORT)" +``` + +图表来源 +- [backend/src/app.js:42-59](file://backend/src/app.js#L42-L59) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:11-29](file://backend/src/config/redis.js#L11-L29) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +章节来源 +- [backend/src/app.js:22-34](file://backend/src/app.js#L22-L34) +- [backend/src/app.js:42-59](file://backend/src/app.js#L42-L59) + +## 依赖关系分析 +- 包管理与运行 + - 依赖 express、sequelize、mysql2、jsonwebtoken、winston、ioredis 等 + - 启动脚本使用 node 或 nodemon dev +- 内部依赖 + - app.js 依赖配置、路由、中间件与引导服务 + - 路由依赖模型与工具 + - 服务依赖配置与日志 + +```mermaid +graph LR +P["package.json"] --> E["express"] +P --> S["sequelize"] +P --> M["mysql2"] +P --> J["jsonwebtoken"] +P --> W["winston"] +P --> R["ioredis"] +APP["app.js"] --> CFG["config/*"] +APP --> RT["routes/*"] +APP --> MW["middleware/*"] +APP --> SVC["services/*"] +RT --> MOD["models/*"] +RT --> UT["utils/*"] +SVC --> CFG +SVC --> LOG["logger.js"] +``` + +图表来源 +- [backend/package.json:11-27](file://backend/package.json#L11-L27) +- [backend/src/app.js:1-14](file://backend/src/app.js#L1-L14) + +章节来源 +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [backend/src/app.js:1-14](file://backend/src/app.js#L1-L14) + +## 性能考虑 +- 数据库层 + - 生产关闭 SQL 日志,避免频繁 I/O + - 合理使用索引与分页 +- 缓存层 + - Redis Hash 结构适合字段级访问 + - 仅读取字段键列表,避免大对象传输 +- 外部接口 + - 设置超时与错误处理,避免阻塞请求 +- 日志 + - 控制台与文件双通道,避免 info 级日志过多 + +## 故障排查指南 +- 认证失败 + - 检查 Authorization 头格式与令牌有效性 + - 查看日志定位具体错误原因 +- 数据库同步失败 + - 检查数据库连接参数与权限 + - 关注启动阶段的日志告警 +- Redis 读取异常 + - 检查 Redis 连接参数与网络连通性 + - 关注错误日志中的具体异常信息 +- S3 读取/上传失败 + - 检查凭证或 IAM 角色配置 + - 关注 NoSuchKey 等特定异常 + +章节来源 +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/app.js:48-51](file://backend/src/app.js#L48-L51) +- [backend/src/config/redis.js:24-26](file://backend/src/config/redis.js#L24-L26) +- [backend/src/services/measurementStorage.js:102-107](file://backend/src/services/measurementStorage.js#L102-L107) + +## 结论 +本后端以 Express 为核心,采用清晰的分层与模块化设计,结合 Sequelize、Redis 与 Winston 实现了稳定的数据访问、缓存与日志能力。认证授权、请求限制与统一响应提升了安全性与一致性。建议后续引入 API 版本前缀、完善错误分类与指标上报,持续优化数据库与缓存策略以提升整体性能与可观测性。 + +## 附录 +- 环境变量 + - APP_ENV:development/production + - DATABASE_*:主机、端口、用户名、密码、数据库名 + - REDIS_*:主机、端口、密码、DB + - JWT_SECRET:令牌签名密钥 + - DASHBOARD_ADMIN_*:超级管理员初始化用户名与密码 + - AWS_*:S3 区域、凭证与桶名 +- 路由示例 + - GET / → 根路径 + - GET /health → 健康检查 + - POST /api/auth/login → 登录 + - GET /api/auth/me → 获取当前用户 + - PUT /api/auth/password → 修改密码 + +章节来源 +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:4-11](file://backend/src/config/database.js#L4-L11) +- [backend/src/config/redis.js:4-7](file://backend/src/config/redis.js#L4-L7) +- [backend/src/utils/jwt.js:3-4](file://backend/src/utils/jwt.js#L3-L4) +- [backend/src/services/userBootstrap.js:9-10](file://backend/src/services/userBootstrap.js#L9-L10) +- [backend/src/services/measurementStorage.js:9-12](file://backend/src/services/measurementStorage.js#L9-L12) +- [backend/src/app.js:22-34](file://backend/src/app.js#L22-L34) +- [backend/src/routes/auth.js:24-77](file://backend/src/routes/auth.js#L24-L77) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/系统架构/数据流设计.md b/.qoder/repowiki/zh/content/系统架构/数据流设计.md new file mode 100644 index 0000000..4dbdbc7 --- /dev/null +++ b/.qoder/repowiki/zh/content/系统架构/数据流设计.md @@ -0,0 +1,362 @@ +# 数据流设计 + + +**本文引用的文件** +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/utils/password.js](file://backend/src/utils/password.js) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [backend/src/routes/brands.js](file://backend/src/routes/brands.js) +- [backend/src/models/Brand.js](file://backend/src/models/Brand.js) +- [backend/src/validators/brand.js](file://backend/src/validators/brand.js) +- [backend/src/services/measurementStorage.js](file://backend/src/services/measurementStorage.js) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [frontend/src/main.js](file://frontend/src/main.js) +- [frontend/src/utils/request.js](file://frontend/src/utils/request.js) +- [frontend/src/api/brand.js](file://frontend/src/api/brand.js) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 引言 +本文件面向系统数据流与处理机制,覆盖从前端用户交互到后端数据持久化的完整路径;阐述 API 请求/响应模式、数据验证流程与错误传播机制;说明缓存策略、数据同步与一致性保障;并给出数据安全传输、加密存储与隐私保护建议,以及监控、性能分析与故障排查指引。 + +## 项目结构 +系统采用前后端分离架构: +- 前端基于 Vue 3 + Element Plus,通过 Axios 封装的请求模块统一访问后端 /api 前缀接口。 +- 后端基于 Express,使用中间件处理鉴权、请求体限制等;路由层组织各业务模块;模型层通过 Sequelize 访问 MySQL;服务层封装外部存储(S3)与缓存(Redis);统一响应格式与日志输出。 + +```mermaid +graph TB +FE["前端应用
Vue 3 + Element Plus"] --> AX["Axios 请求封装
/api 前缀"] +AX --> MW["Express 中间件
鉴权/请求体限制"] +MW --> RT["路由层
业务路由汇总"] +RT --> SVC["服务层
S3/Redis/业务逻辑"] +SVC --> DB["MySQL 数据库
Sequelize ORM"] +SVC --> S3["S3 对象存储"] +SVC --> RDS["Redis 缓存"] +``` + +图表来源 +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +章节来源 +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) + +## 核心组件 +- 应用入口与中间件 + - Express 应用初始化、CORS、JSON 解析、请求体大小限制、根路径与健康检查、路由注册、数据库同步与启动。 +- 鉴权中间件 + - Bearer Token 解析与校验,超时与无效凭证处理,超级管理员权限控制。 +- 统一响应格式 + - 成功/错误/无数据三态封装,分页数据容器。 +- 数据库与缓存 + - MySQL 连接配置与日志开关;Redis 连接池与错误日志。 +- 外部存储服务 + - S3 客户端按凭证或 IAM 角色自动选择;频响文件上传/下载与键构建规则。 +- 前端请求封装 + - 自动注入 Authorization 头、统一错误处理与 401/403 提示与跳转。 + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [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/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) + +## 架构总览 +下图展示典型“品牌管理”数据流:从前端发起请求,经鉴权中间件,到路由处理、模型查询与持久化,再到统一响应返回客户端。 + +```mermaid +sequenceDiagram +participant U as "用户界面" +participant F as "前端请求封装" +participant M as "鉴权中间件" +participant R as "品牌路由" +participant S as "品牌模型" +participant D as "MySQL 数据库" +U->>F : "GET /api/brands/" +F->>M : "携带 Bearer Token" +M-->>F : "校验通过/拒绝" +F->>R : "转发请求" +R->>S : "findAndCountAll()" +S->>D : "执行 SQL" +D-->>S : "结果集" +S-->>R : "rows/count" +R-->>F : "ApiResponse.success(...)" +F-->>U : "渲染列表" +``` + +图表来源 +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 详细组件分析 + +### 品牌管理数据流(含验证与错误传播) +- 前端调用 + - 品牌 API 封装提供列表、详情、创建、更新、删除方法,均通过 /api 前缀访问。 +- 路由与鉴权 + - 所有品牌接口前置鉴权中间件;超级管理员权限可通过独立守卫控制。 +- 业务处理 + - 列表支持分页与模糊查询;创建/更新进行名称非空与唯一性校验;删除级联销毁。 +- 错误传播 + - 服务异常统一记录日志并返回统一错误响应;前端拦截 401/403 并引导至登录页或提示权限不足。 + +```mermaid +flowchart TD +Start(["进入路由处理"]) --> Validate["参数与输入校验"] +Validate --> Valid{"校验通过?"} +Valid -- 否 --> RespErr["返回统一错误响应"] +Valid -- 是 --> Oper["执行数据库操作"] +Oper --> DBOK{"数据库操作成功?"} +DBOK -- 否 --> LogErr["记录错误日志"] --> RespErr +DBOK -- 是 --> BuildResp["构建分页/对象响应"] +BuildResp --> Done(["返回统一成功响应"]) +``` + +图表来源 +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [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) + +章节来源 +- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [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) + +### 验证与数据模型 +- 输入验证 + - 使用 Zod Schema 对创建/更新请求进行最小长度、最大长度与可选字段约束。 +- 模型定义 + - 品牌模型定义主键、唯一索引与注释,确保数据库层面约束一致。 +- 业务约束 + - 名称唯一性检查与更新时排除自身 ID 的冲突判断。 + +```mermaid +classDiagram +class BrandModel { ++id : number ++name : string +} +class BrandCreateSchema { ++name : string +} +class BrandUpdateSchema { ++name : string? +} +BrandModel <.. BrandCreateSchema : "约束输入" +BrandModel <.. BrandUpdateSchema : "约束输入" +``` + +图表来源 +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) + +章节来源 +- [backend/src/validators/brand.js:1-12](file://backend/src/validators/brand.js#L1-L12) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +### 缓存策略与一致性 +- 缓存键设计 + - EQ 缓存以“品牌+型号”作为 Redis Hash Key,字段为具体 EQ 参数键,避免一次性返回全部值导致响应过大。 +- 读取策略 + - 先 hkeys 获取字段列表,再按需 hget 读取具体字段值;未命中返回空字段列表。 +- 一致性与容错 + - 读取异常统一记录日志并抛出错误;缓存未命中不阻断主流程,可回退到数据库或外部存储。 + +```mermaid +flowchart TD +A["请求 EQ 字段列表"] --> B["构造 Redis Key"] +B --> C{"Key 是否存在?"} +C -- 否 --> D["返回空字段列表"] +C -- 是 --> E["hkeys 取字段名"] +E --> F["返回字段列表"] +G["请求 EQ 单字段值"] --> H["构造 Redis Key"] +H --> I["hget 读取"] +I --> J{"是否未命中?"} +J -- 是 --> K["抛出字段不存在错误"] +J -- 否 --> L["返回字段值"] +``` + +图表来源 +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) + +章节来源 +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) + +### 外部存储(S3)与数据同步 +- S3 客户端 + - 支持显式凭证或 IAM 角色访问;根据区域与桶名配置。 +- 键构建规则 + - 频响文件路径包含来源、佩戴方式、品牌首字母与品牌+型号文件名,便于检索与归档。 +- 上传/下载 + - 上传设置 Content-Type 为 CSV;下载读取字符串内容;对 404/NoSuchKey 映射为“未找到频响文件”。 + +```mermaid +sequenceDiagram +participant Svc as "测量存储服务" +participant S3 as "S3 客户端" +Svc->>Svc : "buildMeasurementKey()" +Svc->>S3 : "PutObjectCommand(Body=CSV)" +S3-->>Svc : "上传成功/失败" +Svc->>S3 : "GetObjectCommand(Key)" +S3-->>Svc : "返回内容/404" +``` + +图表来源 +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +章节来源 +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +### 前后端数据契约与错误传播 +- 前端 + - Axios 实例统一设置 baseURL=/api;请求头自动注入 Bearer Token(除登录接口);响应拦截器将 code=0 的业务错误标准化为异常并提示;401 清理本地认证并跳转登录。 +- 后端 + - 统一响应格式 ApiResponse.success/error/noData;路由层捕获异常并返回标准错误;日志记录关键信息。 + +```mermaid +sequenceDiagram +participant FE as "前端" +participant AX as "Axios 拦截器" +participant BE as "后端路由" +participant RESP as "统一响应" +FE->>AX : "发送请求" +AX->>BE : "注入 Authorization" +BE-->>RESP : "构造响应" +RESP-->>AX : "返回 {code,data,msg}" +AX-->>FE : "成功/错误处理" +``` + +图表来源 +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +章节来源 +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) + +## 依赖关系分析 +- 组件耦合 + - 路由依赖模型与服务;服务依赖数据库/缓存/S3;中间件贯穿所有受保护路由;前端仅依赖后端 /api 接口。 +- 关键依赖链 + - 品牌路由 → 品牌模型 → MySQL;品牌路由 → 统一响应;鉴权中间件 → JWT 工具;S3/Redis 服务 → 配置模块。 +- 循环依赖 + - 当前结构未见循环依赖迹象;路由汇总文件仅做导出聚合。 + +```mermaid +graph LR +R["品牌路由"] --> M["品牌模型"] +R --> U["统一响应"] +R --> S3["S3 存储服务"] +R --> RDS["Redis 缓存服务"] +MW["鉴权中间件"] --> JWT["JWT 工具"] +APP["应用入口"] --> MW +APP --> R +CFG["配置模块"] --> DB["数据库"] +CFG --> RDS +CFG --> LOG["日志"] +``` + +图表来源 +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) + +章节来源 +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) + +## 性能考虑 +- 数据库 + - 开发环境开启 SQL 日志便于调试;生产关闭日志以降低开销;分页 limit 最大值限制防止高负载。 +- 缓存 + - Redis 连接设置重试次数与连接超时;优先读取字段键列表,避免一次性返回大量字段值。 +- 外部存储 + - S3 上传设置明确 Content-Type;对 404/NoSuchKey 做快速错误映射,减少无效重试。 +- 前端 + - Axios 超时设置与错误提示,避免长时间挂起;401 自动跳转登录,减少无效请求。 + +章节来源 +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) + +## 故障排查指南 +- 401 未授权 + - 前端检测到 401 清理本地认证并跳转登录页;后端鉴权中间件对缺失/过期/无效 Token 分类返回。 +- 403 权限不足 + - 超级管理员权限校验失败时返回相应提示。 +- 业务错误 + - 后端路由捕获异常并记录日志,返回统一错误响应;前端拦截 code=0 的业务错误并提示。 +- 缓存问题 + - Redis 读取失败记录错误日志;字段不存在抛出明确错误;可回退到数据库或外部存储。 +- S3 问题 + - 上传/下载失败记录错误日志;404 映射为“未找到频响文件”,便于前端提示。 + +章节来源 +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +## 结论 +本系统通过统一的请求拦截、鉴权中间件、统一响应与日志体系,实现了从前端到后端的清晰数据流;结合 Redis 缓存与 S3 外部存储,兼顾了性能与扩展性;通过 Zod 校验与模型约束保障了数据质量。建议在生产中进一步完善指标埋点与告警、敏感字段加密存储与传输加密,持续优化缓存命中率与数据库查询计划。 + +## 附录 +- 环境与部署 + - 环境变量区分开发/生产;数据库与 Redis 默认值可按部署调整;日志模块集中输出。 +- 安全与隐私 + - 传输:建议启用 HTTPS;前端仅在受保护路由注入 Bearer Token;后端严格校验 Token。 + - 存储:敏感字段建议加密存储;S3 访问凭证优先使用 IAM 角色;最小权限原则。 + - 隐私:对用户标识与日志脱敏;仅保留必要审计日志。 + +章节来源 +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/系统架构/系统架构.md b/.qoder/repowiki/zh/content/系统架构/系统架构.md new file mode 100644 index 0000000..47046eb --- /dev/null +++ b/.qoder/repowiki/zh/content/系统架构/系统架构.md @@ -0,0 +1,482 @@ +# 系统架构 + + +**本文引用的文件** +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/models/index.js](file://backend/src/models/index.js) +- [backend/src/services/userBootstrap.js](file://backend/src/services/userBootstrap.js) +- [backend/Dockerfile](file://backend/Dockerfile) +- [backend/package.json](file://backend/package.json) +- [frontend/src/main.js](file://frontend/src/main.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [frontend/src/App.vue](file://frontend/src/App.vue) +- [frontend/package.json](file://frontend/package.json) +- [docker-compose.yml](file://docker-compose.yml) +- [DEPLOY.md](file://DEPLOY.md) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 引言 +本系统是一个前后端分离的耳机品牌与型号管理平台,采用 Vue 3 + Express 的技术栈,通过 Nginx 作为静态资源与反向代理服务,配合 Docker Compose 实现快速部署与运维。系统遵循分层架构与 MVC 设计模式,后端以路由-控制器-模型(R-C-M)为核心组织业务逻辑,前端以组件化与路由守卫保障安全与导航体验。 + +## 项目结构 +- 后端(Node.js + Express):集中于 backend 目录,包含配置、中间件、路由、模型、服务与工具模块,并通过 Dockerfile 与 docker-compose.yml 提供容器化运行支持。 +- 前端(Vue 3 + Element Plus):集中于 frontend 目录,包含入口、路由、布局、视图与通用工具,构建产物由 Nginx 提供静态托管。 +- 部署与运维:通过 docker-compose.yml 统一编排前端 Nginx 与后端 Node 服务,共享网络与卷,便于升级与日志管理。 + +```mermaid +graph TB +subgraph "前端Nginx 静态" +FE_Main["frontend/src/main.js"] +FE_Router["frontend/src/router/index.js"] +FE_App["frontend/src/App.vue"] +end +subgraph "后端Node.js + Express" +BE_App["backend/src/app.js"] +BE_Routes["backend/src/routes/index.js"] +BE_MW_Auth["backend/src/middleware/auth.js"] +BE_Utils_JWT["backend/src/utils/jwt.js"] +BE_Config_Env["backend/src/config/env.js"] +BE_Config_DB["backend/src/config/database.js"] +BE_Config_Logger["backend/src/config/logger.js"] +BE_Config_Redis["backend/src/config/redis.js"] +BE_Models_Index["backend/src/models/index.js"] +BE_Services_Bootstrap["backend/src/services/userBootstrap.js"] +end +subgraph "基础设施" +DC["docker-compose.yml"] +DF["backend/Dockerfile"] +end +FE_Main --> FE_Router +FE_Router --> FE_App +FE_Router --> BE_App +BE_App --> BE_Routes +BE_App --> BE_MW_Auth +BE_App --> BE_Config_DB +BE_App --> BE_Config_Logger +BE_App --> BE_Config_Redis +BE_App --> BE_Config_Env +BE_Routes --> BE_MW_Auth +BE_Routes --> BE_Models_Index +BE_App --> BE_Services_Bootstrap +DC --> DF +``` + +图表来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +## 核心组件 +- 后端入口与中间件 + - 入口文件负责加载环境、初始化日志、同步数据库表、挂载路由与启动服务。 + - 中间件包括 CORS、JSON 解析、请求体大小限制等。 +- 路由与控制器 + - 路由汇总文件统一导出路由集合,各业务路由按模块划分,控制器职责清晰。 +- 认证与授权 + - 基于 JWT 的认证中间件,支持超级管理员权限校验。 +- 配置与环境 + - 环境变量统一管理,支持开发/生产环境切换;数据库、日志、Redis 等配置模块化。 +- 模型与数据层 + - ORM 层通过 Sequelize 管理实体,模型导出统一入口。 +- 服务与工具 + - 用户引导服务用于首次部署创建超级管理员;JWT 工具封装签发与解析;密码工具用于安全存储。 +- 前端入口与路由 + - Vue 应用在入口文件中注册路由与 UI 组件库;路由守卫处理鉴权与权限跳转。 + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 架构总览 +系统采用前后端分离架构,前端通过 Nginx 提供静态资源与 API 代理,后端以 Express 提供 RESTful 服务。核心交互流程如下: + +```mermaid +sequenceDiagram +participant Browser as "浏览器" +participant Nginx as "Nginx 前端服务" +participant Backend as "Express 后端" +participant DB as "数据库" +participant Redis as "Redis 缓存" +Browser->>Nginx : "GET /" +Nginx-->>Browser : "返回前端静态页面" +Browser->>Nginx : "POST /api/login" +Nginx->>Backend : "代理转发 /api/login" +Backend->>DB : "查询用户信息" +DB-->>Backend : "返回用户数据" +Backend-->>Nginx : "返回 JWT Token" +Nginx-->>Browser : "设置 Cookie/LocalStorage 并返回响应" +Browser->>Nginx : "GET /api/dashboard/stats" +Nginx->>Backend : "代理转发 /api/dashboard/stats" +Backend->>Redis : "读取缓存" +Redis-->>Backend : "返回缓存数据" +Backend-->>Nginx : "返回统计结果" +Nginx-->>Browser : "返回响应" +``` + +图表来源 +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/utils/jwt.js:7-21](file://backend/src/utils/jwt.js#L7-L21) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) + +## 详细组件分析 + +### 后端入口与启动流程 +- 加载环境变量与日志配置 +- 初始化数据库连接并尝试同步表结构 +- 启动 HTTP 服务并打印健康检查与文档地址 + +```mermaid +flowchart TD +Start(["启动入口"]) --> LoadEnv["加载环境变量"] +LoadEnv --> InitLogger["初始化日志"] +InitLogger --> SyncDB["同步数据库表结构"] +SyncDB --> BootstrapAdmin["引导超级管理员"] +BootstrapAdmin --> Listen["启动 HTTP 服务"] +Listen --> Health["健康检查接口 /health"] +Health --> Docs["文档接口 /docs, /redoc"] +``` + +图表来源 +- [backend/src/app.js:42-57](file://backend/src/app.js#L42-L57) +- [backend/src/services/userBootstrap.js:5-25](file://backend/src/services/userBootstrap.js#L5-L25) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/services/userBootstrap.js:1-28](file://backend/src/services/userBootstrap.js#L1-L28) + +### 路由与控制器(MVC) +- 路由汇总:统一导出各业务路由模块,便于集中挂载。 +- 控制器职责:处理请求参数、调用服务层、返回标准化响应。 +- 中间件:认证与权限校验在路由层前置,确保受保护接口的安全性。 + +```mermaid +graph LR +RoutesIndex["路由汇总
backend/src/routes/index.js"] --> AuthRouter["认证路由"] +RoutesIndex --> BrandsRouter["品牌路由"] +RoutesIndex --> ModelsRouter["型号路由"] +RoutesIndex --> OtaRouter["OTA 路由"] +RoutesIndex --> UsersRouter["用户路由"] +RoutesIndex --> DashboardRouter["仪表盘路由"] +AuthMW["认证中间件
backend/src/middleware/auth.js"] --> AuthRouter +AuthMW --> BrandsRouter +AuthMW --> ModelsRouter +AuthMW --> OtaRouter +AuthMW --> UsersRouter +AuthMW --> DashboardRouter +``` + +图表来源 +- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12) +- [backend/src/middleware/auth.js:3-33](file://backend/src/middleware/auth.js#L3-L33) + +章节来源 +- [backend/src/routes/index.js:1-13](file://backend/src/routes/index.js#L1-L13) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) + +### 认证与授权(JWT) +- 登录成功后签发带过期时间的访问令牌,前端持久化存储并在后续请求头携带。 +- 中间件从 Authorization 头解析 Bearer Token,验证失败返回 401。 +- 超级管理员权限在路由守卫中进行二次校验。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Front as "前端路由" +participant AuthMW as "认证中间件" +participant JWTU as "JWT 工具" +participant DB as "数据库" +Client->>Front : "访问受保护路由" +Front->>AuthMW : "携带 Authorization : Bearer " +AuthMW->>JWTU : "解码并验证 token" +JWTU-->>AuthMW : "返回用户信息" +AuthMW->>DB : "可选:刷新用户状态" +DB-->>AuthMW : "返回最新状态" +AuthMW-->>Front : "放行并注入 req.user" +``` + +图表来源 +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/utils/jwt.js:19-21](file://backend/src/utils/jwt.js#L19-L21) + +章节来源 +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +### 数据模型与分层 +- 表层(Models):定义实体与字段,统一导出便于上层引用。 +- 服务层(Services):封装业务逻辑与外部集成(如 S3、Redis、Meilisearch)。 +- 控制器层(Routes):接收请求、参数校验、调用服务、返回响应。 +- 配置层(Config):数据库、日志、Redis、环境变量等配置模块化。 + +```mermaid +graph TB +Controllers["控制器Routes"] +Services["服务Services"] +Models["模型Models"] +Config["配置Config"] +Utils["工具Utils"] +Controllers --> Services +Services --> Models +Services --> Config +Controllers --> Utils +Controllers --> Config +``` + +图表来源 +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) + +章节来源 +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) + +### 前端路由与导航 +- 路由守卫:根据 meta 字段决定是否需要登录与超级管理员权限;对已登录但无权限的用户进行重定向。 +- 导航组件:基于 Element Plus 与 Vue Router 组合,提供侧边栏与标签页导航。 + +```mermaid +flowchart TD +Enter["进入路由"] --> NeedAuth{"是否需要登录?"} +NeedAuth --> |否| Next["直接放行"] +NeedAuth --> |是| CheckToken["检查 Token 是否存在且未过期"] +CheckToken --> |否| RedirectLogin["重定向至登录页"] +CheckToken --> |是| CheckRole{"是否需要超级管理员?"} +CheckRole --> |否| Next +CheckRole --> |是| IsAdmin{"是否为超级管理员?"} +IsAdmin --> |否| Home["重定向至首页"] +IsAdmin --> |是| Next +``` + +图表来源 +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) + +章节来源 +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/App.vue:1-30](file://frontend/src/App.vue#L1-L30) + +## 依赖分析 +- 技术栈与版本 + - 后端:Node.js 22、Express、Sequelize、MySQL2、jsonwebtoken、axios、winston、ioredis、@aws-sdk/client-s3、zod 等。 + - 前端:Vue 3、Element Plus、Vue Router、Vite、axios 等。 + - 容器与编排:Docker、Docker Compose。 +- 第三方集成 + - 数据库:MySQL(通过 Sequelize)。 + - 缓存:Redis(ioredis)。 + - 对象存储:AWS S3(@aws-sdk/client-s3)。 + - 日志:Winston。 + - 校验:Zod。 +- 版本兼容性 + - 后端固定使用 pnpm 11.5.2 与 Node 22;前端使用 Vite 6.x 与 Vue 3.x 生态。 + +```mermaid +graph TB +subgraph "后端依赖" +Node["Node.js 22"] +Express["Express"] +Sequelize["Sequelize + MySQL2"] +JWT["jsonwebtoken"] +Axios["axios"] +Winston["winston"] +Redis["ioredis"] +S3["@aws-sdk/client-s3"] +Zod["zod"] +end +subgraph "前端依赖" +Vue["Vue 3"] +EP["Element Plus"] +VR["Vue Router"] +Vite["Vite"] +end +Node --> Express +Express --> Sequelize +Express --> JWT +Express --> Axios +Express --> Winston +Express --> Redis +Express --> S3 +Express --> Zod +Vue --> EP +Vue --> VR +Vite --> Vue +``` + +图表来源 +- [backend/package.json:11-27](file://backend/package.json#L11-L27) +- [frontend/package.json:10-22](file://frontend/package.json#L10-L22) + +章节来源 +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) + +## 性能考虑 +- 前端静态资源与缓存 + - Nginx 提供静态资源托管与缓存策略,减少后端压力。 +- 后端缓存与数据库 + - Redis 用于热点数据缓存,降低数据库读取压力;ORM 查询应结合索引与分页。 +- API 限流与请求体大小限制 + - 通过中间件限制请求体大小,避免异常流量导致内存压力。 +- 部署与伸缩 + - Docker Compose 支持水平扩展与滚动更新;建议引入负载均衡与多副本部署。 + +## 故障排查指南 +- 健康检查 + - 访问后端 /health 接口确认服务可用。 +- 日志定位 + - 查看后端容器日志与 Nginx 访问/错误日志,定位连接失败与权限问题。 +- 环境变量 + - 修改 .env 后需重启后端容器使新配置生效。 +- 常见问题 + - 前端白屏:确认 dist 目录上传与 Nginx 配置正确。 + - API 失败:检查数据库、Redis、Meilisearch 连接与权限。 + - 构建失败:确认上传了 package.json 与 pnpm-lock.yaml,且 Node 版本匹配。 + +章节来源 +- [DEPLOY.md:104-113](file://DEPLOY.md#L104-L113) +- [DEPLOY.md:226-256](file://DEPLOY.md#L226-L256) + +## 结论 +该系统通过前后端分离与分层架构实现了清晰的职责划分与良好的可维护性。后端以 Express + Sequelize 为核心,结合 JWT、Redis、S3 等组件满足业务与扩展需求;前端以 Vue 3 为基础,配合路由守卫与 UI 组件库提供良好的用户体验。Docker Compose 提供了稳定的部署与运维能力,适合在生产环境中持续演进。 + +## 附录 + +### 系统上下文图 +```mermaid +graph TB +Browser["浏览器"] +Nginx["Nginx前端静态 + 代理"] +Backend["Node.js 后端Express"] +MySQL["MySQL"] +Redis["Redis"] +S3["AWS S3"] +Browser --> Nginx +Nginx --> Backend +Backend --> MySQL +Backend --> Redis +Backend --> S3 +``` + +图表来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/package.json:21](file://backend/package.json#L21) + +### 组件分解图(后端) +```mermaid +graph TB +App["入口 app.js"] +Routers["路由汇总 routes/index.js"] +AuthMW["认证中间件 middleware/auth.js"] +JWTU["JWT 工具 utils/jwt.js"] +Env["环境配置 config/env.js"] +DB["数据库配置 config/database.js"] +Logger["日志配置 config/logger.js"] +RedisCfg["Redis 配置 config/redis.js"] +Models["模型导出 models/index.js"] +Bootstrap["引导服务 services/userBootstrap.js"] +App --> Routers +App --> AuthMW +App --> DB +App --> Logger +App --> RedisCfg +App --> Env +Routers --> AuthMW +Routers --> Models +App --> Bootstrap +AuthMW --> JWTU +``` + +图表来源 +- [backend/src/app.js:14-37](file://backend/src/app.js#L14-L37) +- [backend/src/routes/index.js:4-12](file://backend/src/routes/index.js#L4-L12) +- [backend/src/middleware/auth.js:3-33](file://backend/src/middleware/auth.js#L3-L33) +- [backend/src/utils/jwt.js:7-25](file://backend/src/utils/jwt.js#L7-L25) +- [backend/src/config/env.js:7-12](file://backend/src/config/env.js#L7-L12) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [backend/src/services/userBootstrap.js:5-25](file://backend/src/services/userBootstrap.js#L5-L25) + +### 部署拓扑与端口映射 +- 前端(Nginx):宿主端口 8082 -> 容器端口 80,静态资源来自 dist,代理 /api 到后端。 +- 后端(Node.js):宿主端口 8083 -> 容器端口 8000,容器内固定 PORT=8000 以匹配 Nginx 代理。 +- 网络:两服务加入同一桥接网络,便于内部通信。 +- 卷:OTA 升级包本地存储卷挂载至后端容器,便于 X9 设备离线升级。 + +章节来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [DEPLOY.md:7-11](file://DEPLOY.md#L7-L11) +- [DEPLOY.md:157-171](file://DEPLOY.md#L157-L171) + +### 安全性、监控与灾备 +- 安全性 + - JWT 过期时间控制、中间件统一鉴权、超级管理员权限校验。 + - 生产环境必须修改 JWT_SECRET 与默认管理员密码。 +- 监控 + - Winston 输出日志,Docker 日志轮转配置,建议接入集中式日志系统。 +- 灾难恢复 + - 数据库与 Redis 建议启用备份与异地复制;对象存储 S3 建议开启版本控制与跨区域复制。 + +章节来源 +- [backend/src/utils/jwt.js:3-5](file://backend/src/utils/jwt.js#L3-L5) +- [backend/src/middleware/auth.js:28-33](file://backend/src/middleware/auth.js#L28-L33) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [docker-compose.yml:1-5](file://docker-compose.yml#L1-L5) + +### 架构演进路线图与未来规划 +- 短期 + - 引入统一的 OpenAPI/Swagger 文档与校验(Zod 已具备基础校验能力)。 + - 增强日志与指标采集,完善告警机制。 +- 中期 + - 引入消息队列(如 Redis Streams/RabbitMQ)处理异步任务(如 OTA 文件处理、通知发送)。 + - 前端组件库与路由按功能域进一步拆分,提升可维护性。 +- 长期 + - 服务网格与 API 网关(如 Kong/Envoy)增强可观测性与治理能力。 + - 多环境(Dev/Staging/Prod)与蓝绿/金丝雀发布策略。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/系统架构/集成模式.md b/.qoder/repowiki/zh/content/系统架构/集成模式.md new file mode 100644 index 0000000..49d64aa --- /dev/null +++ b/.qoder/repowiki/zh/content/系统架构/集成模式.md @@ -0,0 +1,404 @@ +# 集成模式 + + +**本文档引用的文件** +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/middleware/auth.js](file://backend/src/middleware/auth.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/services/curveClient.js](file://backend/src/services/curveClient.js) +- [backend/src/services/measurementStorage.js](file://backend/src/services/measurementStorage.js) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [backend/src/services/otaStorage.js](file://backend/src/services/otaStorage.js) +- [backend/src/routes/brands.js](file://backend/src/routes/brands.js) +- [backend/src/routes/models.js](file://backend/src/routes/models.js) +- [backend/src/routes/ota.js](file://backend/src/routes/ota.js) +- [backend/package.json](file://backend/package.json) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件系统性梳理后端服务与外部系统及组件的集成策略,覆盖日志系统、文件上传与对象存储、第三方 API 调用、微服务间通信与事件驱动、缓存层与数据库连接池、资源管理、集成测试、监控告警与故障转移、配置管理与版本兼容性等主题。目标是帮助开发者与运维人员快速理解系统的集成边界与运行机制,并提供可操作的优化建议与排障指引。 + +## 项目结构 +后端采用 Express 应用入口集中加载中间件、路由与数据库初始化;配置模块按职责拆分,分别负责环境、日志、数据库与 Redis;服务层封装对外部系统的调用与存储逻辑;路由层统一鉴权并编排业务流程;工具与验证器模块提供通用能力。 + +```mermaid +graph TB +A["应用入口
backend/src/app.js"] --> B["配置模块
env.js / logger.js / database.js / redis.js"] +A --> C["中间件
auth.js / bodyLimit.js"] +A --> D["路由模块
brands.js / models.js / ota.js"] +D --> E["服务层
curveClient.js / measurementStorage.js / eqCacheStorage.js / otaStorage.js"] +E --> F["外部系统
Meilisearch / AWS S3 / Redis / 第三方曲线 API"] +B --> G["数据库
MySQL(Sequelize)"] +``` + +图表来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [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/services/curveClient.js:1-147](file://backend/src/services/curveClient.js#L1-L147) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) + +## 核心组件 +- 环境与配置:通过统一环境变量判断开发/生产,控制日志级别与数据库日志输出。 +- 日志系统:基于 Winston 控制台与文件双通道输出,统一时间戳与结构化日志格式。 +- 数据库:Sequelize 连接 MySQL,按环境启用 SQL 日志,冻结表名与关闭时间戳。 +- 缓存:Redis 客户端按需懒加载,错误事件记录到日志。 +- 鉴权:JWT 令牌解析与中间件拦截,支持超级管理员校验。 +- 外部集成:Meilisearch 文档检索、AWS S3 对象存储、第三方曲线 API、OTA 包上传与本地落盘。 + +章节来源 +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) + +## 架构总览 +系统采用“HTTP API + 多外部系统”的集成架构:Express 提供 REST 接口,路由层统一鉴权与参数编排,服务层封装具体集成动作,配置层统一管理外部系统凭据与行为。 + +```mermaid +graph TB +subgraph "应用层" +R1["路由
brands.js / models.js / ota.js"] +M1["中间件
auth.js / bodyLimit.js"] +U1["工具
jwt.js"] +end +subgraph "服务层" +S1["曲线服务
curveClient.js"] +S2["频响存储
measurementStorage.js"] +S3["缓存读取
eqCacheStorage.js"] +S4["OTA 存储
otaStorage.js"] +end +subgraph "外部系统" +E1["Meilisearch"] +E2["AWS S3"] +E3["Redis"] +E4["第三方曲线 API"] +end +R1 --> M1 +R1 --> U1 +R1 --> S1 +R1 --> S2 +R1 --> S3 +R1 --> S4 +S1 --> E4 +S2 --> E2 +S3 --> E3 +R1 --> E1 +``` + +图表来源 +- [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/services/curveClient.js:1-147](file://backend/src/services/curveClient.js#L1-L147) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +## 详细组件分析 + +### 日志系统集成 +- 输出介质:控制台与文件双通道,文件自动创建日志目录。 +- 格式:时间戳、级别、消息与附加元数据 JSON 字符串化。 +- 环境控制:开发环境开启数据库 SQL 日志,生产环境关闭以降低噪声。 +- 使用场景:所有服务与路由均通过统一 logger 记录请求、响应与异常。 + +```mermaid +flowchart TD +Start(["请求进入"]) --> LogInfo["记录请求信息"] +LogInfo --> Process["业务处理"] +Process --> Ok{"处理成功?"} +Ok --> |是| LogOk["记录成功日志"] +Ok --> |否| LogErr["记录错误日志"] +LogOk --> End(["响应返回"]) +LogErr --> End +``` + +图表来源 +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/config/database.js:15](file://backend/src/config/database.js#L15) + +章节来源 +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) + +### 文件上传与对象存储集成(S3) +- Meilisearch 集成:提供文档查询与删除能力,支持超时与 404 特判。 +- S3 频响文件:根据品牌/型号/佩戴方式生成键值,支持凭证直连与 IAM 角色两种模式。 +- 上传流程:路由接收 multipart/form-data,服务层转换 TXT→CSV 并上传至 S3。 +- 读取流程:按模型来源与佩戴方式定位键值,返回 CSV 内容。 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant R as "路由(models.js)" +participant S as "S3 服务(measurementStorage.js)" +participant A as "AWS S3" +C->>R : "POST /api/models/ (含 measurement_file)" +R->>R : "校验扩展名/转换TXT为CSV" +R->>S : "uploadMeasurementToS3(buffer, params)" +S->>A : "PutObjectCommand(Bucket, Key, Body)" +A-->>S : "返回结果" +S-->>R : "返回 S3 Key" +R-->>C : "返回上传结果" +``` + +图表来源 +- [backend/src/routes/models.js:306-361](file://backend/src/routes/models.js#L306-L361) +- [backend/src/services/measurementStorage.js:61-80](file://backend/src/services/measurementStorage.js#L61-L80) + +章节来源 +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [backend/src/services/measurementStorage.js:1-115](file://backend/src/services/measurementStorage.js#L1-L115) + +### 第三方 API 调用模式(曲线 API) +- 目标:拉取并校验第三方曲线数据,支持自定义 Base64 映射与 parametric_eq 结构校验。 +- 流程:构造查询参数 → 发起 HTTP 请求 → 提取编码数据 → Base64 解码 → JSON 校验 → 返回结果。 +- 错误处理:对响应为空、格式异常、解码失败、JSON 非法、payload 异常进行分类处理并记录日志。 + +```mermaid +flowchart TD +A["输入: 品牌/型号/佩戴方式"] --> B["构造 URL 查询参数"] +B --> C["GET 曲线 API"] +C --> D{"HTTP 200?"} +D --> |否| E["返回错误: HTTP 状态"] +D --> |是| F["提取编码数据"] +F --> G{"提取成功?"} +G --> |否| H["返回错误: 未找到可解码数据"] +G --> |是| I["自定义 Base64 解码"] +I --> J{"解码成功?"} +J --> |否| K["返回错误: Base64 解码失败"] +J --> |是| L["JSON 解析"] +L --> M{"JSON 合法且结构正确?"} +M --> |否| N["返回错误: 曲线数据异常"] +M --> |是| O["返回成功"] +``` + +图表来源 +- [backend/src/services/curveClient.js:81-138](file://backend/src/services/curveClient.js#L81-L138) + +章节来源 +- [backend/src/services/curveClient.js:1-147](file://backend/src/services/curveClient.js#L1-L147) + +### 缓存层集成(Redis) +- 客户端:按需懒加载,支持密码、超时与重试次数配置,错误事件统一记录日志。 +- 读取:提供哈希键集合与单字段读取,避免一次性返回过大响应体。 +- 场景:EQ 缓存字段列表与单字段值读取,便于前端按需加载。 + +```mermaid +sequenceDiagram +participant R as "路由(models.js)" +participant S as "缓存服务(eqCacheStorage.js)" +participant RC as "Redis 客户端(config/redis.js)" +R->>S : "getEqCacheKeys(brand, model)" +S->>RC : "exists(redisKey)" +alt "存在" +S->>RC : "hkeys(redisKey)" +RC-->>S : "field 列表" +else "不存在" +S-->>R : "返回空字段" +end +R->>S : "getEqCacheField(brand, model, key)" +S->>RC : "hget(redisKey, key)" +RC-->>S : "value 或 null" +S-->>R : "返回解析后的值" +``` + +图表来源 +- [backend/src/routes/models.js:183-223](file://backend/src/routes/models.js#L183-L223) +- [backend/src/services/eqCacheStorage.js:24-66](file://backend/src/services/eqCacheStorage.js#L24-L66) +- [backend/src/config/redis.js:11-29](file://backend/src/config/redis.js#L11-L29) + +章节来源 +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/routes/models.js:183-223](file://backend/src/routes/models.js#L183-L223) + +### 微服务间通信与事件驱动 +- 当前实现:内部路由通过 Express 提供 REST 接口,未发现内置消息队列或事件总线代码。 +- 建议:若未来引入异步任务或跨服务事件,可考虑引入消息队列(如 RabbitMQ/Kafka)与事件驱动架构,结合幂等与重试策略。 + +章节来源 +- [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) + +### 数据库连接池与资源管理 +- 连接:Sequelize 连接 MySQL,开发环境打印 SQL,生产环境关闭。 +- 表定义:冻结表名、关闭时间戳,减少迁移成本。 +- 初始化:应用启动时尝试同步数据库表结构,失败记录警告并继续运行。 + +```mermaid +flowchart TD +A["启动应用(app.js)"] --> B["加载配置(database.js)"] +B --> C["创建 Sequelize 实例"] +C --> D{"开发环境?"} +D --> |是| E["开启 SQL 日志"] +D --> |否| F["关闭 SQL 日志"] +E --> G["同步数据库表结构"] +F --> G +G --> H["监听端口并启动服务"] +``` + +图表来源 +- [backend/src/app.js:42-57](file://backend/src/app.js#L42-L57) +- [backend/src/config/database.js:14](file://backend/src/config/database.js#L14) + +章节来源 +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) + +### 鉴权与安全 +- JWT:签发与解析使用固定密钥与算法,设置 12 小时有效期。 +- 中间件:统一 Bearer Token 校验,支持超级管理员权限校验。 +- 路由保护:多数业务路由挂载 auth 中间件,部分公开接口(如 OTA 最新版本检查)允许匿名访问。 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant R as "路由(models.js/brands.js/ota.js)" +participant M as "鉴权中间件(auth.js)" +participant T as "JWT 工具(jwt.js)" +C->>R : "携带 Authorization : Bearer " +R->>M : "校验头部格式" +M->>T : "decodeToken(token)" +T-->>M : "用户负载" +M-->>R : "注入 req.user" +R-->>C : "继续业务处理" +``` + +图表来源 +- [backend/src/middleware/auth.js:3-26](file://backend/src/middleware/auth.js#L3-L26) +- [backend/src/utils/jwt.js:7-21](file://backend/src/utils/jwt.js#L7-L21) +- [backend/src/routes/models.js:70-71](file://backend/src/routes/models.js#L70-L71) +- [backend/src/routes/brands.js:11-12](file://backend/src/routes/brands.js#L11-L12) +- [backend/src/routes/ota.js:104-105](file://backend/src/routes/ota.js#L104-L105) + +章节来源 +- [backend/src/middleware/auth.js:1-36](file://backend/src/middleware/auth.js#L1-L36) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) + +### OTA 升级包存储策略 +- X8:上传至 S3,按年月/设备/MD5 前缀组织键值,返回公共下载地址。 +- X9:保存到本地目录(开发/生产目录可配置),按年月/设备/MD5 前缀组织路径,返回公共 URL。 +- 校验:计算 MD5 用于命名与去重。 + +```mermaid +flowchart TD +A["接收文件(Multer)"] --> B["计算 MD5"] +B --> C{"设备型号"} +C --> |X8| D["构建 S3 Key (年月/设备/MD5前缀)"] +D --> E["S3 上传"] +E --> F["返回下载地址与 Key"] +C --> |X9| G["构建本地路径 (年月/设备/MD5前缀)"] +G --> H["写入文件"] +H --> I["返回下载地址与文件名"] +``` + +图表来源 +- [backend/src/routes/ota.js:24-66](file://backend/src/routes/ota.js#L24-L66) +- [backend/src/services/otaStorage.js:51-103](file://backend/src/services/otaStorage.js#L51-L103) + +章节来源 +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) + +### 配置管理、版本兼容与升级策略 +- 环境变量:APP_ENV 控制开发/生产;数据库、S3、Redis、JWT 等均通过环境变量配置。 +- 版本与依赖:后端使用 Node 生态主流库,S3 SDK 与 Winston 等均支持多版本共存,建议在 CI 中锁定版本并定期扫描安全漏洞。 +- 升级策略:建议采用蓝绿/滚动发布,配合健康检查与回滚脚本;数据库变更通过迁移工具与只增不改策略降低风险。 + +章节来源 +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/utils/jwt.js:3](file://backend/src/utils/jwt.js#L3) +- [backend/package.json:1-29](file://backend/package.json#L1-L29) + +## 依赖关系分析 +- 应用入口依赖配置模块与路由集合,路由依赖中间件与服务层,服务层依赖外部系统 SDK。 +- 关键外部依赖:Express、Sequelize、Winston、Axios、AWS S3 Client、ioredis、jsonwebtoken。 + +```mermaid +graph LR +App["app.js"] --> Cfg["config/*"] +App --> Rt["routes/*"] +Rt --> Mid["middleware/*"] +Rt --> Svc["services/*"] +Svc --> Ext["外部系统 SDK"] +Ext --> Dep["package.json 依赖"] +``` + +图表来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/package.json:11-24](file://backend/package.json#L11-L24) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/package.json:1-29](file://backend/package.json#L1-L29) + +## 性能考量 +- 日志:生产关闭数据库 SQL 日志,避免 I/O 抖动;必要时将日志输出到集中式日志系统。 +- 缓存:优先使用 Redis 哈希字段读取,避免一次性传输大对象;合理设置连接超时与重试。 +- 存储:S3 上传使用内存流,注意文件大小限制与超时;对大文件可考虑分片上传。 +- 数据库:批量写入与查询时使用分页与索引;避免 N+1 查询。 +- API:对第三方曲线 API 设置合理超时与重试;对 Meilisearch 推送使用批量接口并限流。 + +## 故障排查指南 +- 日志定位:所有关键路径均有 info/warn/error 日志,优先查看日志文件与控制台输出。 +- 数据库:启动阶段同步表失败会记录警告并继续运行,检查数据库连接与权限。 +- S3:凭证缺失或 IAM 角色不可用会导致上传失败,检查 AWS_REGION、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY。 +- Redis:连接超时或认证失败会触发错误事件,检查主机、端口、密码与网络连通性。 +- JWT:令牌过期或签名不匹配导致 401,检查密钥与 TTL。 +- Meilisearch:404 与状态码特判,确认索引存在与 API Key 正确。 + +章节来源 +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/app.js:42-57](file://backend/src/app.js#L42-L57) +- [backend/src/services/measurementStorage.js:76-107](file://backend/src/services/measurementStorage.js#L76-L107) +- [backend/src/config/redis.js:24-26](file://backend/src/config/redis.js#L24-L26) +- [backend/src/utils/jwt.js:21](file://backend/src/utils/jwt.js#L21) +- [backend/src/routes/models.js:89-128](file://backend/src/routes/models.js#L89-L128) + +## 结论 +本系统通过清晰的配置模块、统一的日志与鉴权、完善的外部系统集成与资源管理,实现了稳定高效的后端服务能力。建议后续在异步任务与跨服务事件方面引入消息队列与可观测性体系,持续提升系统的弹性与可维护性。 + +## 附录 +- 健康检查:根路径与 /health 均无需登录,可用于容器探针与负载均衡健康检查。 +- 文档:/docs 与 /redoc 可用于 API 文档浏览。 + +章节来源 +- [backend/src/app.js:22-34](file://backend/src/app.js#L22-L34) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/部署与运维/故障排除.md b/.qoder/repowiki/zh/content/部署与运维/故障排除.md new file mode 100644 index 0000000..3759af7 --- /dev/null +++ b/.qoder/repowiki/zh/content/部署与运维/故障排除.md @@ -0,0 +1,507 @@ +# 故障排除 + + +**本文引用的文件** +- [DEPLOY.md](file://DEPLOY.md) +- [docker-compose.yml](file://docker-compose.yml) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/utils/response.js](file://backend/src/utils/response.js) +- [frontend/nginx.conf](file://frontend/nginx.conf) +- [frontend/src/utils/request.js](file://frontend/src/utils/request.js) +- [scripts/upload.sh](file://scripts/upload.sh) +- [backend/package.json](file://backend/package.json) +- [frontend/package.json](file://frontend/package.json) +- [backend/start.sh](file://backend/start.sh) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件面向运维与开发人员,提供 Audio Dashboard 在 Docker 环境下的系统性故障排除与常见问题解答(FAQ)。覆盖前端页面空白、API 请求失败、后端构建失败、Docker 相关问题、网络连接问题、数据库连接问题、日志分析方法、错误代码含义、调试技巧、性能诊断、内存泄漏检测与系统瓶颈分析,以及紧急情况下的快速恢复与回滚策略。 + +## 项目结构 +- 前端采用 Vite 构建,Nginx 提供静态托管与 /api 代理。 +- 后端采用 Express + Sequelize,通过 Docker Compose 编排,前端反向代理到后端容器。 +- 环境变量集中于根目录 .env,Compose 读取并注入到容器。 + +```mermaid +graph TB +subgraph "宿主机" +FE["前端静态资源
frontend/dist"] +NGINX["Nginx 配置
frontend/nginx.conf"] +DC["Docker Compose
docker-compose.yml"] +ENV[".env 环境变量"] +end +subgraph "容器" +F["frontend(Nginx)"] +B["backend(Node.js)"] +DB["MySQL"] +REDIS["Redis"] +S3["S3 存储"] +end +FE --> F +NGINX --> F +ENV --> B +DC --> F +DC --> B +F --> |"HTTP 80"| B +B --> DB +B --> REDIS +B --> S3 +``` + +图表来源 +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [frontend/nginx.conf:1-34](file://frontend/nginx.conf#L1-L34) +- [DEPLOY.md:157-171](file://DEPLOY.md#L157-L171) + +章节来源 +- [DEPLOY.md:157-171](file://DEPLOY.md#L157-L171) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +## 核心组件 +- 前端请求封装与拦截器:统一设置 /api 基础路径、Token 注入、401/403 处理与错误提示。 +- 后端入口与健康检查:Express 应用、CORS、Body 解析、/health 健康检查、表初始化与启动日志。 +- 日志系统:Winston 控制台与文件输出,按时间戳格式化。 +- 数据库连接:Sequelize 初始化,开发/生产日志开关。 +- 环境变量:APP_ENV 切换开发/生产,PORT 控制监听端口。 +- Nginx 代理:/api 代理到 backend:8000,静态缓存与上传大小限制。 +- 上传脚本:rsync 同步前端 dist、后端 src/package/pnpm-lock、compose 文件。 + +章节来源 +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [frontend/nginx.conf:1-34](file://frontend/nginx.conf#L1-L34) +- [scripts/upload.sh:1-191](file://scripts/upload.sh#L1-L191) + +## 架构总览 +- 前端通过 Nginx 将 /api 请求转发至 backend:8000。 +- 后端监听容器内 8000 端口,宿主机映射 8083。 +- 健康检查端点 /health 用于快速验证后端状态。 +- 环境变量 .env 通过 env_file 注入,确保数据库、Redis、S3 等配置一致。 + +```mermaid +sequenceDiagram +participant U as "用户浏览器" +participant N as "Nginx(Frontend)" +participant E as "Express(API)" +participant DB as "MySQL" +participant R as "Redis" +U->>N : "GET /api/xxx" +N->>E : "proxy_pass http : //backend : 8000" +E->>DB : "查询/写入" +E->>R : "缓存/计数" +E-->>N : "JSON 响应" +N-->>U : "HTML/JS + JSON" +``` + +图表来源 +- [frontend/nginx.conf:11-21](file://frontend/nginx.conf#L11-L21) +- [backend/src/app.js:31-34](file://backend/src/app.js#L31-L34) +- [docker-compose.yml:19-20](file://docker-compose.yml#L19-L20) + +## 详细组件分析 + +### 前端请求与错误处理 +- 基础路径:/api,超时 10 秒。 +- Token 注入:除登录接口外自动附加 Authorization。 +- 401:清理本地认证并重定向到登录页。 +- 403:提示无权限。 +- 通用错误:控制台记录并全局消息提示。 + +```mermaid +flowchart TD +Start(["发起请求"]) --> Inject["注入 Token非登录"] +Inject --> Send["发送到 /api"] +Send --> Resp{"响应 code"} +Resp --> |code==0| Err["抛出错误并显示消息"] +Resp --> |401| AuthErr["清理认证并跳转登录"] +Resp --> |403| PermErr["提示无权限"] +Resp --> |其他| Ok["返回数据"] +Err --> End(["结束"]) +AuthErr --> End +PermErr --> End +Ok --> End +``` + +图表来源 +- [frontend/src/utils/request.js:11-69](file://frontend/src/utils/request.js#L11-L69) + +章节来源 +- [frontend/src/utils/request.js:1-72](file://frontend/src/utils/request.js#L1-L72) + +### 后端启动与健康检查 +- CORS 开放,支持 JSON/URL 编码请求体。 +- /health 返回健康状态。 +- 启动时尝试同步数据库表并引导超级管理员账户。 +- 日志输出包含时间戳与元信息。 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant A as "Express(app)" +participant S as "Sequelize" +participant L as "Logger" +A->>L : "info : Creating database tables..." +A->>S : "sync()" +S-->>A : "成功/失败" +A->>L : "info/error 日志" +A->>A : "listen(PORT)" +C->>A : "GET /health" +A-->>C : "{ status : 'healthy' }" +``` + +图表来源 +- [backend/src/app.js:42-56](file://backend/src/app.js#L42-L56) +- [backend/src/config/logger.js:10-26](file://backend/src/config/logger.js#L10-L26) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +### 数据库连接与环境变量 +- 通过 DATABASE_* 环境变量配置主机、端口、库名、账号、密码。 +- 生产环境关闭 Sequelize 日志,开发环境开启。 +- 定义冻结表名与禁用时间戳,减少迁移成本。 + +```mermaid +flowchart TD +Env["读取 .env DATABASE_*"] --> NewDB["创建 Sequelize 实例"] +NewDB --> Dev{"APP_ENV 是否 development"} +Dev --> |是| LogOn["开启 Sequelize 日志"] +Dev --> |否| LogOff["关闭 Sequelize 日志"] +LogOn --> Sync["启动时 sync()"] +LogOff --> Sync +Sync --> Ready["应用可用"] +``` + +图表来源 +- [backend/src/config/database.js:4-21](file://backend/src/config/database.js#L4-L21) +- [backend/src/config/env.js:7-10](file://backend/src/config/env.js#L7-L10) + +章节来源 +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) + +### Nginx 代理与静态资源 +- /api 代理到 http://backend:8000。 +- 支持 Vue Router 历史模式回退到 index.html。 +- 静态资源缓存一年,Gzip 压缩常用类型。 +- 上传文件最大 8MB。 + +```mermaid +flowchart TD +Req["浏览器请求"] --> Path{"路径匹配"} +Path --> |/api*| Proxy["代理到 backend:8000"] +Path --> |/| HTML["返回 index.html"] +Path --> |静态资源| Cache["缓存一年 + Gzip"] +Proxy --> Resp["返回后端响应"] +HTML --> Resp +Cache --> Resp +``` + +图表来源 +- [frontend/nginx.conf:11-26](file://frontend/nginx.conf#L11-L26) +- [frontend/nginx.conf:28-32](file://frontend/nginx.conf#L28-L32) + +章节来源 +- [frontend/nginx.conf:1-34](file://frontend/nginx.conf#L1-L34) + +### 上传与部署脚本 +- 支持同步前端 dist、后端 src/package/pnpm-lock、compose 文件。 +- 默认目标服务器与密钥可配置。 +- 支持虚拟执行预览同步内容。 + +```mermaid +flowchart TD +Run["执行 upload.sh"] --> Resolve["解析预设/自定义路径"] +Resolve --> Sync["rsync 同步到远端"] +Sync --> Done["完成"] +``` + +图表来源 +- [scripts/upload.sh:77-151](file://scripts/upload.sh#L77-L151) +- [scripts/upload.sh:142-187](file://scripts/upload.sh#L142-L187) + +章节来源 +- [scripts/upload.sh:1-191](file://scripts/upload.sh#L1-L191) + +## 依赖关系分析 +- 前端依赖 axios、Vue、Element Plus 等,构建后由 Nginx 提供。 +- 后端依赖 Express、Sequelize、MySQL2、Winston、ioredis、@aws-sdk 等。 +- Compose 将 .env 注入后端容器,前端挂载 dist 与 nginx.conf。 + +```mermaid +graph LR +FE_PKG["frontend/package.json"] --> FE_DEPS["运行时依赖"] +BE_PKG["backend/package.json"] --> BE_DEPS["运行时依赖"] +DC["docker-compose.yml"] --> ENV[".env 注入"] +FE_DEPS --> FE_APP["Nginx 静态服务"] +BE_DEPS --> BE_APP["Express 应用"] +ENV --> BE_APP +FE_APP --> |"HTTP"| BE_APP +``` + +图表来源 +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [docker-compose.yml:13-14](file://docker-compose.yml#L13-L14) + +章节来源 +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +## 性能考虑 +- 日志轮转:单文件最大 10MB,最多 5 个文件,避免磁盘占用过大。 +- Nginx 缓存:静态资源一年缓存,降低带宽与后端压力。 +- Gzip 压缩:对文本与 JS/CSS/JSON 启用压缩。 +- 上传大小限制:8MB,避免大体积请求导致内存压力。 +- 健康检查:/health 快速定位后端存活状态。 + +章节来源 +- [docker-compose.yml:1-5](file://docker-compose.yml#L1-L5) +- [frontend/nginx.conf:28-32](file://frontend/nginx.conf#L28-L32) +- [frontend/nginx.conf:19](file://frontend/nginx.conf#L19) +- [backend/src/app.js:31-34](file://backend/src/app.js#L31-L34) + +## 故障排除指南 + +### 一、前端页面空白 +- 检查点 + - 前端构建产物是否上传至 /data/project/dashboard/frontend/dist。 + - Nginx 是否加载正确的 default.conf。 + - 浏览器控制台是否存在 404 或跨域错误。 + - 健康检查 /health 是否可达。 +- 排查步骤 + - 登录服务器,确认 dist 目录存在且内容完整。 + - 查看 Nginx 日志与容器日志。 + - 确认 /api 代理指向 backend:8000。 +- 快速修复 + - 重新构建并上传前端,或重启 frontend 容器。 + +章节来源 +- [DEPLOY.md:226-233](file://DEPLOY.md#L226-L233) +- [frontend/nginx.conf:11-21](file://frontend/nginx.conf#L11-L21) +- [docker-compose.yml:33-35](file://docker-compose.yml#L33-L35) + +### 二、API 请求失败 +- 检查点 + - backend 容器状态是否 running。 + - /health 是否返回 healthy。 + - 数据库、Redis、Meilisearch 连接是否正常。 + - Nginx 代理是否正确指向 backend:8000。 +- 排查步骤 + - docker compose ps 查看服务状态。 + - docker compose logs -f backend 查看错误堆栈。 + - curl http://localhost:8083/health 验证健康检查。 + - 检查 .env 中 DATABASE_*、REDIS_*、AWS_* 等配置。 +- 快速修复 + - 修正 .env 后,强制重建并重启 backend 容器。 + +章节来源 +- [DEPLOY.md:234-249](file://DEPLOY.md#L234-L249) +- [backend/src/app.js:31-34](file://backend/src/app.js#L31-L34) +- [docker-compose.yml:19-20](file://docker-compose.yml#L19-L20) + +### 三、后端构建失败(pnpm / Node 版本) +- 检查点 + - 后端镜像基于 node:22-alpine。 + - package.json 与 pnpm-lock.yaml 是否随后端一起上传。 +- 排查步骤 + - 确认上传脚本包含 backend 相关文件。 + - 在服务器执行 docker compose build --no-cache backend。 +- 快速修复 + - 重新上传后端文件并重新构建。 + +章节来源 +- [DEPLOY.md:240-244](file://DEPLOY.md#L240-L244) +- [scripts/upload.sh:14-18](file://scripts/upload.sh#L14-L18) +- [backend/package.json:5](file://backend/package.json#L5) + +### 四、修改 .env 后不生效 +- 现象 + - 更改环境变量后,容器未感知。 +- 排查步骤 + - docker compose up -d --force-recreate backend。 +- 快速修复 + - 强制重建后端容器以加载新 .env。 + +章节来源 +- [DEPLOY.md:245-249](file://DEPLOY.md#L245-L249) + +### 五、停止与重启服务 +- 停止 + - docker compose down。 +- 仅重启前端 + - docker compose restart frontend。 +- 仅更新后端 + - 上传后端文件,build 并 up -d backend。 + +章节来源 +- [DEPLOY.md:251-255](file://DEPLOY.md#L251-L255) +- [DEPLOY.md:135-144](file://DEPLOY.md#L135-L144) + +### 六、Docker 相关问题 +- 端口冲突 + - 检查宿主机 8082/8083 是否被占用。 +- 权限问题 + - 确认 dist 与 nginx.conf 挂载权限。 +- 日志过大 + - 使用日志轮转配置,必要时清理历史日志。 + +章节来源 +- [docker-compose.yml:19-20](file://docker-compose.yml#L19-L20) +- [docker-compose.yml:33-35](file://docker-compose.yml#L33-L35) +- [docker-compose.yml:1-5](file://docker-compose.yml#L1-L5) + +### 七、网络连接问题 +- 前端无法访问 /api + - 检查 Nginx 代理配置与 backend 容器连通性。 + - 确认容器网络 audio-network 是否创建成功。 +- 后端无法访问外部服务 + - 检查 DNS、防火墙、安全组规则。 + - 确认 AWS 凭证或 IAM 角色配置。 + +章节来源 +- [frontend/nginx.conf:11-21](file://frontend/nginx.conf#L11-L21) +- [docker-compose.yml:23-24](file://docker-compose.yml#L23-L24) +- [DEPLOY.md:190-203](file://DEPLOY.md#L190-L203) + +### 八、数据库连接问题 +- 检查点 + - DATABASE_HOST/PORT/NAME/USER/PASSWORD 是否正确。 + - MySQL 服务可达,账号具备权限。 + - 容器内网络与端口映射是否正确。 +- 排查步骤 + - 在 backend 容器内测试连接(nslookup/mysql 命令)。 + - 查看后端启动日志中的数据库连接错误。 +- 快速修复 + - 修正 .env 中数据库配置并重建后端容器。 + +章节来源 +- [backend/src/config/database.js:4-21](file://backend/src/config/database.js#L4-L21) +- [backend/src/app.js:42-51](file://backend/src/app.js#L42-L51) + +### 九、日志分析方法 +- 后端日志 + - 控制台与文件同时输出,查看启动阶段的表同步与错误信息。 +- 前端日志 + - 浏览器开发者工具 Network/Console。 +- Nginx 日志 + - 容器标准输出,关注 4xx/5xx 与代理错误。 +- 建议 + - 结合时间戳定位问题发生时段,优先查看 ERROR/异常堆栈。 + +章节来源 +- [backend/src/config/logger.js:10-26](file://backend/src/config/logger.js#L10-L26) +- [backend/src/app.js:42-56](file://backend/src/app.js#L42-L56) +- [docker-compose.yml:21-22](file://docker-compose.yml#L21-L22) +- [frontend/nginx.conf:11-21](file://frontend/nginx.conf#L11-L21) + +### 十、错误代码含义与调试技巧 +- 响应结构 + - code=1:成功;code=0:业务错误;code=2:无数据。 +- 前端拦截器 + - code=0:统一错误提示与拒绝 Promise。 + - 401:清除本地认证并跳转登录。 + - 403:提示无权限。 +- 调试技巧 + - 打开浏览器 Network 面板,观察请求头与响应体。 + - 在后端添加最小复现接口,逐步缩小范围。 + - 使用 curl 直连 /health 与关键业务接口验证后端状态。 + +章节来源 +- [backend/src/utils/response.js:1-25](file://backend/src/utils/response.js#L1-L25) +- [frontend/src/utils/request.js:27-69](file://frontend/src/utils/request.js#L27-L69) +- [backend/src/app.js:31-34](file://backend/src/app.js#L31-L34) + +### 十一、性能问题诊断 +- CPU/内存飙升 + - 检查后端日志中慢查询与异常堆栈。 + - 关注 Nginx 代理错误与后端队列积压。 +- 静态资源加载慢 + - 确认缓存头与 Gzip 是否生效。 + - 检查 dist 是否最新版本。 +- 数据库慢 + - 查看数据库连接数与锁等待。 + - 优化查询与索引。 + +章节来源 +- [frontend/nginx.conf:28-32](file://frontend/nginx.conf#L28-L32) +- [backend/src/config/database.js:15](file://backend/src/config/database.js#L15) + +### 十二、内存泄漏检测与系统瓶颈分析 +- 方法 + - 使用 Node.js 内置分析工具生成 Heap/Profile 快照。 + - 持续监控容器资源使用率与错误日志。 + - 逐步禁用功能模块定位可疑代码段。 +- 建议 + - 限制并发与批量操作,增加重试与熔断机制。 + +[本节为通用指导,无需特定文件引用] + +### 十三、紧急恢复与回滚策略 +- 快速恢复 + - 重启 frontend 与 backend 容器。 + - 回滚到上一个稳定版本的 dist 与后端镜像。 +- 回滚步骤 + - 前端:恢复上一版 dist。 + - 后端:切换镜像标签或重新 build 上一版。 +- 预案 + - 保留最近一次构建产物与镜像快照。 + - 使用只读挂载与备份卷保障数据安全。 + +章节来源 +- [DEPLOY.md:122-154](file://DEPLOY.md#L122-L154) +- [scripts/upload.sh:142-187](file://scripts/upload.sh#L142-L187) + +## 结论 +通过统一的日志输出、清晰的 Nginx 代理、严格的环境变量注入与完善的健康检查,Audio Dashboard 在 Docker 环境下具备良好的可观测性与可维护性。遇到问题时,建议按照“前端空白 → API 失败 → 构建失败 → 网络/数据库 → 日志分析 → 性能诊断 → 回滚恢复”的顺序逐层排查,结合本文提供的图示与步骤,可高效定位并解决问题。 + +## 附录 + +### A. 常用命令速查 +- 启动/更新 + - docker compose build --no-cache backend + - docker compose up -d +- 停止/重启 + - docker compose down + - docker compose restart frontend +- 日志 + - docker compose logs -f backend + - docker compose logs frontend +- 健康检查 + - curl http://localhost:8083/health + +章节来源 +- [DEPLOY.md:92-118](file://DEPLOY.md#L92-L118) +- [DEPLOY.md:122-154](file://DEPLOY.md#L122-L154) + +### B. 环境变量参考 +- 数据库:DATABASE_HOST、DATABASE_PORT、DATABASE_NAME、DATABASE_USER、DATABASE_PASSWORD +- 应用:APP_NAME、APP_ENV +- 认证:JWT_SECRET、DASHBOARD_ADMIN_USERNAME、DASHBOARD_ADMIN_PASSWORD +- 搜索:MEILISEARCH_URL、MEILISEARCH_API_KEY、MEILISEARCH_INDEX +- S3:AWS_REGION、AWS_S3_OTA_BUCKET、AWS_S3_MEASUREMENT_BUCKET +- OTA:OTA_X8_PUBLIC_BASE、OTA_X9_URL_BASE、OTA_UPLOAD_DIR +- Redis EQ:REDIS_HOST、REDIS_PORT、REDIS_PASSWORD、REDIS_EQ_DB + +章节来源 +- [DEPLOY.md:190-203](file://DEPLOY.md#L190-L203) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/部署与运维/环境配置.md b/.qoder/repowiki/zh/content/部署与运维/环境配置.md new file mode 100644 index 0000000..f0fc2f1 --- /dev/null +++ b/.qoder/repowiki/zh/content/部署与运维/环境配置.md @@ -0,0 +1,351 @@ +# 环境配置 + + +**本文引用的文件** +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/loadEnv.js](file://backend/src/config/loadEnv.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/services/otaStorage.js](file://backend/src/services/otaStorage.js) +- [backend/src/services/eqCacheStorage.js](file://backend/src/services/eqCacheStorage.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/package.json](file://backend/package.json) +- [docker-compose.yml](file://docker-compose.yml) +- [DEPLOY.md](file://DEPLOY.md) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件系统性梳理后端服务的环境配置,覆盖数据库连接、JWT 认证、Redis 缓存、S3 存储等关键模块,并给出开发、测试、生产三类环境的配置差异建议、安全存储与版本控制策略、配置验证方法、常见错误与修复方案,以及配置模板与示例文件说明。 + +## 项目结构 +后端通过入口文件统一加载环境变量与初始化各子系统;配置层按功能拆分,便于独立维护与替换。 + +```mermaid +graph TB +A["入口应用
backend/src/app.js"] --> B["加载环境变量
backend/src/config/loadEnv.js"] +A --> C["数据库配置
backend/src/config/database.js"] +A --> D["JWT 工具
backend/src/utils/jwt.js"] +A --> E["Redis 客户端
backend/src/config/redis.js"] +A --> F["OTA 存储S3/本地
backend/src/services/otaStorage.js"] +A --> G["EQ 缓存读写
backend/src/services/eqCacheStorage.js"] +A --> H["日志配置
backend/src/config/logger.js"] +A --> I["环境判断
backend/src/config/env.js"] +J["Docker Compose
docker-compose.yml"] --> A +K["部署文档
DEPLOY.md"] --> A +``` + +图示来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [DEPLOY.md:190-204](file://DEPLOY.md#L190-L204) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [DEPLOY.md:190-204](file://DEPLOY.md#L190-L204) + +## 核心组件 +- 环境变量加载:统一从项目根目录加载 .env,支持本地与 Docker 两种模式。 +- 环境判断:通过 APP_ENV 判断 development/production,影响日志与部分行为。 +- 数据库:基于 Sequelize 的 MySQL 连接,支持日志输出与表定义选项。 +- JWT:基于 HS256 的签名与校验,支持自定义密钥与过期时间。 +- Redis:EQ 缓存专用客户端,支持密码、超时与错误日志。 +- S3:OTA 包上传,支持显式凭证与 IAM 角色两种方式。 +- 日志:Winston 控制台与文件双通道输出。 + +章节来源 +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +## 架构总览 +下图展示环境变量在系统中的流向与依赖关系。 + +```mermaid +graph TB +subgraph "运行时" +ENV["环境变量
.env 加载"] +APP["应用入口
src/app.js"] +DB["数据库
Sequelize"] +JWT["JWT 工具"] +RDS["Redis 客户端"] +S3["S3 客户端"] +LOG["日志"] +end +ENV --> APP +APP --> DB +APP --> JWT +APP --> RDS +APP --> S3 +APP --> LOG +``` + +图示来源 +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +## 详细组件分析 + +### 数据库连接配置(MySQL/Sequelize) +- 关键变量 + - DATABASE_HOST:数据库主机,默认 localhost + - DATABASE_PORT:数据库端口,默认 3306 + - DATABASE_NAME:数据库名,默认 audio + - DATABASE_USER:用户名,默认 root + - DATABASE_PASSWORD:密码,默认 root123 +- 行为特征 + - 开发环境启用 SQL 日志打印 + - 冻结表名、禁用时间戳 +- 配置验证 + - 启动时尝试同步模型,失败会记录警告但继续运行 +- 常见错误 + - 凭据错误:核对 DATABASE_USER/PASSWORD + - 端口/主机不可达:确认网络连通与防火墙 + - 字符集问题:确保 utf8mb4 支持 + +章节来源 +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/app.js:42-56](file://backend/src/app.js#L42-L56) + +### JWT 认证配置 +- 关键变量 + - JWT_SECRET:签名密钥(必须在生产环境强制设置) + - 算法:HS256 + - 过期时间:12 小时 +- 安全建议 + - 生产环境务必设置强随机密钥,避免硬编码 + - 密钥长度至少 256 位 +- 常见错误 + - 密钥缺失:默认值仅用于开发,生产会失效 + - 过期频繁:检查客户端刷新逻辑与服务端时钟 + +章节来源 +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [DEPLOY.md:39](file://DEPLOY.md#L39) + +### Redis 缓存配置(EQ 缓存) +- 关键变量 + - REDIS_HOST:默认 127.0.0.1 + - REDIS_PORT:默认 6379 + - REDIS_PASSWORD:可选 + - REDIS_EQ_DB:默认 1 +- 行为特征 + - 单例客户端,带最大重试与连接超时 + - 连接错误通过日志上报 +- 常见错误 + - 密码错误:确认 REDIS_PASSWORD 与 ACL 设置 + - DB 选择错误:核对 REDIS_EQ_DB + - 连接超时:检查网络与 Redis 性能 + +章节来源 +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) + +### S3 存储配置(OTA 升级包) +- 关键变量 + - AWS_REGION:默认 eu-central-1 + - AWS_ACCESS_KEY_ID:可选(本地开发) + - AWS_SECRET_ACCESS_KEY:可选(本地开发) + - AWS_S3_OTA_BUCKET:默认 luxsin-app-bucket + - OTA_UPLOAD_DIR:X9 本地存储目录(开发默认临时目录,生产默认 /data/projects/source) + - OTA_X8_PUBLIC_BASE:X8 下载地址前缀 + - OTA_X9_URL_BASE:X9 下载地址前缀 +- 行为特征 + - X8:上传至 S3,支持显式凭证或 IAM 角色 + - X9:保存到宿主机卷(/data/projects/source) +- 常见错误 + - S3 权限不足:检查 IAM 角色或凭证 + - 本地目录权限:确认写入权限与磁盘空间 + - 地址拼接异常:核对 OTA_X8_PUBLIC_BASE/OTA_X9_URL_BASE 结尾斜杠处理 + +章节来源 +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [docker-compose.yml:26](file://docker-compose.yml#L26) + +### 环境变量加载与环境判断 +- 加载策略 + - 本地开发:读取项目根目录 .env + - Docker:通过 compose env_file 注入,容器内不覆盖已有变量 +- 环境常量 + - APP_ENV:development/production + - isDevelopment/isProduction:用于分支逻辑(如数据库日志) + +章节来源 +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [docker-compose.yml:13-18](file://docker-compose.yml#L13-L18) + +### Meilisearch 搜索引擎配置 +- 文档中明确列出变量类别与变量名,但未在后端代码中直接实现对应客户端。 +- 建议在实际集成时新增配置模块,遵循现有命名风格与加载方式。 + +章节来源 +- [DEPLOY.md:199](file://DEPLOY.md#L199) + +## 依赖关系分析 +- 入口应用依赖配置模块与服务模块 +- 配置模块之间低耦合,通过 process.env 解耦 +- Docker Compose 提供环境变量注入与端口映射 + +```mermaid +graph LR +APP["app.js"] --> LOADENV["loadEnv.js"] +APP --> DB["database.js"] +APP --> JWTU["jwt.js"] +APP --> REDIS["redis.js"] +APP --> OTAS["otaStorage.js"] +APP --> EQCS["eqCacheStorage.js"] +APP --> LOGF["logger.js"] +DC["docker-compose.yml"] --> APP +``` + +图示来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/utils/jwt.js:1-28](file://backend/src/utils/jwt.js#L1-L28) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/services/otaStorage.js:1-113](file://backend/src/services/otaStorage.js#L1-L113) +- [backend/src/services/eqCacheStorage.js:1-73](file://backend/src/services/eqCacheStorage.js#L1-L73) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +章节来源 +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +## 性能考虑 +- 数据库 + - 开发环境开启 SQL 日志便于调试,生产关闭以降低开销 + - 合理设置连接池参数(如需扩展) +- Redis + - 控制最大重试次数与连接超时,避免阻塞请求 + - 使用独立 DB 隔离 EQ 缓存,减少键冲突 +- S3 + - 上传前计算 MD5,避免重复上传 + - 生产环境优先使用 IAM 角色,减少凭证泄露风险 + +## 故障排查指南 +- 环境变量不生效 + - Docker:修改 .env 后需重建容器或强制重启 + - 本地:确认根目录 .env 是否存在且格式正确 +- 数据库连接失败 + - 核对主机、端口、凭据与字符集 + - 检查防火墙与网络策略 +- Redis 连接失败 + - 核对主机、端口、密码与 DB 选择 + - 检查 Redis 服务状态与资源限制 +- S3 上传失败 + - 核对区域、桶名与凭证或 IAM 角色 + - 检查网络与对象权限 +- 健康检查 + - 访问 /health 确认服务可用 + - 查看容器日志定位具体错误 + +章节来源 +- [DEPLOY.md:245-255](file://DEPLOY.md#L245-L255) +- [backend/src/app.js:31-34](file://backend/src/app.js#L31-L34) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +## 结论 +本项目采用集中式环境变量加载与模块化配置设计,结合 Docker Compose 实现多环境一致性。建议在生产环境严格管理敏感变量,采用 IAM 角色与最小权限原则,并完善配置验证与监控告警机制。 + +## 附录 + +### 不同环境配置差异建议 +- 开发环境 + - APP_ENV=development + - 数据库日志开启 + - JWT_SECRET 可使用默认值(仅开发) + - OTA_UPLOAD_DIR 指向本地临时目录 +- 测试环境 + - APP_ENV=production + - 数据库日志关闭 + - JWT_SECRET 强随机值 + - S3 使用测试账号或角色 +- 生产环境 + - APP_ENV=production + - 所有敏感变量通过环境注入 + - S3 优先 IAM 角色 + - 日志与健康检查完善 + +章节来源 +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:15](file://backend/src/config/database.js#L15) +- [DEPLOY.md:39](file://DEPLOY.md#L39) +- [docker-compose.yml:18](file://docker-compose.yml#L18) + +### 敏感信息的安全存储与版本控制策略 +- .env 不纳入版本控制,服务器单独维护 +- 使用 IAM 角色替代明文凭证(S3) +- 密钥轮换流程:生成新密钥 → 更新 .env → 重启服务 → 废弃旧密钥 +- 最小权限原则:仅为需要的功能授予最小权限 + +章节来源 +- [DEPLOY.md:40-41](file://DEPLOY.md#L40-L41) +- [DEPLOY.md:39](file://DEPLOY.md#L39) + +### 配置验证方法 +- 启动日志:观察数据库同步与服务启动信息 +- 健康检查:访问 /health +- 功能测试:登录、查询、上传等关键路径 +- 日志审计:关注错误日志与异常堆栈 + +章节来源 +- [backend/src/app.js:42-56](file://backend/src/app.js#L42-L56) +- [backend/src/app.js:31-34](file://backend/src/app.js#L31-L34) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +### 常见配置错误与解决办法 +- JWT_SECRET 未设置:在生产环境设置强随机密钥 +- S3 凭证或权限问题:检查凭证或 IAM 角色策略 +- Redis 密码或 DB 错误:核对密码与 DB 编号 +- 端口映射冲突:调整宿主机端口或容器端口 +- 环境变量未生效:在 Docker 中强制重建容器 + +章节来源 +- [backend/src/utils/jwt.js:3](file://backend/src/utils/jwt.js#L3) +- [backend/src/services/otaStorage.js:77-83](file://backend/src/services/otaStorage.js#L77-L83) +- [backend/src/config/redis.js:20-22](file://backend/src/config/redis.js#L20-L22) +- [DEPLOY.md:245-249](file://DEPLOY.md#L245-L249) + +### 配置模板与示例文件说明 +- 示例文件位置:项目根目录提供 .env.example(后端 README 中提及) +- 变量分类参考:数据库、应用、认证、搜索、S3、OTA、Redis EQ 等 +- 服务器维护:.env 仅在服务器维护,不提交到版本库 + +章节来源 +- [DEPLOY.md:29-34](file://DEPLOY.md#L29-L34) +- [DEPLOY.md:190-204](file://DEPLOY.md#L190-L204) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/部署与运维/监控运维.md b/.qoder/repowiki/zh/content/部署与运维/监控运维.md new file mode 100644 index 0000000..4a04f45 --- /dev/null +++ b/.qoder/repowiki/zh/content/部署与运维/监控运维.md @@ -0,0 +1,348 @@ +# 监控运维 + + +**本文引用的文件** +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/Dockerfile](file://backend/Dockerfile) +- [docker-compose.yml](file://docker-compose.yml) +- [backend/start.sh](file://backend/start.sh) +- [backend/restart.sh](file://backend/restart.sh) +- [backend/stop.sh](file://backend/stop.sh) +- [backend/package.json](file://backend/package.json) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [frontend/nginx.conf](file://frontend/nginx.conf) +- [DEPLOY.md](file://DEPLOY.md) +- [backend/src/routes/index.js](file://backend/src/routes/index.js) +- [backend/src/routes/dashboard.js](file://backend/src/routes/dashboard.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件面向生产环境的监控与运维,围绕系统监控指标、日志管理、性能调优、容器与服务健康检查、日志轮转与分析、异常告警、服务重启/停止/重新部署流程、备份与灾难恢复以及自动化运维脚本进行系统化说明。文档以仓库现有实现为基础,结合 Docker Compose 部署与 Nginx 代理链路,给出可操作的运维实践。 + +## 项目结构 +- 后端采用 Node.js + Express,使用 winston 输出日志,Dockerfile 在容器内创建日志目录并暴露 8000 端口。 +- 前端通过 Nginx 提供静态资源与反向代理,将 /api 前缀转发至后端容器的 8000 端口。 +- docker-compose.yml 定义了 backend 与 frontend 两个服务,启用 json-file 日志轮转(单文件 10m,最多 5 个),并挂载 OTA 升级包存储卷。 +- 运维脚本提供本地启动、重启与停止能力;部署指南提供完整的构建、上传与验证流程。 + +```mermaid +graph TB +subgraph "宿主机" +HOST["8082:80
8083:8000"] +end +subgraph "容器网络" +NET["bridge 网络"] +end +subgraph "容器: 前端" +NGINX["Nginx
监听 80
反代 /api -> backend:8000"] +end +subgraph "容器: 后端" +NODE["Node.js 应用
监听 8000"] +LOGS["/app/logs
应用日志"] +end +HOST --> NGINX +NGINX --> |"HTTP"| NODE +NET --> NGINX +NET --> NODE +NODE --> LOGS +``` + +图表来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [frontend/nginx.conf:1-34](file://frontend/nginx.conf#L1-L34) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) + +章节来源 +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [frontend/nginx.conf:1-34](file://frontend/nginx.conf#L1-L34) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) + +## 核心组件 +- 日志系统:后端使用 winston 输出到控制台与文件,日志目录在容器内创建;前端通过 Nginx 提供静态资源与 API 代理。 +- 容器编排:Docker Compose 定义服务、端口映射、日志轮转、网络与卷挂载。 +- 运维脚本:start.sh、restart.sh、stop.sh 提供本地启动、重启与停止能力。 +- 健康检查:部署指南中提供 /health 健康检查验证方法。 +- 环境与配置:APP_ENV 控制开发/生产行为;数据库与 Redis 连接通过环境变量注入。 + +章节来源 +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [backend/start.sh:1-5](file://backend/start.sh#L1-L5) +- [backend/restart.sh:1-43](file://backend/restart.sh#L1-L43) +- [backend/stop.sh:1-14](file://backend/stop.sh#L1-L14) +- [DEPLOY.md:104-118](file://DEPLOY.md#L104-L118) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) + +## 架构总览 +下图展示从浏览器到后端 API 的完整链路,包括 Nginx 代理、后端服务与日志输出位置。 + +```mermaid +sequenceDiagram +participant U as "用户浏览器" +participant F as "Nginx(前端)" +participant B as "Node.js(后端)" +participant L as "日志文件" +U->>F : "请求 /api/*" +F->>B : "反向代理到 backend : 8000" +B->>L : "写入应用日志(app.log)" +B-->>F : "返回响应(JSON)" +F-->>U : "返回页面/接口数据" +``` + +图表来源 +- [frontend/nginx.conf:11-21](file://frontend/nginx.conf#L11-L21) +- [backend/src/config/logger.js:19-26](file://backend/src/config/logger.js#L19-L26) +- [backend/Dockerfile:5-6](file://backend/Dockerfile#L5-L6) + +章节来源 +- [frontend/nginx.conf:1-34](file://frontend/nginx.conf#L1-L34) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) + +## 详细组件分析 + +### 日志管理与轮转 +- 日志输出:后端使用 winston,同时输出到控制台与文件;日志目录在容器内创建。 +- 日志轮转:Compose 使用 json-file 驱动,单文件大小限制为 10m,最多保留 5 个文件。 +- 日志分析建议:生产环境建议将容器日志接入集中式日志系统(如 ELK/Fluentd/Loki),以便聚合、检索与告警。 + +```mermaid +flowchart TD +Start(["应用启动"]) --> Init["初始化 winston 日志器"] +Init --> DirCheck{"日志目录存在?"} +DirCheck --> |否| Mk["创建 /app/logs"] +DirCheck --> |是| Ready["准备就绪"] +Mk --> Ready +Ready --> Write["写入控制台与文件(app.log)"] +Write --> End(["运行中"]) +``` + +图表来源 +- [backend/src/config/logger.js:5-26](file://backend/src/config/logger.js#L5-L26) +- [backend/Dockerfile:5-6](file://backend/Dockerfile#L5-L6) +- [docker-compose.yml:1-5](file://docker-compose.yml#L1-L5) + +章节来源 +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) +- [docker-compose.yml:1-6](file://docker-compose.yml#L1-L6) + +### Docker 容器监控 +- 端口与网络:后端容器固定监听 8000,前端容器监听 80;通过宿主端口 8082/8083 对外提供服务。 +- 卷挂载:OTA 升级包存储挂载到宿主机目录,便于持久化与备份。 +- 重启策略:unless-stopped,提升稳定性。 +- 日志轮转:json-file 驱动,max-size/max-file 控制磁盘占用。 + +章节来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [backend/Dockerfile:15-16](file://backend/Dockerfile#L15-L16) + +### 服务健康检查 +- 健康检查端点:部署指南提供 curl 命令验证 /health。 +- 建议:在生产中可将 /health 设计为返回 200/500 并携带简要状态信息,便于监控系统自动探测。 + +章节来源 +- [DEPLOY.md:104-118](file://DEPLOY.md#L104-L118) + +### 性能监控指标定义 +- 后端指标(建议采集): + - QPS/吞吐:每秒请求数、成功/失败率 + - 响应时间:P50/P95/P99 延迟 + - 错误率:4xx/5xx 比例 + - 资源使用:CPU、内存、线程数 + - 数据库连接:活跃连接数、等待队列长度 + - Redis 连接:可用性、命令耗时 + - IO:磁盘读写、日志文件大小增长 +- 前端指标(建议采集): + - 静态资源命中率、缓存命中 + - Nginx 连接数、请求速率、错误码分布 + +章节来源 +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) + +### 资源使用跟踪与异常告警 +- 建议使用 Prometheus + Grafana 或云监控(如 CloudWatch/Azure Monitor)采集容器与主机指标,并设置阈值告警。 +- 关键告警场景: + - CPU/内存持续高位 + - 响应时间 P95 超过阈值 + - 数据库/Redis 连接池耗尽 + - 日志文件增长过快(接近 max-size) + +章节来源 +- [docker-compose.yml:1-5](file://docker-compose.yml#L1-L5) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) + +### 服务重启、停止与重新部署流程 +- 本地开发: + - 启动:backend 下执行启动脚本 + - 重启:使用重启脚本,内部查找并终止占用宿主 8083 端口的进程,随后启动应用 + - 停止:使用停止脚本,查找并终止占用 8083 的进程 +- 生产部署: + - 仅更新前端:本地构建后上传前端产物,服务器执行 frontend 重启 + - 仅更新后端:上传后端代码,服务器执行后端镜像重建与 up + - 一键流程:前端构建 + 上传 + 后端重建 + 部署 +- 停止服务:docker compose down + +```mermaid +flowchart TD +A["开始"] --> B{"选择操作类型"} +B --> |本地启动| S["执行 start.sh"] +B --> |本地重启| R["执行 restart.sh
终止旧进程并启动新进程"] +B --> |本地停止| T["执行 stop.sh
终止占用 8083 的进程"] +B --> |生产更新前端| U1["本地构建 -> 上传前端 -> 服务器 restart frontend"] +B --> |生产更新后端| U2["上传后端 -> 服务器 build --no-cache backend -> up -d backend"] +B --> |停止服务| D["docker compose down"] +S --> E["完成"] +R --> E +T --> E +U1 --> E +U2 --> E +D --> E +``` + +图表来源 +- [backend/start.sh:1-5](file://backend/start.sh#L1-L5) +- [backend/restart.sh:1-43](file://backend/restart.sh#L1-L43) +- [backend/stop.sh:1-14](file://backend/stop.sh#L1-L14) +- [DEPLOY.md:122-153](file://DEPLOY.md#L122-L153) + +章节来源 +- [backend/start.sh:1-5](file://backend/start.sh#L1-L5) +- [backend/restart.sh:1-43](file://backend/restart.sh#L1-L43) +- [backend/stop.sh:1-14](file://backend/stop.sh#L1-L14) +- [DEPLOY.md:104-153](file://DEPLOY.md#L104-L153) + +### 备份策略、数据恢复与灾难恢复 +- 数据库备份: + - MySQL:定期执行逻辑备份(mysqldump)或物理备份(Percona XtraBackup),并校验归档与异地存放 +- 缓存数据: + - Redis:导出 RDB 快照或开启 AOF,确保快照与增量日志定期归档 +- 文件与升级包: + - OTA 升级包:/data/projects/source 目录作为挂载卷,纳入常规文件备份策略 +- 日志: + - 容器日志:json-file 轮转,建议将日志目录也纳入备份范围 +- 恢复演练: + - 定期进行备份恢复演练,验证备份完整性与恢复时间目标(RTO/RPO) + +章节来源 +- [docker-compose.yml:25-26](file://docker-compose.yml#L25-L26) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) + +### 自动化运维工具与脚本 +- 上传脚本:scripts/upload.sh 支持上传 frontend、backend、compose 等子任务,便于一键部署 +- Compose 命令:build、up、down、logs、ps 等用于构建、启动、停止与日志查看 +- 建议扩展: + - CI/CD:在流水线中集成前端构建、上传与后端镜像构建 + - 健康检查钩子:在部署前后执行 /health 校验 + - 告警联动:当部署失败或健康检查失败时自动回滚 + +章节来源 +- [DEPLOY.md:63-90](file://DEPLOY.md#L63-L90) +- [DEPLOY.md:100-102](file://DEPLOY.md#L100-L102) +- [DEPLOY.md:148-153](file://DEPLOY.md#L148-L153) + +## 依赖关系分析 +- 后端应用依赖: + - Express 提供 Web 服务与路由 + - Winston 提供日志记录 + - Sequelize/MySQL 提供数据持久化 + - ioredis 提供 Redis 连接 + - dotenv 加载环境变量 +- 前端依赖: + - Nginx 提供静态资源与反向代理 +- 运维依赖: + - Docker Compose 管理多容器编排 + - Shell 脚本提供本地启动/停止/重启 + +```mermaid +graph LR +APP["后端应用"] --> W["winston"] +APP --> S["sequelize/mysql"] +APP --> R["ioredis"] +APP --> E["express"] +APP --> D["dotenv"] +FE["前端(Nginx)"] --> APP +OPS["运维"] --> DC["docker-compose"] +OPS --> SH["shell 脚本"] +``` + +图表来源 +- [backend/package.json:11-27](file://backend/package.json#L11-L27) +- [frontend/nginx.conf:1-34](file://frontend/nginx.conf#L1-L34) +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [backend/start.sh:1-5](file://backend/start.sh#L1-L5) + +章节来源 +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [frontend/nginx.conf:1-34](file://frontend/nginx.conf#L1-L34) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [backend/start.sh:1-5](file://backend/start.sh#L1-L5) + +## 性能考虑 +- Nginx 层优化: + - 启用 gzip 压缩静态资源 + - 合理设置 client_max_body_size 与缓存头 +- 后端层优化: + - 数据库连接池与查询优化 + - Redis 命令超时与重试策略 + - 日志级别与格式开销控制 +- 容器层优化: + - 合理设置 restart 策略与资源限制 + - 使用只读卷与最小权限原则 + +章节来源 +- [frontend/nginx.conf:7-32](file://frontend/nginx.conf#L7-L32) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js:10-26](file://backend/src/config/logger.js#L10-L26) +- [docker-compose.yml:21-22](file://docker-compose.yml#L21-L22) + +## 故障排查指南 +- 前端页面空白: + - 检查 dist 是否上传、路径是否正确 + - 查看前端容器日志 +- API 请求失败: + - 确认后端容器处于 running 状态 + - 查看后端容器日志,关注数据库、Redis、搜索引擎连接错误 + - 核对 Nginx 代理目标为 backend:8000 +- 后端构建失败: + - 确认已上传 package.json 与 pnpm-lock.yaml + - 使用指定 Node 版本与包管理器版本 +- 修改 .env 不生效: + - 强制重建后端容器使其加载新环境变量 +- 停止服务: + - 使用 docker compose down + +章节来源 +- [DEPLOY.md:226-256](file://DEPLOY.md#L226-L256) + +## 结论 +本运维文档基于现有代码与部署配置,给出了日志管理、容器监控、健康检查、性能指标、异常告警、服务运维流程、备份与灾难恢复以及自动化脚本的实践建议。建议在生产环境中补充集中式日志、指标采集与告警体系,并完善备份与恢复演练,以保障系统稳定与可追溯性。 + +## 附录 +- 健康检查端点:/health(参考部署指南中的 curl 示例) +- 环境变量参考:数据库、应用、认证、搜索、S3、OTA、Redis EQ 等(参考部署指南中的表格) + +章节来源 +- [DEPLOY.md:104-118](file://DEPLOY.md#L104-L118) +- [DEPLOY.md:190-203](file://DEPLOY.md#L190-L203) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/部署与运维/部署与运维.md b/.qoder/repowiki/zh/content/部署与运维/部署与运维.md new file mode 100644 index 0000000..2b2145c --- /dev/null +++ b/.qoder/repowiki/zh/content/部署与运维/部署与运维.md @@ -0,0 +1,349 @@ +# 部署与运维 + + +**本文引用的文件** +- [docker-compose.yml](file://docker-compose.yml) +- [DEPLOY.md](file://DEPLOY.md) +- [backend/Dockerfile](file://backend/Dockerfile) +- [frontend/Dockerfile](file://frontend/Dockerfile) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/loadEnv.js](file://backend/src/config/loadEnv.js) +- [backend/src/config/database.js](file://backend/src/config/database.js) +- [backend/src/config/redis.js](file://backend/src/config/redis.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [scripts/upload.sh](file://scripts/upload.sh) +- [backend/package.json](file://backend/package.json) +- [frontend/package.json](file://frontend/package.json) +- [backend/start.sh](file://backend/start.sh) +- [backend/restart.sh](file://backend/restart.sh) +- [backend/stop.sh](file://backend/stop.sh) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本文件面向部署与运维工程师,系统性说明项目的容器化部署、环境配置、生产部署流程、容器编排、服务依赖与网络设置、部署脚本使用、自动化流程、环境变量与数据库/缓存配置、监控与日志、性能调优、故障排除、备份恢复与灾难恢复、CI/CD 与版本发布/回滚策略,以及安全配置与访问控制。 + +## 项目结构 +- 前端采用 Nginx 静态托管,后端为 Node.js API,二者通过 Docker Compose 在同一自定义桥接网络中通信。 +- 前端不构建镜像,直接挂载服务器上的构建产物与 Nginx 配置;后端以独立镜像运行。 +- 日志轮转策略在 Compose 层统一配置,便于生产环境管理。 +- OTA 升级包本地存储通过宿主机卷挂载到后端容器,确保升级资源可用性。 + +```mermaid +graph TB +subgraph "宿主机" +V1["/data/projects/source
OTA 存储卷"] +FDist["/data/project/dashboard/frontend/dist
前端静态资源"] +NConf["/data/project/dashboard/frontend/nginx.conf
Nginx 配置"] +end +subgraph "Docker 网络 audio-network" +FE["容器 dashboard-frontend
Nginx:80"] +BE["容器 dashboard-backend
Node.js:8000"] +end +V1 --> BE +FDist --> FE +NConf --> FE +FE --> |"反向代理 /api → http://backend:8000"| BE +``` + +图表来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) + +章节来源 +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [DEPLOY.md:1-120](file://DEPLOY.md#L1-L120) + +## 核心组件 +- 后端服务(Node.js) + - 基于 Node.js 22 Alpine 镜像,使用 pnpm 生产依赖安装,工作目录包含日志目录,暴露 8000 端口。 + - 通过环境变量驱动数据库、Redis、搜索、S3、OTA 等配置。 +- 前端服务(Nginx) + - 使用 Nginx Alpine 镜像,挂载静态资源与 Nginx 配置,不构建镜像,减少部署复杂度。 +- 容器编排与网络 + - Compose 定义自定义桥接网络,前后端在同一网络内通信;前端通过 Nginx 将 /api 代理到后端容器的 8000 端口。 +- 部署脚本 + - 提供一键上传前端、后端、Compose 的 rsync 脚本,支持虚拟执行与多目标组合。 + +章节来源 +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) +- [frontend/Dockerfile:1-32](file://frontend/Dockerfile#L1-L32) +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [scripts/upload.sh:1-191](file://scripts/upload.sh#L1-L191) + +## 架构总览 +- 端口映射 + - 前端 Nginx 暴露 80,映射到宿主机 8082。 + - 后端 Node.js 暴露 8000,映射到宿主机 8083。 +- 服务依赖 + - 前端依赖后端 API;Compose 通过 depends_on 实现启动顺序。 +- 网络 + - 两容器加入同一自定义桥接网络,实现容器间通过服务名访问。 +- 日志 + - 每个服务启用 JSON 文件日志轮转,单文件最大 10MB,最多 5 个文件。 + +```mermaid +sequenceDiagram +participant U as "用户浏览器" +participant FE as "dashboard-frontend(Nginx)" +participant BE as "dashboard-backend(Node.js)" +U->>FE : "访问 http : // : 8082/" +FE->>FE : "解析路由与静态资源" +U->>FE : "请求 /api/*" +FE->>BE : "反向代理到 http : //backend : 8000" +BE-->>FE : "返回 API 响应" +FE-->>U : "返回 HTML/JS/CSS 与 API 数据" +``` + +图表来源 +- [docker-compose.yml:28-41](file://docker-compose.yml#L28-L41) +- [DEPLOY.md:114-118](file://DEPLOY.md#L114-L118) + +章节来源 +- [DEPLOY.md:5-118](file://DEPLOY.md#L5-L118) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +## 详细组件分析 + +### 后端容器与应用配置 +- 环境变量加载 + - 容器内通过根目录 .env 注入;本地开发与 Docker 部署共享同一 .env 加载逻辑,但 Docker 下容器内无 .env 文件,由 Compose 注入。 +- 环境类型 + - 通过 APP_ENV 判断开发/生产环境,影响日志输出等行为。 +- 数据库连接 + - 使用 Sequelize 连接 MySQL,支持主机、端口、用户名、密码、字符集、日志开关等配置项。 +- Redis 缓存 + - 提供 EQ 缓存客户端工厂方法,支持主机、端口、密码、数据库编号、超时与重试配置,并记录错误日志。 +- 日志 + - 使用 Winston 输出到控制台与文件,日志目录位于应用内部 logs 子目录。 + +```mermaid +flowchart TD +Start(["启动后端"]) --> LoadEnv["加载根目录 .envCompose 注入"] +LoadEnv --> EnvCheck{"APP_ENV 是否为 production"} +EnvCheck --> |是| Prod["生产模式:关闭 ORM 日志"] +EnvCheck --> |否| Dev["开发模式:开启 ORM 日志"] +Prod --> DB["初始化数据库连接Sequelize"] +Dev --> DB +DB --> RedisInit["初始化 Redis 客户端"] +RedisInit --> Logger["初始化日志记录器"] +Logger --> Ready(["服务就绪"]) +``` + +图表来源 +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +章节来源 +- [backend/src/config/loadEnv.js:1-15](file://backend/src/config/loadEnv.js#L1-L15) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/config/database.js:1-24](file://backend/src/config/database.js#L1-L24) +- [backend/src/config/redis.js:1-32](file://backend/src/config/redis.js#L1-L32) +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) + +### 前端容器与 Nginx 配置 +- 镜像与构建 + - 使用 Nginx Alpine 镜像,挂载静态资源与 Nginx 配置文件,不构建前端镜像。 +- 代理规则 + - 前端通过 Nginx 将 /api 代理到后端容器的 8000 端口,确保 SPA 与 API 请求分离。 +- 卷挂载 + - 前端 dist 与 nginx.conf 通过宿主机卷挂载,便于快速更新与热替换。 + +章节来源 +- [frontend/Dockerfile:1-32](file://frontend/Dockerfile#L1-L32) +- [docker-compose.yml:28-41](file://docker-compose.yml#L28-L41) + +### 容器编排与网络 +- 自定义桥接网络 + - 两容器加入同一网络,实现通过服务名访问后端 API。 +- 端口映射 + - 前端 80:8082,后端 8000:8083,避免端口冲突。 +- 日志轮转 + - 每个服务启用 JSON 文件日志轮转,单文件 10MB,最多 5 份。 + +章节来源 +- [docker-compose.yml:43-46](file://docker-compose.yml#L43-L46) +- [docker-compose.yml:1-5](file://docker-compose.yml#L1-L5) + +### 部署脚本与自动化 +- 功能特性 + - 支持同步前端、后端、Compose 三类目标,也支持指定路径与虚拟执行。 + - 默认目标包含前端 dist、后端 src 与依赖锁文件、Compose 文件。 + - SSH 密钥与远程路径可配置,便于跨环境复用。 +- 使用场景 + - 本地构建前端后,一键上传前端与 Compose 并在服务器执行 docker compose up -d。 + - 后端代码变更后,上传后端文件并在服务器重建后端镜像并启动。 + +```mermaid +sequenceDiagram +participant Dev as "开发者" +participant Script as "upload.sh" +participant Server as "服务器" +Dev->>Script : "执行 ./scripts/upload.sh frontend" +Script->>Server : "rsync 前端 dist 到 /data/project/dashboard/frontend/dist" +Dev->>Script : "执行 ./scripts/upload.sh compose" +Script->>Server : "rsync docker-compose.yml" +Dev->>Server : "在服务器执行 docker compose up -d" +Server-->>Dev : "验证服务状态与日志" +``` + +图表来源 +- [scripts/upload.sh:1-191](file://scripts/upload.sh#L1-L191) +- [DEPLOY.md:49-113](file://DEPLOY.md#L49-L113) + +章节来源 +- [scripts/upload.sh:1-191](file://scripts/upload.sh#L1-L191) +- [DEPLOY.md:49-113](file://DEPLOY.md#L49-L113) + +### 本地开发与非容器部署 +- 本地开发 + - 后端在 8083 端口启动,前端在 3000 端口启动并通过代理转发 /api 到后端。 +- 非容器部署 + - 通过 start.sh/stop.sh/restart.sh 管理本地进程,便于调试与快速迭代。 + +章节来源 +- [DEPLOY.md:259-269](file://DEPLOY.md#L259-L269) +- [backend/start.sh:1-5](file://backend/start.sh#L1-L5) +- [backend/stop.sh:1-14](file://backend/stop.sh#L1-L14) +- [backend/restart.sh:1-43](file://backend/restart.sh#L1-L43) + +## 依赖分析 +- 后端依赖 + - Web 框架、ORM、MySQL 驱动、JWT、S3 SDK、Redis 客户端、日志、校验等。 +- 前端依赖 + - Vue 3、Element Plus、路由、HTTP 客户端等。 +- 版本锁定 + - 后端与前端均使用 pnpm 并固定版本,保证构建一致性。 + +```mermaid +graph LR +BE["后端 Node.js"] --> PkgBE["package.json 依赖"] +FE["前端 Vue 应用"] --> PkgFE["package.json 依赖"] +PkgBE --> Express["express"] +PkgBE --> Sequelize["sequelize + mysql2"] +PkgBE --> JWT["jsonwebtoken"] +PkgBE --> S3["@aws-sdk/client-s3"] +PkgBE --> Redis["ioredis"] +PkgBE --> Winston["winston"] +PkgBE --> Dotenv["dotenv"] +PkgFE --> Vue["vue"] +PkgFE --> EP["element-plus"] +PkgFE --> Axios["axios"] +PkgFE --> Router["vue-router"] +``` + +图表来源 +- [backend/package.json:11-27](file://backend/package.json#L11-L27) +- [frontend/package.json:10-22](file://frontend/package.json#L10-L22) + +章节来源 +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) + +## 性能考虑 +- 日志轮转 + - Compose 层启用日志轮转,避免磁盘膨胀;建议结合系统日志聚合与保留策略。 +- 静态资源优化 + - 前端构建产物通过 Nginx 提供,建议配合缓存头与压缩策略提升首屏性能。 +- 数据库与缓存 + - 生产环境建议使用专用数据库与 Redis 实例,合理设置连接池与超时参数。 +- 容器资源 + - 建议在生产环境中为容器设置 CPU/内存限制与健康检查,增强稳定性。 +- CDN 与反代 + - 对静态资源与 API 可引入反向代理与 CDN,降低后端压力。 + +## 故障排除指南 +- 前端页面空白 + - 检查 dist 是否上传成功、Nginx 代理是否指向后端 8000 端口、浏览器控制台是否存在 404。 +- API 请求失败 + - 确认后端容器处于 running 状态、查看后端日志定位数据库/Redis/Meilisearch 连接问题。 +- 后端构建失败(pnpm/Node 版本) + - 确保上传了 package.json 与 pnpm-lock.yaml,后端镜像基于 node:22-alpine。 +- .env 修改不生效 + - 通过重新创建容器使新环境变量生效。 +- 停止/重启服务 + - 使用 docker compose down 或在服务器执行 restart.sh/stop.sh/stop.sh 管理本地进程。 + +章节来源 +- [DEPLOY.md:226-256](file://DEPLOY.md#L226-L256) +- [backend/restart.sh:1-43](file://backend/restart.sh#L1-L43) +- [backend/stop.sh:1-14](file://backend/stop.sh#L1-L14) + +## 结论 +本项目采用轻量化的容器化方案:前端 Nginx 静态托管、后端 Node.js API,通过 Compose 统一编排与网络隔离,辅以集中式 .env 管理与 rsync 自动化脚本,形成可重复、可审计的生产部署流程。建议在生产中进一步完善资源限制、健康检查、日志聚合与监控告警体系,以满足高可用与可观测性要求。 + +## 附录 + +### 环境变量与配置清单 +- 数据库 + - DATABASE_HOST、DATABASE_PORT、DATABASE_NAME、DATABASE_USER、DATABASE_PASSWORD +- 应用 + - APP_NAME、APP_ENV +- 认证 + - JWT_SECRET、DASHBOARD_ADMIN_USERNAME、DASHBOARD_ADMIN_PASSWORD +- 搜索 + - MEILISEARCH_URL、MEILISEARCH_API_KEY、MEILISEARCH_INDEX +- S3 + - AWS_REGION、AWS_S3_OTA_BUCKET、AWS_S3_MEASUREMENT_BUCKET +- OTA + - OTA_X8_PUBLIC_BASE、OTA_X9_URL_BASE、OTA_UPLOAD_DIR +- Redis EQ + - REDIS_HOST、REDIS_PORT、REDIS_PASSWORD、REDIS_EQ_DB + +章节来源 +- [DEPLOY.md:190-203](file://DEPLOY.md#L190-L203) + +### 目录结构(服务器) +- /data/project/dashboard/ + - .env、docker-compose.yml、backend/(含 Dockerfile、package.json、pnpm-lock.yaml、src/)、frontend/(dist、nginx.conf) +- /data/projects/source/(OTA 升级包存储) + +章节来源 +- [DEPLOY.md:206-223](file://DEPLOY.md#L206-L223) + +### 监控指标与日志管理 +- 指标 + - 建议采集容器 CPU/内存/IO、API 响应时间与错误率、数据库连接数、Redis 命中率等。 +- 日志 + - 后端日志写入容器内 logs 文件,结合 Compose 日志轮转;建议接入集中式日志系统进行检索与告警。 + +章节来源 +- [backend/src/config/logger.js:1-29](file://backend/src/config/logger.js#L1-L29) +- [docker-compose.yml:1-5](file://docker-compose.yml#L1-L5) + +### 备份与灾难恢复 +- 数据库 + - 定期导出 MySQL 数据,保存至安全位置或对象存储。 +- 配置与代码 + - .env 与源码版本化管理,确保可追溯与快速回滚。 +- OTA 存储 + - /data/projects/source 作为本地存储,建议异地复制或对象存储归档。 +- 灾难恢复 + - 准备最小化恢复步骤:拉起 Compose、恢复 .env、恢复数据库快照、恢复静态资源与 Nginx 配置。 + +### CI/CD 流程、版本发布与回滚 +- 流程建议 + - 代码合并触发流水线:前端构建、后端构建、上传脚本执行、Compose 启动。 +- 发布与回滚 + - 以标签/分支为版本依据;回滚时使用相同镜像版本或恢复 .env 快照,必要时回退数据库迁移。 + +### 安全配置、防火墙与访问控制 +- 端口与防火墙 + - 仅开放 8082(前端)、8083(后端)与必要的系统端口;限制来源 IP。 +- 认证与密钥 + - 生产环境务必更换 JWT_SECRET、管理员密码;S3 优先使用 IAM 角色而非明文凭据。 +- 网络隔离 + - 将数据库与缓存置于隔离网络,仅允许后端容器访问;必要时启用网络策略。 \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/部署与运维/部署指南.md b/.qoder/repowiki/zh/content/部署与运维/部署指南.md new file mode 100644 index 0000000..885024e --- /dev/null +++ b/.qoder/repowiki/zh/content/部署与运维/部署指南.md @@ -0,0 +1,377 @@ +# 部署指南 + + +**本文引用的文件** +- [docker-compose.yml](file://docker-compose.yml) +- [DEPLOY.md](file://DEPLOY.md) +- [backend/Dockerfile](file://backend/Dockerfile) +- [frontend/Dockerfile](file://frontend/Dockerfile) +- [scripts/upload.sh](file://scripts/upload.sh) +- [frontend/nginx.conf](file://frontend/nginx.conf) +- [backend/start.sh](file://backend/start.sh) +- [backend/restart.sh](file://backend/restart.sh) +- [backend/stop.sh](file://backend/stop.sh) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/config/loadEnv.js](file://backend/src/config/loadEnv.js) +- [backend/src/utils/jwt.js](file://backend/src/utils/jwt.js) +- [backend/src/config/logger.js](file://backend/src/config/logger.js) +- [backend/package.json](file://backend/package.json) +- [frontend/package.json](file://frontend/package.json) +- [frontend/vite.config.js](file://frontend/vite.config.js) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本指南面向首次部署、本地构建上传以及后续更新部署的全流程操作,覆盖服务器准备工作、目录结构创建、环境变量配置、Docker Compose 配置说明、服务端口映射与网络设置、上传脚本使用方法、手动 rsync 方式、构建与启动命令、健康检查与服务验证、常见部署问题解决方案,以及生产环境安全配置建议与最佳实践。 + +## 项目结构 +- 前端采用 Nginx 静态托管,后端为 Node.js API,通过 Docker Compose 统一编排。 +- 前端静态资源挂载至 Nginx 容器,Nginx 将 /api 代理到后端容器。 +- 后端容器暴露 8000 端口,并通过环境变量 PORT 固定该值以匹配 Nginx 代理。 +- 日志采用 JSON 文件轮转策略,单文件最大 10MB,最多保留 5 份。 +- 提供 OTA 升级包本地存储卷挂载,便于 X9 设备升级包管理。 + +```mermaid +graph TB +subgraph "服务器" +FE["Nginx 前端
端口 80 映射 8082"] +BE["Node.js 后端
端口 8000 映射 8083"] +VOL1["/data/project/dashboard/frontend/dist"] +VOL2["/data/projects/source"] +end +FE --> |"/api 代理"| BE +FE --- VOL1 +BE --- VOL2 +``` + +图表来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [frontend/nginx.conf:11-21](file://frontend/nginx.conf#L11-L21) + +章节来源 +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [DEPLOY.md:1-16](file://DEPLOY.md#L1-L16) + +## 核心组件 +- 后端服务(Node.js) + - 基于 Node.js 22 Alpine,使用 pnpm 作为包管理器,生产依赖安装在容器内完成。 + - 通过环境变量 PORT=8000 固定容器内端口,与 Nginx 代理保持一致。 + - 日志目录在容器内创建,便于持久化与查看。 +- 前端服务(Nginx) + - 使用 nginx:alpine 镜像,直接挂载服务器上的 dist 与 nginx.conf。 + - Nginx 监听 80 端口,将 /api 请求代理到后端容器的 8000 端口。 + - 支持静态资源缓存与上传大小限制。 +- 上传脚本(upload.sh) + - 基于 rsync + SSH,支持分模块上传(frontend、backend、compose),也支持自定义路径。 + - 提供虚拟执行(-n)预览能力,便于确认同步范围。 +- 环境变量与配置 + - 根目录 .env 由 Docker Compose 注入后端容器,前端通过 Nginx 挂载配置。 + - 后端支持通过 APP_ENV 切换开发/生产环境行为。 + - JWT 密钥、管理员密码等敏感信息需在生产环境强制替换。 + +章节来源 +- [backend/Dockerfile:1-20](file://backend/Dockerfile#L1-L20) +- [frontend/Dockerfile:1-32](file://frontend/Dockerfile#L1-L32) +- [scripts/upload.sh:1-191](file://scripts/upload.sh#L1-L191) +- [frontend/nginx.conf:1-34](file://frontend/nginx.conf#L1-L34) +- [backend/src/config/env.js:1-12](file://backend/src/config/env.js#L1-L12) +- [backend/src/config/loadEnv.js:1-14](file://backend/src/config/loadEnv.js#L1-L14) +- [backend/src/utils/jwt.js:1-27](file://backend/src/utils/jwt.js#L1-L27) + +## 架构总览 +- 前端通过 Nginx 将 /api 代理到后端容器的 8000 端口。 +- 前端静态资源来自服务器上的 dist 目录,Nginx 直接挂载。 +- 后端容器挂载 OTA 升级包存储目录,便于设备侧访问。 +- Docker Compose 控制服务生命周期与网络隔离。 + +```mermaid +graph TB +U["用户浏览器"] --> P["宿主机端口 8082/Nginx"] +P --> |"/api 代理"| B["后端容器 8000"] +P --> |静态资源"| D["/data/project/dashboard/frontend/dist"] +B --> S["OTA 存储卷 /data/projects/source"] +``` + +图表来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [frontend/nginx.conf:11-21](file://frontend/nginx.conf#L11-L21) + +章节来源 +- [DEPLOY.md:5-16](file://DEPLY.md#L5-L16) +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) + +## 详细组件分析 + +### 首次部署(服务器准备) +- 创建目录 + - 前端 dist 目录:用于存放构建产物 + - OTA 升级包存储目录:用于本地存储 X9 升级包 +- 配置环境变量 + - 在服务器根目录创建 .env,内容参考项目根目录 .env.example + - 关键点:PORT=8000(容器内固定)、JWT_SECRET、DASHBOARD_ADMIN_PASSWORD、数据库、搜索、S3、Redis、OTA 等参数 + - .env 不会被上传脚本自动上传,需在服务器单独维护 +- 上传代码并启动 + - 参考“本地构建 + 上传”章节 + +章节来源 +- [DEPLOY.md:18-46](file://DEPLOY.md#L18-L46) + +### 本地构建 + 上传(推荐) +- 前端构建 + - 在 frontend 目录执行安装与构建,产物输出至 dist +- 上传到服务器 + - 使用上传脚本(推荐):支持 all、frontend、backend、compose 等目标 + - 支持自定义路径上传,如单独上传 nginx.conf 或 Dockerfile + - 虚拟执行(-n)可用于预览同步范围 +- 服务器构建与启动 + - 首次或依赖变更时,执行后端镜像构建 + - 启动/更新:docker compose up -d +- 验证 + - docker compose ps 查看状态 + - docker compose logs -f backend 查看后端日志 + - curl http://localhost:8083/health 进行健康检查 + - 访问地址: + - 前端:http://服务器 IP:8082 + - 后端 API:http://服务器 IP:8083/api/... + - 健康检查:http://服务器 IP:8083/health + +章节来源 +- [DEPLOY.md:49-120](file://DEPLOY.md#L49-L120) +- [scripts/upload.sh:39-75](file://scripts/upload.sh#L39-L75) +- [scripts/upload.sh:142-187](file://scripts/upload.sh#L142-L187) + +### 更新部署 +- 仅更新前端 + - 本地构建后上传前端 dist,服务器重启前端容器 +- 仅更新后端 + - 上传后端代码与依赖文件,服务器重新构建并启动后端 +- 一键流程 + - 本地构建前端并上传,服务器执行后端镜像构建与启动 + +章节来源 +- [DEPLOY.md:122-154](file://DEPLOY.md#L122-L154) + +### docker-compose.yml 说明 +- backend + - env_file: .env 读取根目录环境变量 + - environment: 设置 PORT=8000,覆盖容器内端口 + - ports: 8083:8000(宿主:容器) + - volumes: 挂载 OTA 存储目录 +- frontend + - image: nginx:alpine + - ports: 8082:80 + - volumes: 挂载 dist 与 nginx.conf + - depends_on: 依赖后端容器 +- 日志轮转 + - 每个服务启用 json-file,单文件最大 10MB,最多 5 份 +- 网络 + - 使用自定义桥接网络 audio-network,便于容器间通信 + +章节来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [DEPLOY.md:157-171](file://DEPLOY.md#L157-L171) + +### 后端部署文件清单 +- 后端镜像构建所需文件 + - Dockerfile、package.json、pnpm-lock.yaml、src/ + +章节来源 +- [DEPLOY.md:174-187](file://DEPLOY.md#L174-L187) + +### 环境变量参考 +- 数据库:DATABASE_HOST、DATABASE_PORT、DATABASE_NAME、DATABASE_USER、DATABASE_PASSWORD +- 应用:APP_NAME、APP_ENV +- 认证:JWT_SECRET、DASHBOARD_ADMIN_USERNAME、DASHBOARD_ADMIN_PASSWORD +- 搜索:MEILISEARCH_URL、MEILISEARCH_API_KEY、MEILISEARCH_INDEX +- S3:AWS_REGION、AWS_S3_OTA_BUCKET、AWS_S3_MEASUREMENT_BUCKET +- OTA:OTA_X8_PUBLIC_BASE、OTA_X9_URL_BASE、OTA_UPLOAD_DIR +- Redis EQ:REDIS_HOST、REDIS_PORT、REDIS_PASSWORD、REDIS_EQ_DB + +章节来源 +- [DEPLOY.md:190-203](file://DEPLOY.md#L190-L203) + +### 目录结构(服务器) +- /data/project/dashboard/ + - .env(服务器维护) + - docker-compose.yml + - backend/ + - Dockerfile + - package.json + - pnpm-lock.yaml + - src/ + - frontend/ + - dist/ + - nginx.conf +- /data/projects/source/(OTA 升级包存储) + +章节来源 +- [DEPLOY.md:206-223](file://DEPLOY.md#L206-L223) + +### 上传脚本使用方法 +- 用法与选项 + - 目标:frontend(f)、backend(b)、compose(c)、all(a) + - 自定义路径:可传入任意本地路径,映射到服务器对应位置 + - 虚拟执行:-n 预览同步范围 +- 默认同步范围 + - all:包含前端 dist、后端 src、package.json、pnpm-lock.yaml、docker-compose.yml +- 注意事项 + - 默认不同步 nginx.conf 与 Dockerfile,需要时需显式指定 + - 路径不在项目内会被跳过 + +章节来源 +- [scripts/upload.sh:39-75](file://scripts/upload.sh#L39-L75) +- [scripts/upload.sh:142-187](file://scripts/upload.sh#L142-L187) + +### 手动 rsync 上传方式 +- 前端 + - rsync 前端 dist 至服务器 dist 目录 + - scp nginx.conf 至服务器前端目录 +- 后端 + - rsync backend/src 至服务器 backend/src + - scp backend/Dockerfile、backend/package.json、backend/pnpm-lock.yaml 至服务器 backend/ +- Compose + - scp docker-compose.yml 至服务器根目录 + +章节来源 +- [DEPLOY.md:77-91](file://DEPLOY.md#L77-L91) + +### 构建与启动命令 +- 本地 + - 前端:cd frontend && pnpm install && pnpm build +- 服务器 + - 首次或依赖变更:docker compose build --no-cache backend + - 启动/更新:docker compose up -d +- 停止服务 + - docker compose down + +章节来源 +- [DEPLOY.md:92-103](file://DEPLOY.md#L92-L103) +- [DEPLOY.md:251-256](file://DEPLOY.md#L251-L256) + +### 健康检查与服务验证 +- 健康检查 + - curl http://localhost:8083/health +- 状态与日志 + - docker compose ps + - docker compose logs -f backend +- 访问地址 + - 前端:http://服务器 IP:8082 + - 后端 API:http://服务器 IP:8083/api/... + +章节来源 +- [DEPLOY.md:104-119](file://DEPLOY.md#L104-L119) + +### 后端本地脚本(非 Docker) +- start.sh:在本地直接启动后端服务 +- restart.sh:停止占用 8083 端口的进程并重启服务 +- stop.sh:查找并终止占用 8083 端口的进程 + +章节来源 +- [backend/start.sh:1-5](file://backend/start.sh#L1-L5) +- [backend/restart.sh:1-43](file://backend/restart.sh#L1-L43) +- [backend/stop.sh:1-14](file://backend/stop.sh#L1-L14) + +### 前端开发与 Nginx 配置 +- 前端开发 + - 本地开发使用 Vite,默认端口 3000,/api 代理到后端 8083 +- Nginx 配置 + - 监听 80,将 /api 代理到后端容器 8000 + - 支持静态资源缓存与上传大小限制 + +章节来源 +- [frontend/vite.config.js:17-25](file://frontend/vite.config.js#L17-L25) +- [frontend/nginx.conf:11-21](file://frontend/nginx.conf#L11-L21) + +## 依赖关系分析 +- 组件耦合 + - 前端依赖后端 API,通过 Nginx 代理实现解耦 + - 后端依赖数据库、搜索、对象存储、Redis 等外部服务 +- 直接与间接依赖 + - 后端镜像构建依赖 package.json 与 pnpm-lock.yaml + - 前端镜像构建依赖 package.json 与 pnpm-lock.yaml +- 外部依赖与集成点 + - Docker Compose 管理服务生命周期与网络 + - Nginx 作为反向代理与静态资源服务 + +```mermaid +graph LR +FE["前端(dist)"] --> NGINX["Nginx 反向代理"] +NGINX --> BE["后端容器(8000)"] +BE --> DB["数据库"] +BE --> MEILI["Meilisearch"] +BE --> S3["S3 对象存储"] +BE --> REDIS["Redis"] +``` + +图表来源 +- [docker-compose.yml:7-46](file://docker-compose.yml#L7-L46) +- [frontend/nginx.conf:11-21](file://frontend/nginx.conf#L11-L21) + +章节来源 +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) + +## 性能考虑 +- 日志轮转 + - 每个服务启用 JSON 文件轮转,单文件最大 10MB,最多 5 份,避免日志无限增长 +- 静态资源优化 + - Nginx 对静态资源进行缓存与压缩,提升前端加载速度 +- 端口与网络 + - 明确的端口映射与自定义桥接网络,减少冲突与提升隔离性 + +章节来源 +- [docker-compose.yml:1-5](file://docker-compose.yml#L1-L5) +- [frontend/nginx.conf:7-32](file://frontend/nginx.conf#L7-L32) + +## 故障排查指南 +- 前端页面空白 + - 检查 dist 是否上传成功、路径是否正确 + - 查看浏览器控制台是否存在 404 或 API 错误 + - 查看前端容器日志 +- API 请求失败 + - 确认后端容器处于 running 状态 + - 查看后端日志,定位数据库、Redis、Meilisearch 连接问题 + - 确认 Nginx 代理目标为 http://backend:8000 +- 后端构建失败(pnpm / Node 版本) + - 后端镜像基于 node:22-alpine,确保上传了 package.json 与 pnpm-lock.yaml +- 修改 .env 后不生效 + - 通过 docker compose up -d --force-recreate 使新环境变量生效 +- 停止服务 + - docker compose down + +章节来源 +- [DEPLOY.md:226-256](file://DEPLOY.md#L226-L256) + +## 结论 +本指南提供了从服务器准备、目录与环境配置、本地构建与上传、Docker Compose 编排与启动、健康检查与验证,到更新部署与故障排查的完整流程。遵循本文档可快速、稳定地完成 Audio Dashboard 的部署与运维。 + +## 附录 + +### 环境变量与安全配置建议 +- 生产环境必须替换的敏感项 + - JWT_SECRET:强随机密钥,避免使用默认值 + - DASHBOARD_ADMIN_PASSWORD:初始管理员密码,部署后立即修改 +- 最小权限原则 + - S3 通常通过云服务 IAM 角色访问,避免在 .env 中硬编码密钥 +- 网络与端口 + - 仅开放必要端口,防火墙策略最小化 +- 日志与监控 + - 结合日志轮转与容器日志采集,定期巡检 +- 配置加载 + - 后端通过 APP_ENV 切换开发/生产行为,确保生产环境严格校验 + +章节来源 +- [DEPLOY.md:36-42](file://DEPLOY.md#L36-L42) +- [backend/src/config/env.js:1-12](file://backend/src/config/env.js#L1-L12) +- [backend/src/utils/jwt.js:1-27](file://backend/src/utils/jwt.js#L1-L27) \ No newline at end of file diff --git a/.qoder/repowiki/zh/content/项目概述.md b/.qoder/repowiki/zh/content/项目概述.md new file mode 100644 index 0000000..e4c9d3b --- /dev/null +++ b/.qoder/repowiki/zh/content/项目概述.md @@ -0,0 +1,339 @@ +# 项目概述 + + +**本文引用的文件** +- [README.md](file://README.md) +- [DEPLOY.md](file://DEPLOY.md) +- [backend/README.md](file://backend/README.md) +- [frontend/README.md](file://frontend/README.md) +- [backend/package.json](file://backend/package.json) +- [frontend/package.json](file://frontend/package.json) +- [backend/src/app.js](file://backend/src/app.js) +- [backend/src/config/env.js](file://backend/src/config/env.js) +- [backend/src/models/index.js](file://backend/src/models/index.js) +- [backend/src/models/Brand.js](file://backend/src/models/Brand.js) +- [backend/src/models/Model.js](file://backend/src/models/Model.js) +- [backend/src/routes/brands.js](file://backend/src/routes/brands.js) +- [backend/src/routes/models.js](file://backend/src/routes/models.js) +- [backend/src/routes/ota.js](file://backend/src/routes/ota.js) +- [backend/src/routes/shareCodeLogs.js](file://backend/src/routes/shareCodeLogs.js) +- [frontend/src/main.js](file://frontend/src/main.js) +- [frontend/src/router/index.js](file://frontend/src/router/index.js) +- [docker-compose.yml](file://docker-compose.yml) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构总览](#架构总览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考虑](#性能考虑) +8. [故障排查指南](#故障排查指南) +9. [结论](#结论) +10. [附录](#附录) + +## 简介 +本项目是一个面向“耳机品牌与型号管理”的全栈平台,采用前后端分离架构:前端使用 Vue 3 + Element Plus + Vue Router + Vite,后端使用 Express + Sequelize + MySQL,配合 Nginx 代理与 Docker Compose 进行部署。系统围绕四大核心业务展开: +- 品牌管理:对耳机品牌进行增删改查与分页检索 +- 型号配置:管理型号元数据、频响测量文件上传与存储、EQ 缓存与 Meilisearch 搜索索引 +- OTA 固件升级:支持 X8/X9 设备的升级包上传、版本管理与设备端“最新版本检查” +- 用户权限管理:基于 JWT 的登录认证、超级管理员可见的账号管理 +- 分享码日志追踪:记录导入/导出等动作的 MAC 地址、分享码、IP、过期时间等审计信息 + +项目具备清晰的开发与生产部署流程,支持本地开发与 Docker 一键编排部署,便于团队协作与持续交付。 + +## 项目结构 +项目采用多模块组织方式,前后端独立仓库,通过 Docker Compose 在同一网络中协同工作。根目录提供统一的环境变量与部署脚本,后端负责 API 服务与数据库交互,前端负责用户界面与路由导航。 + +```mermaid +graph TB +subgraph "前端" +FE_MAIN["frontend/src/main.js"] +FE_ROUTER["frontend/src/router/index.js"] +end +subgraph "后端" +BE_APP["backend/src/app.js"] +BE_ENV["backend/src/config/env.js"] +BE_MODELS["backend/src/models/index.js"] +BE_BRANDS["backend/src/routes/brands.js"] +BE_MODELS["backend/src/routes/models.js"] +BE_OTA["backend/src/routes/ota.js"] +BE_SHARE["backend/src/routes/shareCodeLogs.js"] +end +subgraph "基础设施" +DOCKER["docker-compose.yml"] +end +FE_MAIN --> FE_ROUTER +FE_ROUTER --> |"HTTP 请求"| BE_APP +BE_APP --> BE_ENV +BE_APP --> BE_MODELS +BE_MODELS --> BE_BRANDS +BE_MODELS --> BE_MODELS +BE_MODELS --> BE_OTA +BE_MODELS --> BE_SHARE +DOCKER --> FE_MAIN +DOCKER --> BE_APP +``` + +图表来源 +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [backend/src/config/env.js:1-13](file://backend/src/config/env.js#L1-L13) +- [backend/src/models/index.js:1-8](file://backend/src/models/index.js#L1-L8) +- [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/shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +章节来源 +- [README.md:1-94](file://README.md#L1-L94) +- [DEPLOY.md:1-269](file://DEPLOY.md#L1-L269) +- [backend/README.md:1-99](file://backend/README.md#L1-L99) +- [frontend/README.md:1-149](file://frontend/README.md#L1-L149) + +## 核心组件 +- 前端框架与生态 + - Vue 3 + Composition API、Vue Router 4、Element Plus UI 组件库、Axios HTTP 客户端、Vite 构建工具 + - 提供品牌/型号/OTA/分享码日志/账号管理等页面与路由守卫 +- 后端框架与生态 + - Express Web 框架、Sequelize ORM、MySQL 数据库、JWT 认证中间件、Multer 文件上传、Winston 日志 + - 提供品牌、型号、OTA、分享码日志等业务路由与数据模型 +- 基础设施与部署 + - Docker Compose 编排:Nginx 前端静态站点 + Node.js 后端 API + MySQL 数据持久化 + - 环境变量集中管理,支持 Meilisearch、S3、Redis、OTA 存储等外部服务集成 + +章节来源 +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [frontend/src/main.js:1-26](file://frontend/src/main.js#L1-L26) +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +## 架构总览 +系统采用“前端 Nginx + 后端 Express + 数据库/缓存/对象存储”三层架构。前端通过 Nginx 将 /api 前缀代理至后端服务,后端通过 Sequelize 访问 MySQL,结合 Redis、S3、Meilisearch 实现缓存、文件存储与搜索索引能力。 + +```mermaid +graph TB +Client["浏览器客户端"] --> Nginx["Nginx 反向代理
前端静态资源与 /api 代理"] +Nginx --> Express["Express 后端 API
JWT 认证 + 路由层"] +Express --> Sequelize["Sequelize ORM"] +Sequelize --> MySQL["MySQL 数据库"] +Express --> Redis["Redis 缓存
EQ 缓存键/字段"] +Express --> S3["S3 对象存储
频响文件/OTA 包"] +Express --> Meili["Meilisearch
型号搜索索引"] +``` + +图表来源 +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) +- [backend/src/app.js:1-60](file://backend/src/app.js#L1-L60) +- [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) + +## 详细组件分析 + +### 品牌管理(Brand) +- 数据模型:品牌表包含自增主键与唯一名称 +- 路由接口:支持分页、模糊查询、创建、更新、删除 +- 关键流程:参数校验、重复性检查、日志记录、统一响应封装 + +```mermaid +sequenceDiagram +participant C as "客户端" +participant R as "品牌路由" +participant M as "品牌模型" +participant L as "日志" +C->>R : "GET /api/brands/?skip&limit&name" +R->>M : "findAndCountAll(where, offset, limit)" +M-->>R : "rows, count" +R->>L : "info(...)" +R-->>C : "ApiResponse.success({items,total,skip,limit})" +``` + +图表来源 +- [backend/src/routes/brands.js:14-40](file://backend/src/routes/brands.js#L14-L40) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +章节来源 +- [backend/src/routes/brands.js:1-147](file://backend/src/routes/brands.js#L1-L147) +- [backend/src/models/Brand.js:1-23](file://backend/src/models/Brand.js#L1-L23) + +### 型号配置(Model) +- 数据模型:型号表包含品牌名、型号名、形式、阻抗、来源、EQ 键、创建时间等字段 +- 路由接口:支持分页、过滤、排序、上传频响文件(CSV/TXT/JSON)、S3 存储、Meilisearch 推送/查询、Redis EQ 缓存读取 +- 关键流程:TXT 转 CSV、文件类型校验、S3 上传、Meilisearch 文档管理、缓存键/字段读取 + +```mermaid +flowchart TD +Start(["进入 /api/models/"]) --> Parse["解析查询参数
skip, limit, brand_name, name, sort"] +Parse --> BuildWhere["构造 where 条件"] +BuildWhere --> Count["统计总数"] +Count --> Find["分页查询记录"] +Find --> Found{"是否有记录?"} +Found -- 否 --> NoData["返回无数据响应"] +Found -- 是 --> MapItems["映射字段为返回结构"] +MapItems --> Done["返回成功响应"] +``` + +图表来源 +- [backend/src/routes/models.js:133-181](file://backend/src/routes/models.js#L133-L181) + +章节来源 +- [backend/src/routes/models.js:1-569](file://backend/src/routes/models.js#L1-L569) +- [backend/src/models/Model.js:1-53](file://backend/src/models/Model.js#L1-L53) + +### OTA 固件升级(OTA) +- 数据模型:OTA 记录包含版本号/名称、下载地址、MD5、强制标志、设备型号/硬件版本、有效期、状态等 +- 路由接口:上传升级包(X8 上传至 S3,X9 本地存储)、设备端“最新版本检查”、后台版本管理 CRUD +- 关键流程:文件内容读取与 MD5 校验、S3/X9 存储策略、版本冲突检测、统一响应封装 + +```mermaid +sequenceDiagram +participant Dev as "设备端" +participant API as "OTA 路由" +participant DB as "OTA 模型" +Dev->>API : "GET /api/ota/latest/check?currentVerCode&model&hw" +API->>DB : "findOne({where : status=1, verCode>current, model, hw})" +DB-->>API : "最新 OTA 记录" +API-->>Dev : "ApiResponse.success(OTA 信息)" +``` + +图表来源 +- [backend/src/routes/ota.js:68-102](file://backend/src/routes/ota.js#L68-L102) + +章节来源 +- [backend/src/routes/ota.js:1-292](file://backend/src/routes/ota.js#L1-L292) + +### 分享码日志追踪(ShareCodeLog) +- 数据模型:记录导入/导出动作的 MAC 地址、分享码、IP、EQ 数据、过期时间、创建时间 +- 路由接口:支持按 MAC/分享码/IP/动作/时间范围过滤,分页排序 +- 关键流程:条件拼装、范围查询、统一响应封装 + +章节来源 +- [backend/src/routes/shareCodeLogs.js:1-88](file://backend/src/routes/shareCodeLogs.js#L1-L88) + +### 用户权限与前端路由 +- 前端路由守卫:登录态校验、Token 过期处理、超级管理员可见区域 +- 登录页面与重定向:未登录访问受保护路由自动跳转登录页,已登录访问 /login 自动跳首页 + +```mermaid +flowchart TD +Enter(["进入页面"]) --> NeedAuth{"是否需要登录?"} +NeedAuth -- 否 --> Allow["放行"] +NeedAuth -- 是 --> HasToken{"是否存在有效 Token?"} +HasToken -- 否 --> RedirectLogin["清除无效状态并跳转登录页"] +HasToken -- 是 --> SuperAdmin{"是否为超级管理员?"} +SuperAdmin -- 否 --> Deny["跳回首页"] +SuperAdmin -- 是 --> Allow +``` + +图表来源 +- [frontend/src/router/index.js:64-88](file://frontend/src/router/index.js#L64-L88) + +章节来源 +- [frontend/src/router/index.js:1-91](file://frontend/src/router/index.js#L1-L91) + +## 依赖关系分析 +- 前端依赖:Vue 3、Element Plus、Vue Router、Axios、Vite +- 后端依赖:Express、Sequelize、MySQL、JWT、Multer、Axios、Winston、ioredis、@aws-sdk +- 部署依赖:Docker、Docker Compose、Nginx、Node.js + +```mermaid +graph LR +FE_PKG["frontend/package.json"] --> FE_DEPS["Vue/ElementPlus/VueRouter/Axios/Vite"] +BE_PKG["backend/package.json"] --> BE_DEPS["Express/Sequelize/MySQL/JWT/Multer/AWS SDK/Winston/ioredis"] +COMPOSE["docker-compose.yml"] --> INFRA["Nginx/Node/MySQL/网络卷"] +``` + +图表来源 +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +章节来源 +- [frontend/package.json:1-24](file://frontend/package.json#L1-L24) +- [backend/package.json:1-29](file://backend/package.json#L1-L29) +- [docker-compose.yml:1-46](file://docker-compose.yml#L1-L46) + +## 性能考虑 +- 前端 + - 使用 Vite 构建与热更新,减少开发等待时间 + - Element Plus 组件按需加载,避免不必要的包体积 +- 后端 + - 分页查询限制每页最大条数,避免大结果集导致内存压力 + - 文件上传使用内存存储(Multer memoryStorage),建议在高并发场景结合 CDN/S3 + - Meilisearch 推送批量处理,避免频繁小请求 +- 基础设施 + - Docker 日志轮转,防止磁盘爆满 + - Nginx 代理静态资源与 API,提升并发与缓存效率 + +## 故障排查指南 +- 前端页面空白 + - 检查前端构建产物是否上传至 Nginx 目录 + - 查看浏览器控制台 404 或 API 错误 + - 使用 docker logs frontend 定位问题 +- API 请求失败 + - 确认后端容器状态为 running + - 查看 docker logs backend,关注数据库、Redis、Meilisearch 连接错误 + - 确认 Nginx 代理目标为 http://backend:8000 +- 后端构建失败(Node/pnpm 版本) + - 后端镜像基于 node:22-alpine,确保上传 package.json 与 pnpm-lock.yaml +- 修改 .env 不生效 + - 通过 docker compose up -d --force-recreate 使新环境变量生效 +- 停止服务 + - 使用 docker compose down 停止所有容器 + +章节来源 +- [DEPLOY.md:226-256](file://DEPLOY.md#L226-L256) + +## 结论 +本项目以清晰的前后端分离架构与完善的部署方案,提供了耳机品牌与型号管理所需的完整能力:品牌与型号的精细化管理、频响文件与 EQ 缓存的高效利用、OTA 升级包的统一管控、用户权限与分享码审计。通过 Docker Compose 一键编排,既满足本地开发的灵活性,也保障了生产环境的稳定性与可扩展性。 + +## 附录 + +### 快速开始(系统要求) +- 前端 + - Node.js(与 package.json 中固定版本一致)、pnpm + - 浏览器访问 http://localhost:3000 +- 后端 + - Node.js(与 package.json 中固定版本一致)、pnpm + - MySQL 数据库(表结构由 Sequelize 自动同步) + - 可选:Redis、Meilisearch、S3 凭据(用于高级功能) + +章节来源 +- [frontend/README.md:36-71](file://frontend/README.md#L36-L71) +- [backend/README.md:32-59](file://backend/README.md#L32-L59) +- [DEPLOY.md:259-269](file://DEPLOY.md#L259-L269) + +### 快速开始(安装步骤) +- 本地开发 + - 后端:根目录创建 .env,cd backend && pnpm install && pnpm start + - 前端:cd frontend && pnpm install && pnpm dev + - 访问 http://localhost:3000(/api 代理至 8083) +- Docker 部署 + - 本地构建前端:cd frontend && pnpm build + - 上传脚本:./scripts/upload.sh all + - 服务器:cd /data/project/dashboard && docker compose build --no-cache backend && docker compose up -d + - 访问 http://服务器IP:8082(前端)与 http://服务器IP:8083(后端 API) + +章节来源 +- [DEPLOY.md:49-118](file://DEPLOY.md#L49-L118) +- [frontend/README.md:36-71](file://frontend/README.md#L36-L71) + +### 快速开始(基本使用) +- 品牌管理:在“品牌管理”页面进行新增/编辑/删除与分页查询 +- 型号管理:在“型号管理”页面上传频响文件、查看/编辑型号信息、推送至搜索索引 +- OTA 管理:在“OTA 管理”页面上传升级包、设置版本与有效期、设备端查询最新版本 +- 分享码日志:在“分享日志”页面筛选导入/导出记录,审计 MAC/IP/过期时间 +- 账号管理:仅超级管理员可见,用于用户管理 + +章节来源 +- [frontend/src/router/index.js:26-54](file://frontend/src/router/index.js#L26-L54) +- [backend/src/routes/brands.js:14-40](file://backend/src/routes/brands.js#L14-L40) +- [backend/src/routes/models.js:133-181](file://backend/src/routes/models.js#L133-L181) +- [backend/src/routes/ota.js:107-143](file://backend/src/routes/ota.js#L107-L143) +- [backend/src/routes/shareCodeLogs.js:14-84](file://backend/src/routes/shareCodeLogs.js#L14-L84) \ No newline at end of file diff --git a/.qoder/repowiki/zh/meta/repowiki-metadata.json b/.qoder/repowiki/zh/meta/repowiki-metadata.json new file mode 100644 index 0000000..eb14443 --- /dev/null +++ b/.qoder/repowiki/zh/meta/repowiki-metadata.json @@ -0,0 +1 @@ +{"knowledge_relations":[{"id":2781,"source_id":"2b5fd78d-2407-4ccc-8807-9bb05c0a687e","target_id":"6b28e060-0be3-411e-8a94-3777d165d10e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2b5fd78d-2407-4ccc-8807-9bb05c0a687e -\u003e 6b28e060-0be3-411e-8a94-3777d165d10e","gmt_create":"2026-06-30T14:40:47.271887+08:00","gmt_modified":"2026-06-30T14:40:47.271887+08:00"},{"id":2782,"source_id":"2b5fd78d-2407-4ccc-8807-9bb05c0a687e","target_id":"941d72b1-8daa-4c53-bfeb-9a0b2aa0f43c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2b5fd78d-2407-4ccc-8807-9bb05c0a687e -\u003e 941d72b1-8daa-4c53-bfeb-9a0b2aa0f43c","gmt_create":"2026-06-30T14:40:47.272516+08:00","gmt_modified":"2026-06-30T14:40:47.272516+08:00"},{"id":2783,"source_id":"2b5fd78d-2407-4ccc-8807-9bb05c0a687e","target_id":"c6f2cb24-ff10-4ae7-87c2-b23b9bbee033","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2b5fd78d-2407-4ccc-8807-9bb05c0a687e -\u003e c6f2cb24-ff10-4ae7-87c2-b23b9bbee033","gmt_create":"2026-06-30T14:40:47.272798+08:00","gmt_modified":"2026-06-30T14:40:47.272798+08:00"},{"id":2784,"source_id":"2b5fd78d-2407-4ccc-8807-9bb05c0a687e","target_id":"4619dc3e-419f-435b-ba7c-e600e188743a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2b5fd78d-2407-4ccc-8807-9bb05c0a687e -\u003e 4619dc3e-419f-435b-ba7c-e600e188743a","gmt_create":"2026-06-30T14:40:47.272953+08:00","gmt_modified":"2026-06-30T14:40:47.272953+08:00"},{"id":2785,"source_id":"1f4b6f57-25c5-444e-a943-d162d896dc21","target_id":"7f894188-cf72-40a2-af95-f13ef3dd1f6e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1f4b6f57-25c5-444e-a943-d162d896dc21 -\u003e 7f894188-cf72-40a2-af95-f13ef3dd1f6e","gmt_create":"2026-06-30T14:40:47.273394+08:00","gmt_modified":"2026-06-30T14:40:47.273394+08:00"},{"id":2786,"source_id":"1f4b6f57-25c5-444e-a943-d162d896dc21","target_id":"b66da3f2-6889-45dc-a824-2591d2f5f0f3","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1f4b6f57-25c5-444e-a943-d162d896dc21 -\u003e b66da3f2-6889-45dc-a824-2591d2f5f0f3","gmt_create":"2026-06-30T14:40:47.273688+08:00","gmt_modified":"2026-06-30T14:40:47.273688+08:00"},{"id":2787,"source_id":"1f4b6f57-25c5-444e-a943-d162d896dc21","target_id":"799e02d2-8358-41a1-9f8e-114f8ac00eae","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1f4b6f57-25c5-444e-a943-d162d896dc21 -\u003e 799e02d2-8358-41a1-9f8e-114f8ac00eae","gmt_create":"2026-06-30T14:40:47.273951+08:00","gmt_modified":"2026-06-30T14:40:47.273952+08:00"},{"id":2788,"source_id":"1f4b6f57-25c5-444e-a943-d162d896dc21","target_id":"be7e1733-8c9e-4849-99b0-bab40fdf271e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1f4b6f57-25c5-444e-a943-d162d896dc21 -\u003e be7e1733-8c9e-4849-99b0-bab40fdf271e","gmt_create":"2026-06-30T14:40:47.274328+08:00","gmt_modified":"2026-06-30T14:40:47.274328+08:00"},{"id":2789,"source_id":"1f4b6f57-25c5-444e-a943-d162d896dc21","target_id":"8f464fc9-6537-45fa-a0dd-eacdf742b5a1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1f4b6f57-25c5-444e-a943-d162d896dc21 -\u003e 8f464fc9-6537-45fa-a0dd-eacdf742b5a1","gmt_create":"2026-06-30T14:40:47.274458+08:00","gmt_modified":"2026-06-30T14:40:47.274458+08:00"},{"id":2790,"source_id":"1f4b6f57-25c5-444e-a943-d162d896dc21","target_id":"77bc73e0-8709-4209-96e0-5522f9356b06","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1f4b6f57-25c5-444e-a943-d162d896dc21 -\u003e 77bc73e0-8709-4209-96e0-5522f9356b06","gmt_create":"2026-06-30T14:40:47.274632+08:00","gmt_modified":"2026-06-30T14:40:47.274632+08:00"},{"id":2791,"source_id":"1f4b6f57-25c5-444e-a943-d162d896dc21","target_id":"799ec9fc-088e-456c-8f93-72516adac3ac","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 1f4b6f57-25c5-444e-a943-d162d896dc21 -\u003e 799ec9fc-088e-456c-8f93-72516adac3ac","gmt_create":"2026-06-30T14:40:47.274784+08:00","gmt_modified":"2026-06-30T14:40:47.274784+08:00"},{"id":2792,"source_id":"4553d9a4-e0e6-4bc3-b285-ecc6df9dc822","target_id":"0efcac71-9db4-49c9-a660-690dcb97cd54","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4553d9a4-e0e6-4bc3-b285-ecc6df9dc822 -\u003e 0efcac71-9db4-49c9-a660-690dcb97cd54","gmt_create":"2026-06-30T14:40:47.275136+08:00","gmt_modified":"2026-06-30T14:40:47.275136+08:00"},{"id":2793,"source_id":"4553d9a4-e0e6-4bc3-b285-ecc6df9dc822","target_id":"ef11f60f-47aa-41bf-8884-6d51bc9ae8ef","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4553d9a4-e0e6-4bc3-b285-ecc6df9dc822 -\u003e ef11f60f-47aa-41bf-8884-6d51bc9ae8ef","gmt_create":"2026-06-30T14:40:47.275339+08:00","gmt_modified":"2026-06-30T14:40:47.275339+08:00"},{"id":2794,"source_id":"4553d9a4-e0e6-4bc3-b285-ecc6df9dc822","target_id":"edd1d813-70d4-49de-9f9e-e3ebf7a68678","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4553d9a4-e0e6-4bc3-b285-ecc6df9dc822 -\u003e edd1d813-70d4-49de-9f9e-e3ebf7a68678","gmt_create":"2026-06-30T14:40:47.27546+08:00","gmt_modified":"2026-06-30T14:40:47.27546+08:00"},{"id":2795,"source_id":"4553d9a4-e0e6-4bc3-b285-ecc6df9dc822","target_id":"b2376dbd-002b-4469-8e6e-71748e46e7c2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4553d9a4-e0e6-4bc3-b285-ecc6df9dc822 -\u003e b2376dbd-002b-4469-8e6e-71748e46e7c2","gmt_create":"2026-06-30T14:40:47.275789+08:00","gmt_modified":"2026-06-30T14:40:47.275789+08:00"},{"id":2796,"source_id":"4553d9a4-e0e6-4bc3-b285-ecc6df9dc822","target_id":"b5718a44-f452-496d-83c3-4e89b844c709","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4553d9a4-e0e6-4bc3-b285-ecc6df9dc822 -\u003e b5718a44-f452-496d-83c3-4e89b844c709","gmt_create":"2026-06-30T14:40:47.276097+08:00","gmt_modified":"2026-06-30T14:40:47.276097+08:00"},{"id":2797,"source_id":"4553d9a4-e0e6-4bc3-b285-ecc6df9dc822","target_id":"539729a8-aa4b-40c6-bf3b-ec9f467f7717","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 4553d9a4-e0e6-4bc3-b285-ecc6df9dc822 -\u003e 539729a8-aa4b-40c6-bf3b-ec9f467f7717","gmt_create":"2026-06-30T14:40:47.276606+08:00","gmt_modified":"2026-06-30T14:40:47.276606+08:00"},{"id":2798,"source_id":"ed153077-3827-4586-8838-812707189c14","target_id":"b6857b45-a960-4168-92dd-1edcf6567e47","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ed153077-3827-4586-8838-812707189c14 -\u003e b6857b45-a960-4168-92dd-1edcf6567e47","gmt_create":"2026-06-30T14:40:47.277101+08:00","gmt_modified":"2026-06-30T14:40:47.277101+08:00"},{"id":2799,"source_id":"ed153077-3827-4586-8838-812707189c14","target_id":"2971fa4f-335a-4294-9668-0967b9047d66","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ed153077-3827-4586-8838-812707189c14 -\u003e 2971fa4f-335a-4294-9668-0967b9047d66","gmt_create":"2026-06-30T14:40:47.277268+08:00","gmt_modified":"2026-06-30T14:40:47.277268+08:00"},{"id":2800,"source_id":"ed153077-3827-4586-8838-812707189c14","target_id":"f0978b42-6f98-470e-922f-22dec2fac24d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: ed153077-3827-4586-8838-812707189c14 -\u003e f0978b42-6f98-470e-922f-22dec2fac24d","gmt_create":"2026-06-30T14:40:47.277627+08:00","gmt_modified":"2026-06-30T14:40:47.277627+08:00"},{"id":2801,"source_id":"c45b2f5f-49f8-4c8d-b489-44b4c6800e99","target_id":"5ab55e3b-04bc-4e92-93f7-52bec7ad8dde","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c45b2f5f-49f8-4c8d-b489-44b4c6800e99 -\u003e 5ab55e3b-04bc-4e92-93f7-52bec7ad8dde","gmt_create":"2026-06-30T14:40:47.277787+08:00","gmt_modified":"2026-06-30T14:40:47.277787+08:00"},{"id":2802,"source_id":"c45b2f5f-49f8-4c8d-b489-44b4c6800e99","target_id":"62bcda0f-7c78-4109-9649-58bbf9fd68ae","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c45b2f5f-49f8-4c8d-b489-44b4c6800e99 -\u003e 62bcda0f-7c78-4109-9649-58bbf9fd68ae","gmt_create":"2026-06-30T14:40:47.27822+08:00","gmt_modified":"2026-06-30T14:40:47.27822+08:00"},{"id":2803,"source_id":"c45b2f5f-49f8-4c8d-b489-44b4c6800e99","target_id":"86f882d7-9e64-4c38-85e7-4782fd55fed2","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c45b2f5f-49f8-4c8d-b489-44b4c6800e99 -\u003e 86f882d7-9e64-4c38-85e7-4782fd55fed2","gmt_create":"2026-06-30T14:40:47.278376+08:00","gmt_modified":"2026-06-30T14:40:47.278376+08:00"},{"id":2804,"source_id":"c45b2f5f-49f8-4c8d-b489-44b4c6800e99","target_id":"ff04bd0e-99c4-481c-ac8c-3c1a6cae1fb5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: c45b2f5f-49f8-4c8d-b489-44b4c6800e99 -\u003e ff04bd0e-99c4-481c-ac8c-3c1a6cae1fb5","gmt_create":"2026-06-30T14:40:47.278503+08:00","gmt_modified":"2026-06-30T14:40:47.278503+08:00"},{"id":2805,"source_id":"d4cb0c3c-97e9-449f-8918-f1c01e7e3561","target_id":"772c69b5-886e-48f6-bd11-faf8ca2155e8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d4cb0c3c-97e9-449f-8918-f1c01e7e3561 -\u003e 772c69b5-886e-48f6-bd11-faf8ca2155e8","gmt_create":"2026-06-30T14:40:47.278654+08:00","gmt_modified":"2026-06-30T14:40:47.278654+08:00"},{"id":2806,"source_id":"d4cb0c3c-97e9-449f-8918-f1c01e7e3561","target_id":"babe3ec0-01cb-43c3-93db-7e59cdccce68","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d4cb0c3c-97e9-449f-8918-f1c01e7e3561 -\u003e babe3ec0-01cb-43c3-93db-7e59cdccce68","gmt_create":"2026-06-30T14:40:47.278828+08:00","gmt_modified":"2026-06-30T14:40:47.278828+08:00"},{"id":2807,"source_id":"d4cb0c3c-97e9-449f-8918-f1c01e7e3561","target_id":"8d4422fd-bd93-431d-a97c-70b75f370f82","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d4cb0c3c-97e9-449f-8918-f1c01e7e3561 -\u003e 8d4422fd-bd93-431d-a97c-70b75f370f82","gmt_create":"2026-06-30T14:40:47.278985+08:00","gmt_modified":"2026-06-30T14:40:47.278985+08:00"},{"id":2808,"source_id":"d4cb0c3c-97e9-449f-8918-f1c01e7e3561","target_id":"da7627b0-17b7-42c7-a029-e357bc889416","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d4cb0c3c-97e9-449f-8918-f1c01e7e3561 -\u003e da7627b0-17b7-42c7-a029-e357bc889416","gmt_create":"2026-06-30T14:40:47.279133+08:00","gmt_modified":"2026-06-30T14:40:47.279133+08:00"},{"id":2809,"source_id":"d4cb0c3c-97e9-449f-8918-f1c01e7e3561","target_id":"100cbee2-f7a5-4cc9-83a3-900a4aacac7e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d4cb0c3c-97e9-449f-8918-f1c01e7e3561 -\u003e 100cbee2-f7a5-4cc9-83a3-900a4aacac7e","gmt_create":"2026-06-30T14:40:47.279419+08:00","gmt_modified":"2026-06-30T14:40:47.279419+08:00"},{"id":2810,"source_id":"d4cb0c3c-97e9-449f-8918-f1c01e7e3561","target_id":"cf1f3ceb-e3b1-4d5c-8353-f0ea4345414c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: d4cb0c3c-97e9-449f-8918-f1c01e7e3561 -\u003e cf1f3ceb-e3b1-4d5c-8353-f0ea4345414c","gmt_create":"2026-06-30T14:40:47.279584+08:00","gmt_modified":"2026-06-30T14:40:47.279584+08:00"},{"id":2811,"source_id":"2971fa4f-335a-4294-9668-0967b9047d66","target_id":"0e003133-7d1a-4708-8599-fc71707070d6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2971fa4f-335a-4294-9668-0967b9047d66 -\u003e 0e003133-7d1a-4708-8599-fc71707070d6","gmt_create":"2026-06-30T14:40:47.280345+08:00","gmt_modified":"2026-06-30T14:40:47.280346+08:00"},{"id":2812,"source_id":"2971fa4f-335a-4294-9668-0967b9047d66","target_id":"4b6d6abc-bfd2-48a5-9c5e-de89f278f887","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2971fa4f-335a-4294-9668-0967b9047d66 -\u003e 4b6d6abc-bfd2-48a5-9c5e-de89f278f887","gmt_create":"2026-06-30T14:40:47.280628+08:00","gmt_modified":"2026-06-30T14:40:47.280628+08:00"},{"id":2813,"source_id":"2971fa4f-335a-4294-9668-0967b9047d66","target_id":"5b84c784-85d8-46e0-8972-e7816f6bd687","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 2971fa4f-335a-4294-9668-0967b9047d66 -\u003e 5b84c784-85d8-46e0-8972-e7816f6bd687","gmt_create":"2026-06-30T14:40:47.280745+08:00","gmt_modified":"2026-06-30T14:40:47.280745+08:00"},{"id":2814,"source_id":"f0978b42-6f98-470e-922f-22dec2fac24d","target_id":"ad988472-7d0b-4076-86c8-f14661c5923d","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f0978b42-6f98-470e-922f-22dec2fac24d -\u003e ad988472-7d0b-4076-86c8-f14661c5923d","gmt_create":"2026-06-30T14:40:47.281057+08:00","gmt_modified":"2026-06-30T14:40:47.281057+08:00"},{"id":2815,"source_id":"f0978b42-6f98-470e-922f-22dec2fac24d","target_id":"7eee30c6-7725-456b-8b43-35b5e4df7e99","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f0978b42-6f98-470e-922f-22dec2fac24d -\u003e 7eee30c6-7725-456b-8b43-35b5e4df7e99","gmt_create":"2026-06-30T14:40:47.281191+08:00","gmt_modified":"2026-06-30T14:40:47.281191+08:00"},{"id":2816,"source_id":"f0978b42-6f98-470e-922f-22dec2fac24d","target_id":"791c01a2-dea1-407b-948d-3e2da8cbebed","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f0978b42-6f98-470e-922f-22dec2fac24d -\u003e 791c01a2-dea1-407b-948d-3e2da8cbebed","gmt_create":"2026-06-30T14:40:47.281365+08:00","gmt_modified":"2026-06-30T14:40:47.281365+08:00"},{"id":2817,"source_id":"f0978b42-6f98-470e-922f-22dec2fac24d","target_id":"9f2c6c14-12ae-48cc-a1ee-fe703cd12a1a","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f0978b42-6f98-470e-922f-22dec2fac24d -\u003e 9f2c6c14-12ae-48cc-a1ee-fe703cd12a1a","gmt_create":"2026-06-30T14:40:47.281523+08:00","gmt_modified":"2026-06-30T14:40:47.281523+08:00"},{"id":2818,"source_id":"f0978b42-6f98-470e-922f-22dec2fac24d","target_id":"6003d293-f2aa-4c49-817a-c7fa652890ed","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f0978b42-6f98-470e-922f-22dec2fac24d -\u003e 6003d293-f2aa-4c49-817a-c7fa652890ed","gmt_create":"2026-06-30T14:40:47.28164+08:00","gmt_modified":"2026-06-30T14:40:47.28164+08:00"},{"id":2819,"source_id":"f0978b42-6f98-470e-922f-22dec2fac24d","target_id":"7d8f2ef6-290d-4952-b59c-a1d95af0d438","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f0978b42-6f98-470e-922f-22dec2fac24d -\u003e 7d8f2ef6-290d-4952-b59c-a1d95af0d438","gmt_create":"2026-06-30T14:40:47.281749+08:00","gmt_modified":"2026-06-30T14:40:47.281749+08:00"},{"id":2820,"source_id":"f0978b42-6f98-470e-922f-22dec2fac24d","target_id":"73336201-a22f-4329-afc6-40fb5f00f4f1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: f0978b42-6f98-470e-922f-22dec2fac24d -\u003e 73336201-a22f-4329-afc6-40fb5f00f4f1","gmt_create":"2026-06-30T14:40:47.281894+08:00","gmt_modified":"2026-06-30T14:40:47.281894+08:00"}],"wiki_catalogs":[{"id":"dd61923f-65f8-4e98-85f4-0e0a0a649a27","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"项目概述","description":"project-overview","prompt":"为耳机品牌与型号管理平台创建全面的项目概述内容。详细介绍项目的目标、核心功能和技术架构。解释系统的主要用途:品牌管理、型号配置、OTA固件升级、用户权限管理和分享码日志追踪。描述前后端分离架构,包括Vue 3前端和Express后端的技术组合。说明项目的业务价值和应用场景。提供快速开始指南,包括系统要求、安装步骤和基本使用方法。使用与代码库一致的术语,为初学者提供概念性概述,同时为有经验的开发者提供技术细节。","progress_status":"completed","dependent_files":"README.md,DEPLOY.md,docker-compose.yml","gmt_create":"2026-06-30T14:04:20.633103+08:00","gmt_modified":"2026-06-30T14:09:11.174236+08:00","raw_data":"WikiEncrypted:0MI1/XkBoMl0lTbK6t0Cn/+8FdvqrJ62ianMLvZj02elJtBUgH0Ns0veIx1WPtM9wwkxI+/XAqHLxJLlHB8wV7ojrH0+b4JMz5OewwhBN1ELEwwkQElYbXolx+YIQM0o2FbBtwH/qJtog2gIHchdNwll6Nf1h+JmY9opyg7JsQs/7cTSSrfUmluAQwFCDAvmu/tGmL3XeCzrrmkOI88h7pvsgL2niGJR0xRh4Lglcxbrr0NK4gOQ45RwQchyzpGTB8IiO3XRTcNftONnEzDiJzVODyKOjZe52ws6XblEwu77xu3aef4IAzXLIbyoTb10Z/ue/QVjfqwkoEB9u5ciW4cJImri5dT+xVeLMwEADbmq8MbYy3QkUi4lCv+02P52HSrp5PmR0p110l5NRD3wnUyJ4H3excBt4DYq/WkTlWRnu7SL4FLbChfDRXox0FZjbrSrmstSyjrqOQs0i+3DWG1cAoapA34zEKMkiP2oxZKPn+7VEJ/X8+B7JhsqroKmAs/NykYkyA78uoY/rRIZzhCoDGERQV+E21xUWuvlE/M6M9LjVSnEkBww9yRnijToD6+usihE9d0zbv3MzXNqNqaye4++Ko+2iPoV2eV7lIQXwMto7c2DhmZGyJ5OEE45X826wBdjL/sO1X1QPuglr4HEFXnds8hBA4bPAqVmgptC8bfkf03XDZOL4nlmljZN+Kip5CAYgR9K5mKRD8ZS9gGT6ieJ0jbcHoo6kysaXa+jBICwzeAEQzmvxq2JqEukLdcKXOrZ0CgeeU8SADva7E+gvKzvS/4Zrbv5UEM8NkYcqeX4k9ERuVUjy5J96C0S2GCNR5OPStfW2tKkrorTKngImbE1l0f1/FI2ZhI5sSjUkzAZIKFeXBJpA1hZSNME+E+UIJ+RvcsprmVx62wG1PlwMBeEhu/9cGBj+i+qI6uAlGdhybWAqGSSxsLwdqCiwQEcylelO7fNlSrnz7amb1JuqBfUynCEzpnlNkv6l9jioHXV/fnJIOihiNh7v6/AMwtMvmSnr/j1oUAuJQuDAW149PMRpTre8XUtulayHzPj4ZY7R+4VpHR5kmYcTNmUnCf7Q26XVU6NLlv9Qu/gvQ2TPuGOKCs579fz3jbJC6rn+mQXlkz+vQFu2x4MrUvomEqqCVV9lv7ORQqVPJuJCH5onWcX84PFxIMq38bqGCQ="},{"id":"bcc45977-c058-4033-b0b1-9fd4cd7f4443","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"前端架构","description":"frontend-architecture","prompt":"创建前端架构文档,详细说明Vue 3单页应用的整体架构设计。解释Composition API的使用模式、组件层次结构、路由配置和状态管理策略。文档化Vite构建工具的配置和优化方案。说明前端与后端API的交互模式、错误处理机制和性能优化策略。包含组件通信模式、依赖管理和打包部署流程。提供前端开发环境配置和调试指南。","parent_id":"70ba09ee-60a3-41f9-bdda-3cb904cb26de","progress_status":"completed","dependent_files":"frontend/src/main.js,frontend/src/App.vue,frontend/src/router/index.js,frontend/vite.config.js","gmt_create":"2026-06-30T14:04:44.763098+08:00","gmt_modified":"2026-06-30T14:14:52.87794+08:00","raw_data":"WikiEncrypted:rJ/rIw0gVau8jPGqKFBAsMR2XDSFypkKHZQ6YBOgiEB18etPNKW/AKXxDO5P260N8cfR8zM/FPLMKEziA2ENAEHVfReiRH5pH+fgWYT+2jYTA7RQlp0TufhpU942Hkc/ujxUhYq+V3QzFALbuwWzvx0UL8Xl+TN5xmZ1UNdZO71Qogp53zx2hXdFdKaPDrr4z+LIar4k3xztnrU6feh8nqiV6INc8alIAN875sC2qpjIyq5wlayKyIdU0M+5DXjHjuV+3QmKO4f+JccdKivcFYhs66YKXadO78U+Sx6jpT0RqNqSmB5SNJLPpp6YbwEYtig2YvqVxHgh+FtviAJo+3aiePQw/TkCYVV02sx3HchcKY17yohkf/cGQMfHWKjBC7ZyuuD2WOHobXyyVuIuHVDKntJ2SjXdR7GaQPDZaxSWpeHYcn0+Z1hICSDDP4TfjuXCKtOx01urOs4lYqZsN2SPy3LljUhl9H5uWpEV3VH/LPqTWQ6MdLG8aye4mMcCsw57e+goYu3oRkRf7qvVOAVztMhQTkCgcUPkiPfB+YdqPMMp430Bqr55/AYFsFD2GmYltN+8OgBqLdislp5mudOEF8uE6Awfn0xbNJNePcUD1+Esx+V+RGIXYVMeRXcagKyoftiqtJy7zjwWBmr/oTG428St7QGB+Yha7dSK7y6WiOZjdDUs5Jm354mpkojurMNDW9Pw3s7Rt24W3JHN+Z8iSUq9+Cr2kaQyNT4G8XaqIe0s8pFYoGeAeYcZvyolp+0ZZ6pAH3tyuVe8hrE+3+/x/dOKV5WsDc7Jul/RY0qtkjt39mvXPzbxtMbwGhahGz0xRVYJMlhMkcN/dqJI4Jj0QtNULaonjkU/joC8aUC2Vfa8MFrpfwSTVytGIrfPAvxbxMYgPvqi8KSjqjV5lpDGUcYA+DMgqLOv7mPVrPBosl5m0J5Fitt9KmR1j2OOr77AyteAWJcBvK/idJN48LdNVtAYqErjTGb16luVO1yW9sDX8VXCKzUPBQ8boXaJ","layer_level":1},{"id":"d34906db-4455-4481-9512-b29115655378","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"认证系统API","description":"auth-api","prompt":"为认证系统API创建详细的RESTful API文档。记录用户登录、登出、密码修改等认证相关接口的HTTP方法、URL模式、请求/响应模式和认证方法。包含JWT令牌生成、验证和刷新机制的详细说明。提供认证中间件的使用示例和错误处理策略。文档化密码加密、令牌过期处理和安全最佳实践。包含常见的认证场景、客户端实现指南和调试技巧。","parent_id":"7e9246a0-207e-47e8-bc26-b9d36ae6f2f8","progress_status":"completed","dependent_files":"backend/src/routes/auth.js,backend/src/middleware/auth.js,backend/src/utils/jwt.js,backend/src/utils/password.js","gmt_create":"2026-06-30T14:04:55.151403+08:00","gmt_modified":"2026-06-30T14:15:47.981318+08:00","raw_data":"WikiEncrypted:I6KYYMxpAemyHFwJy5bny+FhLrJAxcHi9isgLCIR7jKgk+RtRRSImYeiedSZDcwnIMYAtWgsiGag9xYiTBcpIby59MhEIf69Ge8Ey272sEwv4rLKoaCbet71KAMUN4denOOfuaKbrwbXK0Y6FbehkE+pCWtq6ubo7or5Tl+PIwwX3Vha0M9C0aYlIBIXgML+2LymHuPdeYf/f+yy7ivDCl4nIRTcM9C82jpKialSDtNyDOeJKcvnuY7WboeTuADzL6A5fX/baERJkVBnSdbIynmMfReneVt5JAopJ+2NyT22CaFtr2L3C+DKZ74FDaU6iC/85eg42OZ2JgeBZXiffstckEhj2B8H2dLfxGDmQUebrfF6cqty5biCE3zW8cU1QI3+bPdfGaoUhj5xFzd437cjGI+IAkNffhuBei52tU9+6Uyp/Ym7bEGnUpxwS1OOijeLKUstO9d9z5MAs5Ip5+HVcliUeAVujyIwd76cvmbhnuaspCX23T55qAvLoTJKWmDBZaKzPE6hCpNAHPfq9b7tOLID4W0tvfFPZnzGWsZK4LhJHC3i/qAGdXsXDc/JijZ7xvhJMYqJMxcoZ4hdtAdv1YjL98AOd++9n9H0hDplAqDf638QwPeaKC6ogkEw5LCWjJFC3FbT+FvpZTxN7RRHFPVNndBrtwSEJR/6/EfA6+9lpuWMXHNhL2Hl4GsMybpXzg4+AihB6Xy9GPv5kkG1enLqgCaaQJ1blr2eb9rUYLvCkQMW+DRqPPQxfniLGGB5WuUkzxn/NzDZ++XhFvmvW6s0+TPiCNMxhx55Jd+O1ta0CeYAptKYmjSJmlT2XDRO/aqedoSZyzYc3L9gtYD4V6FRBsTtOKLyB22oei614ORfyRcALpx0q5/EeyLHYVN0UM2Xsh5n08o9+mCzjkPjSVfG9NIIBhGUTEj1i4dKxB4vM4hLk3x9i8HdfoZ6f4+3iHGqQtHSFId685Izyli748sL55omKo8e0lizEKTrYd5W2vZUviHInfD/D2cIfwRtRBEksNW/6ycVp+dc33cqX6BIN1uwL7uMBhCJyrLl9TbEaEDKPHaGmi4jx9W+","layer_level":1},{"id":"0f657e8b-77cb-4604-81cd-d3e921d28e21","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"布局组件","description":"layout-components","prompt":"创建布局组件的详细文档,重点描述主布局组件的设计架构和实现细节。详细说明布局组件如何组织页面结构,包括侧边栏、头部导航、内容区域的布局方式。记录布局组件的props配置、插槽使用和响应式设计实现。提供布局切换、主题适配和移动端适配的具体示例。解释布局组件与其他页面组件的集成方式和数据流向。包含布局定制化选项和样式覆盖方法。","parent_id":"aa2583bf-2c6e-4792-b794-1563db547d08","progress_status":"completed","dependent_files":"frontend/src/layout/index.vue","gmt_create":"2026-06-30T14:05:00.056535+08:00","gmt_modified":"2026-06-30T14:15:24.296404+08:00","raw_data":"WikiEncrypted:x3LcpLCzT0KOPxd1xeYY3c7iq48qz+WPAPm3x7MWgVl9Ka0y39BYIpkYIXIwXtcEkjLNRqcKoI34Ay7VLfvIoeNd0L9KiPW38nGEktOH2kdRoWStqgftHHDZZMeM3wTiHozP2mtq/BrgXkFbslneMaOqL0jcIeyYsEzK3XOf2IWybFopdsfudEA64erTFyD7rwb4i8M4/OQlv/7phzTi6ud+DXkigQ4QxPbXoU8Pb60EBp1eZghvTXVMFb5rlp+3kbG8uerYS+ciu/fjCScjFieZOug+uuHKkFaFYBj8Za7rmsWg02byP4r8E5yKIzSPDy+NZcyXTRKFGHYtNCtj4aueEWW2oLGYR0/nYHoeMgwdpaKxBg9Ye0gbrAr9gQvUxrzpwdRrUEUmPdp4oTmO1+y7PWruf0IGT+IA7KRfCxZ03rVNE1s6b72zwuUdEps8hXGWIMTqoYJYcYh57cVQj9l1O153yZRu3x4+GhgBW3fblpCW+bEz14xJrftnR/Qve4y83EkfHuQurRD/YlwaAXS6/Wd0aG06MsRzr2xJPgKjLVxTtAsdz5BI8ksED+Rpxs+vKy/CDOvvIUhAx1A0xnzRxDB+ZCR+u/EilCFFyqqqZyWB90BOY5jlYG9Ci2wONLki4Vjgwz6irpTnjyAwev4wTO/8aLJVBupWUqU5MB6mAreomYWt8GYTQqybbkozb5cbV5rNhZTZql0EV7u9+K4mxe4913Os4q+mI5AbzsqzM16xKoV94kRhPaiubGHpXhh9bVmMFx1DyDRVXPlu1zbbRnGMgbH1bIp5FdYRH38HFuxpXMeHfBmyWq2CIVOuMgJQZ+WFbqZPfHN+LjcAOYmhW/MnaBS3TKjqR/3lHriai1eaX6gHyHcqjUCh/6/IwJ311KB5KiG74iE+EWk1a16r+k5oTkTOUMNGX7YnwoVLs+kVHv1fnD14Rwf3OBrXEKFkNyWE9mPL5SV18Yedhg==","layer_level":1},{"id":"7f36202b-af69-4fc0-b62b-a57e415deb69","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"部署指南","description":"deployment-guide","prompt":"创建详细的部署指南文档,涵盖首次部署、本地构建上传、更新部署等完整流程。详细说明服务器准备工作、目录结构创建、环境变量配置步骤。包含Docker Compose配置说明、服务端口映射和网络设置。提供上传脚本使用方法、手动rsync上传方式和构建启动命令。文档化健康检查、服务验证和常见部署问题解决方案。包含生产环境安全配置建议和最佳实践。","parent_id":"a3ddc4e4-116f-4781-ba9f-17c85c85396e","progress_status":"completed","dependent_files":"DEPLOY.md,docker-compose.yml,scripts/upload.sh","gmt_create":"2026-06-30T14:05:12.310696+08:00","gmt_modified":"2026-06-30T14:16:33.828055+08:00","raw_data":"WikiEncrypted:0IKfLNOWe9mZfG1jVts3wxq1Ie83+Lf6EMuycQSN7s3NFV5ooa3Scq2B9C67gTKq2J61WmIo8uwzopEI3o+rxz7q0fBEeW1pmj3Z5yCZzfN7Q3gteOOQtgoQ9YkE4gpYcO2aDGkpGrIWWNjjQ7GyOJYn8FGR2f/tSJ7yy/HcDn5d2NMrcqrwu4CX5Gvyd5xJmIYcuVjpKRByATlNCS1zM5hEwvlL73AQR2eSztdK0b5QNmGctlhqTgf/bfJABgos38mVZQzbH7O9ocFFyJUbFu6uhqIefp9TJkdsbvU1uMF0d4ZiOsIuQb0iFW9suvsoVwvoTRh4P2mAHkIgDv1aQoO66lJ5hTpWGKjuTRoBV+UETV62ofFoNftmlPOqxy+OikSbYqZh3VfJHAM/gj/ehoEfHSCQXl+YPs6HmF0O72rArAXK0t95ls3PNrQO9l0dAP9L1/TwQrroJcZP2FGM7uiesHanN3jdTNXwgBD3l9gUOzOGl/15A7bXkqFfom4mPjqe6+/6cyxTQzxI7oAwU5654D+GtFcAXw7zvEMq0cOeDIeMUocxBNVpRf8SIpWDCB5fuZth/RVBCE29a0lazqZfhtrvKoROmw9go1mbNtfu0GYtrWHuz3BkMaVCGKKYV2TENB8j91AHzomcbKh1sWaWOVzi2XZUHTcZNhOW7Ob8mCxLNxbYWc+goUyiGyu6fI8rJcq69+Eq6MdAlDb8H23H7TSYkPWwvoiI4SRihEX+kEcVRlZgcxYloixMRqcfAirLSbzDrUxdyL+A636HqHK5wbrXT01hUSqhqmuXcDl1jUYIcSZaaS2GdN5sPNr/tfAEvV/QuZx8OV18PJa1uc0WRgGiX/0qbXAJL9l9rZEPkjjNf1X4S/9PNYbQ7y4YCSa1ug33vS9PYtl3eNOvb8aXrgcYnFnrkCIa/XOtmTrizRBLEyjVMUkRb20GAfpUamYhWVOkVmvOU+OtWeD85PtY9aYy61msYID323pMp14=","layer_level":1},{"id":"dbe5d77f-6f4d-476c-88cf-797b80a11a11","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"实体关系设计","description":"entity-relationships","prompt":"创建详细的实体关系设计文档,说明Brand、Model、Ota之间的关联关系和映射策略。文档化一对一、一对多关系的实现方式,包括外键约束、级联操作和数据完整性保证。解释ORM模型间的关联定义,包括hasMany、belongsTo、hasOne等关系映射。提供实体关系图和实际的数据流向示例。说明关系查询的最佳实践和性能优化策略。","parent_id":"0bb34dac-0e1a-4cce-b41d-0194eda77f79","progress_status":"completed","dependent_files":"backend/src/models/index.js,backend/src/models/Brand.js,backend/src/models/Model.js,backend/src/models/Ota.js","gmt_create":"2026-06-30T14:05:22.620322+08:00","gmt_modified":"2026-06-30T14:18:01.587347+08:00","raw_data":"WikiEncrypted:WnER6MhWFG6N6U3R1m3zi9/PE7USWRBJSA4m5rdVd0roBuaFoWjKznz76Q8kOGO4tNwaCSIDcUIRQho0AHAeCEii3WPT3hVXrhQQYjEzvKo6SYnxMHFyoqyC8KkItViNO7QMqwUXCOqIqkKYJbtN9Sajekq73kPvPqvY8BHSNnqfwmaK1orPvHIjh8Q37172/jp+exIQ+FflmU+mfYsQJ0KuorznohYsQIf3qlfg8KiwSW0u0L8K99eblOKDbNN7MYtC9qf0iFzdGSOSwR4u5r4gtdCB7SAZCvwuy+HaSOgXF4oQDX+STWKFSq2xGuZf3y54WkpwBnQtNhvzIQLDsBrIlz9tHbHjMaQwU3a8HTu8JTO3mYJ3BTiKKC+jsgxGTxRRRTQ9PhQo1waFlJnCSVsR+m30u2zHgq9G3gwORjBImo9vcEDistxC+xSWMBsfJzWlXUhx5EjJYrZ1oHpgxmUGyLoTlfCJvJoNqs+vQLDuVZ6jd6juOPkJ7sanKd4TlWRy4lLmetztJb8ZAKPP6R4RV0YcU4IV3Lr/Tm0KzcHdb84aWPsI0EgbfUkJAWjCOieqWTHBE3qfwchsJYJqR3RrOuH+/OgRl1A6P/5XR2tG4/LwC5N356o2YR38E4icxdWGirKniBpii3TVWrqGEkWMsUbRenNq6PCyT/kcGEb1Mn+/c4b1Rb80dNweaNWDSOLmHQFMvwtgxh48I7NXGBAprbcEP+kwn8U6cf+oo+LDgHKyTDMssoP+fUOnruX6Eq9vx3pklQUfost9b2918rL+L5N9/tKoCpCmXHMgjuEE94T77bU7dXpcCRjh6dza/rLHJfo9rcOESul7Y0UthoahAetOF8CRzabuRNfSA3+/EgpkViiYcAqUOfJO9prMaKspC6udBaqAb8GX20oPvVBnGdehFhjW6ZNUKwhOOyBRpudc+qhvrCn14VSOV60QyhfWkkOtqy6adpmbqDfDn/boGiahg8EgnrKUin0NLy9vZH/v3RdDSgNXAhCHJng3as9wGB02Lo7l/LIlX0/+Pw==","layer_level":1},{"id":"1af0f0e8-0c53-41d7-a894-47d9cc19d4f9","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"用户认证系统","description":"authentication-system","prompt":"为用户认证系统创建详细内容,深入解释JWT认证机制、密码加密解密、中间件验证流程的实现细节。包含来自实际代码库的具体示例,展示用户登录、令牌生成、权限验证、超级管理员权限检查等功能。文档化认证中间件的配置选项、参数和返回值。解释与路由系统、前端认证状态管理的关系。解决常见的认证问题如令牌过期、权限不足等场景。使内容对初学者易于理解,同时为有经验的开发者提供足够的技术深度。","parent_id":"08dd4c40-3fd3-476c-bcca-4c8687a8d863","progress_status":"completed","dependent_files":"backend/src/middleware/auth.js,backend/src/utils/jwt.js,backend/src/utils/password.js,backend/src/routes/auth.js,frontend/src/views/login/index.vue,frontend/src/utils/auth.js","gmt_create":"2026-06-30T14:05:25.89264+08:00","gmt_modified":"2026-06-30T14:17:38.563207+08:00","raw_data":"WikiEncrypted:uxAckj1IXK2TQH//kEdeBLXlO/kfAAqZjShpoDF/LwxjObF9jWClg1BjbeyHIZSgS1kW1/rwYWDBEsAU51nyKaMjqaYMMCeAu0tGWpZIc0izGBmzwh6bfOUHboVu8bTGN57x7Ig4dNdDghiUoJkJKQX4Ys9KTK8TqI3fswjZz8hglaQGl4NeRcIcMv/X6D2PrvWe1qVFdZ0SPTExOhFw3RHcXIB6SwncZI+aMeqX09v6wHL4Cp5stm7AWL+txJygRSaQYujDcE62s9wfDJweKf/BQ/zTEigEdc5GbzkMnf5NFxmbi8jVDO7wUEofR5O+0G7fH1Wf3oAZBMkevD8TNGju735s+O957j0f4XKsnnX9lsLIvYZtW3hwTKNBeBoujNYJuApW03clJesocX3Wf8ww8m1IO2jArAjxNy5Kz5feFkFhHiCG8MEacgHT8kg3E7ZzxyNGQ9qNkHcWapTIQs0bhq055rPjXYps6gxDBnOgFKy8B8vJf6NOsu03pfZ3uD3dNNqpYwGSW0z6lGvHkDJd2fJxAFHPmnmL4angdyPotlYsK94FpYGrRt1S9x1phZ9rGSahcTUMsqDcT9Yf+KRzNIDRSVSA32KNeKkIlJ7KkS/Wm0jraxDEOETgabNiprZu9IQc2rO+qgL11sXS2ztPP5P+se2fpoWR4kk1uiZ47ZmEOozxu4PiysCNnQaMA8ANHI+wEeZnkX2tQbrDymKi+ns1ZC695WMnYfGVqqzW7ztwv6hcCxyg1h0cCTV85FVN56EYr/FayPkYHDGEZZVV5ZUDvhVDpwyR3SbeAFQjsbJ0kKXLG89LTiuNzGgRwI4aA6bxge2JglaT1f+mtyXbZSnfdajBzphQGhsXB18VE2IXqwfYJigbP5F/u+e6mB7sN63cqVRQ1ydNmvawS0ojJpoUdPJp746BGGnKgHcDOaskuD4puwZFDNJVLFQql+zdoIL74vkQKXIqKhlm4hvnkOFZ06ODxcJWJqQNMT4gzixw0eo6Edc3t7Gz3J/XGJn+Lm4JoYBdAk0PmDWtQqqAjKqm9ftEqhlBb/nAlZxetLWvyg1railkNORM+louiBsqTKmMqeuxFGvIMxTWvlU0z1uFTBuzUgVEKqUJRQL7XYgPhEQngiJN01Bm3XHt2zKUINah98fqoWiyyAHyX0v/dIbaMiyXnzSIZLIBWZDZL/N1ypvWw8ffozNBXfZhGhoE0OUp+tItqNmnVsYGvwtU1dFJK3ZuLGGkiqACmSRg+oIqURaokDzn4B10iFNXdloxmOHr7bgSoCjlSjyXfECCg+t9GlrWtFGusJSHzWiRdg6rJ9Rd1iTeSafPGd1AD2mZ1bTOdXmS6IT2utJkj4CIc2gIkIpnlTql1NbuOfDA4NTL+t/649wrNxdl/tfq2+8LlsB48ND80XGMdAuipGWEYynvogLDZguqmDXtxMo=","layer_level":1},{"id":"8f0760f5-ef8b-43ef-8fd0-7c6d1f693193","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"侧边栏Logo组件","description":"sidebar-logo-component","prompt":"创建侧边栏Logo组件的详细文档。深入解释SVG图形设计的实现原理,包括渐变色定义、阴影效果和动画过渡。详细说明collapsed属性的作用机制和响应式布局适配。记录组件的CSS样式体系,包括Flex布局、动画过渡和响应式断点。提供在不同侧边栏状态下的使用示例,包括展开和折叠两种模式的视觉差异。解释无障碍访问设计,如aria-hidden属性的使用。包含性能优化建议和自定义样式的扩展方法。","parent_id":"eb78ed75-b786-4b43-ba43-58a5ea8a23a6","progress_status":"completed","dependent_files":"frontend/src/components/SidebarLogo.vue","gmt_create":"2026-06-30T14:05:28.622668+08:00","gmt_modified":"2026-06-30T14:34:09.996181+08:00","raw_data":"WikiEncrypted:fV4HuQ/J1++1YCiBadzlA/Ad9WGt57Xw0P0O4e1aWBZ8j7ewAMLGa30PoRyFOz3WPxWhYzFV771iPkiUIngbYLg/7p5O4HeDzmBW51nlwAWF6h03zUwo1BVzYo/fjr3K/vHHffvWiWcvf6+/Pi/zO1p95ifW1RHBzkGDc4cbtCFnI4TExB7L8RgFPd4xt6LWCmL98hBAGxxSmeVmm2WQY1xGJjqXhRpxokLo77b3Ez1EWub03MklHAlEi4JLgZCXeG0AZMzGl2EApA0orVb+k1nPHohU/sYPxOP1g77oqTo0L6eRrJYqLVzXM4dPj6cJPfoiL1VO/2KqEXmJqEEcvA8tI8Vv7fNcUxexyGaVLP6NrOdFw7GfunFw5t/QC4hNv3P7MI8EUJYJ/PidrenCXzv2FJL9zWw9IsaJbDglurckMqQQka4/AwPlhiPqUP3v9KzvsSqKogDiv94Gx6K87tIpDsodProyn5dx5GKnJIQRuNQYX1lpPTVqMQ2OlAD5KvAnp1VHGyVMPixJgwRLl/SX/Y/mmbAA3QAZC3s3LJSW/Hh6OogBVuThelQoKNB2/rPZ/yEgXcFUj+H9At4yNojzuBdqqMakOsrfs/1WsYmEsUXZ/HgLkCJR2T6jL0BiRhXisXcj5fbzxADw26kbKBhW/suo/JwIzITcMgr+B+vwdmIYlROk2zRWQTcSVdtpdouiZLy50KNTRIQYgqiiE7nEL/p885dM13alTVH7cRjdXV993ONl6tRfBQnS9o2VAa9B/IoHSXQjblj73awUecvCir7Ougv3SPoE8GPBJakIDBiVOGlcooQQjVelDtXjn5zyuz6cLPIZF9rqakHJT7KHTZrM2+Wi+TKoGF4IR0mEcinmwEe+JNRIkItConCqwWx3Ekz+kabb7E1CpVm1yA8794xHHJtDSak71A7IL0KO7cUUC0tFTuy+c5W/vuZfoZX4oiO0lX2SvlQGYkguIQWABQjuuCjerUkGgiScVohUoSA1vJVnraaSNsC3edoxL+W4+juGOZytBN0HGZS0U6a1asEka7fODrK/yhDNJ2XKz7+pcu4DwgRtUHUM26FEG84uR2EBgZRiuI2c7YA9Ag==","layer_level":2},{"id":"105cfe1d-aeeb-44c1-ac3b-6550f2c7a307","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"首页仪表板","description":"home-page","prompt":"创建首页仪表板页面的详细文档。全面介绍首页的功能布局和数据展示机制,包括欢迎信息显示、快捷入口卡片、今日新增统计等核心组件。详细说明首页的数据获取流程,包括getTodayStats API调用、数据格式解析和状态管理。记录首页的响应式布局设计、样式定制和用户体验优化。解释快捷入口的配置方式、路由跳转机制和用户交互行为。提供首页组件的生命周期管理、错误处理和性能优化的最佳实践。","parent_id":"f00798b7-c49f-4260-b9c1-d1ee413b030a","progress_status":"completed","dependent_files":"frontend/src/views/home/index.vue,frontend/src/api/dashboard.js","gmt_create":"2026-06-30T14:05:55.602204+08:00","gmt_modified":"2026-06-30T14:35:15.434226+08:00","raw_data":"WikiEncrypted:l84AvQDvM6QBXs3c27I7iRN2eqIKPqqnLN0fpl6W1NXbpSYLO1ugdN9q3vfdxcOimx9t9/zu6SUc26bwQ+elEbS+I0PRYDRL4shhpb72Ma/Ng8alFtrqEXILpNlDWRs9AoWzQ2KDmoixk2jOewMEH3JllHtJ8DUYUZNp06dby1l7BRtvY2mOkugkoAohYAjj4QyuCm4GXiALmsr7NFR3LC3O0kqbZE21xaDZXflITmtjSkBHJVQtkVH23ciBJVtJx7Co85atOo33DVRVlrOhEJtgP3suOSOLawlRAo6EcizG7y3pDIU5ypo7B8YRrtllA0l35kDhk3pyDTN1sj7bajT9y2fIinJVq2T/AOLyueKRKMFNLrzr1chgaXuxLhiVRpeHk7C325h3AGYYJ9+6Xtr9kmA5H4Ebjk+2sk2YLVBogzJelsdYQqCiBDGzCxN0BAVpEtw7J50eZ+XDVbOY7JUC16j0oiXukJycIku1pthhJUplqc3HiyebwYVuxfxWdM+2IV0+/ic+3NzpGhu19jpGFUZnSD4NLtTW6QCHZMn4FcScTwzn3/5byoDiy6M6RaM3JFXc1XjuZySnsFKAO/Bo/PgZMmoaNUj+gHQTBOhFflMX2DlPEpj+q5NpHNyY11SKV61o7RWYW8r4F9r22VlfvDnLPI2PEvkX4bjKEBeR3vYrx7FpVdNWkqK9JpVWewynEwDS7csRjVfkc43fe6xYto8zEDV1/AjQdPOhSQHP3UOztX3pS7sBLJq/2N8sWJqG+YrGE6N8mVAmjm4/i1jR1vP9HaW3cqoo4fYDacBXqFkEIyqDicgLUVe2+pCWp5Lek0ENTV1TmLovw2a8dsooOU6GQMozpayiXhtI+WzwZxtXAFHTaVyHFJiWYMOOH1xDFV/IfD54CHmfO9/W/bjOZnxKeS/jSJygbW1/5U3jX84UX1n/gqGOsSnO4SKJDEQbdK6PB4+9ounpuIITKPmk7KMn27m//tj8HPjx3W9lenipUy68iqVbiEUqz+/Ty0SFO87eWJGkvXE/HqepzBh5V7XvutH4Y3F0V+GKn9MYQrquYT8PrsUhfk8cZdXdsq28aDUYUl+B4Q35nG0gew==","layer_level":2},{"id":"de69fb0c-330e-4831-813d-94fb958688da","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"快速开始","description":"getting-started","prompt":"创建详细的快速开始指南,帮助开发者快速搭建和运行项目。包含完整的环境要求说明(Node.js、MySQL、Redis等)、依赖安装步骤、数据库初始化过程、环境变量配置和启动命令。提供Docker容器化部署的完整流程,包括镜像构建和容器启动。包含常见安装问题的解决方案和故障排除提示。提供基本的使用示例,展示如何添加第一个品牌、创建型号和进行OTA更新。确保内容对初学者友好,同时提供足够的技术细节。","order":1,"progress_status":"completed","dependent_files":"backend/package.json,frontend/package.json,backend/start.sh,frontend/install.bat,docker-compose.yml","gmt_create":"2026-06-30T14:04:20.637065+08:00","gmt_modified":"2026-06-30T14:07:37.615397+08:00","raw_data":"WikiEncrypted:qfgbutC7oyxR6nMxrwk1ODnNMBEQ3/sG78fQT1yXWju83LC7H/jAM8CEAvWT8huE5OClmQiIfNYNxHQ9s7RRS4I2JpxuOJTz8eCWMUZ1Uyzl3ct5rsyIFu8fuwdbAeggGoVlXxfRcT82rVraC1rlaQRGO5kgcNTJgIeZDa7KIJzJReW1AF2gOcg85NxmyD2QBPU20jUQG8tQZgyOekDGEvFa7bKU1UDQLDNO4yVWuGIsKgfV/whNAizKl0ZZaZ+9iWM2XXBDA9sLrXZQD7fyzUl3elNmWx830Y5ju+KudGoo33Kt/Zp5fVC96xUUwKGcGwH9ptvzXwJy6/w/sF3x8vbGuLrEvc3DHTShxmj7sNOi9NQlkBUDWrQbl44wQC9NfLJYbEHG5mWaT3bFotTFxn/bxdbAce7P9osAkl9SDqVly0X70YjXY4Axe0EdO80cCfQwynIN+uONKc2K+DcTIjJYXIK+dE5l1LUWXxSAWbsgxjnTgTeRqS/RJ7U/LwV6x3M+O42mw7d57H8byAPhaALheFipMQM2Xxemr8LmrCaU/OyB1Zt7NSjO9icOjS7ce0KBJMehTWPQn27B6NBZIwT5MvbL+9Y57TJzYRoPUaywWNeNl20CsE3D7BPdkNz7cT3NEYSTghAfeU0vF120Z/28Pq15ZxBRmIDF6obYSk8NJLSGbOIxYm6QWdJ5c/NnktUQ5V+LKFEgPFSF3HFzIEpolqTpuA30n3Ok0tdZgrCKqqreZOg8uMZPai73OsMcEfntY83IyMpmxd6KNmaZW06B/uk7VOvC6T0wpPksXFRSXonlh0fgnFt4o3fusophHFTQTcpWeBSacU8y2fSx8X6q2zYQj4H/czf/7ijEyOhGFRdm08Eir3Y7kYYFI8hQBfVdDOZ6gFQ5HkQME0ktc5JOWoaqNYrVpVidXpLQ5YMhsh4lHao/nOxWraq/zC3qxrIikrUW0zchTI/h3Jd0fDHMhC2t+Lkbztk3oZ2oCcejCqLBcLrv9ZfkdOxCD+Z4bOao7gjk7dTngaflTdhV8wLJ2RV5IeB0U5YTPVdBfo2VZ3Z5lwdr2Uul/0kxsFfvLfAHgvs+X4oxWle5XW5cu8PoSaCj/pLYjR+/CZ7mtEZLCWj4gas0xmYzqylOaFjIk5cGaAQiW9aRrb4nL6YWK0IH8tum/o61yMkXp4rm6cC3lDsToPthqlHlAoziWtZLPsvc9z6zXUwW38sIA9pz1Q=="},{"id":"5a3639b1-98bc-4bc7-a346-91ed56edd2af","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"后端架构","description":"backend-architecture","prompt":"创建后端架构文档,详细说明Express应用的架构设计和实现。解释MVC模式的具体实现、中间件体系和路由组织结构。文档化数据库连接管理、Redis缓存策略和日志系统配置。说明认证授权机制、错误处理和请求限制策略。包含API版本管理、安全防护和性能优化方案。提供后端服务的启动流程、健康检查和监控配置。","parent_id":"70ba09ee-60a3-41f9-bdda-3cb904cb26de","order":1,"progress_status":"completed","dependent_files":"backend/src/app.js,backend/src/config/database.js,backend/src/config/redis.js,backend/src/middleware/auth.js","gmt_create":"2026-06-30T14:04:44.765806+08:00","gmt_modified":"2026-06-30T14:19:05.642968+08:00","raw_data":"WikiEncrypted:N3UbzwGjCC3xD6BrTM0cq8Y9ccVoDb9n1FwE8c3MNy31fwp7itn1eN/9SBNHQuzqn4Z/E95mV5akFaXhbd+x3Hbeb8Lp+QkTMOKfZNQyKojFvMb3nIaA+mV48tDXDWEqxrlhh4JpRydgTIGrd8n1WR3CjiMs1OtPA6kBQSdqoDuuhqzpLQF8idz+njTnv94/o/48fQBsI6bG1frzakIYWOtViLMUk+plRMY5j0337M+sVWAzgVAFVqgiBfjrTGY6V5DqUqCh8xE5q7CAvBRDT1Jmo2M8F60+ejp31MVUAg6xRp6POj/W3ik2qnAYOVweqNiTiYyns3uz+8l5xceif6+1JZOepuVFsY2Temglybru9Gz2+d+3AJpuvKT5LjJnJ+BMF0P3sGW2ATh6rsJJIu6u7uWn4yr6rsZZYNqdEQW+qWwkT97SWLMa1xtsuNiR3+QKu13kqysVkXG4H/394AJwDoljAoFMTzOsbUlUkY6QrOsx6LagWGbhXIqFrRfDWnSMkE81wWy3pcgFETEzQIaN+xAjV/skriEvn2clKJ6c4DNKTiS/iLu+5T3UPOXO2kbKzPwVqlxhU0xGZ1Pq2RodxcdD2f0abxDz3g0Wx97q+SQUyHL/KmFznoAq7YvBwKc0bWAQXkc1FvmZ6XGHyxoO2JyrbzZOMumcj3gZ6Zxc4nUPXKPoKXDL7unysWj4JDOcJhSB+hGDKjckKvvLLeDFShiGN/JjptjQMBiU39yfOom3FOP/vM/S9QSF3WNTopdDHkSmlh7dZWtHUE/z4TL3fYmzT3iFsTj4yjeoP3+Yx51P+Hz/3jrBPpT92jRo66eNc3GuySe1DeaXPT1YWdIr7S3r5T1r/ojXI4tcYdNj/LkmB+pLLsIvvosu/ETHXLP4L+Brr+mJWjJGSSz7IzsH4UlQFwh0nY8tbkO6UsTnmZY7PQhOHvuLVCOQ3qaLfKU2LxfMTm8oDj/lbOxS9/1KKy/W99UmrkMvhardyA1Y8SqsnkPCXZqFkn7POOgOaIY2vWUs+L4PKd829ZApvZMyukooOwm4NhCvWOp33xo=","layer_level":1},{"id":"779d6806-96dc-4c97-8cfb-15a3d7855bd1","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"品牌管理API","description":"brands-api","prompt":"为品牌管理API创建完整的RESTful API文档。记录品牌CRUD操作的HTTP方法、URL模式、请求/响应模式和数据验证规则。包含品牌列表查询、单个品牌获取、品牌创建、更新和删除接口的详细说明。提供Zod验证器的使用示例和自定义验证规则。文档化品牌与型号的一对一关联关系和数据完整性约束。包含批量操作、分页查询和排序选项的实现指南。","parent_id":"7e9246a0-207e-47e8-bc26-b9d36ae6f2f8","order":1,"progress_status":"completed","dependent_files":"backend/src/routes/brands.js,backend/src/validators/brand.js,backend/src/models/Brand.js","gmt_create":"2026-06-30T14:04:55.154207+08:00","gmt_modified":"2026-06-30T14:19:07.600812+08:00","raw_data":"WikiEncrypted:hJ5e919a6La3vBIeYsDd9H+qoMODEBAlmCzG+cWkGRu78NaFDIi9qITlXW3zUicltUTnty1k0aVuLDmUbWYsq2DQkP84kMUHXEpA6OcQtQQW2b0L3hPiCNJb4ZQrqvo1LXEBjkme7wbSkleJI63o/kaE8846oeYE4AMgjWxEbV54Z95lxWs7OlwO2sCsNbqRc5wR/o7amP61MJ/lKWn8nNLrexqAUu50qeYGngpuqV3zogarV6D9+HK54itBZ/ncQ/+9a/lhzLkb54iR5IcRDOqaVetAPcB7FKWOIWyMYRgn/APHz0vu/Ow/jvrk2IP5VdQBYSzAFPe3odHJBhc53XJToyo3J/RoBJdKTAdLlVolDpTzg9VKOFbCd0ua1syW8RDmRR8CDnzPdnm2/KJn2+vYfnnvQvdbENcsjaVhdZ5GPJSf43fyJOJLXx8L2QjtqQdv69AtBDyTBsnmFqRUG6WKDHnA3WtZJZQ796EgvORbPOAecIhV0hLlvUyUJBOrM4v2ZMmc5RZ+ukl5ruR2PxQRNJRVk5f8BDNoylYtTWow9gb4r9ii7/TP7NjRI37TxCOkatlA10cnKD/24jXu6MRyocnYPVbHAT72NR7srRVXBcqMwlwiK2LCPVG71hlvmt7NiIB+pNCWB8s+qWHNpfV4kmmg9+458bGJdycQgVa4Mb42lqASsqANfZRC0xMGO4JM+Gns7T3vtPmAqjDJB8tZrkZ2p0dnvSBGpkYiLm68HLUpIXD2YldMCbY9ymtkJB6gBWWBUutBXeTQ++SyBn+qRICWqKCnVWYK0rfrYWa76HfOU0xfjpR9sVWFqXvhtkMBd67yy00PkaTUrvIFUq769fpn6KWDb99I8cHWnLIj556iiITHC7TpEqPSdbdkvssbuU0oj7RqG+UAFQWmP5fu2c2dBkaPoaqTfzdrJ4EufHQc+W2V0jZLzdrztAbbrXMIlcSdnIVZcM/yV5kGv89D64a9AfWx3h+b4uVFgMRhqFlACt0/36RwQeI2ZJTp","layer_level":1},{"id":"eb78ed75-b786-4b43-ba43-58a5ea8a23a6","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"业务组件","description":"business-components","prompt":"创建业务组件的综合文档,详细说明通用业务组件的设计理念和实现方式。重点介绍侧边栏Logo组件的品牌展示功能、标签页视图组件的页面导航能力、密码修改对话框的安全交互设计。记录每个组件的props接口、事件回调、插槽配置和样式定制选项。提供组件在不同场景下的使用示例和最佳实践。解释组件间的协作关系和状态管理。包含组件的可访问性设计和性能优化建议。","parent_id":"aa2583bf-2c6e-4792-b794-1563db547d08","order":1,"progress_status":"completed","dependent_files":"frontend/src/components/SidebarLogo.vue,frontend/src/components/TabsView.vue,frontend/src/components/ChangePasswordDialog.vue","gmt_create":"2026-06-30T14:05:00.059997+08:00","gmt_modified":"2026-06-30T14:19:27.855603+08:00","raw_data":"WikiEncrypted:mHLzoBKW/ak+KVdbda4A2f7qh44idx3e5sYOKq4y/WJWBVlKxvfsgrfR5kwEoK+5YZtxFpGvHzwX4IOH+DawEmhTwQMjQgMBCcPS53RmGaHOSgU0nKq03Su0/WZVgYDJfX5EkUz6h2rTPEOvq5PXUInOMgSH6UvRdohktfTAFkzFd7S1FTK58sVzdGQozq7wI1koDtSWO/SNpO4Ee8fMt6DTqQ90rTnMbEPKLcOrCDgBxPksoF4AwVmDiOWy6KkShCEKg5p6r82/HoJV2qfYNRVng+LVbIRQN/zKlyM4YEjleh+mVPfQG9melNixR3cJRG3orSswQpSogfZRK8Bo+TO29dCbmXI9Mg5k9sGaNAq2jbK1UKrydX+oZeXgh1B5BSCmOo6BWUzJqDsP9IX3WZ4YYVL08TTVYxPFyLEuNn34DiKMnez9L3SfJSnMIoqN7ClMC6kQ9CccZ6/1deguTXM4M/nzN1SSJuOFkMC4DjWRStbyZPfqHkfhcEG+DW7eaIurD4brX7qVwpAIDEp+HrF4YB/rpvFHpbpqob5nWRmQN6HzhmXSIBVTDNlvO7PuFOz5bARPKE7RKFrgOc2cFBVLCny0niJuaZXDcspCDEjkKMe/W6KijLPgVdFJ319wQi6WwIpUYQEwwRICmXrDU8UXRluSrnbmkI46ju45vwGnf4ZkUgPQhrtrxxqbDjr3wHgQtU9m0G4JzNonUKrVsTmom54Hx2VWzLxdXVlK1T8uszT0ZI2wtEAFmM+maRys0ZM/v6yzw7S4lK6LI76u9HmAWuPDpalJjO66kRoPPqFHGP12HnREYBCpiyzVDOsMKLP+nC9RJxVJyDqINcMIEQ/cvMqQYtNOCoV8uC4xqdOLLw69jWdiOw30qNnb3DwC64POHfTIjLTuZLWorchvBthVfmMzwqrolaR3VHUVgR/m5h9XEGlzXTqA6znkpkA1TjOTmf6YAAGAQ+Zt0IuWfA18ulyPt6eyriUUPdL4oJqBk5XXy45O8tb73hyaJ09bw6OBSdGlDdIsNotjVXwyfFkMEutcpmMT0v9MKTugGcSfEHSUwMnJkFKSB/PL+vn4zUky0vkjG6dUA1kerjwmjSaNZ7vkhCbbP8OFylL15gHQfCdOMb0AOCZTdEob06yof4MSnaXqMF6dufxLdbwOuqCfJUkhi2qwT7TxlBIB+CQ=","layer_level":1},{"id":"f96081f7-f508-41e2-bd45-a5b36a1ea114","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"环境配置","description":"environment-config","prompt":"创建环境配置文档,详细说明所有环境变量的作用和配置方法。包含数据库连接配置、JWT认证配置、Redis缓存配置、S3存储配置、Meilisearch搜索引擎配置等。提供不同环境(开发、测试、生产)的配置差异说明。文档化敏感信息的安全存储方式、配置文件的版本控制策略。包含配置验证方法、常见配置错误和解决办法。提供配置模板和示例文件说明。","parent_id":"a3ddc4e4-116f-4781-ba9f-17c85c85396e","order":1,"progress_status":"completed","dependent_files":"backend/src/config/env.js,backend/src/config/loadEnv.js,.env.example","gmt_create":"2026-06-30T14:05:12.313659+08:00","gmt_modified":"2026-06-30T14:21:11.825296+08:00","raw_data":"WikiEncrypted:mJFb0eo+82adP8NAeq7d4IIa0ji7BfhWd+tPu7r6OpR4X+XfqeclnD20MHCexQtgFzeY+udCFgwSLYPDydN5R8BNpcJBbveVhePMQWOVKGSx4DICe20Yr3Mg9nlLB9FGlGjUc9Y2pTff0xrwHFSfFG9wRb0k2bAg/j1gbq1g3pZxabmYCBYxTPF026U732n/Ksmolpy1y/q6x9P2vurlaRpr34CvTfVkEYogh6YTLfmAhzHfbr4sP+eShuvQDEHYmhRjzMwhYz18NBjgpMKUbE/pndwBftVShR24efIAv/BElGFzh4ocX9Ye4v5tKSBg10FekOLemFoJ8pOCG+BGhsRKs9n51fBFLOmmhXaTFC3SHhG9AITLshuN0sb92me0NMFI7NrhNuNKzc2UHDUgDyF4Vafg9YZgHju8PxlEwOs1BaPCOk0xYsp3DW0oVsG+AwBQvlvriYibLy7tghBmipp4c6l/pSiJCmGjW0JwUul9lVwbeyMAjsVBJp2ZXwzI9IKB/NXvEH/JyDft3X6uxO5VqdujNwKyJ8t8zvrApsSX4vMXO5+2SnxXAGudlLDTLmP6ozej4/197Za0ickFHWFjLPGNZDXv3dGVJfV+YiyL6wDXurvpHfhX09eVn4DP5NLwrzRsggp5XJR9ojLxzMggtxIbLdbx4xTBkRXRiJflCuRSm12Jrt6+U42gs8umQx0/uQSOJX44A0jxVep0MZK5QMIH7oq4jDqBV685QyNKxM4+IDM/E7zWDh9V8U92lhe3mOm4mqolgFJPfEzZaFsi9hOqp+9ZaAPAlXj3DJCXdSDfa8hNtfgjKJ4UgqP/2ESnAZhrUisYaQnfAMUBQKau+qwn+CnUsXOKcJkQNSoaXdvyBbAr18gNn3wK7A0viPPO1OCMf9E0Za9ghsyaTQ0q5kZuNukjWX1iQbG9QZ3TTkxZOzgSpuC9sndRmv6DY9AWL3TaupI10Ec52w4hOZe9TAcM1iN38mHBSSAf8r1qp1rGeo4bV3v8ONIokVkJP/lLXskyXy8PWwyNyN6yE1CfFAh5xxnrjnHNHYgYz9c=","layer_level":1},{"id":"92f94141-482e-499c-bbc3-6101e70206ff","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"品牌模型","description":"brand-model","prompt":"创建Brand模型的详细文档,包括字段定义、数据类型、验证规则和业务含义。说明品牌名称、描述、创建时间等字段的设计考虑。文档化品牌数据的增删改查操作和相关业务逻辑。提供品牌数据的示例和使用场景。解释品牌模型在系统中的作用和与其他模型的关系。","parent_id":"0bb34dac-0e1a-4cce-b41d-0194eda77f79","order":1,"progress_status":"completed","dependent_files":"backend/src/models/Brand.js","gmt_create":"2026-06-30T14:05:22.62391+08:00","gmt_modified":"2026-06-30T14:21:29.097262+08:00","raw_data":"WikiEncrypted:MpYke5d2PXdqtxI+drCrLlbJ7FPFod4dQS4C2jIEy1Vi+RWBmbRp3cvvlClyElpjY248hN/8uxj/oZc1cBilbx0tRCgx4EXGhbWT0bKPV9CClQk3EyAIvWkjw2qBl1GwoIZaoQbh/lDf7iSv+CjumSc5MqVDv7FeDuoB4BYvqSFuX6/sw/v3wTqRwaKX6wLQyS1j8HSrt/0T9Q28vNhc5WBAPNUs3PzlHBfFfWZpG8H8gVCRsqX5tOhfgNie/doVHGT9Gl74pC4sOjSrm4gseL4GAP1i/34P2j8wpFWOK0PHIrEDdLFB/nl4AmiN3z3GOflyzR8heQlB3L74kyUKX3oVFyL8nei3KJoV9pUbYJJztTdKAUC4USkpOWF2LYTf166CAIIyLuvpGUJmRkxZ9T6fpTbIZ0tWkizC09RvdiaDW1+cjDQhj6Ij23KebNfpMuYYTUkiKJPqASQ9/+A7uNZ43ntzVnopgTzXzDun3QBC7j4m+iF5DLSWdqS3XyRpanF50CvdYz5Px9oLvusDbKohVWQ6zxGf+ZZTXOL5+eTO/qQ3TKNuJA3mkzSqU/zzIodqLG3oFObroU6JLMHgFwXp2OggflULj5njivqDgj90U47CQExGFS8JnCl0dPuxiblN18wZf2ANfUg0IvnU5rAmQ/gz+dtummkOEouqZxCglWdsNKdTIkRWEkDBecIe9oGWuMX8RiWHLnL/Y3EvgSPRu8DkD/n6hbQQPpIrGV7Jf7CIPfqWg8/6VZose+vNR+n9JFdOEU7Q6X9OK8lAsw==","layer_level":1},{"id":"1e3d40bc-a833-4f35-891c-9dd96f09a1a3","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"品牌管理","description":"brand-management","prompt":"为品牌管理功能创建详细内容,深入解释品牌CRUD操作、数据验证规则、缓存策略的实现细节。包含来自实际代码库的具体示例,展示品牌列表查询、新增编辑、删除操作等功能。文档化品牌验证器的配置选项、参数和返回值。解释与型号模型的关联关系、缓存存储的使用场景。解决常见的品牌管理问题如重复品牌、关联删除等。使内容对初学者易于理解,同时为有经验的开发者提供足够的技术深度。","parent_id":"08dd4c40-3fd3-476c-bcca-4c8687a8d863","order":1,"progress_status":"completed","dependent_files":"backend/src/routes/brands.js,backend/src/validators/brand.js,backend/src/models/Brand.js,frontend/src/views/brand/index.vue,backend/src/services/eqCacheStorage.js","gmt_create":"2026-06-30T14:05:25.896897+08:00","gmt_modified":"2026-06-30T14:21:25.623188+08:00","raw_data":"WikiEncrypted:MpYke5d2PXdqtxI+drCrLid0YsRsuFzxrKFl1UH2EDILD+4NmryAJ+q2oYZ42eaiz44GIk6X8OFlUAZ3K10FBvMN69Ne06Y6iVCy+4xZdAsUGmydXuI9LOupHeDUaC3pvkOjqp3EZ4xOBXToKexD3sJwOHDJUYBWddck1pKB+BpUmpIGWGulvtKNd7rUuuNXGGexSoT2k/+fD8cfS96290Who+jupUypdef/VVLQ+SMm9fS7HoCYxsUJ9tvcR9HLpcihb2gc09v40WXl2RSPF2VOKqtBB6T3R/UTcCJV4p8ISn8geesslxEYyvMaCyHxZrZvjir3/r7oVAAh3KAOE+Nx4JTX1AQd1M8iUlzVaup2ZB8XvjcIj9/TKMdIL3PhNerpdIgsAQ8lwCNMPriXoMoZx0MzlaX5d0D7vEbujs1W/0zu4BgcnCjJtUdvCB+34DyEDjZVd5vEPpMDJyN4KZq0V2zz6XEIXr/SWlY7yRweOhgMAw/2UmV15PZmnHQQIsspcBtED/4LZY8sngC1o50KUM+1PQNQamViqAlGCHXBAR7Cj3E+QvjOBSfAVtc7OPeHToJFTO7XdM8xdMMjkRCdrmB8zJ6XSDish3MLo+tv5fNdSlOF8ZFqklGbV+DaphtWW1k3t13oFWP+IjkbW3xwsA8akuLoG+cXEctO4Uq0VFfoiwI8sfioOV/hJo6y06miVzTDvjdjk2vZ50V8j2qsw3eXt2N4bX4b2I/BjLZzItZdmHID3ExYBmo+VjPOmBXQGuZdhG3wTGSRtD7Phhsd0G6umdHsRVF74ih8xOWkjG4+8dj9F6mnmWm7nn84+bv+Es0fsCjoeqagYkgvIU63p9y/FEcjSTEEdHqZ/0qKXA8S1xyEHzPMmW4LjN8jwyNryVJPl2LOI75aXNvdeoMbfPs9qH5u6SeX8rw6TvD6XwAb28N8ehKfUVwJFEY7PkCn3ROnsjFquwaBd+DjPpH3CY7TdpGqGBuP5a+0z72JVUfnjXKn2oKTR35QRVAhdnXk/st1N3eu8SXBHgx2XHzEB4JAnu1nWqNOr0d5Mn9OVFDqOJ6GD37xh0oQvgefNcxCxgURt08010ZPDFx0TvUMLh2g+plGTyUqDgekPLtY93lC9TEtV4x92OjUub4JRNaGBlHVTUaC/pi2JUS/QYcfOPvjYMa7TgyxylESgrt7jf4+lZOJzAOmJSKScT22E+S1o0omg1Imd7YyAt5QFJwBS8Zm25xjGROuORqURPWRYfToJMKQYjB905rLMlW7JS8VHBVaqUp6R+S4827muvsDVj/opXiMkSLPllSH2AwfVfT8AASFSzz66kvjkmYy","layer_level":1},{"id":"727c25ac-db22-4b34-9486-6fd6946f64f3","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"标签页视图组件","description":"tabs-view-component","prompt":"创建标签页视图组件的综合文档。详细说明标签页的状态管理机制,包括激活状态、关闭操作和重新加载功能。解释标签页的数据结构设计,包括标题、路由信息和缓存策略。记录组件的事件处理系统,包括标签点击、右键菜单和拖拽重排序功能。提供标签页的生命周期管理,包括组件缓存、内存优化和性能监控。包含标签页主题定制、图标配置和动态内容渲染的最佳实践。解释与路由系统的集成方式和状态同步机制。","parent_id":"eb78ed75-b786-4b43-ba43-58a5ea8a23a6","order":1,"progress_status":"completed","dependent_files":"frontend/src/components/TabsView.vue","gmt_create":"2026-06-30T14:05:28.623089+08:00","gmt_modified":"2026-06-30T14:35:27.886573+08:00","raw_data":"WikiEncrypted:IBinykhefIyOgdnJDAiniV5kOUee0Xx6UXvrXwmKcQxxhEd32Oxf4/sXerzkozjdwLiRd78FiQyVCsTFnq2ZoJjCPvvphk/28Fyp6jERf6Sd62RGVBf+T/ddf1qyYMGlXTIT63FLUN8lGKH7HE33fo//zcEAInyKuCfcAnUKtGhK/6GYF5OQOK8iu3hTREMVLLGnL+nviHGzi/OieF9xzRK6Q7v1xKhCFPVw7G7pKGvEqIAXkIuI+gtduk+6amkK8DTLEeFc7kADsRYiiGxbnbCwDskX4qqKASfyrXfwkcH6erxtW03zOc0xXxRooa98xza6bb0a8AuGRLxpr39QpjXFHHSkoQOfBajABJjr8Dc2g4/Owp/iz3w2DmuHDD3n/B/iWYgr6mvt3RyCN7WugYmLcAHydpYFY03KrqgMoG6Z++VclV/+iLE/hhCWVXZwOvZExFa1/Nm3L/kQ+lvH/Ok4DwK2s2mjZIJfjmMEbvvPBDip57GwOAh/DEUOz8xDHSc/z3kHBhO8c2gfI+QxQTDodO1T3sDQNvDzNXnOsiGHEa8MFXwnRqOOJdjXpI/V0SeRqH+VF2QLUL0H0zkIRmUfKDToJpYdryAc+g8C/437bvmIINo0hk9dNxyk6OJDyil3WbGVKZty2trCmX+SSkvThP1sjhsXb3A4lCaln+NxaFM2pwSzOI2FrAI/3udagiuCFzkHXVAbL3kW/sByyca+mxh2x0XmZnIacn1rN3mzAbZQw0GomBv3D9BdLhokGDFcRbw0wBF8/CKZIQ2LXwJSliiHSUIxZBPFwOlfuDQLwPZwafFjFgx/iVezVLOrtprdilrMg1icikSwQ2uomd5k/4o4X2RhtHBwVEBnng/I2OnKpp7hx9jW6qnRgl73qL/weon9zfXHb5cIhwqTENIhOakxfLNkPuVZUK+yV5j8hhnf4TSFJur40kvfWrFH8ooRZjxZLVRGEqph6t49E53tpiLKAnc7PCkGqlVdBstHvud1Mi9WyXlP8CHOoDFinYsPol2IYws0Wz58mTUZesjH7Ovtl/r7VUGNRE+V5VOhW3H2ws00vNLRzrCQfstfuwZt7dDBHlJziXNvdgav+pfU3tAHaonl7W+6IJAygI7B1LZ7oTRxEV4fl7vl2G8suLJXZO7UsiezZ0gxqvkzvWkebI3amABggi6vI+xrlr0=","layer_level":2},{"id":"c8151791-2f8d-4e1e-8139-b0cf921ef002","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"登录页面","description":"login-page","prompt":"创建登录页面的详细文档。全面介绍用户身份验证的实现机制,包括登录表单设计、字段验证、提交处理和响应处理。详细说明JWT令牌的获取、存储和刷新机制,以及登录状态的持久化管理。记录登录页面的安全措施,包括密码加密传输、防暴力破解和会话管理。解释登录成功后的路由跳转、权限检查和用户信息初始化流程。提供登录页面的错误处理、用户体验优化和移动端适配的实现细节。","parent_id":"f00798b7-c49f-4260-b9c1-d1ee413b030a","order":1,"progress_status":"completed","dependent_files":"frontend/src/views/login/index.vue,frontend/src/api/auth.js,frontend/src/utils/auth.js","gmt_create":"2026-06-30T14:05:55.602587+08:00","gmt_modified":"2026-06-30T14:36:20.147272+08:00","raw_data":"WikiEncrypted:gVtFIob7WtU/DhLIhhPauHe+OU+v+Wmk6re9yMmllcXpiZ1pp7hfIQRNzw2djMi3kdxg1YOiyCoxBtvZze4FF6edaCgUjs2MTu+j6AA0Iy0cXORNHgcTdEiY29qq3iIiQbohHFi2yVwhY/RbmzBe7lwJOZe9tZJo+9aBXmZXSPQue+eGhVi8nfNwLBVZ8kr2w+IM0Le/0DzLcsNPWWHKW9gEnqOL9qJ2uRnJOeBfYIQm/RFJj6Arc9HTRD2rHKpLgeXT0/7uDlcrcVOeMQgI0MN4e5IsSMOS4i0V8i0QeaOnTMFe1e4ITmzsKBkTM3HbZ1l9Tud2Kc9vwBSxc71qfQSzN6PU2Lg3Aey6Hyu91q0cx/QlQLD9hjPLUl+/LeHHG0eHqrgL7KtiH7e32lisXRG1TYhCgOaOHWCL/heEb3WzujrCLosb3D7MsF/wENRWQGAQTgULpo9tmTHO5PQYppvv0bzI29cZtI53vlNiklobVJr7tvhTy/Ogd57XQ8bYMtnir8CxJnzDZcTSiyutWBKqV1X1lZOAyG+kC+aaRW/C7OYV4ek9b4dwf0XRsWvwr9GNgjIKC4IvOT+MYq8f+lbUllzOJdecNYg/6EvBmc3lESxNAVHxcKCYkpsfwV1pkQKTA8mk0s+6LysznP0NCo0/Wkd7s6eyrR5hNxhX1dI/D3SFOxC18N7Jb1XQTy2olb3oNn3HdurobkjeMAngSA7nxtsFpdVcdX3SqxyouWIMYKCNmLQjxKTUrx7OWx4ylXm4zZnlvaCsuj7hDBp/zdcCNQpVDN0sTMyI3rzj3Xnd9ULyRuTFS7dJzarbaHqSuN4ZVx3pRYSNWmOrrCKKAy2lG2ee8ojCkWtwcykJh9uC6Isdq+OzIY86g6fwtww3sF0b0tl7sLw81MfyakQfpqI09OHCiDHPtmwU1xVSJzriX6latrVG0pN2XqZ5MRWQy7nrzoCg8M6UHar+01QHp7FtE1F8IB7RTjIWNmVxfhgG5GBHk0+X39/mt+u9MCzS/DFWBVoXj2BXOJaos4NKYh8BDbTHC+HrYNlkD0wHs/yly/mlHyPrzMrv6n19GedMYDqebhvi0p2vS83tSPxoFf9tVJ3/0yZN3JuwAPQdGls=","layer_level":2},{"id":"70ba09ee-60a3-41f9-bdda-3cb904cb26de","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"系统架构","description":"architecture-design","prompt":"创建系统架构文档,描述高层设计和架构模式。详细说明前后端分离架构、MVC设计模式的应用、分层架构的实现。解释组件交互关系、数据流向和集成模式。文档化技术决策、权衡考虑和约束条件。包含基础设施需求、可扩展性考虑和部署拓扑。提供系统上下文图和组件分解图。解决横切关注点如安全性、监控和灾难恢复。记录技术栈、第三方依赖和版本兼容性。说明架构演进路线图和未来规划。","order":2,"progress_status":"completed","dependent_files":"backend/src/app.js,frontend/src/main.js,frontend/src/App.vue,backend/src/config/database.js,backend/src/config/redis.js","gmt_create":"2026-06-30T14:04:20.637577+08:00","gmt_modified":"2026-06-30T14:08:09.130141+08:00","raw_data":"WikiEncrypted:EPw1VhZSv2AMLpYzHbCG5QXmatSKh1iukhkKRz99kcWlEvnOwuqXvA4ZgQ6tN+ytovQp8yiqJicl84VZMQ0QFUpSuhdDKqqegwHVHT8m5Qe+hOlpJtwBJv6Gyfd5UzsnMpeYFRNXR8wbkeFBADir/QMuE5xA4w5GwYNyc4GbpnELQTPwTHgWWbWNxlgq3I5D9TCdlGhsRmZA6sOK//txRwki0pH+W5zMNr6nOdulmNq6y7jVc1uB2cnWdogeOMuaAeFHEES4nLloLAu6fZBcuZViwy6PppTyAmckkNr4DBsfUDF8AWA7Tc7/u9k2CUPbxxXn6EzWZLxfzJ8g2+MS5AGoHvdi1/l6Obw5LKcFw4fMrrziZ69qX8Y00Nb4OGTY7Ba9x8nTUpZR+ZQr8C2+b3ian2p5M/jX68T2veatBUXJdORnAdwyu+gsMTlFms2BIWpmJja/SPELEIIsiw02D+YpsgCBoWJwJytlJH/lNURd5C7p6eNTpZ8Ueot4a9kE3/6KkmeteZgfTGCtJVjgtLW3hCuAyhA5zfsNbKDGxNKwkAHaDmWR8R4jKKhAC0JCdk6GSYSbiXLYZG0yPMpDooJP8w3qo5IHgaintV0p4Y+wYwdLe0UJ74U9gCWnfTrlo2R93/rrWiZqe7Wwovt7bAEMnTmtbaWINVb+tXkN3kLfbyjbTHDxjIOc2AAOnFVRGIJpMt50+QEi5TYhA684wr1/vQOBZas07D/sUPjcvl/msZ4kjlgE+YwYMbKPSf9j302dqERpSJODBX9TN2I+B3pRvT8ziUFXF/xr6AsE4DXdyvCy/cCKvmIEp6gyrY78oSE+YwHefC0Cx0ltAwzDpm12AcAoA3YD0TwNDY8zH4cwXHu79zttcgTjZQaebPwhD8L8PbozbJ0lQWo8Tl5Onvbp8hOw6U57Z1U2W/ge1JupnAJt0tMnHek6EpKqkt0z/J2d4/Z5B1JNppZlK1nG+pnKNEfNY4h2m0ydoCRJCad5ccnFJYXhF9XP9vsx0RtqQoedeyfH7X8//4Iv3nVza2b7PZ184/TnYNqUmxItz3yos0ir0gAc+54SDzg0aJlzBs86JFQ9fSep6OJ44sUHkauivK0vBs8Wij0TSI8wUf43PFgjey+c54DZcvXNfsD1hh3PNHe0CRN/oMidSjGTPv6WOJIzp0KnAOn8GXb0kkhk7bpk8eYfe/8luyjlDyaA8QOxpZLfUtQWXtGv9+W4bxOtq8JG3gDpTI/PJ9UxhamLc3zHEgUg2FD0maAM+FBCVu51P66sXPu+fY+bIxalyw=="},{"id":"b47d7f83-5401-4a63-ade2-f087a2f61987","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"数据流设计","description":"data-flow-design","prompt":"创建数据流设计文档,详细说明系统中数据的流转过程和处理机制。解释从前端用户交互到后端数据持久化的完整数据路径。文档化API请求响应模式、数据验证流程和错误传播机制。说明缓存策略、数据同步和一致性保证方案。包含数据安全传输、加密存储和隐私保护措施。提供数据流监控、性能分析和故障排查指南。","parent_id":"70ba09ee-60a3-41f9-bdda-3cb904cb26de","order":2,"progress_status":"completed","dependent_files":"backend/src/models/index.js,frontend/src/api/auth.js,backend/src/services/measurementStorage.js","gmt_create":"2026-06-30T14:04:44.766251+08:00","gmt_modified":"2026-06-30T14:23:25.133463+08:00","raw_data":"WikiEncrypted:PGdHQOrMWxh6s6galmzx6wcoMdYGcfWJlB+MVcSBUNBNKtizTGYmn04CYqWTHq18bpIkVhxruGAwYTOr3jZ71eCHIhmHK7mDbe3H2F258BwPHLGOZJH4+7MFqH3W33roxV3A0mBu2oaH8IeI2N8avzXHaJJypIkSAx9hq3JuRVRCDIeKY3X4NKu/U9NptL74JQm6A7p7Li2mkZiBFKle+4PW/yzuWaITp6kplQfvEI/KpRhmnMRsG3jGv9iyUUFWAGQatGlcpMa3GH4QFw3sBvBajjhTtLtzUczf5Spz1O9WdUbgYOPCpDQ77+Bihsdcy9JfQp4lINGc9Qyfb5uB4DQlnqYiPlbr9a3dDGb/dU073dMLOTbly0p8fq9pG4W7N4v/Qh8PKhHj3MylSLdIGBJUnAVMl5qxvwzxjojm6CXeNAkwfimh+yqf454XGxOTZIAU9k2R2h8YV42MLqjA33Hx50dU7ywv/LpeoPO+YkHYLdJWVag51oeU0dV76GEofIYoyk36dpcxNf9tYMnzovlJz1d32pHkZiEtsRL0hfFpnpiBClN9Eb2M7eXf3h8covZFJVsAMVZ9mruy2FWZoE+Vy70yUrtgKhd+OG9WissVZfI/yqj0Yt2Wsrr1loH4IN2vTs2O8PRfGR+udMBY1TGPS+H1IyXIEa9Q8MGdAQ6PdO/m+9Mecxv3VDjgAPF0c6iiLgP6TWteu3Z/Q9X08FkR307C0YSiy1/W+edhxIveTqz9IG72msKc9KnHpMPW+i/DnIp8sMz0xDt1HKJeWnmP8rVDjGddCRuMdlYI1JTCfO4D+UnLhjf5mrmxD4Oto9HiMMdaM7vcYGorb90OikVE7+bXXS7QBK1eDyLElOaFNMH+fXRZY7dX05PCWloKC0wLxKcyNwDyheNdKuQfCQW/N9u3S+jQqInJWi+fLqqQk1kZ9a8UaYcnCudScV6lmAOswt3fe/4VQQn6BPnOBma0DHTIh046TrqUeM+vxlM=","layer_level":1},{"id":"94ec54d4-0aa0-4e58-8e63-5ad6ddb6edbe","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"型号管理API","description":"models-api","prompt":"为型号管理API创建详细的RESTful API文档。记录型号CRUD操作的HTTP方法、URL模式、请求/响应模式和数据验证规则。包含型号列表查询、型号详情获取、型号创建、更新和删除接口的详细说明。提供型号参数配置的数据结构和验证规则。文档化型号与OTA固件的一对多关联关系和级联操作。包含型号搜索、过滤和排序功能的实现指南。","parent_id":"7e9246a0-207e-47e8-bc26-b9d36ae6f2f8","order":2,"progress_status":"completed","dependent_files":"backend/src/routes/models.js,backend/src/validators/model.js,backend/src/models/Model.js","gmt_create":"2026-06-30T14:04:55.155975+08:00","gmt_modified":"2026-06-30T14:23:05.599822+08:00","raw_data":"WikiEncrypted:bcjkcAe0RFiHL2SPRK7/uu85puYZIX+C2ex4+pzpdOn7cc1yaAAdUNe+7jLI7NvrHR5bm/2WUlZK6ZPtqzIQ5h0MnUhqrqNYJO2n9dYhyGDiNiCLvP7MtADJJoOS9141vtPVyHqN4otRLlyIifGGezJM1vWbuvIjzT3531HuZlQza3qam5PnHzCRxHpdpyS3eiqsaeCSEchsiEDJbUFvYr1KBaXa2ps4E3o7ic8vIuM/9QG22EqqaHhAY0z6biOMmr75iziBVtp1hd5dj+3s51Ve4h3Usic4VsaoBiWRXOdsvNvW/MOlXNkPJEW16bJHBbDpRUxnRtDnllNoDKyIQFv8JCEStTRG2IvVh2idTbw+IeD4K5s/j01K2awd6rxr+fctkw7X7fZhmmSgSrjT83he4gEUIomoKQeB3aFuNkb48nK2QwsvwuSOJ0hxMjItOlEALvBSS67btN8JKIx21hTuR7Mz1TKqrl4m0CuW9B+7j5Q4tjVckzV2Oe3SJkk35c9cay8fZMJyaia1kh3EzZYXlT/w5nSoPQTG0DCVTBHYEp1lzav7p3SLsENxTA8VO7WAwZNLCodOsbVRaxbZiys///S7wbk4U9Qu9CqxOnRaQnmzEgCcrtOtfPyGA5rgUFlnp8GNwGIpn+jn5KCwd/vNLDqxqpWWTPrirGgxvSfXcm8dT8PbNoJMLR0L+rzQGlTayzJq7FQcQBa8Dap8Jl04FxuJy7DupYAQKWdOd2Rh5LNLGErdQjv/vyVLIMsYvWYF+PtkNdSiES22Kx++X2TJyE28/tWA2ovQ/TV0iT3e0NK2YEyPEHpyobJAZo7XI3ItEM+ng22yzxz558FmLg3RTcVuI4OQ3b35JTeQtNU3Pg46YkBj1UWCHavm2CJPKcqi62KcsnHNWMb42y3EGVmaUdnFNOqZz/0JQvTftxV+pjzGj6CdxyaAneGCOUzKjMtvJJIRvc65DB4bOt5s62Aobzi4SlR4LUmmDeZky54cwkMcwrpNdCrvvGWdLoq+","layer_level":1},{"id":"f00798b7-c49f-4260-b9c1-d1ee413b030a","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"页面组件","description":"page-components","prompt":"创建页面组件的详细文档,全面介绍各个功能页面的设计和实现。详细说明首页仪表板的数据展示、登录页面的身份验证、品牌管理页面的数据维护、型号管理页面的技术配置、OTA固件页面的版本控制、系统用户页面的权限管理、分享码日志页面的数据追踪等功能页面。记录每个页面的路由配置、数据获取方式、表单验证和用户交互流程。提供页面组件的状态管理、错误处理和加载状态的实现示例。解释页面间的导航关系和数据传递机制。","parent_id":"aa2583bf-2c6e-4792-b794-1563db547d08","order":2,"progress_status":"completed","dependent_files":"frontend/src/views/home/index.vue,frontend/src/views/login/index.vue,frontend/src/views/brand/index.vue,frontend/src/views/model/index.vue,frontend/src/views/ota/index.vue,frontend/src/views/system/users/index.vue,frontend/src/views/share-code/log.vue","gmt_create":"2026-06-30T14:05:00.060248+08:00","gmt_modified":"2026-06-30T14:24:27.142952+08:00","raw_data":"WikiEncrypted:olK3r0l78uP98ua79qDx7UWSmXb2E1v0sVKrAVzGYuIJHPAueEFJ7X5N2BSDrAuja5b8BTuELO8ubSNrSkgP/Z6rORQB8Z8doMfIZES0MEg18aBljdAOxOLzrDB089hOQpIseNeWKR8TXhStfC7+I83ha5LZRaJMoo3SuuqIzp3RkRQ7Do5v9wPCFg1iCbQYxnjwxm6zBRiSnHN3K9VmnziSCPrAqvYi0G80OkTVJZxFtRGsHzRduLx92WHhDfqsUqydlWWiPmv8K5I43pyYLMEgtXwCTysGp1UWrivekxLpUEkNAc506Rv8F3ZlL0VFyZUPT7bbz9ya0HADXvlAL2I0bLkJFkjPSUFTni2S4GtLHqH4cWROJC9y1Q9blmamNoYY1jJmJyU/NTSMC98Zqe86Efc6uTBDtHxQQX7u47icPzu9gG2J8JodxRFiQ+sVBNhbDm9gZUjKy+a9zXMBxeUGEi/CKi1o9KLgT7+q0gYw+vPb4NHgptzD95TSruRKHAi54z7oxcpJxKyvK170w75cV1bNR1nPVFvWJRzAVB/KKwlo3aLH5aXe4a27+tlLxjJ+pJyZxAv3WxfYqBc7yQQ1sROcMgpuAY+idES+OB+qeRzI2tSm39VjWsmEaq8xxLzlTEgOr7lyZnZ7jpasuYj/ZreCaq6541xuVsJoho8ADkSi8GB7Q/aWZl+UxNj0y4S/8MV8O68/sTSPREEN/QU6DMQsEYODNvz/U0qrzaIU+PBXXbfCJnxqAxYmvhELHwuy9/CUrSSaKC8ZciV+gtAlaV3Yvkfwx+855UxirdWJnEuk4lGX49tVCQG7VYE71gimwTKSsYviOMgmsyzZpUe+UN7UVNjGdW7ttWNYVtnaYua5cmOjtLBUGOrMwvlSeoxkJ5KRXf5Oa/COdfpa4d0fW0dVAtp1T0dTZWSbOk/lswh1YQUqgXj6DDw2qvpyIj2M3OzlFScFjbYizbh3JWD1vz9XxoQZ4C/G3nyi4PLVynnzu8hJrbBYcCb3Vsug5907YxaxmHr6zx+B2O+KaeiBw3vRa+EuQO4lJBH/diEjB1IKlCxZu8j3jcHMP+NLdTEKoAHodIpqhq9SOBjnvrWxzScLZDoU38ngtUQ2H7mSOif6BesJIxuGgMu8L/FRZr3+dLA6odcCvQLRAMXJAtmqmMPVEwJMQufl6WYvE4ZiIZ9sHvMxRAU7vS5cchHtzFte9/luCpsFv3X4xHw5hOmicjsJXCXIH2gXRoD32ZFbnorAo6WQ78LcrZU7jezn9PshnFoSmHH9FkYpd0Udn5J+uubjgRFNeF7inWmeH559LGe5OPLj1eZuQAcbWOy5WCMfC4GshplBJBu06rqv4nfGiMgtpER1L0lXIkxO06qqYWbcHRP4vaOSvprxHyh9iSL99YknTBb32b+dngtSCQ4Y+uxBZ2BOgLbu7KtS2wrf+611BYlSy3j9p7bpPZOxoZYQkvn4roAPOBpPa++5ezB6xMugHAWqPH2kkxrL+fc=","layer_level":1},{"id":"00a9d595-dc79-4ca4-8264-1c3f4a200a28","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"监控运维","description":"monitoring-operations","prompt":"创建监控运维文档,说明系统监控指标、日志管理和性能调优方法。包含Docker容器监控、服务健康检查、日志轮转配置和日志分析方法。提供性能监控指标定义、资源使用情况跟踪和异常告警设置。文档化服务重启、停止和重新部署的操作流程。包含备份策略、数据恢复方案和灾难恢复计划。提供运维脚本使用说明和自动化运维工具配置。","parent_id":"a3ddc4e4-116f-4781-ba9f-17c85c85396e","order":2,"progress_status":"completed","dependent_files":"backend/src/config/logger.js,backend/restart.sh,backend/stop.sh","gmt_create":"2026-06-30T14:05:12.313816+08:00","gmt_modified":"2026-06-30T14:25:08.613907+08:00","raw_data":"WikiEncrypted:HL3VqGjXq8A3aGeLxAjVPqmSWC8Q8z+JISjcpFTl3Rl0A9XVAWpupiaS7EM/Upd2tazZmC4eQGSkervuf1jbMC7w061CAmhFQqOU+czssHD24JzzCW/dzhPQh4OdveHL1lgCBXcR5/EbIuduJDuUmEwJx8aPYEp49Cq2bRpWZ2xXxQ9geEW929vQ0xrspQFu0M2MJkvVnbxR/C1ZA/D+1XfRFtbxiW0x31u8IH0d8nAhLDViHT9HOYnEHPGBjRiTyLhwVlOqUTDNsooW+CtVaXaVamj+Zsvm1Qzfw2XF6Iwkggg0GMA3YkqEB9DFwhzkplZ9FS408azxIS7d4fS0fFXf5diJya6pNlSuA8Iq6y7g4uAB2AiIZJvG94W2dwa7z5qIY979LwHB4DepnmSDztn7ZiE5nt52n+/HGNVea+cOJHee4MvbrnaM3omg7CWLoZG/dawr+mNCxykZ1vRzxrqBbNIvQRMJ+HpOfKUKEho5u+FPTs3ukPlfGiElxzlSrtsP1WAcQFFsET8OsCEk5x6IUkuh1g4u0mqPQxFDojZEl0/RjIoOigi3cHQ14MLApz44bkfadHqnpAuoznkln9hllqFREbHcGqNbIgHnQHRzz4Be2IM/7wIIJIiGbHebHoTXQV+aHxHOWNV8sCBn9aUZRBa8BvZ3UNFtcqEZD+wrKlf8XoKsc1fvfavpnUQ5viCSMfPMK7jwDTGIrqLhf6PL3ibkfDqDFVvIx/FNNdYFfkX/8Cxs8zF79FyeiYx98Yx3rItEZJit0mVmV0SQziiDqTyirtN07F7kZBFSUjWFi/WfFDBGMw+60Qn5WjMW9AipX0KdrVuf85oZIeT3udpIrRencXCwvchZRJU+NJpAqr/6K675EVQ7ybxH7XNUGXCYyCdxqP3nqDQkRqxHZxWsWginc3n4kvhE+zpfTUOp6m5HsO64XllZ+wohWPyjrqJSkEw26JhJIH+eAL29MliX6XBYjvlgT/Vl+dlQMn69VEgVXBBA3BXTV7KzWDUKEtEOMqP6WNKauLQTYqHt53vRnAZvBL+x4IQlA2rXWIk=","layer_level":1},{"id":"72a24a80-f221-49da-88a8-83c0f49f4e9d","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"型号模型","description":"model-model","prompt":"创建Model模型的详细文档,包括型号基本信息、技术规格、参数配置等字段定义。说明型号与品牌的关联关系和数据验证规则。文档化型号的完整生命周期管理,包括创建、更新、删除操作。提供型号数据结构示例和实际应用场景。解释型号模型在OTA升级和固件管理中的作用。","parent_id":"0bb34dac-0e1a-4cce-b41d-0194eda77f79","order":2,"progress_status":"completed","dependent_files":"backend/src/models/Model.js","gmt_create":"2026-06-30T14:05:22.624097+08:00","gmt_modified":"2026-06-30T14:24:50.789071+08:00","raw_data":"WikiEncrypted:o5cr6Bo4m333A3G+lRdTTxRACU8j2qQjGF3ZvWCBRJVg4ygFbHKJwjRB8JHwTktUDQXcECHhFbmE4gRs0t+1cAwN3sdIm9MktHpIRSSYNyl8It7CS8c7Kbko+KOWDiia/4OYzPp1+Ghybtt7VK0zyBQN81qZaR1/UW5X18q6Nd78fsI04PQzw6oOqgto+wxHPnrvKDggDY8SsvvZmncwmrzbsOP2VtJJcNhQMXg1u+soPYJPOBoZxHDWrDPjf0okt1vMMWF5R0WFQv+iUbzBJ8PErbw3ZK+lbHsFncbKAvyI5B3bNirWYLw+0rZkmGJFY1RqV8iitjYAx76OS6oCAYwl4rX538I0xqWuH1+rXHMZIE5YXahUiRCB/5a1f4dUO4hJj4DEeogkMGOhOjR9xYWKVFWpSaTMS5Yu2gt/9XRhRwTypJiHS8yXXsr18QOa+8Z3GlwtXVkca7zVxoDQBL+zxQqUvgAwmCfI/W4+30Diu6dAy8DD1t9TipBisUO/u/LCDNc8k7jxtqnktibaTrSNLQ5aCiRVMFO3S9qwK2gARGh/+/G4ja0DMwD92UpaDcbdghx95nsPmFLkYUNLQCPdANbyN9Em639BakRdlQ4BSEJ5hNgAv246ePTEWXdfRdqUyT0m3gSZWa5Mq32ZA7AH9Go029LdBNBnzy4uJ5sSSoCfIRhPWpD2NHqQrjZEv3tfeWG5i/sx676ZFqNKV2NW2upQSmBHwYVyYDDDoQLCcYEH4WmrHvFqb7nXYmv5zeJu9YvYEf1kdEAmrfV2yg==","layer_level":1},{"id":"93c96675-6099-4ed5-8f40-6a47b3050712","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"型号管理","description":"model-management","prompt":"为型号管理功能创建详细内容,深入解释型号CRUD操作、技术规格管理、测量数据存储的实现细节。包含来自实际代码库的具体示例,展示型号列表查询、详情查看、参数配置等功能。文档化型号验证器的配置选项、参数和返回值。解释与品牌模型的一对一关联、测量存储的使用场景。解决常见的型号管理问题如参数验证、数据一致性等。使内容对初学者易于理解,同时为有经验的开发者提供足够的技术深度。","parent_id":"08dd4c40-3fd3-476c-bcca-4c8687a8d863","order":2,"progress_status":"completed","dependent_files":"backend/src/routes/models.js,backend/src/validators/model.js,backend/src/models/Model.js,frontend/src/views/model/index.vue,backend/src/services/measurementStorage.js","gmt_create":"2026-06-30T14:05:25.897162+08:00","gmt_modified":"2026-06-30T14:26:44.046302+08:00","raw_data":"WikiEncrypted:o5cr6Bo4m333A3G+lRdTTxAyrO2oPW5FnBLfa9j0/NKm3J3s2Q3nFpNDceHQchIAJJY+Esm+kwKbYzPD7sJYvxwkqnm8241LNbU4VUDyMUdH7d6r03XfoF+3X6h0i/nYLsTYAwxBGsip7N4hLZ8pmSKbp3BnXji6UgQjF7/CgfgpNuHgBcS6Ttlr+r0mIQUQWfypIa7BMnm/b+kbCZ6KAxJE2lrnh/B54tDedeqh5AIcFVUgPEE1HfI+I2BKDbbUP6mr7xpRmRgRiKXp8Yu67KEi0BUQ+FZwLXrY1wGjxxfqx9SkDYvu86roCAryofG1eVaY0h4ewMz4SCGkf/SdMml462bXR/sV1zeIIVj1LYEgFOyzujC8mo24XFEyhSI/kPjejVr15vOSotQURQl0xlE2IFjLAFkHMaFQt2fOoF6BqtTfUng2T1ylI0/yJsicbJ9ClK7kiT5d07qaeITW47Lz+/vpzl4Z9SdPAz1tmpazg1IvId5r5npSaoHBeruslMdPktamlToVWKIFh8cao9LDql/Ac0A6n4bvp/Timq79TU8jI1ywBPc4iksAq/WvJllEhreDIo9ooiVo8TN9MarWoxp3sekBzpDLmM59ezqD5cSaL6NZ1GGoB2VInXcOD6FE5RVlRm8v95nL5c9dAh359XB0d2XQt0qL9kk2BTvzCvYluwMux4Q6uODwl4KOTA8wzsnduv4NBrs+0GVI0Lpe6Jzis4IhfbBlkw+qu4kA09IBnhW+VONArqmbMJdXC0ApM9coizPwpgT68V+vhd7yfAOKEdSVNdHU9vZq0CIyW6CNfpfS+jKHimw2Kzhaor0uLsTJi4cQQxXe7L7C4Yp0BcouZC/Ho+SuVmpF3lncKMdA8FsoA9mWEXfucDdM8kZXhQiOb5hDwuNrbj2WLnP6KdtzgeHwIDIaEItLgyf20R5Tczg4vLl/EpWHdC2xfURLEYcZQnSMyvicHCoWScmahBPG7V/Z7HAVdM7WVHJJ/Ie8TPLPx9jFbbPmFEhFLKlLIGFzlv+2FNk0dnPbSUE9JN1qXuzPPIZWqiKnaqMPNkBQF4ff2AZ8zr9rE1un4AAJyKw3CN/Bulad6OBAgA8tQ8OQauG4iPGQftBkGgmTrtpE4lAyxTxOlTgs6vAbglfBzjEp5MFc7o7BKyRcsp1dEZGj/ZhwMT0fyPYTjhoIfXV4r2YKMA23EhKXjVAsJmATLtBTrw5UDJ2Ge4PRxWFvsAT2G+8nsNh2NUvNG6TruybUm8Y5o8ifHmhHRgUDKUvjv5ksLTcv0TKEmwIWg8G37ovmuo0FAwOr1bvXK9utPucmZCGtPMxjLJPBmNpCDTAyc5AZONp3fMeWOU5cWG+DSiMlLU9llTtmGaseWrFc3JWp+lbkwzfLj4WmRElyxO8XHDw8f4TvpO/qeAqwig==","layer_level":1},{"id":"32dbace3-24e6-4a2d-9f87-83f2ec825b71","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"密码修改对话框","description":"change-password-dialog","prompt":"创建密码修改对话框的安全交互文档。详细说明密码强度验证规则,包括长度要求、字符类型和复杂度检查。解释表单验证流程,包括实时验证、错误提示和提交状态管理。记录密码修改的API调用流程,包括旧密码验证、新密码设置和错误处理机制。提供安全最佳实践,包括密码加密传输、防重放攻击和会话管理。包含用户体验优化,如密码可见性切换、自动完成和键盘导航支持。解释与认证系统的集成方式和权限验证机制。","parent_id":"eb78ed75-b786-4b43-ba43-58a5ea8a23a6","order":2,"progress_status":"completed","dependent_files":"frontend/src/components/ChangePasswordDialog.vue","gmt_create":"2026-06-30T14:05:28.623391+08:00","gmt_modified":"2026-06-30T14:36:50.062236+08:00","raw_data":"WikiEncrypted:MTGOV8yMPpR4TI1lgrJ8xG2DJaIBmdXRwPCl7oRCvXmCW21g6Vjoc2Fgt6nmmENvVQk6mZ+b48v5x7n1+0vaA7CHuGOaSKT1JpGPpRS/S04l+JJRC+zDXrImACBhSN+bAa09cBwSvWPWb3abEYtmKZTzRsib/uzjiZZSf1sPa82YEOr2t72Zm1OMMiqS8XA+qsZEzYiwLmiPLYFL+guO/3HaXe46Do0MMkKmltG7SdeWQpg0oka5yh6krSsT/W287f9JlYbkuaKE1DuvTnJQP+AnABLGN4UgZkrNvRu7pkJDAaUqmT59pSsjsT36NdrgsH/M1TPaMUk7joUnZc1IdIj085VEilPnS5PxTJEGHREbxVqxKR30C/5r6GnnzdXr/jrRhHs+UhBMOTdxtXGexuVx3aVzvCeBi3sRmGGNEzB7g7VsMJhc2HjCLYbeoIc2RP4XbivYLI4jkL908EQple4la3X3ggTZmmIRB8tzgdn2H/zDbaJ2ZCuI5cpzFamtwC2X6eLW2I90WLydSARo13ACzls4tu24apN25mQi0O/72z+V7bdoohJxqP+HlYsJ7MW2YFHCc18sKduLVLZsdqma8YQsXwV5EgYIhKAl3Mn0jCJvMHHA1q54m4MpedfXtyxUaV3Z/QbzKZiNGylMaUcTqeSxrwmB2Us4VdoHw89a2hUjp9fpAneq1lii4WlWygpjsZ/xGZPeEZNS2sLZLu2iV9btxVdJtjr14fDw8t817dq71safFgmrfgWmIwy4tBuQt+sUoYEHPBA/8RNuqyzxybwdhwFDxW8nUeyILFVyC0NFnS+jYQiYM4ffGs10mGWaO4Hw5gQWNFE0V2rXXTfx6xSF0eq/KXLoMuB8Pvey/AELPNiW8oveBlR903q+smsgrLd96oVR4kol5YN914XfzjM3kZBz/muAYVbsDBMKbEbczayPubwLm5zMFOuShES9MqJH/Jbzr9kcOugPx6sl3T8EMJGTuzlEnCi0Fc3Xukfm0wRx6j1iRYvbuyk51s+osNojspt1+OlIMIZDXtjf9XdL0wfoUql5ZRzDh3jNfbGv8VRxV6cKWIrlEiYphQre0T838CYjw4UVA3KOwWuvhCXU/fl0llYLZCCmfsyliuUVex+HGMwN4Djvkus4COjxzp4f2DByyquV0del9JCQZJ7XM1H0vW81c70BJuxUZjpLeZK0B46qiiAu1d+7","layer_level":2},{"id":"af7f747a-9be6-41c3-b091-4ee5901d8cc7","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"品牌管理页面","description":"brand-management","prompt":"创建品牌管理页面的详细文档。全面介绍品牌数据的增删改查功能实现,包括品牌列表展示、搜索过滤、分页处理和批量操作。详细说明品牌表单的验证规则、数据绑定和提交流程,以及图片上传和预览功能。记录品牌管理的权限控制、数据同步和缓存策略。解释品牌关联数据的处理方式、级联删除和数据完整性保证。提供品牌管理页面的性能优化、用户体验改进和错误处理的最佳实践。","parent_id":"f00798b7-c49f-4260-b9c1-d1ee413b030a","order":2,"progress_status":"completed","dependent_files":"frontend/src/views/brand/index.vue,frontend/src/api/brand.js","gmt_create":"2026-06-30T14:05:55.602772+08:00","gmt_modified":"2026-06-30T14:37:33.764923+08:00","raw_data":"WikiEncrypted:MpYke5d2PXdqtxI+drCrLid0YsRsuFzxrKFl1UH2EDILD+4NmryAJ+q2oYZ42eaiuwvs0ff3fJrcmeJphvg6shRr3y/1Z6QIqf0SdVu8YJToiL52I9yI/YQ9QmrCLTmSJK1Xn0gikJy/Ur1L6mQ4487hhJQ5ETrEyG74ClVaJFLbUcjoZnico/zSQru9m462u4XEGzLdVl3wBitgKCowMgtQp8iOkg6zYEOvq+vQd5ZMUpRGtPDuGd5LGl/sCyJboNraB5fpHqavDpi5YE7ArXMWdq74EgB0tuJXFndniw/KReaPlNuLs4cZb5MnMb/Zk/FpXzVwYB4qeCuD7TTz94PbPh5lQUUSV1nN7I2Nl7KrP7WCumRo51Bsp0EgDTJ6Lv1FBBouTAIk6SOJy7c7pHKI2bVjdbYhok8sqJoO1zP8R0kKkzlWVqR1eqx3c7vZlMT4qGOrIZltbmw3MS0LlfxkOwLOAeA1wiOuMsyxRh0rW05bslECO6N6C5nvuooj2pIx4UaPhTHmavcOt1kHG9pMEPh2Fb6VZOpYFKDG2zyCIfnU3fVAoD7n68yLyuJHSMnM+EsWqLHsaBCFBaVOUW1k8eMzltfozTQzFUlpASncW1hCZDkH9eAByXunfMzj3cRR5ij6yv+rlMx6Kc8OJtIHMXfY5Uug4RoC41bw1Q5ApjCy7rRFRC3MXbXBQKnufuVAvtk6ldQ64s34dZG6Fs7AuX3T1VWSDjReGTa3JKhARtr2k1xtruRq5ugRY0wrRTCkAiW7nE3grXMt4101VFK4QE1jqRxjkRPVCz8B5lL5TUqxK8KFltj2NZEC24YU36Zz74rntRYqZwbl/pRQk6uP5TGiH3pw7xActW1I6ySnBBrJsUONt01juQ4Tqr7+S/JJbR/vkryj65Kc00zCRsbkeH0dXxmKUKB59e915AlLc0aQRlXRhTlfKUr7/IMAd0n9HGSSaKcRr69ijbll3opHfyRpZF/uF0kmh03HjEredmCzrYx9fGQUTANJX2HqoONB4ms4Qm0j2am+UjAvbBHU++SpwlZBkP1aR9KuMN4uKpX4tUjL8tDJRGW7ZU7W","layer_level":2},{"id":"0bb34dac-0e1a-4cce-b41d-0194eda77f79","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"数据库设计","description":"database-schema","prompt":"创建全面的数据模型文档,详细说明实体关系、字段定义和数据类型。文档化主键/外键、索引和约束条件。解释数据验证规则和业务规则。包含数据库模式图和示例数据。文档化数据访问模式、缓存策略和性能考虑。指定数据生命周期、保留策略和归档规则。包含数据迁移路径和版本管理。解决数据安全、隐私要求和访问控制。详细说明Brand、Model、Ota、DashboardUser、ShareCodeLog等核心实体的设计理念和关系映射。","order":3,"progress_status":"completed","dependent_files":"backend/src/models/index.js,backend/src/models/Brand.js,backend/src/models/Model.js,backend/src/models/Ota.js,backend/src/models/DashboardUser.js,backend/src/models/ShareCodeLog.js","gmt_create":"2026-06-30T14:04:20.637975+08:00","gmt_modified":"2026-06-30T14:10:45.950286+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkKY19u2QVJ1rg3+MIy4jIV1T7LGtk0NNZTeyhAbQ+Kw6nKL19/84a+4Ky8TPQGUBAMv+/6dJGLjO+JY3ZnbVJix+JXTUe92A0fyeezyoI6zxn0BCAAx7GKkFkl72yB7LDQCZmuLQu265aq1IM9ARxC5hoRrKFrUfmial9RptFqCk8tXMOwlttvntP9DLL0Toiim2N8rxuTj3PZ3Sfi2OoqyGs9QmcT5sZkFv2MzdkRWxlRj+lggrQgwwCEi7PAKwJUu8fAL6D0HFdfQ/zGBjnr5HmJCLcdnczST1lLXFTpVqg2yA7ejV2oYI07mzPC8wxSIMZ3razM55hNHeD7TIu0h+AASYH/fMFx+BavsWSWVibAj0+GY3nVB1XGEdf8tKUxCt2tLkzmNC0ONaFrb1sH+u3/NACyBWp1XT485tAbYK8nfQIKYCsxMN3A/5DrVsuo/qHfopngN0j9+Ezecg/k9Tpmt1WNL6Q3XGKE+SH88eF9LePghhx2s0Cyeh8dtxlqwb3KvkFwy/T8YuSy4I5txe2e3KV4B+65RBbbnRPp9CU+X/MAW0EEPjUDUcpVTF1RrZp3uD2ugvmRoN4WNDuXqn+O+o02Vm53g6xy0ZAjX2BiUHbtGhP08k5nBf+6vc6Qw11ko3WnqZtpqJrpu2/pJm40NX/r3Gxcwc0lhxO3Q3EgDEQUNhM6kykwBc5roxz1NZn9gecFJ/vOtO/a9ekqeknKCjw+PYmE7nimMApPoaSzADSa7ZF41I10SWY3CWWqNFfZ8fs1kpjew0mcbEAcyHSEB6Lkt1zJclVbuowc/XC5n6bv4fqkK2/qfT4i/h1zQwLReqBxHagDNUFMA/qXsFwWWSsqOnBtOJV0SnMYqryPf8/tcUVYavxmkBnmXvABNj45AhkJX7xs9fc4CPoEHcxa3AyPkvXSy9v+LTqOitEoO4BOyQ+5o9KELKxVwWW6rA6wTuJK0VnDMTCO+sJoy15gNLfTN1KZORVVwPly7IRW7yO+mCCazqFfoXR477Kif4qeBnWPClMQFLaFJ+pEgvIJWYRUNfKcw4vc/EkyYYeA+Hd1FFr+O5DC0HXhUctk8lYt9MKtZH31RCBZFL95fvmg6+hlxpcnqGgPyYX3RhgESPLtQRADQH9MeBW9GkS7EJElfVnVsfTOAdmSos2AMVYslDP3x1z69CIk+639BSGgJNNyprE87PTRKUxY4eHCuVmALZYeo53/n0ryOP+Pm0RrLO2OoEdwDukBlzJqujjYntHapPf+BV9MDdrQJhuaaDPw+aEW6SkitZwp5cGi5x743nW5gBNH/3CtrEysupQXlFxxgAhYXnXVB7ruWNWK7EuH+8oIfmNMJ4080SwxT6REnUV87E1DChQd20pT7L"},{"id":"6cd96b12-bb94-4748-94a8-9ef9bf21aee0","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"集成模式","description":"integration-patterns","prompt":"创建集成模式文档,详细说明系统与外部服务和组件的集成策略。解释日志系统集成、文件上传服务和第三方API调用模式。文档化微服务间的通信协议、消息队列和事件驱动架构。说明缓存层集成、数据库连接池和资源管理策略。包含集成测试、监控告警和故障转移机制。提供集成点的配置管理、版本兼容性和升级策略。","parent_id":"70ba09ee-60a3-41f9-bdda-3cb904cb26de","order":3,"progress_status":"completed","dependent_files":"backend/src/config/logger.js,backend/src/services/curveClient.js,scripts/upload.sh","gmt_create":"2026-06-30T14:04:44.766596+08:00","gmt_modified":"2026-06-30T14:27:35.809057+08:00","raw_data":"WikiEncrypted:0j4RRfWJQdenLQLpT+DwLY9h0ctWLZwu8+2HoqcoTgcS/p644+VTtfXH7/YdC+18sAix7E/U+9fJqjMUaBv3jH3dXtuWslLxziQhE0mAM6KzXiDK+XHdsDX+pH5TGGreF1MypynKLMokPfyvDKXXvDb/K/htq5rDIK7wn4efMGrpYrHlk26HkWjVSHgXWa8mSvCzhzivdxiPFSzM+bFHKmAil3znEHtkwMtneqShT9/7CHzIwjUUkq4PtBv4zoyd87sLPzIHBxV584WgWr+H9HiHl/rgXIpGmmyxvut6aE6Mc2v5WhKYnBXayO803+sO3YHI6rRIuv/B17E6Q0lLwA+1x9YcSWrwXv0cmDijT/4f8uMl7RC7jSivX0mlv6dFtsZu7V/TF5vyEVrzfMMxsr4VQjceTo4zW+y7QufDdnvlGRr+S0DFgAlt8IpDnp49wmm2oomoTmIRf3OkwdMZEIGJxUmtNR0zcvCIdBh1KA4TQxHOKFZFOt0qaC9wAFXB2mUD/v6im0DNwlC9lxd0YSEHf0ZvG7AFzBTCSu0s4BrXMKjBlQmvbYHIztwKEe+eQLwn+egVBK3fWzCesFrLhQolEWHZge33dHIVt/jl/VAu8cuAjZerwX5ma+nYjVDSkJpDBLFeII5+/XG1QGVnFeHRw8iHrmbFjioXBvDGm3JGK35cJYmKDpCNswcTS4czKP4q6iapCga0KZHCA25UqbmW7fFBBJBnLXJSnap5wZL2/cXVzzrMHq0DwVin4TCmhatx25HzI6WSkier3jGKtRxCBPDJy1i6AaUNVTQNQmf5WXG/3+KTgWXojmRlUQcRPCxOO+jVRiuENVql2W2CFOHb4PNkmO2ybwjNkuLawNXMRTVnDlyGmKOj6/8+1qv7NkG2VU3x7q5QRh4EOn1Xx5OL8wK3ZIo6YDtZQMJ6fAt1a/Q1V1P+xtU7nXtJrP94p+lh+S8as938vJI0ks+Th12f9lM8x2O0q3crMtXpfTiY5KECIAVrHQBXIgP9mDzicaW90vw0PhTRJL3zNVMp1g==","layer_level":1},{"id":"41e8823b-fa7a-4a80-809d-cf21088bdba2","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"OTA固件API","description":"ota-api","prompt":"为OTA固件管理API创建完整的RESTful API文档。记录固件版本管理的HTTP方法、URL模式、请求/响应模式和文件上传处理。包含固件版本列表查询、固件详情获取、固件上传、更新和删除接口的详细说明。提供文件存储服务的配置和使用示例。文档化固件版本比较、强制更新策略和兼容性检查机制。包含固件下载、版本升级通知和错误处理的实现指南。","parent_id":"7e9246a0-207e-47e8-bc26-b9d36ae6f2f8","order":3,"progress_status":"completed","dependent_files":"backend/src/routes/ota.js,backend/src/validators/ota.js,backend/src/services/otaStorage.js","gmt_create":"2026-06-30T14:04:55.156101+08:00","gmt_modified":"2026-06-30T14:26:52.749254+08:00","raw_data":"WikiEncrypted:E/YLj/vjaxHA5L3+/DbcM/RrsyTj+zs2iY0gxO9VwkrctdJ181Ln0L3ooRB4LTne4VfMGKZQ6wlTj5N/X2kXcEukZ9Fut02Bs5XkjPHI+2fVI4RjZN0XzwIQaHtBgl8tPykchP+BDkn7x21JPxM4faRabHD4SQ8f5w6ZTPuozmHMS8B+EHb2T7KjC4DoC1RunkTRgUzQ00ZOlbAQ417Nl5iSzdfmRxQ4xxXxBHxg7QRNmHyXXkYgUat/sYwewRJ7vWadFGMWhqvlypgVFw2ueYVxtwoTgfWRW3xSbHeuJMn7RF/FWundtS5a3WwlcFzvmkpGXhXanm6EBmi/g1nlkr1I62+iPGsBnn/mYzTCs9N0yzg8pjYlkjWLhoYnWzFCcwNjWuOis5TkACe4F3Enn5/lHPaUacKkjRUmCsmyIV+YCfcShFNlf15kqHmAJzFnwpzDTA7n2GDkXwAcTZVUsDiGIo9HcXj42Nj+gmNBocNtwCrq1apaus8+xrRBA1usRtf2XK+beNgVY8HakOY03Q88Yn6RceXtZURlft7w094WixUJXMU2VtwSJLIC/MnKfNzse1s3D/QatR22ivu1UxhLoQwKTdXiOCyrSysBf5CmHP+PJmWexDMBbgw2op1BNhxGV8ENxuFPoq/jJ6AciXYGnhe0HLsQZu3DGhtOKX6bhA/ylWSAqpKAn9MxTvI3s8M/gDD7dKZnrafvi3SyEI58q46R6EEAayRfg7w8pX3mpdDt+O0t2eN96w52Fhh3VFn9jdhnWBnEVhm8E4C2cUIrmVa1SYlBUaC+2Fuf171p3d2LjtzevaIzC3KDVOtX8VCAJVzeLbpOrxd7bo2He6Tj1qG1ElYp329PfO5BbMt+FDxZXT89pJQbxxz6faNUwaVjAWzvfB2RGDuugJFagSKpW/HMZJWgQwWRdG1GJnqI2xu7KnVfTb+VK+QPbH+TOkLtxvZ34sq+Fe9xRTH6ffAgL3GVhFx17Byd1mIyFtAcAr8SadVmB18dr4jmgbxbP2EptnohyUwoYMfihQqTaA==","layer_level":1},{"id":"02f97459-8352-4fff-9216-8fcabb128d77","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"故障排除","description":"troubleshooting-faq","prompt":"创建故障排除和FAQ文档,收集和整理常见问题及其解决方案。包含前端页面空白、API请求失败、后端构建失败等典型问题的诊断步骤和修复方法。提供Docker相关问题、网络连接问题、数据库连接问题的排查指南。文档化日志分析方法、错误代码含义和调试技巧。包含性能问题诊断、内存泄漏检测和系统瓶颈分析。提供紧急情况下的快速恢复流程和回滚策略。","parent_id":"a3ddc4e4-116f-4781-ba9f-17c85c85396e","order":3,"progress_status":"completed","dependent_files":"DEPLOY.md,backend/src/config/logger.js","gmt_create":"2026-06-30T14:05:12.313976+08:00","gmt_modified":"2026-06-30T14:28:16.989136+08:00","raw_data":"WikiEncrypted:CaKOW8OSSWs4aEYk06Hu0tuZET5JxbVXxA/4vFailoRiq8l6SCRMdp2PbHfZPheZsOCEHlBpUkVcsULRxIpKUNxtyrd+LvcQjieQsOib7J2aYZb0jdq6DIsuIi9OwAqdeUo2sZ7WFYO0MjrDHQbEi0Fshph1GHL9lpk4FW6QGVpOX6LlZSlzzcg12dQ/7lfGLDNbZmC+kujhPKYB8y+Qg9DI/RBQ2izmG4m7XYoA9vhnY3btZQDjWIgS571TStZN+2zXE5D5wxyq1xW8sfVZ5aoLYIpOUkLMXsZXRuxThU9QEIsRrWxkIjNZ+DYovCzw6LfTUmjulPUu6g1fGUvjvcoT/wPnkWfZ3G6dkEdl2FNK4YiCrP5dIB4B3Ce5xXB04QOtueqxEA0ky3S10aN1HSYiNKLbR870IYZ5PIh7MQS6IVZ/xNU59dvYs1yYgWQzaTkW6h/wP9Qn9DJK6QJ5DVvqn7nn7UX9cmZTZdcT+EZvg3leLG3nUxl+rMg5moRbt3A+XJT1dR13DsgLjPbPKZ4+nDWJghDjUIQZ99/91AZrw0kPKbFba8YYIeLw3/nhshLooOLS8HHpn1RIwSI5C4biKcdxCPRgDq7LZn0X1aDqrw96+lKqgEm6PjrwBIpvhmWlr49hWd9rom2ohJAa1vkvUioWyGjsohChizidHzag+5Yf0ktjenGomBjPQc0ENMHZVtWmb0PwqR/Aj9IYfdLU9XmIH5NXLlNKtnDGFvqJOmCkUY2CjoQ1zLqXwcQc5CIXmeV/dew+CZh+lzcp19HqYDyuRJJeUuBxtHHC1E2fNZWXAgpNogDVGUEEGAFCS75/yAGV+eZWApwi7P8EYbT8bEi+lkDzWOMRG3R7uHZ012uwytQCgcEAx89CPTQRdvwzuHQCehVV5of8lW29MsJcCKWqYEUbKm9xGdGHMMcALiJh3Iijn108J7RBXVDNLIpQWWYIP3jAufqY8lz7wi06ibX8LgPQdR69b+ZWDEJ9b7RGOf9xsem9kNHlcHExDfpPlIUeYCTnQ+UAvW3BnA==","layer_level":1},{"id":"92ff3472-40b9-4adf-82b2-faf5a4d4b158","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"OTA固件模型","description":"ota-model","prompt":"创建Ota模型的详细文档,包括固件版本号、文件路径、强制更新标志、发布状态等关键字段。说明OTA升级的版本管理和发布策略。文档化固件文件的存储和访问机制。解释强制更新、可选更新等不同升级类型的实现方式。提供OTA升级流程的示例和错误处理机制。","parent_id":"0bb34dac-0e1a-4cce-b41d-0194eda77f79","order":3,"progress_status":"completed","dependent_files":"backend/src/models/Ota.js","gmt_create":"2026-06-30T14:05:22.6246+08:00","gmt_modified":"2026-06-30T14:28:22.050373+08:00","raw_data":"WikiEncrypted:M3g6T5zNL2wYgwI+v2g1k9TI04v1ugoF7zKt9xQvyuZqaGjJRFmBqKV8Wmwm/3SJ9Qv4rq4MrNZm9Mosti7r0obMj+m4wfrTq8co2+WGKMrYflsRbFhqYh3bwnRVAtBUG+oE0xiunIHCkbP/vnG9SBSl9YG0F5IlWVZTiJo4o240+pE9i40J+V8UwXtMXUWVIsQrA45pmgpTn3LfGupDTWIZ32ZD7WlYT4iTdOOe4azDCok4I1Yvh5kjTJYmR6+IggUUDFRxpFqxUyRHUCPAOM+CBB2O8JGPXOsn3M+0GhQ745lCytF2fTMIBwfB95CvsjNL+uIdYn68JkatRsH7lCOQBVWlNM3zJLvpllaYyA0NAYmiDZ9v48O25B6goFiZqSRDq+5ZFHPYhtmEGQvhr6vG3K6UKm1/8MM+Vhj2ys55M2serDCbPBieNvEsFp96ehe/Hg11TRDvaRr+b/cBcNmtD9NulFxM9jS5RmzGOpHtlF0RiurSmlao+eaveVPhKnTINLe0tTYSBtsYc4K2uriWVijJ8XYIvSE/5W9k7yhooovbDmKhWzS1eY1LMTR6uVCGXR6QPj60pNUVRKuuLQYtR5Kir4n5gJLT4VyoOPy5ZfSx2zGEKDHVGxrqdHKxP17z6R3L4wh/TNCj0rYBxmsjekn63MFHY9+xRbzKwuqYjsBjp7MogvotIrInX1awMAsoaZ56ODV1c6oNA+DtlKfy4CHExNfu0v5zbz2siffwiRcjzPcLH03x81xKluRNRjtmC7uzOo6qUnRwlYOHLg==","layer_level":1},{"id":"6dc54635-13f8-4ae3-b3a7-54c65dea2997","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"OTA固件管理","description":"ota-firmware-management","prompt":"为OTA固件管理功能创建详细内容,深入解释固件版本管理、文件上传下载、强制更新配置的实现细节。包含来自实际代码库的具体示例,展示固件版本列表、上传新版本、配置更新策略等功能。文档化OTA验证器的配置选项、参数和返回值。解释与型号模型的一对多关联、文件存储的使用场景。解决常见的OTA管理问题如版本冲突、文件完整性验证等。使内容对初学者易于理解,同时为有经验的开发者提供足够的技术深度。","parent_id":"08dd4c40-3fd3-476c-bcca-4c8687a8d863","order":3,"progress_status":"completed","dependent_files":"backend/src/routes/ota.js,backend/src/validators/ota.js,backend/src/models/Ota.js,frontend/src/views/ota/index.vue,backend/src/services/otaStorage.js","gmt_create":"2026-06-30T14:05:25.897556+08:00","gmt_modified":"2026-06-30T14:29:32.817835+08:00","raw_data":"WikiEncrypted:Ac7eY6kMrW78UEdNaO97Gm1o3tPOqyEc4tsJCJi4h0OJ31qvlpJ6jlqnfQUDd7dUN71F3lGtbIeqZ/k7p+RNJ3eDkB8Htc7ZohZ1af6XH8auv0DBKjzWHeJJ1dB/17+jTLSLPNoBQMsdYlKl7ALHNahBhYhb6mEol7H1VUqhd+2+4kyf/xVY8MOhgHYBX+kiZRs5m/JHGVv2Wl3OwcYB9AYqiRIfvjyxAAydjdbTUJt54pCyZEpKB3Vgb11jxHoLm+LG4gGNLC3YbMmSNC4RChmM8iQjc0kwuL5qCmSFOqJCGV6fOgH2YkXjffq86bA3BzSVzJ4eUzDNyjI7tCm6aSpbHglaJZtFXYdmHHnWL3O2f/KplGBiwcFikwUNSvY4Yh/NFAbxWaMpg/9rvfxxl7gwmisRIXz48UZGDJ73D64P+B0i+ufqRki0V8nDoHFaHBLDlQaxU22+1zK7rZKyMQ6x/kqUYmHQT4oRfIhmNYqv68oloXGH/qQuE9aGvKfgoxLOr4t6q3wcggD3sn5452mlt3vRv046pWHQiTgdh4vqRmzReqMJ9G9Wp0oBo353dk23eWNrh99kJ2FuYswwnXUXXHizB90jsDxQXzV/oLHuaQC8e2Ct1Qf1vLkWfGDSl7j8T3IEostDzLZKxjFmzW1HAtJ6RayrxQ+3mY+uCfuaMvgyFZtdfQoY0iigfE0hobUU7WNn4EaN88o+ulikPq5BgmSqn0AS+IyliI6qlkZdgBfCcBmOmka9FpuGFxJGUhcoEsmGUVVCiSxygCOGTmimP/O1eVKoa/DE4oRJdBKntaT2hQlib9q/LiJZwZSZ8Q0cBeEEGh9sNtFRjh2CAuUdFE/nl8XG+7U+wnpI8vjFvpMb0qJM+P5ZAMzZAEvp6HVxQ/UlywUZ1HbUoi8uXk/RlWeGDc8jkd9XSAxXzpQ4heVRrQ+N8mwkwr8b2m78e93x29Uu9XT1CQ3JBhMcQphGFs/742C+BRtHNQvnv7CWHSQAz8oMkDdlGKwHAmfEt/9g3ZMMwLbIcZMj3I5CdoCt6sLaVAJdiE8yz/eE4J6vrYYOqEGM6ntY+Z2CJGA5hWs8ijOJbFHUMZxyHjSygI39w2JW1gZ8LEbjJJ4nMZeO2DRY5F7rWMClSIi8WHv62I8IrXsKifCXD1NAl/IYsO+gD7aUYii8F9KaXjQTqZ7nOfAYly7rzQ26ATdLxL4NIbbtDbQTFCfhjl4mWPL1t+sX9zn23ePeIrS/+aKjotNl3yCa4T+ls+ThZ6zQXZ+VNyoqouVVyyg+jtfYuOd122Zzf47UALOvFza6NqYuFoq2EPKntvJ8VRNs8V2G6RPEfqXW4TUpugSF4an8ProwPFPAndjCOCXp/5vm/ycSGAZKQzvJocOUnaksP25pPO0ziagn4PzRzAQNxJ1CZReKPg==","layer_level":1},{"id":"748c8db9-9197-4c3b-ae1d-a6e51d058342","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"型号管理页面","description":"model-management","prompt":"创建型号管理页面的详细文档。全面介绍耳机型号的技术参数管理功能,包括型号列表、详细信息展示、参数配置和品牌关联。详细说明型号表单的数据结构、字段验证和复杂表单处理。记录型号与品牌的关联关系、级联数据管理和外键约束处理。解释型号参数的动态配置、数据格式验证和存储优化。提供型号管理页面的搜索过滤、排序功能和批量操作的实现方案。","parent_id":"f00798b7-c49f-4260-b9c1-d1ee413b030a","order":3,"progress_status":"completed","dependent_files":"frontend/src/views/model/index.vue,frontend/src/api/model.js","gmt_create":"2026-06-30T14:05:55.602966+08:00","gmt_modified":"2026-06-30T14:38:54.075872+08:00","raw_data":"WikiEncrypted:o5cr6Bo4m333A3G+lRdTTxAyrO2oPW5FnBLfa9j0/NKm3J3s2Q3nFpNDceHQchIA7qn1xYiWgntWVEgz+AljimoZFfM3LVrNE3kMQpRlr2skTY6uMKWNkql4Ag3cC0UTnPNlQvkWJwYOEmU10Jn89d7l77rUg8Nwxyqzn2zoYbPoCpCLqpS8KxOTLbtRa2QLL8voH5tzFwVkGGH+5a+agk+PV3DL5DT+IAFNnknZsll3MPRW5gOtSgjc/uNcO9KnUZqA7DVC9jnEKxUlUMLTAA6jEn4/+ouQ3rC1ZG9Myu9b6C5HXybXVNf8hq8XWA+JEhitA+WW+GMX7Wsdwuha6x2PffjCctS+KLLThiy9R5cyhREhzW5QP3dj3wPa2CF9RpqxSDa7oto2W4XCr9a4zPrHL6z0HaFwjqvDmtC8FrJRfW8EEDJA/ZHv9hFD2dZLrqt+gwCJljcCEMGoVFxUB9oAxAkSn9URKXY4E7NUB4cMSpv/FwDDziT6+nl5ES8Sgvp6nasY6IDTdCzghLBLPhde/EfQAM0So8dNb8+qG7cwAtM/HgHnwVd9Oze1BXt8OD/Vx/Ejew+SzBNnhiyKBp8cStpfDtRH8Q3aoAzcORSMIquP3z0lTGPcwCXthaosYwARfgY2rchDag8FYVyfX19M9NMXAIN6asqgomUyQJYWCU7FFB4R2EYF4IBwFnBqb242GVwsiJS+tyNEaDZr/y/BdFm4dhND8qqHybXRKA1yHa/1gQwU54HejhF7CdUEE6z0mAbJ+Jaxc9jQiG7MLTLoQHMOWW4DrqWrTvN2vSlFAn7ZGBMV7MGPwFJjEdNSd7Sflql7/BA9UoJr3HUjthBTJdSqLmF6lJMII5X1IyH6VzHYU93xrnUFqHrwuHymszjb/RAE/pC0kHfuCVSozcEUmusUI/7f2u14x9pbL2phEYOlWC6vHlp/7bhURZAnNr7HGk8hNmSqYv282J4g+i9F2R67Z+c/O85cA70RIWoL1dojsAOun+2qVy90nbbujCeG9BPmjEXI6DKaUC10VQ==","layer_level":2},{"id":"7e9246a0-207e-47e8-bc26-b9d36ae6f2f8","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"后端API文档","description":"backend-api","prompt":"为RESTful API创建完整的API文档。对于每个API端点,记录HTTP方法、URL模式、请求/响应模式和认证方法。包含认证系统API、品牌管理API、型号管理API、OTA固件API、用户管理API和分享码日志API的详细说明。提供协议特定示例、错误处理策略、安全考虑、速率限制和版本信息。文档化常见用例、客户端实现指南和性能优化技巧。包含API调用示例、参数说明和返回值格式。提供调试工具和监控方法。包含已弃用功能的迁移指南和向后兼容性说明。","order":4,"progress_status":"completed","dependent_files":"backend/src/routes/index.js,backend/src/routes/auth.js,backend/src/routes/brands.js,backend/src/routes/models.js,backend/src/routes/ota.js,backend/src/routes/users.js,backend/src/routes/shareCodeLogs.js","gmt_create":"2026-06-30T14:04:20.638264+08:00","gmt_modified":"2026-06-30T14:10:41.230618+08:00","raw_data":"WikiEncrypted:N3UbzwGjCC3xD6BrTM0cq1j04iiCHEqviOrAoLLUfGDtCxYctzqR2At1GtmCrwAkNRcHgUzXC/oU+pquLUAJyJG4QbY4uH8HShHwsSaBVDFWOUg5Yt9aKSem2W6e8/XsvBH+yP21CSU0WyXIunvAbMDWN2E2tdW6Wzy85z2Q/R5uQyWZgy2mpBkGdGtFA8tnpiTWGrll3lHHu51hSPp8fubLI6JOYB7Pcw5m81DnxNYl30Rt/HNSOzY2hn6YlxZZe6LYmbGYTHJFaQ+1mi9pLEDLwyAsd2NXDHCvcH5PyODvHQQiWusTZ2CJRbKqnQ29hlTXhH7vxfD6JA4CJLUr1IQO4O+sNaKIJM2yqvq9AtsVFlDiSbBbx0hHeupPxyxoyJrkbQ0YEnJYE8vcEVwUMFYBaA73AgBMVIgg7EIO6aoO1qtVQOCj8O6WC/bpRRG0VsKJKCG0cWJF2x1R0da2454d/mYk0E3sNIdLAYefmKn5znpcSVxPYUmIasm7sRHIngjfBQy3oRnj8iMwUo4jJVzUnK7+SXmAFMGJnkGsPff2MYZK1ziPEV2jaUxxsuLG+ZJVOkkPArausPuO+h0DzRYrD5rtNlQHj/M+VdBjK/fZjUHU1VYdsOAE1Owe/XiTW736BtdVxEahqzEy4KjCuHnbdYOecFSzuuJBu8+IlaAIS12uC5MPrhIyhcgnimmvjDGib+IlTsmikIQS8yj/M1+iuWVwDonBYGcgL/M4fnP9tsUdLa0iICT02XF5rsFc0k3qg8BcCd1qTG1LzSDn0OGKkrowiNxsp7if26Sm14qjk/kMrLV35NzhCrv6AE1YQGMD/Dw9P+dhQT+6f+GNG7vvKDnkf14/8gSVoiZsVqvGFSRbn+uscXceS5KZOfRVqzG+beWC5lBGoBu9NDft5xzAlWLF3xkgw3v7JBOOs53KoXfRuWlF4MjpF/L9Pi0K8Zdy4N1kOcHDKfzZTX19J7qHEHGfaKEhLP+EJzuy2zgGMtSYa9GSR8ku/SMuX6kyUbmmBRECqXb4ohzFJZVKEysRjplQzr9b6kLmHq3DOFdeYpQjJVFbehRbFgziE66TVVVeSbE7EuqOl3E7mVe0w7GgLODvHmOCTJFVMvcc3Ci5Fe9jWyomiNykvjfxv5+iLlDrwAGoXHYeu0dvl32TPy2yen6q+hOAxVtrIQh2efNFU7L9NmApvpdARKuQC9oYmvDtTYb3ifOXMRtdWJNUVz8DQCf8jo9QF/5mlamAcnhWOR/muhUCtnB+WZbireNw26SGG5yt5NZLrMJRjNxWgM/mQ/K47LoKgPimdSfBDApR6MRTXyI/wKP5Lxg+UYUGLapLKqHrfamPFlWtyAMER1HR+wzMaIU/5E66GbWmR2s9oQgJpWfELjIUlODtmHh8trWp1yzOUXksZH/Kooshmmse4XmZ9upGxeADqhi9sY2ReO9DJZcGZzy04R570EuL/pWLoXP7E9b406rBlQ+pGAtw/Lj+/nK1LkZFclvYsH4="},{"id":"b4054b83-f0cb-4b7e-9b3d-effc904a5686","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"用户管理API","description":"users-api","prompt":"为系统用户管理API创建详细的RESTful API文档。记录用户CRUD操作的HTTP方法、URL模式、请求/响应模式和权限控制机制。包含用户列表查询、用户详情获取、用户创建、更新和删除接口的详细说明。提供用户权限验证、角色管理和状态控制的实现指南。文档化用户密码重置、账户激活和权限分配的功能。包含批量用户操作和导入导出的实现示例。","parent_id":"7e9246a0-207e-47e8-bc26-b9d36ae6f2f8","order":4,"progress_status":"completed","dependent_files":"backend/src/routes/users.js,backend/src/models/DashboardUser.js,backend/src/services/userBootstrap.js","gmt_create":"2026-06-30T14:04:55.156387+08:00","gmt_modified":"2026-06-30T14:30:22.110712+08:00","raw_data":"WikiEncrypted:pOan1y/G3TzMEng6wi54Vc5wz1mwLua9oaQGTUm9cssalr5g1toTPIfYljFY5WaWYpIfvMfcOIPjVC5YrZe6T0ZeXnIn6qFUeNFA9VkQiOd+eP8PI9TknxwVIlnH8jIbIwUHH+P6UkkSNKkoEQ1Dgy4tQyZQ/BwhCdLqQABUIXBPU5meJ+X6w0MX1tiAe3bz/ckrWZcMva22ulspZnMMC1Wk3aVoZim2mC/orMFko2LdLZbXjVX8uNiFeB8UyaHHY0eGKN3MEHmSchfVJBXzLJAuJlUXl365b+bzfvnnzO1j6LwNYJMluGW/Bm8YNNXxv/nIBbzYwvWGjn/7eXoSDSP8c2D1QpN1Vtejf68ju2Xll64t71U4ToaQ6nUYw5uqsUgZDj9zsGfOjV52J2RWSeXnUQ7cUo+WLL/4N/5+3+KBlnUUuc5rvgZ/SdfIBzoYoyeDi+IU/K8j1B2CXPKNjSY7YV929LeSJGbcYxEdA7eH0c0zY7gNqyy/28oMx0Drkn/jYuCiMnKuQHF05L3581zmgFITJkAamXJV087BZCHex0iiYzrB2yS3QXrUCRMa5YfiO3mhv7u6C5A1bzqtY1b2pX30yhhKw71FwAuA172/tw63XUnOXjQ3M38mTt5hhxI+Z27ySXPk7jZs6OQosySBxga+SW59BdQWICrvO0/Jr8CqbIQ4usht8J3plxZpAOasjahz4ung4eJEzGEngpdQmNouctQvHBWOSXzbubhIGXplonmBfLNDPRk81plmJsV/vS9cNjIOPCmHJxQAXdEExTKuqASOCeD02Q7iDS3H8lUuIkNaF2mqaGwJXYsGwglkH2PtJIPpV7OLPmu7BT1QM3Vx/EK6EgWK4AkX8njheLaiGDxuJ1ZboRwInEgTcPY7PBX/x6jg4JI0TnG7jozxFYvNGlQR8xCJZ4SXSGF5mUM2MerylFlNh4SvGysXSDbMoo9tzYOFrwN7HD8ao7wuyTqK5EauHRjJiy7DQ1xhkAR+8xbFglSPmyzymu4KVhXnBy+ad2/UhT1vc3j5G2I+My/soGEHQUDr4q6/0Jk=","layer_level":1},{"id":"7a728623-5bd2-48eb-80d9-0f253bc74123","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"用户模型","description":"user-model","prompt":"创建DashboardUser模型的详细文档,包括用户名、密码哈希、角色权限、状态管理等字段定义。说明用户认证和授权机制的实现。文档化密码加密、JWT令牌管理和会话控制。解释超级管理员和普通用户的权限差异。提供用户管理的完整操作流程和安全考虑。","parent_id":"0bb34dac-0e1a-4cce-b41d-0194eda77f79","order":4,"progress_status":"completed","dependent_files":"backend/src/models/DashboardUser.js","gmt_create":"2026-06-30T14:05:22.624965+08:00","gmt_modified":"2026-06-30T14:30:58.467643+08:00","raw_data":"WikiEncrypted:piKNT601qxwAxFbFc+bbNzJoKRWjVA24DZgSuXUMKeYDI+Vpob6SIDpceCgG+l/ARXk22LQbqNrJSpxaw3lYcwfCs/ysy8OCLL5SJdUHJVrbRwBO9VCr7EM1ykzkC72RNFstSYAcnBFNhGMXw+lvldpEXlEqZE9WwOHqS96NXNWqbxrN5aNChpOr2Rclp1ATRSAz2nUS+IeeSx64uQOVL3aSyP9BxlRPnARz3KagI4h5xFbrFRmGOu+2fHjVv4mfGuyBi2m7BOAvsQRAReO4aLFcrb4Q4d/YoU05hkkDJCsF+uw1h2wLNYqLbKVPnnQ+vXJsPReY5PN1qLbXnK4SYp2DGFm9mcWTWJYYzE3plH87IhZQUyYfFFWSWzNA+oWacGaaij336n0rQ1emfUynmp20c5H12gaAdeJnKNtilwuveESCgjV+cpQeQFNPuSBymzN2EYIYg9aAesv2HK1H3PBo1BRPR8jsYXLLErgqgfSevZLVZGasl1cVMkdzhHd3jXywieDpMk0OiXw2TzVbfD/R59mDLQ/8RFFCxIY4Seg7wwXx+w9Nk4zHDmIGcT2ciMFdmomMHsiK9TT5/bl0pCM8PpQi8V/abMOyhNZqK2NO8mgxpys8XDLzN2vunY5DWeD1FwI9Do09XWWByBmvOhSAQnZp5IvO+Yc1FEzRSo4NHjxKOXDmFE6f4WRlmoKnttDNUMGRnE0MXXnbj33ztpBqhSkH2IHqEDWAYGb03f12CEM2q4RcTHO1fbB3ZAECoyGOC3pmIqTyin9JECRtDQ==","layer_level":1},{"id":"4d08f4ca-84f9-4f9c-8d9a-0983f78a7005","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"用户权限管理","description":"user-permission-management","prompt":"为用户权限管理功能创建详细内容,深入解释系统用户管理、权限分配、状态控制的实现细节。包含来自实际代码库的具体示例,展示用户列表管理、权限分配、用户状态控制等功能。文档化用户模型的配置选项、参数和返回值。解释超级管理员权限验证、用户引导初始化的使用场景。解决常见的权限管理问题如权限继承、状态同步等。使内容对初学者易于理解,同时为有经验的开发者提供足够的技术深度。","parent_id":"08dd4c40-3fd3-476c-bcca-4c8687a8d863","order":4,"progress_status":"completed","dependent_files":"backend/src/routes/users.js,backend/src/models/DashboardUser.js,backend/src/services/userBootstrap.js,frontend/src/views/system/users/index.vue","gmt_create":"2026-06-30T14:05:25.898001+08:00","gmt_modified":"2026-06-30T14:30:59.497744+08:00","raw_data":"WikiEncrypted:A2q6dsB1G5KaNgPAwP2ZpD/NNAqdMxLD500dNl3wstxRlsTO1UAX3pxjxaiFL3z0As1vXXbkbHu4vNUGPLAL5aQdvyDy/rpc97235R5NBNTdhWQsZBMstzLADK9pZc2FHGxl73wo/dEkASQtxoZ8c/HAPRkbzM7NeoD9dIYUm8IACZdB7XsWNk9eYgM1s+F7EamxXZeo9LRcbb/Y/YFKbxweyfSjWzXvXjvoJz8YZ3tGNPnZgwl5qgSc7Iqd/zEcwe9suFPVJyoHFnfJNUH/kaeWu8f/cHWsyJGasZNAaAwZBBs3yTizjbbGBQE3c3I9OoTx3e45q++1SKXw87o4e/05qmBvNeVZolDT9qztewrGf8fDjB1GqNNK4z78df0HVIaQFZhhhIFgSY47aR+4kMu5z6cAMD04SbGH/sGtdnmsA6r40hK+TgrjJ7YJEn5YDMV6ULhMS2AGgCAgoOoOaQAYdtp00rHL6DqxWP7Ayw/PrS1EGjonvJDwqy2YY4Wu06Ti9Sv/p3stKU6l6v600sAU/HYdfnDB8XXCaiCnr1aOXNMMzow2YRdFlIzdIuCnb20FmdM6scyabPlKwJ+Q0bqI1kP3t1AzsMWzBOu/hSduzKJtqJdugcKam/IQ9dK5dNWVHOLXVwDMONyaqpurXeP0qrftDRCgr7tfAe7T1F17lX6F8vAAFXSSGlwuyU3jsLTxYLSnIBOiSsa8RpX4QosLNkYfmULBdd3rabnHteIWLCeywBzzAZwJL9/1WtaxYZ6upIjMsLu6LvNaXz7d7tfg2XqQT5SckfhVnsfs7251aj+Xj1CmFmER0EUEKiMtS1VlphUcRYaWP3cwRjPgIItB7hTHnDqlj4l8pW6pQm9DFy4luQ83CJlsw/FEjW6lloK8XYhGAiGN0PR8dTYL0LzjOi7h9MbZ3uCqrW4Sus9kHxcVPN1Ubt6Pl3KOadbrS5pfUae8rpFVss4Dx4K00tLXLycXKmVHa5Ctl1Z5EhAHn6/G+a2oo9L9ymOTVHWuMrH7peksW83s4aykHZ+cX5kVMOf4+wmVmLlrnYNHZ/erqFhdMHJjX3WoWzfJ9JbFm6j3AL0Rr/+/gY0h2U5dGO/ioG+M11sSM0TnmIHFSvQ5BMA7LQKYm734RsnlDaNiR5GUtVCC4ZGa0Z8ijU4iHI2N9XnTa3R1UEQAqMMGE8eAg7Mhy+eieZyElZFJTkhPbbPE/T/rMkbtaGNqMan3KohQvlP8qX0Mtb4UOYnI8fd0RwahU3KVQYEEtwhMvf7LRH6zLOVlQjtT56TgSAPCkla0Co4fMEDZpLDuSPD972VDq5r4NnMIk0ZaPfNHWcTgD+pAIL7IDmO04KLJV0h9lEguVWpMWskakEkbQsD28FQ=","layer_level":1},{"id":"f23cd2ae-fcf4-445f-b8e9-b3382f277ae0","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"OTA固件管理页面","description":"ota-management","prompt":"创建OTA固件管理页面的详细文档。全面介绍固件版本管理功能,包括固件上传、版本控制、强制更新配置和发布状态管理。详细说明固件文件的上传流程、格式验证、大小限制和存储策略。记录OTA版本的兼容性检查、更新策略配置和用户通知机制。解释固件下载统计、版本历史和回滚功能的实现。提供OTA管理页面的进度监控、错误处理和用户体验优化方案。","parent_id":"f00798b7-c49f-4260-b9c1-d1ee413b030a","order":4,"progress_status":"completed","dependent_files":"frontend/src/views/ota/index.vue,frontend/src/api/ota.js","gmt_create":"2026-06-30T14:05:55.603184+08:00","gmt_modified":"2026-06-30T14:40:01.705802+08:00","raw_data":"WikiEncrypted:Bqe2/ExZLi+JPY3rrDJCu4ubXW3Wu2slfxMmRGTJQqMXOsjUivTF8gq55k/ZVOW+qZZHxg9zSQKIb8WiQsewLmXgIwuo3SupWcGnQ6xF8EUGFe30PQg5NQi4zZp00qKICGa403ukVqzU2XiwImrT/03199tKl57/lGzAsuxMqCbCvofh+Tw/qkW1OCtqga9ModmN5Dft+y3G669f4K2vjCerp4PVPrnXstFjtHtJiQ2CSbAfFwR35DhUHJZ2jHWPhH/Lk27TAymaQvjsi4Ogb8+GAGwfCWS1TSwC405U0aG7roHUnS8c7xt0X0krD6N3MlMpALYNuaTJ5vX7QfIFlvBA6+8wosL6w661TXbheeqMctU9cw4aU2yLEIYnEUInbkNj0zQqS+voyIOv95iDeSi1Ru5CRACjstDChsqpHkHriqoqCok0uSTARtI858U0DqqiosWFKEqQH6JjULYAYuO+zjO7CX/BnDUZlT81OoWgqviMBL6qIFaAB8ViFoU11gN4tjjrDXRDm+G8RyTyj0+ZoIWqqPSNvC9iD15/p5PHfW82PBYCNGj8eUu2HUrpdCbD7HWAz/YZ6LeSdPmCt7XPOAYLFJFdZL1W/3i4rRewmcEF9EKmMdF4CZI2g39O8kG2LylACAR0kxH4x/DPnqTF549pkQd9f1YBp35qFwRyAKR0JstDapveMFxUL1gV7hokfezFDXhFxs1EjNU03tYLxzC9fUzOBSZlMF+dK1kJOyiEOucLLB3fT8nlHTKH0vGle+AEfoTbysclDjRcd9NIQt9h4hvozLxVx35GmOx5+CLrGHAXVBMiGh2weSdXXbYknBYNChL0ADfk1cdItvBaGtR0qU6p6VDieA5ejNsyVua9xo0MY0eWgCMmwqbFXILJFNDq0nr1qnyfluFaYq/FyiLVNO9yN2GMFa82QITc/2xEBXJgv82OFOBZdqk20PqcmG5489ZEJJ+D8wDl9LtxqGFUka9lt5yTTFuu6QtnKMXHxEXoqAkmCAIwdj1Z","layer_level":2},{"id":"aa2583bf-2c6e-4792-b794-1563db547d08","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"前端组件","description":"frontend-components","prompt":"创建详细的UI组件文档,描述组件的视觉外观、行为和用户交互模式。记录props/属性、事件、插槽和自定义选项。包含使用示例和代码片段。提供响应式设计和无障碍访问合规性指南。记录组件状态、动画和过渡效果。包含样式自定义选项和主题支持。解决跨浏览器兼容性和性能优化。记录组件组合模式和与其他UI元素的集成。详细说明侧边栏Logo、标签页视图、布局组件和各个功能页面组件的设计和实现。","order":5,"progress_status":"completed","dependent_files":"frontend/src/components/SidebarLogo.vue,frontend/src/components/TabsView.vue,frontend/src/layout/index.vue,frontend/src/views/home/index.vue,frontend/src/views/login/index.vue,frontend/src/views/brand/index.vue,frontend/src/views/model/index.vue,frontend/src/views/ota/index.vue,frontend/src/views/system/users/index.vue,frontend/src/views/share-code/log.vue","gmt_create":"2026-06-30T14:04:20.638638+08:00","gmt_modified":"2026-06-30T14:11:17.430176+08:00","raw_data":"WikiEncrypted:rJ/rIw0gVau8jPGqKFBAsBQkxmdK9VEWEB6rlQ8V+1n3+8ehC1YI3uvDR9AKl6JkUxV+3U9CRiifnSLpQnnLCcDHafY0ujJqoG3mrKKLwcRefLIG97HCvpjj9xp4OJcObEYBvlH2pirjv5kfcD3coj+uej2+6It4OTgW2/0oKQer4Q7Jd3Xj3CROmzgzm1LeW9oHFyhqH7niUp8ounxYBAbQB6XdHwIaefNnUgBxo1FjRY5CB1LpLxEjRSkY9CBNS2Dfpl69BuhxVtiLlOBNsl22N9tUH0iPTEXk6TAQLd4Vb7QtJ8CCyPAtkpYnKU5QcfIO0Bcvp3MjVk52MPrRkpqhDzgLNq/58gj0RreavkJSyaecu5m5ingaM2ajsfwmWctlEFTbw7A7cpt15Z1RrVcJLo5T/4M0EFp2moBm1frk6hoO/SHg+ZmmZaSeN0CvbCvOu4VnNuh25cYO5dfRb5bD7aInrtFDRIEFVioUhtHbToaLmNbDxgYKC8jX0WO/lCgsNRyAqBMOVG9YywTcUyCao4ULaOYmT7bGHur1f7MHzT3Hcx7v+f5YDgtl7gIF3c37iMffA16fAhftd84iZA7DCWaR+x6ijSk6EVit7zN4bWFerdddsjBKgaNBH8WGTtsw4GmTfKcQ4lOr6kHuWwzvyJNbUAxVswCW7Kl7ofivxTaQwWtkjD8l6roq19h8uSRl7hqI2NFmLS/Mxuw5m9PNBlo3vptugDd5TAmLgLPkXnnPAHW5GBqe29HdNyEhU1vWTlQJu6TWrfVmeJrgLD7o4ciYSWBNzEJ0CMY19O60jiToNgpa2eBMrM6zgdhA9AdCdyk0sCCEGrNB18vMHFvtY96o/H+sVIVQsAsOoTx5sxOH0A2SJQX0NWZ270aO/huXZgV1r6rJV+iSPSpCAC4cXQ0EfI2bDDSzzWOSWezC2pwi8hfePFC64jC55cf1K03jW/4TH/MRixvP7PzBgDJ9WFTF5wLqV0IL6Rs/SDHnWnsbJ3+k2MGhSaMOncA89PGFNupdNbrk4x5luggzyTcc84zOUmn60WPhUrJZMAZfkkE4tKS1XRLUkHoxR/1WwL+VDZlaseEEFKZLWyNFBuGAscN09RzwicXS0WVW8CGZaAxZ8oMaydUMrZSqZMjVh7rFciLtXlbV2udQvIWE9dLuZVEGazVv+8BwkERKAXlPfl7VKo4Jpave0m0QS3JnRoK9RpQwsDXspauvY7XhvO4HvSwxXI1MFGjZBaqWEJCoEDzioluPgZ59mP+Zcf5AOw8qx+xLBLYVuJimxSmpplLeIcpRAD6GXIgXIpAQ0ZW629iB40UUtegO6jlZZMjEBNfW2h+7tArd5TmsR1GjBW04FHckaxFGn2sd8WOF1DbTN5g0lAkAKy/cGNjvEE1ZWKAKCGgv4IkAnme5huEBC2w9jqVDA6/cxoVNI1PqCHuZXtfmBqsygXhLj977b7lhgSMLm+ZyOl0F6tiopYxNMXhWjy1wCRXMPU7hHtqjeBok3Sb25XahZAuSPqzZ3MYjV4+PJHTejHONP9ch60/4uTU1ZmPSbYxlP3W91KjEOUHl4J79bUda7/K9+Fa84mMZvhiy1EOrsjAANGlQFE4+GAMHNdiLb69Zhc/CH0q2EaU="},{"id":"a6304333-66ad-4b0c-834f-a6a514069e3f","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"分享码日志API","description":"share-code-logs-api","prompt":"为分享码日志API创建完整的RESTful API文档。记录分享码使用记录查询的HTTP方法、URL模式、请求/响应模式和数据统计功能。包含日志列表查询、日志详情获取、日志筛选和统计分析接口的详细说明。提供时间范围查询、用户筛选和设备类型的过滤条件。文档化日志数据的存储格式、查询优化和大数据量处理方案。包含日志导出、报表生成和趋势分析的实现指南。","parent_id":"7e9246a0-207e-47e8-bc26-b9d36ae6f2f8","order":5,"progress_status":"completed","dependent_files":"backend/src/routes/shareCodeLogs.js,backend/src/models/ShareCodeLog.js","gmt_create":"2026-06-30T14:04:55.156497+08:00","gmt_modified":"2026-06-30T14:32:04.002947+08:00","raw_data":"WikiEncrypted:Vv0H16AayoBzPxX7ZlaOUGyGBdIMK4cf0QP9R1E4ivY78WzOdR/wvtMHeKsZOPO0asW2W/MvDKc2jNyZQ+LHngb47F7NF4YJSkCgZxByRVJgj10T4wWac0DckADW5AH88CZpVx4BBCtuW5KRlakkySQXJ0Vhm+mv0KwUrtthQTb+hq/5FeNYbS+kOr5euCqYQ6wwEmLbt10MSZp1WKWdfCf7X9KcgY2Io011J6+JnBsJnbbWDcnhkvMDFUdGk4GwKyEMiedTBkgb+39rNaRYcnJAsprHfzqiWCLqNoVAWgXLhDwpQo+Rj9Bju4u0x7yWdcWAVxIhjtS1HTrpnn7SF1fT+zQ9CwvBC1jdBr6zPv2EEfd9aDeDmF9fusxmxrz6O9t8G8p8DZU+16l6SzrO24RGp0ljE2hnue5SjY7K50OQ+9U35K/w+G/qOjEOt/Xm9AhDSALYcylw0X+3TFn0Dw17GvH6f/i4Rkt7qMYvBGYUby2TfoOMz8t6dGm1c9yflUtfXDVmMEwmVvMHLCRtuD5TyA5dQ/ZMntXUjliHSeS+A6CWlqs3JxRZ1RzMhrWSMPoLaP7KkI0jtFbNfasJ0Og/s0lvoq5QfTYeaB3SPAVOrEJCTUAk1WJBefCXaJLQJWM5BL41nZaNCLL5xFdD7vrcFofJoqf8rJdD76QntawCuPNY82NOq776fFPBqp80R5e0OAsB0SDbQ8ij7hs892TDLCAZD/uQpah7kDXRz3wpPMv5Fvw1Vx5dqBUU1Ft8O6oV36Svb9q7kzHN4uEsXSGmQqxigR/bDvMFj9wUMlwgWUOgeKVG3mvewBOFOO553ePEGez98IygIUSyEQH9u0EEnfXlX8Ctc1L/advVhMuLFfDBj9GSPmfqkcpEekoG2IhmUo15MFwKOmoR6YpBqaOeGU3M+ulhTXCdC/XVY/mQ+Tbruxlx4wSxvEVLqggywoVkMab3NqXnh2yrndnibentA5ka4iDfLNAT2NAPvzDWenmrtjYrZNRTiDoH4ZjahTBysR+ESqmTOnYPQcmU9ilGcP7Kf8y8xEndb3tWlBE=","layer_level":1},{"id":"e1d1f354-edc2-4c91-8d91-63d256dced21","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"分享码日志模型","description":"share-code-log-model","prompt":"创建ShareCodeLog模型的详细文档,包括分享码生成、使用记录、时间戳、用户信息等字段设计。说明分享码的生成算法和唯一性保证。文档化日志记录的完整流程和数据追踪机制。解释分享码的生命周期管理和过期策略。提供日志查询和统计分析的功能说明。","parent_id":"0bb34dac-0e1a-4cce-b41d-0194eda77f79","order":5,"progress_status":"completed","dependent_files":"backend/src/models/ShareCodeLog.js","gmt_create":"2026-06-30T14:05:22.625325+08:00","gmt_modified":"2026-06-30T14:32:46.410606+08:00","raw_data":"WikiEncrypted:Vv0H16AayoBzPxX7ZlaOUGlhYbZc4czqT8CWfnD/TT0eAt7tg/OAA6mgsocPcmsvG2PVtH5KfyjJ18P9rTMPxOEyjU1Gec605uXe0T2Yc9Mio8lwWTXlLiR9CHDgdmESC5j1t2aKR8fRd/OqASPFvLiR0grE99PCeoM7ob/y5BtcgxZWjzfCnfZNCwnjfkkosGhR45PqgoCyAC2Bvm0kMJCqP4lVPKf04wOTjSbr4eSl32wo9TqavhtHLUKJhoU1BhZbZ6uV7Gmzaq1mQWqsX71L36aDcvYYmopGt7DE2LJksbYCFrrNBgRhFv+N43uZbN5WL7wVhpvK8O4TVwd0FOwp+aZ7iAbUL7tgjCR8xtXJS5q57NTemsro4PJNWVbllR6P5VHcrSDBmtHsa6L1bXDOBei3zTdzkwRq37T3c3mujEECBZ/+Mz/9ujMM0yIhcbbPT/YGEGDAiU/BRLBAOMuV3WWC2MQhqRkoipHvCj8loLpu05az/NRT/cd/X5gfi0y7vJvNz1FLlIiiUEZfQro7D7k5gwTCP6/FBmDYgfPSOCN8xZdyb7gHNanf1+Cqj69JaEgpM8cJM/v7a47fURXAUR+wy+lsKH+YapUusdACBBPvzGrGTJGzBX9gZVLFdPZFt35TATN0bywZa5At1ySd8SIj2B3St+GopTloe/mXlC4w6a5oi4MsUi1aQNJUFynSnhmsvMHTFxp20vLRYRzH2gO2ReFyg+ErSFjXFKLsd7zrW/lMF0PFW90/eb7fGWQwoQT/GJ8bv50VRjO84z4xEz6cvM/y2o4LjMcbv2elQDtp6lJ6TC2Z9jG61tVu","layer_level":1},{"id":"c6207e0a-6059-40f8-a27d-367356363cbf","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"分享码日志管理","description":"share-code-log-management","prompt":"为分享码日志管理功能创建详细内容,深入解释分享码使用记录追踪、日志查询统计的实现细节。包含来自实际代码库的具体示例,展示日志列表查询、统计分析等功能。文档化分享码日志模型的配置选项、参数和返回值。解释日志记录的触发条件、查询过滤的使用场景。解决常见的日志管理问题如性能优化、数据清理等。使内容对初学者易于理解,同时为有经验的开发者提供足够的技术深度。","parent_id":"08dd4c40-3fd3-476c-bcca-4c8687a8d863","order":5,"progress_status":"completed","dependent_files":"backend/src/routes/shareCodeLogs.js,backend/src/models/ShareCodeLog.js,frontend/src/views/share-code/log.vue","gmt_create":"2026-06-30T14:05:25.898159+08:00","gmt_modified":"2026-06-30T14:33:14.029388+08:00","raw_data":"WikiEncrypted:Vv0H16AayoBzPxX7ZlaOULG3Baig8xCTbO2Ahhfn4705w5gj8ZRYmh46RDQMtCZDcT2ci8E8rsm8C/ie07Z01SjriTUMDr+8A42/BBZb/vivf/I1Ur0WP4FZh/48LAYVnwRQ0GNifiKYZ6r/iL/jguQ3fWxzUE0M/+R6HIELC8yJAbp7rcQIITL2AxtPIlU2pCBK/DCcqQD+ZybcLujwZWxLN3sOZv7I9hqca2d8RAp0ZUgYqh+tSW9DGD0yS9XHY1QrXl7hsXfIgSTvVprJ8RT5HOeKTMeBxcM288vxkz1ghLqaMTAik+OQN0BzR56crsJmaCilWkrOAX9R2xm8hLfGTGTwdwv0P6fYaXu6VwOHBRDHoIHfGrImp4IIqNl/qAQnBVEIF90ZUdARF/K4lVsKi5QByQzHd4xlLllAAhTWwK9S7HsZZ7T9HP6og6LjL0bhFAv7f4lX1gq2+EcdF4EC/sLc6w4D+SdCSFgVU0xdT56IyK2HCqk+Oa3x3yOT6iwe5gfFarTyyXSrSV3RDHIGxTQjw5ZLgrseB4w/uQSPLjoDkZLP8d/jXwMcNr4bqp8w9PxWyrUNViTfQB/UvF0DUtxSE2j6+nUvqGdl8Ix1VA62otvJvJFAikk9gVFtOHg+3qSjX3bq++/RQqakUc0NNE5MChQJYL/ZUX+MsmET7zMf7f8n+x8AWQTkhv433TAIPxZDEO7EVVshX752wWI5rwX+6dwESN5VijNJl/emYmtP7TslKL6O12aJ/nVMD0zmRsBl2iHy0RZkN9eLWDa/pklLR/Oqz4Pm2r2Dd1lh8gU5sHdMMVYjz/g/hdk4KVkvOKz7kAFP0wHLPPzNiplQ18EUANo91+uz1Y5VdeODz9dktzaFqMjD1octmfT4pX5YAT/zhIQc9MsKjbHTAueD6bqZxj3x0qiZ9gh05gFbrskmk5q2ogQ/HzE3E4lrM6f2tYMv8KzXjP7yKEHcMOBJpO9dQZd5i7it8/RiUAHSb7Vti8AKU8Vw+TOV55DcDhFbK5P9y2qvuxqUldoMQK17B9wEx2nncwPjOJP5wXEELVSCNDm9Z29WK5LjvNExjGy7E61ilKE+rLRV8OMZoA5ighPPFXalAtu7mLH9y8P8lhjNfSKFoGWqPz0GeSGHgYiYIJ2uAMIsp8PabUEf93feQ4gaKPupXFYXWZQFV+XZOLHbet0vp6KH5TBD2X2fQHG4FVe4IHTI4T5kGOpx+ZDv3WPjRDrHHl+CCVCwlkaovZU1dGMSoUsss8uXaSH63mv5fUu9tAM01OquwkJLbg==","layer_level":1},{"id":"ff078afb-bb04-4600-b51d-5af48a6a6f06","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"系统用户管理页面","description":"system-users","prompt":"创建系统用户管理页面的详细文档。全面介绍用户权限管理功能,包括用户列表展示、角色分配、权限控制和状态管理。详细说明用户的增删改查操作、密码重置和权限验证机制。记录用户角色的定义、权限矩阵和访问控制策略。解释用户登录日志、活动监控和安全审计功能。提供用户管理页面的批量操作、搜索过滤和数据导出的实现方案。","parent_id":"f00798b7-c49f-4260-b9c1-d1ee413b030a","order":5,"progress_status":"completed","dependent_files":"frontend/src/views/system/users/index.vue,frontend/src/api/user.js","gmt_create":"2026-06-30T14:05:55.603342+08:00","gmt_modified":"2026-06-30T14:39:03.429018+08:00","raw_data":"WikiEncrypted:gWB8HBj+8+/15rQhXgtMjBvJUaTQCtYwqrk1rWKWMXJ2ByhuPeDEe4J4aaVwd0GgkvyTIoPxLy0LzUPY8r27d/l3kXaZv/WIKLhXGNj4yqu/L9TGNhQd7PzwpK1IySbUybplyf6amFlUaZuCaMERjNdevMyzFYtpxg6ayafgmP7QZecNCYUUM3UDhFO+jU77Y3eONzUMc7vXH/eCT/Dc8cixl5LBJezboIymPfUKgJeIdetGX7IbiD8pL9tqiP3VV20ENuC361bvx5BHKgEgEz8r0ZRf+9GIa42eaVqFk9oS/OowsTalFP/WZp8IvsoQDgbxWtLfVja9CdwkAVvNFFoL92QsKVmMWwH4lC52GOFGmDtwWsWbsAQ7SC3FGCM9JqnaqrBk9L4OpLg7pbEGasp9n9YM4uL0i51ofbrskfLA7c5Ic8YWcfSq+YpP2Jfq2SfzWhkv6/69JsVm+ZeGECDYz/0BGLtJxuOHkE/X64/lMwm31m7RCbzrAT8s4fv70FYcrJ/e8ZTbBJJZ3nT1xOeu7NNolSYaUNRMKjj1f5XkM/bMio6syjKv3/sgDYeom2Z7KNC6qSiTtHSnUhR42TA/gepnPqFc654KQYnEbgtAxassS1rRCPSzZImnQue+Fm/xTdC7aQoeH7W9EGQhx9d/VKgE3DtmwgFfod4b9BL2E8Y+tjinaohB3LFSs0ywB30qKQeXZ0P5O00PShkYvMrnbrMgSYl9v1ikd2ca0x7UQMeS/9tanT+Nifwq7peDxs+vuwD8itOpOhe9lmEGyaunK3mOmMNU2qUP/IsFh7AG+0RI+ia2YOGLXRp/DAbZQOeiJotMpzzCetWsU2C7tkh4up/34yJu+PlIernbNrohRmq012Vk43bJsJuE/ozXHeWh2abw++XRn0rdJUXv4oHuxv/x/ou4BNRGgqxxLsK2sH44gu1qYF38dnjvjwos07VT3aeLuJQHfsrl3acgM+AniQul0Xzht3gFgcf88x++sScG3dMcqdCzRdr2YrFR","layer_level":2},{"id":"08dd4c40-3fd3-476c-bcca-4c8687a8d863","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"核心功能模块","description":"core-features","prompt":"为核心功能模块创建详细内容,深入解释实现细节、调用关系、接口、领域模型和使用模式。包含来自实际代码库的具体示例。文档化配置选项、参数和返回值。解释与其他组件的关系。解决常见问题及其解决方案。使内容对初学者易于理解,同时为有经验的开发者提供足够的技术深度。详细说明用户认证系统、品牌管理、型号管理、OTA固件管理、用户权限管理和分享码日志管理等核心功能的实现原理和使用方法。","order":6,"progress_status":"completed","dependent_files":"backend/src/middleware/auth.js,backend/src/services/userBootstrap.js,backend/src/validators/brand.js,backend/src/validators/model.js,backend/src/validators/ota.js,backend/src/utils/jwt.js,backend/src/utils/password.js","gmt_create":"2026-06-30T14:04:20.638906+08:00","gmt_modified":"2026-06-30T14:13:04.758812+08:00","raw_data":"WikiEncrypted:luoNp8LvFa7zGThvIT9T4gfD6KbzJyTAydbcRfVv0b71O04CYqWd+mhwOAKx5JsjRdElm0elYpXWbl1GcuBvfF0k/N/rYqIOGrNDyuFsYrr3vrPVHqwKfwIO8ii5FyJ9G2/CDKYKxfMvL5/eI5LLiI4dLJtQQ/EdXK+jGK6/3zTIZqdWj6UWzEW0mzY+65TLZKIQZsNDvuMmW4V+typo30j85XSOUpwUwj+/2P69d0p3/7KOTGhpxkQJpKwSS+Ou5oR7kyDTwjuBkFTeJYqyV4VYROOqBypa7dwYKe6Knr1LT+azHmTqixb1zXUPJQ6p979figgTjll32+b/GM+0T95z9Ds7J33B5KOsO0LOJ2cNLWiB+C528YQV0AHDkFf1mTE6bKTBGolo1fT4KVvufyT4JAn0aYmpJDe7tiniUE6tbKy3fen2CQn9ieLIOKFMeUBmDsDefoy1030Wnd5JzFcKgRtb87NRHcsiF5I+V+X2E2TlZUoJoBh2+PIAZYkxWcpXMD8Zpcfv17FAZo34dTydLS3wYxVC1tKcqor5qPs+woQNYAnvSCdaK3H0Hd9zIb2V13Yw4TRtaGR93SOAPzmuaylTjsqmJkhkPpPdL9RfBPI0NWsglIj0e7zkEcku4zGa6Hs0rFAUnvrmhf0fWTCe2cSQGsKT/x/At4Bbv1VXx/iJB5IG9L92sH9auvd3zPQzrXgvmZtIf5veeHTENNsFXlRqyHIlznBprPM1GVkTnIUQw7mmC+4Q/6jSl1Fv7xI6EG/1udBu/KeaPO67Hp8A1YNTf1ZspoQoSGsV4deaNlmJgBEN8AIyClPwel1TmRAOmWv+F7NI9qVhpN4XyaOA5Z3wLMRdd1TAxRzRXgbQWvO74iEk524UaIecqPr3oFFsE3HHj52svrYNQ4mHfD37w2y52cOqC/kcS+4oPBgecVMRLNK8zQe6TeyZZHyFxLrnPE3yPqPlVq908l/SlqwcGa2igXYfFHCVeaXwT6cPl+MscEbagyBiX4x1QnH/S6eX2dvxx0XY+44nhTYGW1tTBXetozbFeMqqAtV0XePJizOGsP3Lj2vFRJAHZ0N4cgNkiQhJ3KlyCoakiATQXJ/Ff/3M4frqDjOKNgpcGoZJVi8mS1gxHRzr2RdQoq+7KSMhmyGjVSrCbNN1TYIcbahutqBg+nR3vJ99qFoP53jpWwT8PrBP9LqIgRxcpoRf37MTX5j/d86fQw49ZGESGNenE5At8gBSjU2xnAIjZ+F33NfP8+Gz0UQ55JvwG8CjDXbe2noRsLFhkX2mEpZZURkUCUwgViZJht+EkhmoJGdb20nl7nQcUCRyeyH6+kS2RDlqP0MbMuZC3N8E2Cb6QEXiCy8cJTjg8OWpIOvFGO7W1FPwPDXlYJsM09Oo/VhFPx5ImU84OMMy2ku3T1pdBwi8FjXr1WPwwNmRTK4aqj4wrLgLiW5u7UXyrUQBDbS8o3sc5W2z0P8oFWcBaUYRtKmdryx/ogHWLuINkyfSUHAgkWx/keTw6SlEAPYdQGXbal3G4vO3aEnA4oCPhflkrg=="},{"id":"7272429b-c7fb-4bd8-9bd1-0093025d68b4","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"仪表板API","description":"dashboard-api","prompt":"为仪表板API创建详细的RESTful API文档。记录系统统计数据查询的HTTP方法、URL模式、请求/响应模式和数据聚合功能。包含品牌数量统计、型号分布情况、OTA更新状态和用户活跃度等指标的查询接口。提供数据聚合查询、时间序列分析和图表数据格式的实现指南。文档化缓存策略、性能优化和实时数据更新机制。包含自定义统计维度和数据导出功能的使用示例。","parent_id":"7e9246a0-207e-47e8-bc26-b9d36ae6f2f8","order":6,"progress_status":"completed","dependent_files":"backend/src/routes/dashboard.js","gmt_create":"2026-06-30T14:04:55.156596+08:00","gmt_modified":"2026-06-30T14:34:26.686007+08:00","raw_data":"WikiEncrypted:rL6JaAWnwczCsZW+uBgt2MaU2Sf5hn65RLINj/MhHZqs/HaL1M/vKzdpRke4FGDeaqlgIkX0Vsq6pgMDhS1PLtsNQBQbbup3R7hfDCWHR7czvQfTQrqQOghuXOCS5RshiZIhSV5UutgR3IhtdYwYuC1cGrxnqubBTLaiNlwSkSCBwNnKv5wnHnP/kSTtGschyyeMxsR0xgLm93y19LUJxzQ35x+o+JHgNt7L1clDn1f2Q/ndGER8N5G6D30Ca4ktQc/XzBkD73s6Y6ATaZU4fF9lJjkb7Xouo6VBeWM/AWnZDx7lOLLIfGHZwEixsbqfV3DPFQnQ5ouP8ITf9zPIvOLqXdiBK/eE4w9o+KnoarDckNX5GdOib9xHogvsjnppRV6HPQAkLwj79jVPVWMDFLLrOA7s4nnSkQ2unS6yWJOH41xes7IM36ZsyWIWGoF/ZfncMR2vb1d6KRd6jKE7U1rWCkhwBMRCtJWteXsXljdFTmntEBDtsnylR8gDBvxw3yX85/iRQE3fgUnx1bzG1Csq7hyeTpYLzKCJGgsoGmXQcuPQy3kvG53RM8x3PLEYSYlDCNn77yDInY9vGLH3AEhP8HfRR/ZpbZtEbTEenKBq3Lpp9JNVMypx8WTiGDNr7Uox6UrnQJn77vaDePXLU9RL2zqzb/ft4ghSWgWkGdxcVZuueg+R6jh5VidCS/2lM4RB6CLZx8B4fjDo0lPC5qjbZfKjw3oBNOXus90NdOMlDs9sK5B5bdAy+xI12Ku3TaX9pvbhun/UkHYHxw/izxoU5pEPmr5H4iOsOOjz723tH+aqaoOA3SfDR3E9vWvd1I8qWQrmf409xaZfuoDpga88y+qC2speLpfqP5XDm76K0m5hvzZI5F54vflZN5TXb6GFYN7/9nNbsPZ4oBgYfPy3GhtEe/eoit9VkApe/PFsqnJ/5EEdU8SvT1wjGsczIvpTY4dSR5q8YpQL6lNH2Q==","layer_level":1},{"id":"830433a7-7370-479c-aa05-c21ff47b059e","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"分享码日志页面","description":"share-code-log","prompt":"创建分享码日志页面的详细文档。全面介绍分享码使用记录的查询和分析功能,包括日志列表展示、时间筛选、用户搜索和统计分析。详细说明日志数据的格式化显示、分页加载和实时更新机制。记录分享码的生成规则、有效期管理和使用状态跟踪。解释日志查询的高级功能,包括条件筛选、数据导出和报表生成。提供分享码日志页面的性能优化、数据可视化和用户体验改进方案。","parent_id":"f00798b7-c49f-4260-b9c1-d1ee413b030a","order":6,"progress_status":"completed","dependent_files":"frontend/src/views/share-code/log.vue,frontend/src/api/shareCodeLog.js","gmt_create":"2026-06-30T14:05:55.603485+08:00","gmt_modified":"2026-06-30T14:40:47.220384+08:00","raw_data":"WikiEncrypted:Vv0H16AayoBzPxX7ZlaOUKj5ui7aJNjWR2KaITM+ncU6ladAgr1aX4O1zoYG4BKYxYSLSuvZ2LqnWBJ2QqydzLeyBat1iN9bTXVMqMkgeJtkcSlNEEEBOpwdoKxUJii0pBbTaTPljEgvGCJAdvtM6yaGorC0QzbypPecbpVh3DAjgPtWtUIfgnh/GYXu7HMfEOLjMMyQuJypBLnNAvdE2xXmS/QoHf10Z8jKuZHUEbhw3ognUK++ZjIED7IEMXsM2HoDIWWy2lZE539AcsA9nkIOFMRa34TlykOLVIWGhN+H7uZGRqff0XX8Lwt5hNvL1a/3ZPm/zZJtFJRzY1PmfxyaUjEbF7KQMiGdKNAX1ycQenLZ/ynZX1xiEakxuX4S5qxospfzPGG27gDX8bJKL+3QoqYMxU/6AdnQ3DIox9pP4fapR3p3RYlpJRtSqqFEeeU0AUWmUNHPyBCPgHccE+XNZpISolk2Hln2oVX4yMeI9psNaMz1DpxYj4xlswa92pmvtFEAcryIpMdytbdeAPC2p6O1fyHRkNXdSzu513mdblf+dxvTQs9AEKnzH5IISdpT3oqa0TxsQIonzIXjfyPDQ23xC74ZjI+olJBdCnklVb77alqfTKijeVHqhz8E/oBRslPIuRrBTmbr4MUfnnGv4ABxmqo/MJdG1aSWK+VLXi2S9P5Yi5E/Wwu8H8cYl86z0TdwDM5Hl0l+X0abPVyDJOcHyVvz80tpUlxcC6G9Xz4/vjCq0xfqYtDV4NM2ClDyMsuxq67I9S6UOCBAZbHH5N3WOzgPrZNyfbeFUpydMKmMOgBh5GjkQ3Pz2D+83z+wBDSk8PV0mzk0Re6AqwtuTJtZLBFtavN7E0GJp1Bq+B9fOhkW73CxJvwqIx6freEb2JUkKP8CUVULlLyar8uKaRA6QH9uFiT1SJZkH1fc9CMBH3H/RzAhtB21FP4KFAVk/ha2CsflO9bdZVM3OkChSKQ3qPNzib6+R66ZevkbT7skK19HcLJO3Rr1NOP9tTy0Hy9THr5msllCLl7NDMQi1yiK5GSaztoHJr7ZWuX4FV7iAHww5fyqzLeaVFXK","layer_level":2},{"id":"a3ddc4e4-116f-4781-ba9f-17c85c85396e","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"部署与运维","description":"deployment-operations","prompt":"创建部署与运维文档,详细说明Docker容器化部署、环境配置和生产部署流程。包含容器编排配置、服务依赖关系和网络设置。提供部署脚本的使用说明和自动化部署流程。文档化环境变量配置、数据库连接设置和缓存配置。包含监控指标、日志管理和性能调优建议。提供故障排除指南、备份恢复策略和灾难恢复计划。说明CI/CD流程、版本发布和回滚策略。包含安全配置、防火墙设置和访问控制。","order":7,"progress_status":"completed","dependent_files":"backend/Dockerfile,frontend/Dockerfile,scripts/upload.sh,backend/restart.sh,backend/stop.sh,DEPLOY.md","gmt_create":"2026-06-30T14:04:20.639263+08:00","gmt_modified":"2026-06-30T14:12:37.808551+08:00","raw_data":"WikiEncrypted:0IKfLNOWe9mZfG1jVts3w2XbjO+yyEmY3ONOjrL5GjA8+3c0QEcD9OcCVHu+1BW/N5NkoQV86wegqQ9ShX8iSQ2xYIaslcmoc/Kv5OAnUwWV3nuAw37SIDSnlfEVjxgdWIfKDpMe9ANqqSg43yyyS0j6a1ZNPv/lWSKJTBIXQlfQxEh97cKf/j/LT7ms4fDbTvmHrdkW/jEQefQD7MAtQ00jFlMbUkoCaGNftGOahpB8DxiKjvXF2XHkIBSB+ljy8IAN480duozYW3EHkn9BG5DRSK26AvZUAJe48qfnGYdQfTAGEglE/1Hn6EV/Nm/Lb8UvgmdnuBaKTUiZRNooEwAeDN9FVwpQ7worjnl8Wzo8Ngbl2o07Zf9fN+KcjkIURxsPmfGu9sD6V9l1RLWZ6dtbz4WoDiQPm5pDkI0VaVo0KZrYJVqQnyYHiGLgYtwhQ7nukY+LoRhX7Hvp89YdV9IhrLTE1jsDAeCRw579FnnAzgvBLN6zixDwRCyr3c/VerMICukg17xUZBvIhgXPW2oB8aKCvEWd1DoVOOwTTeSRGaBc3YL768bwg/fgb5nMcpkKKEG8oFTiD0WQgV1WrAWmdgqLUic6njl7DH/nPwtU4kvstO6ylEWrBJh8WjjnuFdwsNYNFOXm0yLRUDPlwltGbjmmrB5+TUJes5jh7PSvyD1XFtM0grPtQpYdIM5GZtNYa172rLsqEbW9ZLMORo0XYf0lxg0pNCmBI7/OgcsUnosbnfqoLleFwHsBwIR6IWox1cSj2a8ZP2DdIF1EkS1STU4kcntPhJg/MU6IAHZByl9NaNnPAT9fbjHNYrjgvAocunW1h/GGjsi8yIsr/MYBKQRMHt0Ebx6FyjCoTdVyEZBmj1Ln8n53VqlQUaTLOTlY/+PLW72ayeVV1dbw6nODIElixkXST6BfiyyzGX4NcPjHvrMEj0x7iuPn5XqyNW9cCnIYaLK1POgQXVHvC78pjRvPdQcV2ofQwNXhiUd3OqejjZKYOiXsozbPI2ZmCy/R1XmqKiDotFyd9coZZagRFDm+CP5hAAYjGnqmUIWlnx031QhinbQ19YgTQyPe91UfMnBMYE4piy3j0ar6hKLZHqUrpDdEZc5IhsPiIpVEuUWChMcy/y5JR+jvcKVuXqaFmjA9MVUhyp8t4AslTb+B3O4g1WLlMBmUN1HYwc9S1io68uObIzwvIOg0IF1WiR4jj+F6m4Pqw+Zd+Bvs8HEJ0br7bBtr39YNX1ya0Us="},{"id":"0545bd33-f65c-4e1f-b2cb-04bea825925d","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"开发指南","description":"development-guide","prompt":"创建开发指南,提供代码规范、开发流程和测试策略。包含项目结构说明、命名约定和编码标准。文档化开发环境配置、调试技巧和性能优化方法。提供Git工作流程、分支策略和代码审查指南。包含单元测试、集成测试和端到端测试的实施方法。说明依赖管理、版本控制和发布流程。提供常见开发问题的解决方案和最佳实践。包含团队协作规范和文档维护指南。","order":8,"progress_status":"completed","dependent_files":"frontend/vite.config.js,backend/src/config/env.js,backend/src/config/loadEnv.js,.gitignore,frontend/package.json,backend/package.json","gmt_create":"2026-06-30T14:04:20.639515+08:00","gmt_modified":"2026-06-30T14:13:05.375027+08:00","raw_data":"WikiEncrypted:F3QgleoEfoy16cQggYe9C/ucQxiwh0okVA48AmODs5RKNS8ZgNngqmnHSFcG/1UaJxx+3dUn+EkMTpYUsOg40oH68Nx1IqebKqiC8fCVx8Z5dT3AgUInNoQcVloeb4yQhs1Oufr9wTZo7fZfd2EizXXbLOV05/YLO/Bja3sQV4rbFZH21TOR2bzMC4+Bvh1azFozPC/ma5QkwfbGmawutVaO402XGO+5xnrsGCsVAQr2M8O409R1wh77/5lzca6ZD0OFo1iagqoMSEXyVx6XsW38aoy3TPa93+p8MSYGEXZKUGuo0U8H/GetcXMJ21wi60fPOQhiVg9ePRXxG8wnT9Q0YxxUIb7JWiGkDgtE0n5qcCo7xcA3FzYOZ2CH4OR+2LjRjmTWUU2SbXJ9jXKWnXP8HREN4oERnOXLRcGVAA7zHN3BIkCz7pscIxGQ+sNh+xZdhrgSBP4BqoZEnRQQlyDrqA29kJpJXZs60se4zqy3SRe8xpB8DiB6puJqsECj+osTyJFPENV14Gb/ixpNzHho1UY3Ohpt+Eabp6RG572PwSRkBaegUf5Y5MXeueFRfD4XghD+p9yS8u6aohyV378+hS80kvZnTWd2eiveVL7Q90v5DiOSQLApGbIV2G44IxEw2uIKsuWvffHT8JHO2RxJkitMMfOC+OSLMwph76bCPS+0hYM8kFgEl4xFyTGggt/JE3njsBxW49xeYZfnUYUDndPRxIWDFVT2WqUKup7aZQ4gUFcycaEH97G5lD1JgGQVGN5jGL2XjksL8EL2WrkZkj7Mkwlo03MFQYETI/wPTEqUdcsgFdXOCGMw34z5Pz2VlnNXn3faJcb/EmO700V9FtLl4sedrhQFfq8oyBIwwycQNtQGBdx2pfCJhjeLMKSeQ+BYoUxddVIpPoBdo0d4G4rrlK2BREXPCuyeH4dmB3rCPyTcWheDZtVLdid/MJwCujHV9jJVj3W5UTW5+pwkcBenKNyb/A0yYUqFDaylhA4Ff6dgxMUqeZiNfxGXORFKuNgQwd/4941XXqA/U0pX1uyPm8Z+ydGBmtScMw2cLtmWLFtUYA04OsqUWVaaX63Dvyr0OuohK8gSIX2m89KrHPV5hcCaH32WycKCi3zgSG+RfFLX9+I+LG0YQ2dcyRU5VVK4h1mkv4MRIqphyEjifJBweXHgmS8nP8kbRuPQfeM++y+1VPvUYwiTlHK48YW/H0Q/FLkXfQA6l3gVZA2jHJ5zPTJcbfY+3fRJr2g="}],"wiki_items":[{"catalog_id":"de69fb0c-330e-4831-813d-94fb958688da","title":"快速开始","description":"getting-started","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"817d80e4-81ba-4f8a-b0e2-85e99d8a73ef","gmt_create":"2026-06-30T14:07:37.609842+08:00","gmt_modified":"2026-06-30T14:07:37.615532+08:00"},{"catalog_id":"70ba09ee-60a3-41f9-bdda-3cb904cb26de","title":"系统架构","description":"architecture-design","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"2b5fd78d-2407-4ccc-8807-9bb05c0a687e","gmt_create":"2026-06-30T14:08:09.125669+08:00","gmt_modified":"2026-06-30T14:08:09.130252+08:00"},{"catalog_id":"dd61923f-65f8-4e98-85f4-0e0a0a649a27","title":"项目概述","description":"project-overview","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"190d3cad-a28e-4cf2-a8c7-64d953415cca","gmt_create":"2026-06-30T14:09:11.170718+08:00","gmt_modified":"2026-06-30T14:09:11.17433+08:00"},{"catalog_id":"7e9246a0-207e-47e8-bc26-b9d36ae6f2f8","title":"后端API文档","description":"backend-api","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"1f4b6f57-25c5-444e-a943-d162d896dc21","gmt_create":"2026-06-30T14:10:41.226897+08:00","gmt_modified":"2026-06-30T14:10:41.230722+08:00"},{"catalog_id":"0bb34dac-0e1a-4cce-b41d-0194eda77f79","title":"数据库设计","description":"database-schema","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"4553d9a4-e0e6-4bc3-b285-ecc6df9dc822","gmt_create":"2026-06-30T14:10:45.945099+08:00","gmt_modified":"2026-06-30T14:10:45.95039+08:00"},{"catalog_id":"aa2583bf-2c6e-4792-b794-1563db547d08","title":"前端组件","description":"frontend-components","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"ed153077-3827-4586-8838-812707189c14","gmt_create":"2026-06-30T14:11:17.426266+08:00","gmt_modified":"2026-06-30T14:11:17.430273+08:00"},{"catalog_id":"a3ddc4e4-116f-4781-ba9f-17c85c85396e","title":"部署与运维","description":"deployment-operations","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"c45b2f5f-49f8-4c8d-b489-44b4c6800e99","gmt_create":"2026-06-30T14:12:37.804986+08:00","gmt_modified":"2026-06-30T14:12:37.808728+08:00"},{"catalog_id":"08dd4c40-3fd3-476c-bcca-4c8687a8d863","title":"核心功能模块","description":"core-features","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"d4cb0c3c-97e9-449f-8918-f1c01e7e3561","gmt_create":"2026-06-30T14:13:04.754131+08:00","gmt_modified":"2026-06-30T14:13:04.758965+08:00"},{"catalog_id":"0545bd33-f65c-4e1f-b2cb-04bea825925d","title":"开发指南","description":"development-guide","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"d7d400d2-aa83-47a2-b61a-55a62369b426","gmt_create":"2026-06-30T14:13:05.373036+08:00","gmt_modified":"2026-06-30T14:13:05.375096+08:00"},{"catalog_id":"bcc45977-c058-4033-b0b1-9fd4cd7f4443","title":"前端架构","description":"frontend-architecture","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"6b28e060-0be3-411e-8a94-3777d165d10e","gmt_create":"2026-06-30T14:14:52.873609+08:00","gmt_modified":"2026-06-30T14:14:52.878043+08:00"},{"catalog_id":"0f657e8b-77cb-4604-81cd-d3e921d28e21","title":"布局组件","description":"layout-components","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"b6857b45-a960-4168-92dd-1edcf6567e47","gmt_create":"2026-06-30T14:15:24.293181+08:00","gmt_modified":"2026-06-30T14:15:24.2965+08:00"},{"catalog_id":"d34906db-4455-4481-9512-b29115655378","title":"认证系统API","description":"auth-api","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"7f894188-cf72-40a2-af95-f13ef3dd1f6e","gmt_create":"2026-06-30T14:15:47.975759+08:00","gmt_modified":"2026-06-30T14:15:47.98224+08:00"},{"catalog_id":"7f36202b-af69-4fc0-b62b-a57e415deb69","title":"部署指南","description":"deployment-guide","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"5ab55e3b-04bc-4e92-93f7-52bec7ad8dde","gmt_create":"2026-06-30T14:16:33.823992+08:00","gmt_modified":"2026-06-30T14:16:33.828188+08:00"},{"catalog_id":"1af0f0e8-0c53-41d7-a894-47d9cc19d4f9","title":"用户认证系统","description":"authentication-system","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"772c69b5-886e-48f6-bd11-faf8ca2155e8","gmt_create":"2026-06-30T14:17:38.562007+08:00","gmt_modified":"2026-06-30T14:17:38.563255+08:00"},{"catalog_id":"dbe5d77f-6f4d-476c-88cf-797b80a11a11","title":"实体关系设计","description":"entity-relationships","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"0efcac71-9db4-49c9-a660-690dcb97cd54","gmt_create":"2026-06-30T14:18:01.58459+08:00","gmt_modified":"2026-06-30T14:18:01.58743+08:00"},{"catalog_id":"5a3639b1-98bc-4bc7-a346-91ed56edd2af","title":"后端架构","description":"backend-architecture","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"941d72b1-8daa-4c53-bfeb-9a0b2aa0f43c","gmt_create":"2026-06-30T14:19:05.640846+08:00","gmt_modified":"2026-06-30T14:19:05.643035+08:00"},{"catalog_id":"779d6806-96dc-4c97-8cfb-15a3d7855bd1","title":"品牌管理API","description":"brands-api","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"b66da3f2-6889-45dc-a824-2591d2f5f0f3","gmt_create":"2026-06-30T14:19:07.598117+08:00","gmt_modified":"2026-06-30T14:19:07.600914+08:00"},{"catalog_id":"eb78ed75-b786-4b43-ba43-58a5ea8a23a6","title":"业务组件","description":"business-components","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"2971fa4f-335a-4294-9668-0967b9047d66","gmt_create":"2026-06-30T14:19:27.851755+08:00","gmt_modified":"2026-06-30T14:19:27.855695+08:00"},{"catalog_id":"f96081f7-f508-41e2-bd45-a5b36a1ea114","title":"环境配置","description":"environment-config","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"62bcda0f-7c78-4109-9649-58bbf9fd68ae","gmt_create":"2026-06-30T14:21:11.821343+08:00","gmt_modified":"2026-06-30T14:21:11.825384+08:00"},{"catalog_id":"1e3d40bc-a833-4f35-891c-9dd96f09a1a3","title":"品牌管理","description":"brand-management","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"babe3ec0-01cb-43c3-93db-7e59cdccce68","gmt_create":"2026-06-30T14:21:25.618321+08:00","gmt_modified":"2026-06-30T14:21:25.623289+08:00"},{"catalog_id":"92f94141-482e-499c-bbc3-6101e70206ff","title":"品牌模型","description":"brand-model","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"ef11f60f-47aa-41bf-8884-6d51bc9ae8ef","gmt_create":"2026-06-30T14:21:29.093976+08:00","gmt_modified":"2026-06-30T14:21:29.097382+08:00"},{"catalog_id":"94ec54d4-0aa0-4e58-8e63-5ad6ddb6edbe","title":"型号管理API","description":"models-api","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"799e02d2-8358-41a1-9f8e-114f8ac00eae","gmt_create":"2026-06-30T14:23:05.595716+08:00","gmt_modified":"2026-06-30T14:23:05.599954+08:00"},{"catalog_id":"b47d7f83-5401-4a63-ade2-f087a2f61987","title":"数据流设计","description":"data-flow-design","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"c6f2cb24-ff10-4ae7-87c2-b23b9bbee033","gmt_create":"2026-06-30T14:23:25.129255+08:00","gmt_modified":"2026-06-30T14:23:25.133578+08:00"},{"catalog_id":"f00798b7-c49f-4260-b9c1-d1ee413b030a","title":"页面组件","description":"page-components","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"f0978b42-6f98-470e-922f-22dec2fac24d","gmt_create":"2026-06-30T14:24:27.13852+08:00","gmt_modified":"2026-06-30T14:24:27.143035+08:00"},{"catalog_id":"72a24a80-f221-49da-88a8-83c0f49f4e9d","title":"型号模型","description":"model-model","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"edd1d813-70d4-49de-9f9e-e3ebf7a68678","gmt_create":"2026-06-30T14:24:50.785915+08:00","gmt_modified":"2026-06-30T14:24:50.78921+08:00"},{"catalog_id":"00a9d595-dc79-4ca4-8264-1c3f4a200a28","title":"监控运维","description":"monitoring-operations","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"86f882d7-9e64-4c38-85e7-4782fd55fed2","gmt_create":"2026-06-30T14:25:08.609638+08:00","gmt_modified":"2026-06-30T14:25:08.61406+08:00"},{"catalog_id":"93c96675-6099-4ed5-8f40-6a47b3050712","title":"型号管理","description":"model-management","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"8d4422fd-bd93-431d-a97c-70b75f370f82","gmt_create":"2026-06-30T14:26:44.041445+08:00","gmt_modified":"2026-06-30T14:26:44.046413+08:00"},{"catalog_id":"41e8823b-fa7a-4a80-809d-cf21088bdba2","title":"OTA固件API","description":"ota-api","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"be7e1733-8c9e-4849-99b0-bab40fdf271e","gmt_create":"2026-06-30T14:26:52.74545+08:00","gmt_modified":"2026-06-30T14:26:52.749367+08:00"},{"catalog_id":"6cd96b12-bb94-4748-94a8-9ef9bf21aee0","title":"集成模式","description":"integration-patterns","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"4619dc3e-419f-435b-ba7c-e600e188743a","gmt_create":"2026-06-30T14:27:35.804293+08:00","gmt_modified":"2026-06-30T14:27:35.809224+08:00"},{"catalog_id":"02f97459-8352-4fff-9216-8fcabb128d77","title":"故障排除","description":"troubleshooting-faq","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"ff04bd0e-99c4-481c-ac8c-3c1a6cae1fb5","gmt_create":"2026-06-30T14:28:16.984682+08:00","gmt_modified":"2026-06-30T14:28:16.989286+08:00"},{"catalog_id":"92ff3472-40b9-4adf-82b2-faf5a4d4b158","title":"OTA固件模型","description":"ota-model","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"b2376dbd-002b-4469-8e6e-71748e46e7c2","gmt_create":"2026-06-30T14:28:22.047078+08:00","gmt_modified":"2026-06-30T14:28:22.050489+08:00"},{"catalog_id":"6dc54635-13f8-4ae3-b3a7-54c65dea2997","title":"OTA固件管理","description":"ota-firmware-management","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"da7627b0-17b7-42c7-a029-e357bc889416","gmt_create":"2026-06-30T14:29:32.814324+08:00","gmt_modified":"2026-06-30T14:29:32.817942+08:00"},{"catalog_id":"b4054b83-f0cb-4b7e-9b3d-effc904a5686","title":"用户管理API","description":"users-api","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"8f464fc9-6537-45fa-a0dd-eacdf742b5a1","gmt_create":"2026-06-30T14:30:22.103174+08:00","gmt_modified":"2026-06-30T14:30:22.110852+08:00"},{"catalog_id":"7a728623-5bd2-48eb-80d9-0f253bc74123","title":"用户模型","description":"user-model","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"b5718a44-f452-496d-83c3-4e89b844c709","gmt_create":"2026-06-30T14:30:58.462691+08:00","gmt_modified":"2026-06-30T14:30:58.467737+08:00"},{"catalog_id":"4d08f4ca-84f9-4f9c-8d9a-0983f78a7005","title":"用户权限管理","description":"user-permission-management","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"100cbee2-f7a5-4cc9-83a3-900a4aacac7e","gmt_create":"2026-06-30T14:30:59.491588+08:00","gmt_modified":"2026-06-30T14:30:59.497862+08:00"},{"catalog_id":"a6304333-66ad-4b0c-834f-a6a514069e3f","title":"分享码日志API","description":"share-code-logs-api","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"77bc73e0-8709-4209-96e0-5522f9356b06","gmt_create":"2026-06-30T14:32:03.999307+08:00","gmt_modified":"2026-06-30T14:32:04.003175+08:00"},{"catalog_id":"e1d1f354-edc2-4c91-8d91-63d256dced21","title":"分享码日志模型","description":"share-code-log-model","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"539729a8-aa4b-40c6-bf3b-ec9f467f7717","gmt_create":"2026-06-30T14:32:46.405942+08:00","gmt_modified":"2026-06-30T14:32:46.410705+08:00"},{"catalog_id":"c6207e0a-6059-40f8-a27d-367356363cbf","title":"分享码日志管理","description":"share-code-log-management","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"cf1f3ceb-e3b1-4d5c-8353-f0ea4345414c","gmt_create":"2026-06-30T14:33:14.023031+08:00","gmt_modified":"2026-06-30T14:33:14.02952+08:00"},{"catalog_id":"8f0760f5-ef8b-43ef-8fd0-7c6d1f693193","title":"侧边栏Logo组件","description":"sidebar-logo-component","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"0e003133-7d1a-4708-8599-fc71707070d6","gmt_create":"2026-06-30T14:34:09.992825+08:00","gmt_modified":"2026-06-30T14:34:09.99631+08:00"},{"catalog_id":"7272429b-c7fb-4bd8-9bd1-0093025d68b4","title":"仪表板API","description":"dashboard-api","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"799ec9fc-088e-456c-8f93-72516adac3ac","gmt_create":"2026-06-30T14:34:26.68183+08:00","gmt_modified":"2026-06-30T14:34:26.686097+08:00"},{"catalog_id":"105cfe1d-aeeb-44c1-ac3b-6550f2c7a307","title":"首页仪表板","description":"home-page","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"ad988472-7d0b-4076-86c8-f14661c5923d","gmt_create":"2026-06-30T14:35:15.427082+08:00","gmt_modified":"2026-06-30T14:35:15.43438+08:00"},{"catalog_id":"727c25ac-db22-4b34-9486-6fd6946f64f3","title":"标签页视图组件","description":"tabs-view-component","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"4b6d6abc-bfd2-48a5-9c5e-de89f278f887","gmt_create":"2026-06-30T14:35:27.880644+08:00","gmt_modified":"2026-06-30T14:35:27.886677+08:00"},{"catalog_id":"c8151791-2f8d-4e1e-8139-b0cf921ef002","title":"登录页面","description":"login-page","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"7eee30c6-7725-456b-8b43-35b5e4df7e99","gmt_create":"2026-06-30T14:36:20.14068+08:00","gmt_modified":"2026-06-30T14:36:20.14737+08:00"},{"catalog_id":"32dbace3-24e6-4a2d-9f87-83f2ec825b71","title":"密码修改对话框","description":"change-password-dialog","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"5b84c784-85d8-46e0-8972-e7816f6bd687","gmt_create":"2026-06-30T14:36:50.047707+08:00","gmt_modified":"2026-06-30T14:36:50.062351+08:00"},{"catalog_id":"af7f747a-9be6-41c3-b091-4ee5901d8cc7","title":"品牌管理页面","description":"brand-management","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"791c01a2-dea1-407b-948d-3e2da8cbebed","gmt_create":"2026-06-30T14:37:33.758372+08:00","gmt_modified":"2026-06-30T14:37:33.76504+08:00"},{"catalog_id":"748c8db9-9197-4c3b-ae1d-a6e51d058342","title":"型号管理页面","description":"model-management","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"9f2c6c14-12ae-48cc-a1ee-fe703cd12a1a","gmt_create":"2026-06-30T14:38:54.071337+08:00","gmt_modified":"2026-06-30T14:38:54.075977+08:00"},{"catalog_id":"ff078afb-bb04-4600-b51d-5af48a6a6f06","title":"系统用户管理页面","description":"system-users","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"6003d293-f2aa-4c49-817a-c7fa652890ed","gmt_create":"2026-06-30T14:39:03.424765+08:00","gmt_modified":"2026-06-30T14:39:03.42914+08:00"},{"catalog_id":"f23cd2ae-fcf4-445f-b8e9-b3382f277ae0","title":"OTA固件管理页面","description":"ota-management","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"7d8f2ef6-290d-4952-b59c-a1d95af0d438","gmt_create":"2026-06-30T14:40:01.702004+08:00","gmt_modified":"2026-06-30T14:40:01.705908+08:00"},{"catalog_id":"830433a7-7370-479c-aa05-c21ff47b059e","title":"分享码日志页面","description":"share-code-log","extend":"{}","progress_status":"completed","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","reference_count":0,"id":"73336201-a22f-4329-afc6-40fb5f00f4f1","gmt_create":"2026-06-30T14:40:47.216934+08:00","gmt_modified":"2026-06-30T14:40:47.220483+08:00"}],"wiki_overview":{"content":"\u003cblog\u003e\n\n# 耳机品牌与型号管理平台项目概述\n\n## 1. 项目介绍\n\n### 项目目的\n这是一个基于Vue 3 + Express的耳机品牌与型号管理平台,旨在为音频设备制造商和经销商提供完整的品牌、型号、OTA固件更新以及用户权限管理功能。\n\n### 核心目标\n- 提供统一的品牌和型号数据管理界面\n- 支持OTA固件升级管理和版本控制\n- 实现多用户权限体系和访问控制\n- 提供分享码日志追踪功能\n- 构建现代化的前后端分离架构\n\n### 目标用户\n- 音频设备厂商管理员\n- 技术支持人员\n- 系统维护人员\n\n## 2. 技术架构\n\n### 整体架构设计\n\n```mermaid\ngraph TB\n subgraph \"前端层 (Frontend)\"\n FE_Vue[Vue 3 应用]\n FE_Router[Vue Router]\n FE_API[API 请求封装]\n FE_Components[组件库]\n end\n \n subgraph \"后端层 (Backend)\"\n BE_Express[Express 框架]\n BE_Routes[路由模块]\n BE_Middleware[中间件]\n BE_Services[业务服务]\n end\n \n subgraph \"数据层 (Data Layer)\"\n DB_MySQL[MySQL 数据库]\n DB_Sequelize[Sequelize ORM]\n Cache_Redis[Redis 缓存]\n end\n \n subgraph \"基础设施\"\n Docker[Docker 容器化]\n Nginx[Nginx 反向代理]\n Env[环境配置]\n end\n \n FE_Vue --\u003e FE_Router\n FE_Vue --\u003e FE_API\n FE_API --\u003e BE_Express\n BE_Express --\u003e BE_Routes\n BE_Express --\u003e BE_Middleware\n BE_Routes --\u003e BE_Services\n BE_Services --\u003e DB_Sequelize\n DB_Sequelize --\u003e DB_MySQL\n BE_Services --\u003e Cache_Redis\n BE_Express --\u003e Nginx\n Nginx --\u003e FE_Vue\n Docker --\u003e BE_Express\n Docker --\u003e FE_Vue\n```\n\n### 核心设计模式\n- **MVC架构**: 后端采用经典的模型-视图-控制器模式\n- **分层架构**: 清晰的业务逻辑分层,便于维护和扩展\n- **中间件模式**: 统一的请求处理流程\n- **依赖注入**: 通过模块化设计实现松耦合\n\n## 3. 关键实现\n\n### 主要入口点\n\n#### 后端入口\n- **入口文件**: `backend/src/app.js` - 应用程序主入口,配置中间件、路由和数据库连接\n- **配置文件**: `backend/src/config/database.js` - 数据库连接配置,支持环境变量\n- **路由聚合**: `backend/src/routes/index.js` - 所有路由模块的统一导入和导出\n\n#### 前端入口 \n- **应用入口**: `frontend/src/main.js` - Vue应用初始化,配置Element Plus和路由\n- **应用根组件**: `frontend/src/App.vue` - 根组件模板\n- **路由配置**: `frontend/src/router/index.js` - 路由定义和导航守卫\n\n### 核心模块\n\n#### 数据模型 (Models)\n```mermaid\nerDiagram\n BRAND ||--o{ MODEL : \"包含\"\n MODEL ||--o{ OTA : \"支持\"\n BRAND ||--|| DASHBOARD_USER : \"管理\"\n \n BRAND {\n int id PK\n string name\n }\n \n MODEL {\n int id PK\n int brand_id FK\n string name\n string description\n }\n \n OTA {\n int id PK\n int model_id FK\n string version\n string file_path\n datetime create_time\n }\n \n DASHBOARD_USER {\n int id PK\n string username\n string password_hash\n boolean is_super_admin\n int status\n }\n```\n\n#### API 路由结构\n```mermaid\ngraph TD\n Auth[认证路由] --\u003e Login[用户登录]\n Auth --\u003e Profile[用户信息]\n Auth --\u003e Password[修改密码]\n \n Brands[品牌路由] --\u003e BrandList[品牌列表]\n Brands --\u003e BrandCRUD[品牌增删改查]\n \n Models[型号路由] --\u003e ModelList[型号列表]\n Models --\u003e ModelCRUD[型号增删改查]\n \n OTA[OTA路由] --\u003e OTAList[OTA列表]\n OTA --\u003e OTACRUD[OTA增删改查]\n \n Users[用户路由] --\u003e UserList[用户列表]\n Users --\u003e UserCRUD[用户增删改查]\n \n Dashboard[仪表板路由] --\u003e Stats[统计信息]\n Dashboard --\u003e Reports[报表生成]\n```\n\n### 配置管理\n\n#### 环境配置\n- **Docker Compose**: `docker-compose.yml` - 容器化部署配置,包含前后端服务和网络设置\n- **开发配置**: `frontend/vite.config.js` - Vite构建工具配置,支持代理和别名\n- **包管理**: 使用pnpm作为包管理器,支持工作空间\n\n#### 数据库配置\n- **ORM配置**: `backend/src/config/database.js` - Sequelize ORM配置\n- **Redis缓存**: `backend/src/config/redis.js` - Redis连接配置\n- **日志系统**: `backend/src/config/logger.js` - Winston日志配置\n\n### 外部依赖\n\n#### 后端依赖\n```mermaid\ngraph LR\n Express[Express 4.21] --\u003e Middleware[中间件生态]\n Sequelize[Sequelize 6.37] --\u003e MySQL[MySQL2 3.11]\n JWT[jsonwebtoken 9.0] --\u003e Auth[认证系统]\n Axios[Axios 1.7] --\u003e HTTP[HTTP客户端]\n Zod[3.23] --\u003e Validation[数据验证]\n AWS[aws-sdk 3.650] --\u003e S3[对象存储]\n Redis[ioredis 5.6] --\u003e Cache[缓存系统]\n```\n\n#### 前端依赖\n```mermaid\ngraph LR\n Vue[Vu3 3.3.4] --\u003e Composition[组合式API]\n Router[Vue Router 4.2.4] --\u003e Navigation[路由导航]\n ElementPlus[Element Plus 2.3.14] --\u003e UI[UI组件库]\n Axios[Axios 1.5.0] --\u003e HTTP[HTTP通信]\n Icons[图标库] --\u003e Components[图标组件]\n```\n\n### 集成点\n\n#### API 接口设计\n```mermaid\nsequenceDiagram\n participant Client as 前端客户端\n participant Auth as 认证接口\n participant User as 用户接口\n participant Data as 数据接口\n \n Client-\u003e\u003e+Auth: POST /api/auth/login\n Auth--\u003e\u003e-Client: 返回JWT令牌\n \n Client-\u003e\u003e+User: GET /api/auth/me\n User--\u003e\u003e-Client: 返回用户信息\n \n Client-\u003e\u003e+Data: GET /api/brands\n Data--\u003e\u003e-Client: 返回品牌数据\n \n Client-\u003e\u003e+Data: POST /api/models\n Data--\u003e\u003e-Client: 返回创建结果\n```\n\n## 4. 核心功能\n\n### 功能概览\n\n#### 用户认证系统\n- **登录认证**: 基于JWT的无状态认证\n- **权限控制**: 支持超级管理员和普通用户的权限区分\n- **密码安全**: 密码哈希存储和验证\n\n#### 品牌管理系统\n- **品牌维护**: 品牌的增删改查操作\n- **品牌关联**: 与型号的多对一关系管理\n- **数据验证**: 基于Zod的输入验证\n\n#### 型号管理功能\n- **型号列表**: 支持分页和搜索\n- **型号详情**: 包含详细的技术规格\n- **OTA关联**: 与固件更新的关联管理\n\n#### OTA固件管理\n- **版本控制**: 固件版本管理和发布\n- **文件上传**: 支持固件文件的上传和存储\n- **更新推送**: 向设备推送固件更新\n\n### 功能架构图\n\n```mermaid\nstateDiagram-v2\n [*] --\u003e 未登录\n 未登录 --\u003e 登录中: 用户输入凭据\n 登录中 --\u003e 已登录: 认证成功\n 登录中 --\u003e 未登录: 认证失败\n \n 已登录 --\u003e 品牌管理: 管理员权限\n 已登录 --\u003e 型号管理: 普通用户权限\n 已登录 --\u003e OTA管理: 技术支持权限\n \n 品牌管理 --\u003e 数据库操作: CRUD操作\n 型号管理 --\u003e 数据库操作: CRUD操作\n OTA管理 --\u003e 文件上传: 固件上传\n \n 已登录 --\u003e 修改密码: 用户操作\n 修改密码 --\u003e 已登录: 更新成功\n \n 已登录 --\u003e 退出登录: 用户操作\n 退出登录 --\u003e 未登录: 清除会话\n```\n\n### 实现亮点\n\n#### 响应式设计\n- **组件化开发**: 基于Vue 3 Composition API的组件化架构\n- **状态管理**: 结合Vue Router实现的单页应用体验\n- **主题系统**: 支持暗色主题切换\n\n#### 开发体验\n- **热重载**: Vite提供的快速开发服务器\n- **TypeScript支持**: 良好的类型安全保障\n- **代码分割**: 按需加载优化性能\n\n#### 生产部署\n- **容器化**: Docker支持一键部署\n- **反向代理**: Nginx配置优化静态资源服务\n- **环境隔离**: 支持开发、测试、生产多环境配置\n\n## 5. 总结与建议\n\n### 项目优势\n1. **架构清晰**: 前后端分离,职责明确\n2. **技术栈现代**: Vue 3 + Express + MySQL的成熟技术组合\n3. **可扩展性强**: 模块化设计便于功能扩展\n4. **部署友好**: Docker化部署简化运维\n\n### 改进建议\n1. **增加单元测试**: 补充前端和后端的测试覆盖率\n2. **完善文档**: 添加详细的API文档和开发指南\n3. **监控告警**: 集成应用性能监控和错误追踪\n4. **安全加固**: 增强CSRF防护和API限流机制\n\n### 下一步计划\n1. 实现完整的用户权限管理\n2. 添加数据导入导出功能\n3. 优化移动端适配\n4. 集成自动化测试和CI/CD流水线\n\n---\n\n**Sources:**\n- [README.md](README.md)\n- [backend/package.json](backend/package.json)\n- [frontend/package.json](frontend/package.json)\n- [backend/src/app.js](backend/src/app.js)\n- [backend/src/config/database.js](backend/src/config/database.js)\n- [backend/src/models/index.js](backend/src/models/index.js)\n- [backend/src/routes/index.js](backend/src/routes/index.js)\n- [frontend/src/main.js](frontend/src/main.js)\n- [frontend/src/App.vue](frontend/src/App.vue)\n- [docker-compose.yml](docker-compose.yml)\n- [frontend/vite.config.js](frontend/vite.config.js)\n- [backend/src/models/Brand.js](backend/src/models/Brand.js)\n- [backend/src/routes/auth.js](backend/src/routes/auth.js)\n- [frontend/src/router/index.js](frontend/src/router/index.js)\n- [frontend/src/api/auth.js](frontend/src/api/auth.js)\n\n\u003c/blog\u003e","gmt_create":"2026-06-30T14:01:22.420851+08:00","gmt_modified":"2026-06-30T14:01:22.420851+08:00","id":"f0295b72-1b14-4146-868c-8a0c307045c3","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414"},"wiki_readme":{"content":"No readme file","gmt_create":"2026-06-30T13:59:47.635503+08:00","gmt_modified":"2026-06-30T13:59:47.635503+08:00","id":"60f4194d-74f4-49d9-ae65-220e9f5829cc","repo_id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414"},"wiki_repo":{"id":"8836b2d0-e4ff-4f3c-b5c9-e5b0659fd414","name":"dashboard","progress_status":"completed","wiki_present_status":"COMPLETED","optimized_catalog":"\".\\n├── .pnpm-store/v11/\\n│ ├── files/\\n│ │ ├── 00/\\n│ │ ├── 01/\\n│ │ ├── 02/\\n│ │ ├── 03/\\n│ │ ├── 04/\\n│ │ ├── 05/\\n│ │ ├── 06/\\n│ │ ├── 07/\\n│ │ ├── 08/\\n│ │ ├── 09/\\n│ │ ├── 0a/\\n│ │ ├── 0b/\\n│ │ ├── 0c/\\n│ │ ├── 0d/\\n│ │ ├── 0e/\\n│ │ ├── 0f/\\n│ │ ├── 10/\\n│ │ ├── 11/\\n│ │ ├── 12/\\n│ │ ├── 13/\\n│ │ ├── 14/\\n│ │ ├── 15/\\n│ │ ├── 16/\\n│ │ ├── 17/\\n│ │ ├── 18/\\n│ │ ├── 19/\\n│ │ ├── 1a/\\n│ │ ├── 1b/\\n│ │ ├── 1c/\\n│ │ ├── 1d/\\n│ │ ├── 1e/\\n│ │ ├── 1f/\\n│ │ ├── 20/\\n│ │ ├── 21/\\n│ │ ├── 22/\\n│ │ ├── 23/\\n│ │ ├── 24/\\n│ │ ├── 25/\\n│ │ ├── 26/\\n│ │ ├── 27/\\n│ │ ├── 28/\\n│ │ ├── 29/\\n│ │ ├── 2a/\\n│ │ ├── 2b/\\n│ │ ├── 2c/\\n│ │ ├── 2d/\\n│ │ ├── 2e/\\n│ │ ├── 2f/\\n│ │ ├── 30/\\n│ │ ├── 31/\\n│ │ ├── 32/\\n│ │ ├── 33/\\n│ │ ├── 34/\\n│ │ ├── 35/\\n│ │ ├── 36/\\n│ │ ├── 37/\\n│ │ ├── 38/\\n│ │ ├── 39/\\n│ │ ├── 3a/\\n│ │ ├── 3b/\\n│ │ ├── 3c/\\n│ │ ├── 3d/\\n│ │ ├── 3e/\\n│ │ ├── 3f/\\n│ │ ├── 40/\\n│ │ ├── 41/\\n│ │ ├── 42/\\n│ │ ├── 43/\\n│ │ ├── 44/\\n│ │ ├── 45/\\n│ │ ├── 46/\\n│ │ ├── 47/\\n│ │ ├── 48/\\n│ │ ├── 49/\\n│ │ ├── 4a/\\n│ │ ├── 4b/\\n│ │ ├── 4c/\\n│ │ ├── 4d/\\n│ │ ├── 4e/\\n│ │ ├── 4f/\\n│ │ ├── 50/\\n│ │ ├── 51/\\n│ │ ├── 52/\\n│ │ ├── 53/\\n│ │ ├── 54/\\n│ │ ├── 55/\\n│ │ ├── 56/\\n│ │ ├── 57/\\n│ │ ├── 58/\\n│ │ ├── 59/\\n│ │ ├── 5a/\\n│ │ ├── 5b/\\n│ │ ├── 5c/\\n│ │ ├── 5d/\\n│ │ ├── 5e/\\n│ │ ├── 5f/\\n│ │ ├── 60/\\n│ │ ├── 61/\\n│ │ ├── 62/\\n│ │ ├── 63/\\n│ │ ├── 64/\\n│ │ ├── 65/\\n│ │ ├── 66/\\n│ │ ├── 67/\\n│ │ ├── 68/\\n│ │ ├── 69/\\n│ │ ├── 6a/\\n│ │ ├── 6b/\\n│ │ ├── 6c/\\n│ │ ├── 6d/\\n│ │ ├── 6e/\\n│ │ ├── 6f/\\n│ │ ├── 70/\\n│ │ ├── 71/\\n│ │ ├── 72/\\n│ │ ├── 73/\\n│ │ ├── 74/\\n│ │ ├── 75/\\n│ │ ├── 76/\\n│ │ ├── 77/\\n│ │ ├── 78/\\n│ │ ├── 79/\\n│ │ ├── 7a/\\n│ │ ├── 7b/\\n│ │ ├── 7c/\\n│ │ ├── 7d/\\n│ │ ├── 7e/\\n│ │ ├── 7f/\\n│ │ ├── 80/\\n│ │ ├── 81/\\n│ │ ├── 82/\\n│ │ ├── 83/\\n│ │ ├── 84/\\n│ │ ├── 85/\\n│ │ ├── 86/\\n│ │ ├── 87/\\n│ │ ├── 88/\\n│ │ ├── 89/\\n│ │ ├── 8a/\\n│ │ ├── 8b/\\n│ │ ├── 8c/\\n│ │ ├── 8d/\\n│ │ ├── 8e/\\n│ │ ├── 8f/\\n│ │ ├── 90/\\n│ │ ├── 91/\\n│ │ ├── 92/\\n│ │ ├── 93/\\n│ │ ├── 94/\\n│ │ ├── 95/\\n│ │ ├── 96/\\n│ │ ├── 97/\\n│ │ ├── 98/\\n│ │ ├── 99/\\n│ │ ├── 9a/\\n│ │ ├── 9b/\\n│ │ ├── 9c/\\n│ │ ├── 9d/\\n│ │ ├── 9e/\\n│ │ ├── 9f/\\n│ │ ├── a0/\\n│ │ ├── a1/\\n│ │ ├── a2/\\n│ │ ├── a3/\\n│ │ ├── a4/\\n│ │ ├── a5/\\n│ │ ├── a6/\\n│ │ ├── a7/\\n│ │ ├── a8/\\n│ │ ├── a9/\\n│ │ ├── aa/\\n│ │ ├── ab/\\n│ │ ├── ac/\\n│ │ ├── ad/\\n│ │ ├── ae/\\n│ │ ├── af/\\n│ │ ├── b0/\\n│ │ ├── b1/\\n│ │ ├── b2/\\n│ │ ├── b3/\\n│ │ ├── b4/\\n│ │ ├── b5/\\n│ │ ├── b6/\\n│ │ ├── b7/\\n│ │ ├── b8/\\n│ │ ├── b9/\\n│ │ ├── ba/\\n│ │ ├── bb/\\n│ │ ├── bc/\\n│ │ ├── bd/\\n│ │ ├── be/\\n│ │ ├── bf/\\n│ │ ├── c0/\\n│ │ ├── c1/\\n│ │ ├── c2/\\n│ │ ├── c3/\\n│ │ ├── c4/\\n│ │ ├── c5/\\n│ │ ├── c6/\\n│ │ ├── c7/\\n│ │ ├── c8/\\n│ │ ├── c9/\\n│ │ ├── ca/\\n│ │ ├── cb/\\n│ │ ├── cc/\\n│ │ ├── cd/\\n│ │ ├── ce/\\n│ │ ├── cf/\\n│ │ ├── d0/\\n│ │ ├── d1/\\n│ │ ├── d2/\\n│ │ ├── d3/\\n│ │ ├── d4/\\n│ │ ├── d5/\\n│ │ ├── d6/\\n│ │ ├── d7/\\n│ │ ├── d8/\\n│ │ ├── d9/\\n│ │ ├── da/\\n│ │ ├── db/\\n│ │ ├── dc/\\n│ │ ├── dd/\\n│ │ ├── de/\\n│ │ ├── df/\\n│ │ ├── e0/\\n│ │ ├── e1/\\n│ │ ├── e2/\\n│ │ ├── e3/\\n│ │ ├── e4/\\n│ │ ├── e5/\\n│ │ ├── e6/\\n│ │ ├── e7/\\n│ │ ├── e8/\\n│ │ ├── e9/\\n│ │ ├── ea/\\n│ │ ├── eb/\\n│ │ ├── ec/\\n│ │ ├── ed/\\n│ │ ├── ee/\\n│ │ ├── ef/\\n│ │ ├── f0/\\n│ │ ├── f1/\\n│ │ ├── f2/\\n│ │ ├── f3/\\n│ │ ├── f4/\\n│ │ ├── f5/\\n│ │ ├── f6/\\n│ │ ├── f7/\\n│ │ ├── f8/\\n│ │ ├── f9/\\n│ │ ├── fa/\\n│ │ ├── fb/\\n│ │ ├── fc/\\n│ │ ├── fd/\\n│ │ ├── fe/\\n│ │ └── ff/\\n│ └── projects/7abbab685605e7ae627cb6fc4a2315b1/\\n│ └── package.json\\n├── backend/\\n│ ├── src/\\n│ │ ├── config/\\n│ │ │ ├── database.js\\n│ │ │ ├── env.js\\n│ │ │ ├── loadEnv.js\\n│ │ │ ├── logger.js\\n│ │ │ └── redis.js\\n│ │ ├── middleware/\\n│ │ │ ├── auth.js\\n│ │ │ └── bodyLimit.js\\n│ │ ├── models/\\n│ │ │ ├── Brand.js\\n│ │ │ ├── DashboardUser.js\\n│ │ │ ├── Model.js\\n│ │ │ ├── Ota.js\\n│ │ │ ├── ShareCodeLog.js\\n│ │ │ └── index.js\\n│ │ ├── routes/\\n│ │ │ ├── auth.js\\n│ │ │ ├── brands.js\\n│ │ │ ├── dashboard.js\\n│ │ │ ├── index.js\\n│ │ │ ├── models.js\\n│ │ │ ├── ota.js\\n│ │ │ ├── shareCodeLogs.js\\n│ │ │ └── users.js\\n│ │ ├── services/\\n│ │ │ ├── curveClient.js\\n│ │ │ ├── eqCacheStorage.js\\n│ │ │ ├── measurementStorage.js\\n│ │ │ ├── otaStorage.js\\n│ │ │ └── userBootstrap.js\\n│ │ ├── utils/\\n│ │ │ ├── jwt.js\\n│ │ │ ├── password.js\\n│ │ │ └── response.js\\n│ │ ├── validators/\\n│ │ │ ├── brand.js\\n│ │ │ ├── model.js\\n│ │ │ └── ota.js\\n│ │ └── app.js\\n│ ├── .gitignore\\n│ ├── Dockerfile\\n│ ├── README.md\\n│ ├── package.json\\n│ ├── pnpm-lock.yaml\\n│ ├── restart.sh\\n│ ├── start.sh\\n│ └── stop.sh\\n├── frontend/\\n│ ├── public/\\n│ ├── src/\\n│ │ ├── api/\\n│ │ │ ├── auth.js\\n│ │ │ ├── brand.js\\n│ │ │ ├── dashboard.js\\n│ │ │ ├── model.js\\n│ │ │ ├── ota.js\\n│ │ │ ├── shareCodeLog.js\\n│ │ │ └── user.js\\n│ │ ├── components/\\n│ │ │ ├── ChangePasswordDialog.vue\\n│ │ │ ├── SidebarLogo.vue\\n│ │ │ └── TabsView.vue\\n│ │ ├── layout/\\n│ │ │ └── index.vue\\n│ │ ├── router/\\n│ │ │ └── index.js\\n│ │ ├── styles/\\n│ │ │ └── lux-theme.css\\n│ │ ├── utils/\\n│ │ │ ├── auth.js\\n│ │ │ ├── request.js\\n│ │ │ └── tabs.js\\n│ │ ├── views/\\n│ │ │ ├── brand/\\n│ │ │ │ └── index.vue\\n│ │ │ ├── home/\\n│ │ │ │ └── index.vue\\n│ │ │ ├── login/\\n│ │ │ │ └── index.vue\\n│ │ │ ├── model/\\n│ │ │ │ └── index.vue\\n│ │ │ ├── ota/\\n│ │ │ │ └── index.vue\\n│ │ │ ├── share-code/\\n│ │ │ │ └── log.vue\\n│ │ │ └── system/users/\\n│ │ │ └── index.vue\\n│ │ ├── App.vue\\n│ │ └── main.js\\n│ ├── .gitignore\\n│ ├── Dockerfile\\n│ ├── README.md\\n│ ├── build-and-deploy.bat\\n│ ├── index.html\\n│ ├── install.bat\\n│ ├── nginx.conf\\n│ ├── package-lock.json\\n│ ├── package.json\\n│ ├── pnpm-lock.yaml\\n│ ├── pnpm-workspace.yaml\\n│ ├── start.bat\\n│ └── vite.config.js\\n├── scripts/\\n│ └── upload.sh\\n├── .gitignore\\n├── DEPLOY.md\\n├── README.md\\n└── docker-compose.yml\\n\"","current_document_structure":"WikiEncrypted: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","catalogue_think_content":"WikiEncrypted:17Xjeq1nUM3ZtzeaKMgxqhJuLMWwB2z1/Jlj1FqkaS0ggT6TbP2GlrPkAvnugUvh/i3oXkVZoIcunGAIUNq/6Oz7A06yvc0QIP65HrRB6X+ulxrHKV2hJ6+dQriITZCkEnoDec3juyB5/PQkX1DzoFWW1ligHy938YvwJGKNcrmE5W7GYpekfCKq+FvXEYaYdIXEWgp54LYWN33EQnwnCZJCRWIGeNvFrSBFebbLTb8TUntgbWKcb9a/tl0Z208htI8/QuOJK5G7MjMg6h/JxAeJGHjwA92E+VHcbtSA/qCuu1WM9Wk6vRz/PYwpSDFt3+3iHMJ1WTBhN9RtMyTynHayw1OfgLCUIS1N24rPXpuIAZsphCCpCzmGPZ8ybDGIAag/NYzSMC8FR54+sZ/c0UZiQa4za5uifjKYK5Wy6sY4kMliWlXd+1NxBQM2i50Lcc5TVB8fpeV5Wbz0hWXXFlCzYEEkWYFECBQSl8e6LQW3EeX8oheqH5q/Syf0flDAf7F3wl47GKgatJpdwxRDXE+63V4ldg8MPMu6JWqJsooFG+itc+yiaFqefswBHi/8HDRh/xKv0qzpV3HP1SNrpyq34Fg45IKYmu+FubD2p2BMyzI3tQZRrCXq2KzlC6nS56TCMh4AuR7qHtHu0SkfMZb1QbDb0xng1g3IC+GC+mKQ5d0dGTWi8ObFyVunW1I6bKhbYWIN68nTf72fd/QbKCCf7heeybb8bIvT+/R6ECmijGDeUZl/iZS663ykIkBrbfkfIX3PpFAwPVl3zD0DFj6DCGVokrOCcb+FiLzRqQqlR6Eo4eS8pJznsZGrG8OJTuolVyI+pfJnHhAMOue5iPweb2w0gfjFyUrMlI9k3srtWcPldv1q7MuVoHJkQ6zbDmWQHQCR1RdLagBuHjzfCWI5rv/jPgPZy3J1O6ZmF7kL/gfKHHkje4BlcYVdTw9sS11LAJaMtAIFUd9HxULZFsn0o+C6L7C365cvebkkm6CMVZMALiJ0Gb3MlC0mbIxzewI60daDpbbqOc/5u/WJBRjvHfVXUsdRMiEns4RBlw+CnI777Cb3xZyRdBxib3vSkGdnBqO43afTIq04mX/3e4dmZD4m0laNdPMqAmflRUOnLF6MQqLQ5eb0ZOKBlKs/kF6oAFRhN6VH8RroyCsLm8LkXkwzdLpF2rNKxj4raAYACQJfjYsyRnaJN8fgQxvGfyxX2aWtovjMe7t3eB0fg5VIyASWBAZ3kYtK6ImvXyPaGUq2p7PjTAnxibO8QPlkqZaCWrFrfqaE7fKciwM9QiHlQnWbadPN/xsqJlwENUfLNAJdLtLu2knkj7eCJcJHYD/sy+cirpDlgjoTYrAdTX3dCnm8CRS5t+AwVGoEfgRbx23ygyX5/jB47O6c6L3OFhK1x4jOm1zFqL7JQiPQVE9adP366Hhye+nvweC49arV+8aE6PnvDuuj61doZcQe7n4Oq8bqsF7o9d98njeKm6EYXPLQHWc9kiE8a9iqD1Pav39P668HnLPdxyZNUeQbxzvCLiZx/8x1V5q7L2UpOUsSslKT2/vIlxVUqq4u5UdkzWAgmW5SdkyEagynyWhW+y3oO4ov5yv0zehMOx//8uVvij5kEYsQUFx62r6KeCk+WRl/C8MsC7tCXFqkT1S+b8mgfIfaXG7jDtN9ZCRmXHn4j7W5JYFyctIBJoSA2jPdUNRypZWYi2n47DwQb+xJkbfo7JWgikcK4LKIKHs81loR2ST7wpt/8kRnfdelCFGcMSt2BrkHzCd+AZFx1XrwUcEmRuUAuolQ3TkOXUDPNPlg/Xzqaqf2Xl3EP9ektQ1nY97GtNrHm35i8odtTb5g21s0Jvunmnq0Jo3hNdp6Dty1ngmu/RntjzS4UFFKEdkj1MVl7OAUoBu2RK2tzRJP9Cm3UgknzFjyedWtAwn2qVbNc/IWrhb8uJMb+WBZok/5V++UoOZPEjqkXby2qul/4r5RWErbq5i/ulyJfS3g5qynaNmhFxzPzo23OEOLC6WRQboc5rvbMuCK2j043BNjdCuTVk9mVqGxr8YnIF6Wx0EJzpJCxkoDy4dY3SVuETJDlaNpQLSws4eHToShEoB56NozdIvN42U0UeazGCZJKMthgBtbw6g0GFourp1Yx3+XK4/ORVv8Cl1AbduH8fX7xx7uXIkhsSvc2UGBkFhxqiOdMjwjj6jcBI1zMkO5MykTyFXZx5sfqDtjrQCuH3dKq1FrdkGLPL2NfPtaFHWmpufnlc9HjeH7jRknwOHWfxsr06lNOg4PkhoKPucPbrz8K7Ekee0CBcoN8X2WoJl4rc8qPgOYFZ3GtRPJchEA66NMj/K6s2DnyGla+7B6westNr35hOm2H83YSoPznoPX3qANtTo1zZGTVxrmTPI/caxG+hS+Qs6r8lzmXsLsyFSdmf3uoezV9xNn18747hW1a0wLUBx9Az5l1SiIDMc3t7rQXsOctp9DtNogv+6V9L6PpeLqKmiAzVfTX1mmOBrX3c/u1Egs23NuxyhlNpzxYmVrfhuk2r4kHIdn7hpKkmBRZ/ausIi6erNB71c9bsqZcYxMmE/LGKL0Vdis0PMkjgRqhtVDgN5oDzxk/1V5rgVDvv55TLrqRGHclVSVn4f2l+ZP7IklCqhxOA+mBVxiEb2BxVAt0kv0P9vFwClQzX1WVnKmNoQcykXuJiYfAasJLjS1S1QXkBZhF3tDPMvgT7sCX9uTsn/kWKZUiwJXxDgsfmd4IDIBeaBNEtIdzNp5TMFb48vvn53O8bDqHGEaYrNAusigrRMEN28Pj2oB3GPxpNts9qgZ4UAOal5Gjg5FPsNkm7QrDTad8dQO3cGUPyeFxE4ZRG5vSa94ezCzHzhvLjP9QTxVHL4I/pZ3l6NuL/qNen/JM/LAwJPBSfagqS1OoBB+jJDubfwN5/arqsf8I4x+20TInuP8ZoYRPuBboIljFrdnSyPg0phc9hRmxGxv+fGQHz9VavhSFeuItkJltnzCQ+HcZP13nO9q/xZDm3rOYwUR4OpDAQDEEp4hWlKh6NzIeCDMVn6fAjKrAasQsRne5Vdqz2Y8NEQybta46BSwFprQQpe7mBWYhtvO51aygNixIdDXL1C3t9KG73w2KtsnQEh2G56ShyFz1C0iN3XRKTvS4WBE4l8daXLnFlzPDxHeE1QpYtfOxlKnVkmS94dTPGk2jEyo+dT/OOL/sJfzK4vjNQtWdQJrI/RL1Qy3AIFhJnfRtitoVp6dcmRW68w/8CkKSIBGIw6fEyt5z0PjIbNolgrgXAfJSPLNzx+J3HDiMaCldUUgqnBCoHPe4OD9N64zAbSKfnAeJ6HMk+ctWTgrR++17LcxeqTvlmC61D4Aqmb5npdsn0Z7XZ4aNbv6fzCwgdAQXjM3z4gIEMMYA4gVQ+Y3QiW2+UC3NW95fwk9kD5GUOTtvbbiIVFcBpV5tMtnWAyykZX5Fy7n4jKE2Gp/Bn8YsNHLW4rnI9zpmTuRDrU19YzhAOnegwssAGF1JEolpuAD9RDrVP+4catq+xCJBlqyfpDWyIl2/rpJPUXucXwFUHKTEYuznU9tkN7gOn6AdVlpliOu3l/hSVfnphgS5+WL8AN2cFjJFENEKiAimM0kyOZCCApW+RF/5B+JLmSfWTN4yMmeXcMZRov/1KfX0WEfPCgsbJ8NHDrCW51IlQz5Df/rzNFCbWDQgqBppyRknpJ6iAam7c9QHxvEFRH8YUQjOGAYfVz824/hoCkmL3eIgR6YCo4CTKUegn8C7zwRFSGWTlLb6LHUwad2qVRlUdynyIFK1YJuKI4ntadpNbfBwiPw1hgHJgRZUQebrbaKe9DaAy0FpKmM8NP/ez9/OiN+5HniORSAQvLhBkj1Gs66e98Ajdm1sdwvv1Ao39zmZWzZvFy1VDkCtxIwYfMTtVl6SnpPv2bRP/kw3NlBZupKmAGtwV8IFXMnPQvrSVFU8XmaSGy7Rt9Hq6pY/F0Nq5PmKYHJyz0KZE7gs+cxlbcH331WQKCPgXTuMjptqsgE0QLjN6k0LmuT0fgEhPUv0DYzEkdr4cKdbKP6MM4UKIuYI+hRGxzkuMzZ103bIHA2SsSmRLWLN6qM5s0msiJ5hQpCHbALgLfR4naGJ+EdomPZGI/ZLxGRx3IaptcfLc0RuLYJWV31EgMSkVeFmleotUCCCQNjHqCx1CVKRzmZNEitzZa5xbBDyhwBjHCASjzn5c132PL4yyLiA1wo3wBzSAIhmoQV6ftwy1gPO8NeQut/eg5vlD/0KaDKn8PQYa+RNjp+4jUju3IAYvREH3M3BckXONvv4v25Mrg1vGYqbRoAUFrLJSfrKsUY6P6C/MYjTdfy7GhOpzhUfMySRz3HBBlgN6Qw0sxAVILSg5UmPibl7z/v1HyZyI0qhy0xE9peVooglrQN9qWi7ZZ355HRpxlxjVehK8vY9tPEbWzEp7yhvektJEywC4JWTx/5n1Jpb4oSL6IG4/6hOoVsIURptvw7XrOkO5j8U6pnGKLMHJ6jeKzacksHFnuwtsT7J7981y/7Ll9jgdkvqv/jVzmkrIPvpSxDzI1nz5IXuBDxi0OX2yqXebXVGACguTgwRVGm+dKljgkupBiNuaK5DylC8Y8af+ZfWmOWMhfws9ok4EdL10ItJXbJD1jtNkihutAR9zYc2CU5wI/v+mXUZpBQ5gmCN/xS9pkHruUQd6moZ04MOIqPZWp92x+sMvvuN+0X2LnePUNFWTrMWq1vskBjPG7RYcnJcicr2s2QC6JH4OSMLrokUDWVFiLewOn9ivE4tPU4qTCvlx+zrlKYpHQBPtvyhteL084JBRnUbce6dMWsyqLBTSmvjcE6tmUkYyyndeVoohCobdWwDWQXo5dJHuZgkVKl2//Wx7i+NcTXr5Wqk2r2mUoU3OvLkIgIsV3oJCBn50TaXZ/BUJyISq+pKaeBy0kCczoajmVdnPSMKlmNNL+QILq/oFC68SDvzB6NjnP1m9cjnfTX2VkD8BklLFNDEz0th2lPPwux8y1EfGsSmDg1dtaZ6CItY3FeS+SOg0h0lPg6GgJnXPFUzyfew7LMFMTEWkt2k94dMtbwDs9GHDaRFP1bHLrGiPpO9rHv9eyo4AsJugVHNhxd5cqVyHtRLhMAgoqbaSdiwDv1hd9wxYjvFqv71H4JsIY4YxHZirSC9nhuKbtpFmK7dHt5nKd1c50PlI5srvmZ7FlLIOGn+uWRMVin5/QcFeqqDA90WLvHw4ZY+uhEIxjkuRfrYENNLoDo00XTkxNWcIfoxYcGbjb03wcwJxLLpTxGQG4dxneZYsGVRG9xz+DPnM/lPZA+LilTLBJSYx7glPmqjoZm9kxiRaVCB41qV5zwPHHxA4hFLky+Y0PehlF8ZBvxn7JGUds4tUEEOkP5VbrnM6Q7+Vn85kSsRKaPVkooK9KFDUYyvoygE9ZbXZL8AZTEZ3Pyk9OSbDWN8XA+IZFqll58ZGaVJjUTLYMIBBzS8Y68Ba7lJXxlt6ul0NlVE0C1RYv4Coz+J40r++GF92UKjEMeLrLVyTEOBnMtlCHaTyYn6oLKUqXFRAdg2MA/Bl710aXosYl8k6q4YJWs8geoB9J3Bgz3GCEZgHEJMrTph8mO1aUxEkb6yvgCcsrighOh65ntxu7G2IxF/9agllU6SpKVYLm1FdlRP32lHvRoObDgl6mcRFeetYwiQeGLB/jVAjBaDMvMKzGpGXhrp8FJVKRnntqtz0FrqU53H218/GSav3+/MW9nXr+etdnnwjcXWrerxgnnfjwciIuKh3iDscNhFoUuh/ghSp48WpBmQ+Dgo7jp9q7xup6kTeFzVav8Z12gzgMFfNXi1QAONZ6yP4twIyr8lUDFUrTEJWNXcWXIrCC4HGfB15c3JsDKwANSwHG84gkIKmMaVoVufh5JsLpgrz377dQbHmk9JExOzaidks3BcaqNCLtny47xqgo9vAkOvL/C4uzS8T19TyCjx45s9ChatNCYwOXqxXHVw0jdUCJpsCN2DHK3cDqq3NblLsDRvnrb3s7eSSdkTE3MIEFcCbsA5IsZ61IDGoKKcjXh1ojFr1k9OB2vXqh2zu4x95OUnaRRVp40fTZ65i9OQ/eeaq1jfpRTbGyXbTqj/yIYaUucImq6knKC6g8cjIn3AnvrLSMRsKvgHw9Bce54x0hoNFKLB+LExZnZPGk9+OwRlwdpxtm49S+tqiLAbKDZI3xQfRPDB0uxj+FTuGwMXexS1ahnmUEWHfSnHKU+WLFWp4cd5tgEzoZfFuWu4HE/MI231QmZVJCUFjubedhh4zi0w2VxcUpSKzNVAat/Gx2deBisq/sJK+FUI6g17OTIjsqtCwQcucsY1rFkRmdXnkzEKjWHK6oJTzsXBsU+GCq+SzLohuh/2UTS8KO6oFOAVB/TIi+058rCke1oSui9ra76YcBvMuU0W1gquus90OMv5MVXTHt0f/d5l6JaSkqk05MFVraTKA9x3WWHfbiRA5JPSaPOiYnLktRqAbwqqEj7vbLilstc01zXyNtbos6hXPzV3qaOoQUxFnl0XU2G8jSHa57xL8SQ5CDUOuaVyWk60J3nhCdHTEGCvyHkAo/NsckFQTNPaG09Tj6mcj8VG0iPVkT0o+XNifpyCw+nAtuqIBT//UHBIXIVWJ0/GWScRadUfLJVx669uz787LlxcwqH29C2rGqz9eITogGATQjMCECcMf8T5ACVQojTJbelhQXyFrqvGevmZ8ms8vlrd8DayNzcLd20lR89ztc0VoFkiw1tQG+VD7R2OceOcc0ThpYqUiEkkzPKRZ3+5IFzCU14sHDm3Cv3cNpHCPgwTZCHiHExHNKEVRLyd9G70GAeazQWBE2q2h+1N0dr4KsO3lAe9roJ376CVpmFyHZVNRJyRAklEMq/TsG8bXadooOJEfRY141lrcFe2arALHcIRnTzwTfMrgCD9qXV0HeM6aCf38x6Tfk2Q5x9IHB+DH0cxB1+pxloRda0JDNdMVmLB3hHup8rpFqurwNC9cX37BdQm4Y8Mfv2id25x48AFov++sfdmWkSNmQENz4fO/fm1PhjhCYa1M6q8J8NawdpWgCebqKhw2qNdmBjYA54O1ylTcaml/uXS4pCn33Gm4hl91BUm01MTf9ZLB2yDh2yfoohXlqwHSVZwYBT0S1EB1QwwioGD9Nft3ACPGqSO46Ls4kVV1hmwthbAA8PmPtOEjPmy7hVX0UkfdWMmhqcy4IIcIHHM+D9nK2xnXIAjjWdBcQMZlMulg5fnQlV2PLU5hJXdlW0nCVERv+Buz6Da167J3ro5rbJmfqHS3YWApQIfKIkRWyt+9BwMJNGLPrtOx3peiGFsiZpZgUtxJHLbZCdzU6Qgdb00IyCMnqC0FELc8AkcBGmTIN+V/husP8w7xKgTA9co5rAaH478+OsNf9tpfL7E6WNmg6EtgDgnqsvTBZCgjvLOO0mI0bSOuBq4G6MA5cAZMrat8rLp1TWGt/q+Cw8CXEnrjA9tmRbTOBBc3iG20skW0dr7dBSR2AB11391U+0b3jQkCb5PgWI3208PeYTuel1D8zC8s2J6to6IwnujnKuPNqjQlEx4s46bumC0zr831bPELPr5y+Qn1sn8ryz6k4Y32er77FuBsrrrECyDSaplfNRn6anYJ+xo8bqTXopxmsiaukDZef7LnUw5ASUj8i5H/oOkytBEafi2go5PgY95VDW1NTaEX1KzR0M2ViX8LWmTlFLkmxw/MNbKcYz6rh6xelQq0WQdaaLGcOGmK3smG+ava5l1eTF4ozID1JoELSPcLdK/3Y0b5r603mEBaFAfOR95z9VFXsZ7CUa+PqTIrlC+LJ34CWIFnBrpnmUE/deYOOEZ7NrT9Nr9nRz56/Ly3PGhuAUd2tiuOwCAgEzzGdmPLM6s/Lx2kyXS40WVfeP+h/Z8bwcwRAcSYpI+Khy9lNTUws6VeHrX/rFDbJG1SkjzJscZDM9C8BaMPTB0tJ7sEQovkciKG7UwZELtiaZj+WKROkACtYJ+E+97p6Y6TVOAI80RLB6T8W6ApdbL9YC2JzmGbA8fGHIbL7lOkzZlBSrvyTU+vxGgIvxRES11dyBsKWZqHlhZbOOMtYMSWqZubZbbc5tG9mV2DKLT7oQhdMwjbzHFe06O7j3bAqr2ren1BzkbgXLSTMcwpYVaeE2+6URLLTUngboKFBoUjIzvDxaFN4NFkb8LcMHBciZ6i2lAtHmnnN+fZPtxzRJTuUsukPq8zUO4pGAFEtHIiEdxrw0+Vy0Yxho3xc4RC11gKuYzZ6fN7616CEEJjYkM4mHl/fj6Un315COHRxEAchaxzNHJ8W/ib91SvtL3rvJxzpNc4rC1BXdQekAmufhksxCfQpRcpDuC0YkUPXLsBAEkhn16jTl1ZSEVi6llp6kQ4yG/mncDKwv0J55WlO0PJeRXx/OeB6KYnNF0LboSujydXLaLvWN2Eqvz1YEysPo27dRAesCC/fbx5q9P74WLciUXckHDN3L+zV2KkpSAMSXnm3mt5IB9tzFByA+0uinNMUPQMKskhvBLR1GLZBEdvnGpMILQ80aDJafbKSomRQTqFVMSYIpFnAHHee+YAQKINyPr6OGd9efQZwdaPAcMMbJ2EQ+a2Z1KQYBH7r0ZZicq5Bxm+IeULPl3JKTL59I+1g8fjMsZqgs8pQ2vyk290OKKAcLO0cE3h+XUQQfqH1rg+8vlEb5ao1UWWxsl+PtXD+ugoqhsOE2RboAOTt5V89dtz2pslhxDmnQk0W1PHKqMm/183K994qZE2N7kT1S0ETxaKG0IPSfFFBewsCFuoRT1oJ+b6ZNDwzH3vRNlSaPAwQFoVsoR9UDn0ZzaGz8+r2epae9DfiFlFiLLUgI3evKiTUybmaTh5qNn/v/MqlBknyC7anIDztsq7CsoZXDN+sQkidW6PK8Vjo15iu6EdP5j5drX1U2EvSd/X8jWOMo8waWeUmY7DX14dQszyKuXRK793zpol7wyMKxTL5KFUP2wryC276ZY/nf8YpW0UAi6L+agRLEfFLyNDuZWEAxDK+fqah5ybspL7LAs+IobHsYVl7pmvN8VW+b3uJROymqlRe7eEeGDfu6EmDAHp+Ct3/9JCD9tJQgZYwnn13Q2v92VBD7K3tF3mOG0SP889Xxn7ZSJEJbVou8xze2RgSH4k4THCCcVmfYHVPcs/M5aZk/ujWJGGCTRIrwG5vJ+tBahEUfzah/5yP/tHcI1na0WH+CjfSCeDHOYl5LMkVtnZJNwBkoXzL5A8E8msOMhnyhYMcsWZwv/vsOaRyGtwrOOlySEWiYmBhM+cJSpolsAxNZVA6sDsO7k6LJ+LhnPrXPOn73jrej+gyo9N71kOFsPLmcvsMWd3wCAZrV8yKX0/G+PUJtLkJXdk9eqCFNfdqzpLMMs//pshpNFXpaUtAtihl3Q7Bni+VRxba9I0dSd6JxnivvnHYyqToNPRCHAnecCR6wJ5HBvs3fDLTq5v80+7bzVZPdYLz7jPUjl/eA3YlBg2YoV+R9K0So4mMCCGO/+FOHdjHVFD3cUrtaqrHv5xm0pW2tbQdiFb8/mUJRo0HtYzuUVqJEJcQpkiiSFdjoccBdJhOCWA0o4ntcs9XvXXFEDza5PRoP51YNr/PZ0p4zx4q4Ytx6zftAJvDfhJAEPJ+VIPfiNhMQhvwFIEq92PegUCYOdeBOWthy5pxT2pAGGYlDLnc815+7Ic2NIzdK3+biv2mlRur6x3whnWC/Air0dIYwo59nvo1rjzJrXO5HIGxNpbTGhgD4Jd8f1hO5WkExQzVY4mH8/vpPgd57L3dEKHA3yRIkiiIxm8dbmUM0+tWyzR+gKmskI0xe7KZjH6gFQfz5TWEDMaAgd5dHFtTaSwbjiFBdMWV0s+8cODpJbgnbx5motgi++J5EyXJtwu7jQ3C9HGxRiFB2RnFGEaaI1VOurDXvXtydCnabbZl10kaHOoVWVSUoig1hVzzVoQx+VRE9NMrHWvPkauF0YALLy64cHNPyDCAvJjBzERByBVfAMsYojAzOCyDdV/j68x/aI8jSYmm7NDv8Dq008UJ9LxQP2uLTeekIPkQoZ0TCNLVdVSOFoJ837zTpA6drfmYT8nGDjhOGasmnO1HPPomMZltyXMvE72SHdUHrITYzHYDPJ/8IcwneHvw3L9BDCvkFeVjLw1rzQxbUA5XRt1nueWsbypLgcVNKrlwhb9XpR71pIAnXBzkockUa/1ssnZZPQhdZ7he+Oyttmoe78A8+QgM3hEMXxbHtQBa4uGeAZhovDJS/7Ph4NCjxIRdz26VdCvoE0LUNEA1tT3qZ2KPqlK9ulWOIwu04T/4rKYuuy4qu0F0Axr7Wz7gIQI2Sl4HUHXJMCmFI4LWmurDX9mgufrbrhw/ZGbwGrF0t3Rh/F7LNIrEHHJNvWRnAaYQUZXROPGeoMG7pO60ggg5R8wM605ApCqvVuV6qAaTbElViL1IZmahy152IdPAafiG87OGwyQUfNxs0DSgNzN985mb4wKFnWaPvyZ3vlwUA13cq29XhtzGGbFVKKvGeGIPk7S6aD9F5w3X4DePo6dpt+Batt6uyvhjfRk+5QME5uSfV8Wa44gZcqKWmLxuvzCXg048dw4WP7DCQRKvLPfwlRqd3Sn2TZCp4BkxzlRCLVKgXjLnr0EKtUb8Jb9tkQLT1sFTWS5tzU9GgO44pLH8p/yzzKPEtMxrixRtvK2LKR5NRVXa7vxt8448/PJEDO/I1cfw53VCxo6wWnvXMylo20xfN9dVewx9MKVvmlFfmbe25hsxYbtHoLHWfyATJsAwyuPyjoaEjlRMAwacKN/8qroaIH5vv0R1JrIx28oHJoArByc6xJKvEUpmBQgWcpsrkS47S0A4JXiMDEgurBsbxDuIfhhi6OtwLBKVU4Irhu1S+MFGRwnOGAYlnHdq8sozqtOPfkCDvTH/PfPc2iXRGBAxomJ4mBAnbb1KXzHbc7RvhKDqymIfklRgfc5qfxZOyp3P8TLK1NzpsnTdM3HdfN92JZFyhuPnWACjRs3xDrJMdzxZpqW87SVd0ZWq8MMeIR8Z2IFOrWNUfo0OnFJV34/jjnYdGZMNKD2NuzqB5WivTyHRaJwD7UJtv8mK8lMqy0Y8F/O1LgEl8ThfBSSQqgEebKMFJXwAW+QbXH+GlVqrrC9937QQMHUXdtbPqvvlUDUtrqGvSlvudS4Robfs6RzQxP6WVIGC+8njGp7qXG+fM95/m1CNYcW7zYD2cK7KBzBKf77TDv46oj6hsE+l1QAoQHw0o7tuWXBB16LgLkxvEuQ88Iva2FaTcT7KA0N8GMx8pRkK3YENyO5Y7Qcb7Bb4EJ1RkjsbgS0tyR3I49GzU1w892namX2Ard1fOkrg4U3PDb0+sY9bRu0lXDaCGfAKL8I43cXsimG/RtFMrTOIRbC2Oe9nsAHt0rhXgq1JQvU4RbtndWpt3fHEFVj6wTDCfX6zI0dteBnu2DlpGHXAHS0tMJ+269y4OOTpl4USvu1JHFGUAdCuJ4VkxWdcrR77OmcvpyJ+C3o7M29WnjTuUmpvUxc+UPAgyPYN2mY+xG40+/qUg+E/hk2MM48seqSnUaAPDMlyyvnSIwQm+a5GV2sGRk8AkIaB5WpmbSid1+6W4zj7MOGLI8l9U5Z184+yZHKoQicR0N2S4+madsLmwa3Hz2FNVJe/UFmLfjW/K2K7WYDfHwY2vwXCnoGY8gT42HLzNiHq3MYIPl1AzyF2AwSQPGb8c/Fa0Bo3iiaTr7O1xXJtsrvEpKxVOgJCEMecMT4XluKlbGwV0uIZed8oTDGrJNr7035XEIf2ttf/E48RoqmMnsx+Wt9Cqumm3TQPfviFLd0kS5WgYW0U3TNkvuM7ww+ck8csgvMQVyMeQSPNoUWts7WwMIq4sPm19J4TsNIoibpqXtK5HhzfLSTWJL9t8F73+pnTzO9PttG9ikwhb3Lkjktj7x0Si+vgCm4wkrJL80LyFcZiwJvNAdzWYUowqzf+Q6m6Effbg6NX+2x68dm/N5AYd7eUDrnhrnAvLdRRRae7Xrs5rP94HKpmfyKSgGVt+DLnZLiMwXuwSd9YwKdqdvzkHq/51y+/3ykc9F+pkdJeVzuHthbesGnuFhyNPKBHB4h/ToHlfowg3jDQz/UaRBXzTQJ7WpgFKfeYRYww/XgA03XTR2X00aTxkzvcWZBOfQWZxMtnnzJYzDq67T5zO0mKv46tVEjAzfBCg332rL3E8EE14yEg0Btssyn4YD7sotbfEv+vuek6ZAy6SYfeAzIDE+rHTwCi5/X65izZJYK/98g1vefswd3h/hMStSwyktqniYgMvfM9rhIxh29jX0qqMWDCNUcVNQCTSmodaqYntxUGP/K2aZH6lMu1z8358g6smB77eO2PZ1cviN8qw3uPYjhW7YcAdXIOMYHV51se9Du8EfmGR9YK8Dr93g0Z/ah64LZKBFquAh+ke+A3jOoj85ZYn31VETfaV7JKQbC9J5mJm3zsz+gI8IFzrqbSyWTRtFfiibxI5lmfgDMoulJK61LDgcuArSdigutV7pvU4mxhNt4GIhLUBMMiOQ1j25o0Jxlv2vRpEa9vu+ZZ7lkLFOeh72G5eEif5oOdlCC/OQwGi6iSXj71sjtuwAjWrvg7hdwouvMZ7tJ/LzI2NjkRMGW/sjK2mYfH6yyCgL0rvnC8nHMOVYep0SnMa8BvTaOnrofi4oh+sqC6r3BoCFn8rx1pNmdoLw8mr1MTHoO1Na98L12iwMdICirh7sX1l5tO88Ra5BEwAPPBLsbw3zsM6cs6r7GydLuCeZMkH5lzFxl/cCajwVqeWm6ef1yuqDSnxaq1dr5cFY9NjyuMpg1ZF/VikFrba+9bnw2JS5Ptr7GVmiG5aUyEw79R3YymCElO1dzaLAu5uzaUiUKWxKFCPvVi5RK4zpadANcPSevHnoerYt+25bmZ1C2Ad6H6ALm682rRswO+ewyLWqvYz9ROkPiXtXdxGKjpv3uORfYDcsCjFMgI27kNG6a3p5nk4j7ILDlZ6S0P8t/V3KAkiYo+C0TW9mx4TTvPZ6HgGDJscOcgcXI1hMv8n1Uw4Tx1KrFi5FRO6eBqe4Qg52HlRFw/5EkiRAECL+L0NqOV5w9HmMPWrHSGhOEulNY57Uk3R1HasMQOQhEAypweVH47iPyBtzpdGwDPEmgQZRN3zkVQBYw+Uug6d8xh6L3wvMd7Jved7+yPqAwUUW6MxxFj8Vtuxw7EHulvOU+3gae/k1zD0Ty5BNnggwxcVcA54Yf3Xwncp62qPbeAjRd708IAy4lm0qc7T7hXTHTA0dUr2uAMY+02GdFvI7IMosv52d+Y+vbxfSFxaHc5o0C+kG5gAhK8ypVNEdbeVnSD5STYRHnN5hloPh3ZaZRTM7oCTEvfnws2qfJlX38mUwR+Mq92nHOosE2m0Y9C7SZSyzEHc8Gos/abVs7/pnJ9AMsduLkF8uG1KPaGUL0j4qmAOpOUjXFeSb6TeisLSGQEvthhv6hq0ytSOMGaMI6oA9y9zTyQfQv/askPaEt4y+zSpImC11bQTgB+iLkUPpZu03hltt0Le59yhQcHIduwdGG0/nuDpvLz8TqNN1404ObghoqFlZq9mNPQagjuyB3C3saSYvy7npPmYq+vTEY6NI8Nwr0xdCGnBBMvYqKw/DlXIjnX4ugJ+M11V7X72Vmi/JmhqCUuqJXGIWzlAVmpbQLdgltvpljf7h1N9BVObdI8FqBkBj0hYfBsDOm/vz6n1rJbwtHZiCuEEihGhAOtGNoov7JWCebJRDV3ZSUpBfeCWIGbjlQNeJZF3nBj/tpWNSA4AyCuU2IkSRQj/68UsljqLskkO78xuywll/LS5S8tXilXqlWYKIRxtaT5iNYiqubiAzlJSENuCuOFzSywlSWt0CU/wOTJDk3+zfYXGyJbh4bKqBbcweKJHE3rb3BMvBbEbqfArA8wsldOczxs113SZ4nqT+wXlh5HWWHdfouuvWD0JqZ9n5isoC6xJRSvDEdEFNqdhl2hZezrskzCo3TkRKFBy9gI1+V4R5La+nvOTBCy+BW9HM5b4v6wF6TGJ9eZSSezM9wGEng9ukSt1mrg1UOkmbw62XC7x82UnUXd9cCuKvM7OLOk0HgsCQx1cOoc8GTg1dJps0AGQ07FIYrbobuTGpxALRxr2j7hCHzHFv0bWR92ttY5oZSAA3mGe4OgZzsVscOg9ivK82WPKSzrphEaqCpUcM2qg/J93pvjFPDxJq3XhNIFjWJ9dGJyDhVGIqAoZ4zUGYbL9mty6Nf/+6NcQAUvTam7EVkyPEdB4gtfz4KFxB6jy8hGC6wlOqTbopsV0IRUpobAeArpkGMi5cnPHFyybxaXCXa+PFOG3MVKjWBbZEEiVD5d6c5HqN+VgNBLC6Ia8o7lczCd0hwyZET0O4zFDeulgq+j5zSxOWby8JofxMxB99eNTfsq5/+BzPSPd8Yo+Bz3ES9qXTFIUGIG8df0XT2kQBvZm6YP9R3n8ofgiauWnoKW51PbEd9lQPMQcaLnb2FN5tQDdmBJhbV4EwcG3CSH81eVvWJvg6hfNdzH4LKksNKJ3gtiYbeA1DoBAtoPD8cjUrgJ3xkS1SVXpAwbdzJDGyslFu7AZMGBudBUubOMma6JvrWA/wFcl3g7Mw/AZ2lOdkaBf81z42DjOTBT6roTYZUpkan/4vJpRK0+aCccaEuQohWv1eXiosh2fRXssXobyiwLGfnirvjbe2b4N5JjUvYwMVFP/ywPKjBGU9XVoAn6Mnr5UszqCwaeD/2MO7Ubx+VvP1VJaSex7HA+3j+hzni+EtFFbo2T8RI4aneiqh8aDLmAUiXncQhd/OlFQTebmiLZWnwtd6zOKyfKLBx7zFj42zxKL1/Elrq3i8+V62JIq5/0Lxgw2hJ3pdqKScwqdoLLKV1ILQV2IESubQOUdEvXwZdteoLWBFY/PsQ3wiHKPBdJYfiXFKW2Ihg/lN7lsFzNbSH/yXh0FCoGwaKJ5UsOOAi3VwGFgnQl7ZfKAoMH3Tfkdyi0xKAMbCoB8RNGpCIa502uosAnHfOaWXmI0rqHgr6bxNQU=","recovery_checkpoint":"wiki_generation_completed","last_commit_id":"cac5bef5a72e08be6a05cd5e918ed34a7f12612a","last_commit_update":"2026-06-30T14:40:47.300586+08:00","gmt_create":"2026-06-02T14:43:54.575428+08:00","gmt_modified":"2026-06-30T14:40:47.300587+08:00","extend_info":"{\"language\":\"zh\",\"active\":true,\"branch\":\"main\",\"shareStatus\":\"\",\"server_error_code\":\"\",\"cosy_version\":\"1.4.0\"}"}} \ No newline at end of file