Files
dashboard/.qoder/repowiki/zh/content/前端组件/页面组件/型号管理页面.md
T

613 lines
30 KiB
Markdown
Raw Normal View History

2026-06-30 14:46:52 +08:00
# 型号管理页面
<cite>
**本文档引用的文件**
- [frontend/src/views/model/index.vue](file://frontend/src/views/model/index.vue)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/composables/useModelList.js](file://frontend/src/views/model/composables/useModelList.js)
- [frontend/src/views/model/components/ModelFormDialog.vue](file://frontend/src/views/model/components/ModelFormDialog.vue)
- [frontend/src/views/model/components/CsvViewerDialog.vue](file://frontend/src/views/model/components/CsvViewerDialog.vue)
- [frontend/src/views/model/components/EqCacheDialog.vue](file://frontend/src/views/model/components/EqCacheDialog.vue)
- [frontend/src/views/model/components/PushProgressDialog.vue](file://frontend/src/views/model/components/PushProgressDialog.vue)
- [frontend/src/views/model/components/PushViewDialog.vue](file://frontend/src/views/model/components/PushViewDialog.vue)
- [frontend/src/api/model.js](file://frontend/src/api/model.js)
2026-06-30 14:46:52 +08:00
- [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/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)
2026-07-09 10:33:19 +08:00
- [backend/src/services/squiglink.js](file://backend/src/services/squiglink.js)
2026-06-30 14:46:52 +08:00
- [frontend/src/utils/request.js](file://frontend/src/utils/request.js)
- [frontend/src/router/index.js](file://frontend/src/router/index.js)
</cite>
2026-07-09 10:33:19 +08:00
## 更新摘要
**变更内容**
- 新增useModelList组合式函数,提供统一的数据管理与状态控制
- 新增5个专用对话框组件,增强用户体验和功能完整性
- 新增squig.link外部数据导入功能,支持从第三方网站抓取频响数据
- 增强型号表单的复杂处理能力,支持文件上传、品牌自动创建等功能
- 完善批量操作的进度跟踪与错误处理机制
- **更新**:标准化搜索和重置按钮为圆形图标格式,使用Vue 3组合式API图标,减少视觉混乱同时通过工具提示保持清晰的可用性
2026-07-09 10:33:19 +08:00
2026-06-30 14:46:52 +08:00
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
2026-07-09 10:33:19 +08:00
本文件面向"型号管理页面"的技术实现与使用说明,覆盖以下关键能力:
2026-06-30 14:46:52 +08:00
- 型号列表展示、搜索过滤、排序与分页
- 型号详情查看与参数配置
- 型号表单的数据结构、字段验证与复杂表单处理(含频响文件上传)
- 型号与品牌的关联关系、级联数据管理与外键约束处理
- 型号参数的动态配置、数据格式验证与存储优化
- 批量操作(复制、推送搜索)的实现方案
2026-07-09 10:33:19 +08:00
- **新增**squig.link外部数据导入功能
- **新增**:组合式函数useModelList的状态管理
- **新增**:5个专用对话框组件的完整功能
- **更新**:标准化的圆形图标搜索和重置按钮设计
2026-06-30 14:46:52 +08:00
## 项目结构
型号管理页面位于前端单页应用中,后端提供 REST 接口与数据模型支撑,前端通过 API 模块与后端交互。系统现已包含完整的对话框组件体系和组合式函数支持,并采用统一的UI设计规范。
2026-06-30 14:46:52 +08:00
```mermaid
graph TB
subgraph "前端"
FE_Model["型号视图<br/>frontend/src/views/model/index.vue"]
2026-07-09 10:33:19 +08:00
FE_useModelList["组合式函数<br/>useModelList.js"]
2026-06-30 14:46:52 +08:00
FE_API_Model["型号 API<br/>frontend/src/api/model.js"]
FE_API_Brand["品牌 API<br/>frontend/src/api/brand.js"]
FE_Request["请求封装<br/>frontend/src/utils/request.js"]
FE_Router["路由<br/>frontend/src/router/index.js"]
2026-07-09 10:33:19 +08:00
FE_Components["对话框组件<br/>components/"]
FE_ModelFormDialog["ModelFormDialog.vue"]
FE_CsvViewerDialog["CsvViewerDialog.vue"]
FE_EqCacheDialog["EqCacheDialog.vue"]
FE_PushProgressDialog["PushProgressDialog.vue"]
FE_PushViewDialog["PushViewDialog.vue"]
2026-06-30 14:46:52 +08:00
end
subgraph "后端"
BE_Routes_Models["型号路由<br/>backend/src/routes/models.js"]
BE_Models_Model["型号模型<br/>backend/src/models/Model.js"]
BE_Validators_Model["型号校验器<br/>backend/src/validators/model.js"]
BE_Routes_Brands["品牌路由<br/>backend/src/routes/brands.js"]
BE_Models_Brand["品牌模型<br/>backend/src/models/Brand.js"]
BE_Services_Measure["频响存储服务<br/>backend/src/services/measurementStorage.js"]
BE_Services_EQ["EQ 缓存服务<br/>backend/src/services/eqCacheStorage.js"]
2026-07-09 10:33:19 +08:00
BE_Services_Squiglink["squig.link 服务<br/>backend/src/services/squiglink.js"]
2026-06-30 14:46:52 +08:00
end
2026-07-09 10:33:19 +08:00
FE_Model --> FE_useModelList
2026-06-30 14:46:52 +08:00
FE_Model --> FE_API_Model
FE_Model --> FE_API_Brand
2026-07-09 10:33:19 +08:00
FE_useModelList --> FE_API_Model
FE_useModelList --> FE_API_Brand
2026-06-30 14:46:52 +08:00
FE_API_Model --> FE_Request
FE_API_Brand --> FE_Request
FE_Router --> FE_Model
2026-07-09 10:33:19 +08:00
FE_Model --> FE_Components
FE_Components --> FE_ModelFormDialog
FE_Components --> FE_CsvViewerDialog
FE_Components --> FE_EqCacheDialog
FE_Components --> FE_PushProgressDialog
FE_Components --> FE_PushViewDialog
2026-06-30 14:46:52 +08:00
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
2026-07-09 10:33:19 +08:00
BE_Routes_Models --> BE_Services_Squiglink
2026-06-30 14:46:52 +08:00
BE_Routes_Brands --> BE_Models_Brand
```
2026-07-09 10:33:19 +08:00
**图表来源**
- [frontend/src/views/model/index.vue:1-524](file://frontend/src/views/model/index.vue#L1-L524)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/composables/useModelList.js:1-191](file://frontend/src/views/model/composables/useModelList.js#L1-L191)
- [frontend/src/views/model/components/ModelFormDialog.vue:1-555](file://frontend/src/views/model/components/ModelFormDialog.vue#L1-L555)
- [frontend/src/views/model/components/CsvViewerDialog.vue:1-50](file://frontend/src/views/model/components/CsvViewerDialog.vue#L1-L50)
- [frontend/src/views/model/components/EqCacheDialog.vue:1-306](file://frontend/src/views/model/components/EqCacheDialog.vue#L1-L306)
- [frontend/src/views/model/components/PushProgressDialog.vue:1-303](file://frontend/src/views/model/components/PushProgressDialog.vue#L1-L303)
- [frontend/src/views/model/components/PushViewDialog.vue:1-60](file://frontend/src/views/model/components/PushViewDialog.vue#L1-L60)
2026-06-30 14:46:52 +08:00
2026-07-09 10:33:19 +08:00
**章节来源**
- [frontend/src/views/model/index.vue:1-524](file://frontend/src/views/model/index.vue#L1-L524)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/composables/useModelList.js:1-191](file://frontend/src/views/model/composables/useModelList.js#L1-L191)
- [backend/src/routes/models.js:1-659](file://backend/src/routes/models.js#L1-L659)
2026-06-30 14:46:52 +08:00
## 核心组件
2026-07-09 10:33:19 +08:00
- **组合式函数**useModelList提供统一的数据加载、搜索、排序、分页和状态管理功能
- **主视图组件**:型号管理页面的核心容器,协调各对话框组件和业务逻辑
- **对话框组件族**
- ModelFormDialog:完整的型号表单对话框,支持文件上传和squig.link导入
- CsvViewerDialogCSV频响数据查看对话框
- EqCacheDialogEQ缓存查看对话框,支持JSON树形展示
- PushProgressDialog:推送进度跟踪对话框
- PushViewDialog:推送状态查看对话框
- **API模块**:封装所有型号相关的HTTP请求,包括新增的squig.link导入功能
- **后端路由**:提供完整的REST接口,包括squig.link数据抓取功能
- **服务层**:频响文件上传、EQ缓存读取、squig.link数据抓取等服务
- **UI组件**:标准化的圆形图标按钮,提升界面一致性和用户体验
2026-07-09 10:33:19 +08:00
**章节来源**
- [frontend/src/views/model/composables/useModelList.js:1-191](file://frontend/src/views/model/composables/useModelList.js#L1-L191)
- [frontend/src/views/model/components/ModelFormDialog.vue:1-555](file://frontend/src/views/model/components/ModelFormDialog.vue#L1-L555)
- [frontend/src/views/model/components/CsvViewerDialog.vue:1-50](file://frontend/src/views/model/components/CsvViewerDialog.vue#L1-L50)
- [frontend/src/views/model/components/EqCacheDialog.vue:1-306](file://frontend/src/views/model/components/EqCacheDialog.vue#L1-L306)
- [frontend/src/views/model/components/PushProgressDialog.vue:1-303](file://frontend/src/views/model/components/PushProgressDialog.vue#L1-L303)
- [frontend/src/views/model/components/PushViewDialog.vue:1-60](file://frontend/src/views/model/components/PushViewDialog.vue#L1-L60)
- [frontend/src/api/model.js:1-165](file://frontend/src/api/model.js#L1-L165)
2026-06-30 14:46:52 +08:00
## 架构总览
2026-07-09 10:33:19 +08:00
型号管理页面采用现代化的Vue 3 Composition API架构,结合Element Plus组件库和Axios进行数据交互。系统支持完整的数据流:从组合式函数的状态管理到对话框组件的用户交互,再到后端服务的业务处理。
2026-06-30 14:46:52 +08:00
```mermaid
sequenceDiagram
participant U as "用户"
participant V as "型号视图<br/>index.vue"
2026-07-09 10:33:19 +08:00
participant CM as "组合式函数<br/>useModelList"
participant MD as "ModelFormDialog"
participant API as "API 模块<br/>model.js"
participant R as "后端路由<br/>models.js"
participant S as "服务层<br/>squiglink.js"
2026-06-30 14:46:52 +08:00
U->>V : 打开型号管理页面
2026-07-09 10:33:19 +08:00
V->>CM : 初始化状态管理
CM->>API : 加载品牌列表
API->>R : GET /api/models/
R->>S : 调用squig.link服务
S-->>R : 返回数据
R-->>API : 品牌数据
API-->>CM : 品牌选项
CM-->>V : 渲染界面
U->>MD : 点击"新型号"
MD->>API : 上传文件或导入squig.link
API->>R : POST /api/models/squiglink-fetch
R->>S : 抓取外部数据
S-->>R : 返回CSV内容
R-->>API : 处理结果
API-->>MD : 成功响应
MD-->>V : 关闭对话框并刷新
2026-06-30 14:46:52 +08:00
```
2026-07-09 10:33:19 +08:00
**图表来源**
- [frontend/src/views/model/index.vue:218-424](file://frontend/src/views/model/index.vue#L218-L424)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/composables/useModelList.js:31-191](file://frontend/src/views/model/composables/useModelList.js#L31-L191)
- [frontend/src/views/model/components/ModelFormDialog.vue:158-464](file://frontend/src/views/model/components/ModelFormDialog.vue#L158-L464)
- [frontend/src/api/model.js:157-165](file://frontend/src/api/model.js#L157-L165)
- [backend/src/routes/models.js:307-369](file://backend/src/routes/models.js#L307-L369)
- [backend/src/services/squiglink.js:261-310](file://backend/src/services/squiglink.js#L261-L310)
**章节来源**
- [frontend/src/views/model/index.vue:218-424](file://frontend/src/views/model/index.vue#L218-L424)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/composables/useModelList.js:31-191](file://frontend/src/views/model/composables/useModelList.js#L31-L191)
2026-06-30 14:46:52 +08:00
## 详细组件分析
2026-07-09 10:33:19 +08:00
### useModelList组合式函数
useModelList是型号管理页面的核心状态管理函数,提供统一的数据操作接口。
**核心功能**
- **数据加载**:统一处理型号列表的加载、搜索、排序和分页
- **状态管理**:维护表格数据、选中行、品牌选项等状态
- **搜索过滤**:支持品牌名称和型号名称的模糊搜索
- **排序控制**:支持按ID和创建时间的升序/降序排序
- **分页处理**:支持不同页面大小的分页控制
- **批量操作**:提供复制功能和格式化工具方法
**状态属性**
- `loading`: 数据加载状态
- `tableData`: 当前表格数据
- `selectedRows`: 选中的行数据
- `selectedIds`: 选中行的ID数组
- `brandOptions`: 品牌下拉选项
- `sortBy`: 排序字段
- `sortOrder`: 排序顺序
- `searchForm`: 搜索表单数据
- `pagination`: 分页配置
**方法功能**
- `loadData()`: 加载型号列表数据
- `loadBrands()`: 加载品牌选项
- `handleSearch()`: 执行搜索
- `handleReset()`: 重置搜索条件
- `handleSortChange()`: 处理排序变更
- `handleSizeChange()`: 处理页面大小变更
- `handlePageChange()`: 处理页码变更
- `handleSelectionChange()`: 处理选择变更
- `handleCopyName()`: 复制单个型号
- `handleCopyBrand()`: 复制品牌名称
- `handleCopySelectedNames()`: 复制选中型号
- `formatDateTime()`: 格式化日期时间
- `formatFormLabel()`: 格式化佩戴方式
**章节来源**
- [frontend/src/views/model/composables/useModelList.js:1-191](file://frontend/src/views/model/composables/useModelList.js#L1-L191)
### 标准化搜索和重置按钮设计
**更新**:搜索和重置按钮已标准化为圆形图标格式,提升界面一致性和用户体验。
**设计特点**
- **圆形图标按钮**:使用`circle`属性创建圆形外观,减少视觉混乱
- **Vue 3组合式API图标**:通过`:icon`属性绑定Search和Refresh图标
- **工具提示**:使用`title`属性提供清晰的功能说明
- **统一样式**:搜索按钮使用`type="primary"`强调主要操作,重置按钮使用默认样式
**实现代码**
```vue
<el-button type="primary" circle :icon="Search" title="搜索" @click="handleSearch" />
<el-button circle :icon="Refresh" title="重置" @click="handleReset" />
```
**图标资源**
- Search图标:来自`@element-plus/icons-vue`
- Refresh图标:来自`@element-plus/icons-vue`
**章节来源**
- [frontend/src/views/model/index.vue:29-31](file://frontend/src/views/model/index.vue#L29-L31)
- [frontend/src/views/model/index.vue:221-228](file://frontend/src/views/model/index.vue#L221-L228)
2026-07-09 10:33:19 +08:00
### ModelFormDialog型号表单对话框
ModelFormDialog是完整的型号创建和编辑对话框,支持复杂的表单处理和外部数据导入。
**核心特性**
- **squig.link导入**:支持从第三方网站抓取频响数据
- **文件上传**:支持CSV、TXT、JSON格式的频响文件上传
- **品牌自动创建**:当品牌不存在时自动创建新品牌
- **文件名智能解析**:根据文件名自动解析品牌和型号
- **表单验证**:完整的字段验证和错误处理
- **多步骤提交**:支持单次提交和连续提交模式
**squig.link导入流程**
1. 用户输入squig.link分享链接
2. 系统抓取phone_book.json获取可用文件列表
3. 自动匹配或让用户选择目标文件
4. 下载TXT频响文件并转换为CSV格式
5. 自动填充表单字段(品牌、型号、佩戴方式等)
**文件上传处理**
- 支持multipart/form-data格式
- 自动检测文件扩展名并验证格式
- TXT文件自动转换为CSV格式
- 上传成功后与型号记录关联
**章节来源**
- [frontend/src/views/model/components/ModelFormDialog.vue:1-555](file://frontend/src/views/model/components/ModelFormDialog.vue#L1-L555)
- [backend/src/routes/models.js:307-499](file://backend/src/routes/models.js#L307-L499)
- [backend/src/services/squiglink.js:261-310](file://backend/src/services/squiglink.js#L261-L310)
### 对话框组件体系
系统包含5个专用对话框组件,每个组件都有明确的功能边界和使用场景。
**CsvViewerDialog**
- 功能:查看CSV频响数据内容
- 特点:支持S3 Key显示和只读文本区域
- 适用:仅限特定来源的型号查看
**EqCacheDialog**
- 功能:查看EQ缓存的Redis数据
- 特点:支持JSON树形结构展示,可展开查看嵌套数据
- 适用:调试和分析EQ参数配置
**PushProgressDialog**
- 功能:跟踪批量推送的进度
- 特点:显示校验和推送两个阶段的状态,支持错误详情
- 适用:批量型号推送操作
**PushViewDialog**
- 功能:查看推送状态和文档详情
- 特点:简洁的信息展示,支持加载状态
- 适用:查看单个型号的推送结果
**章节来源**
- [frontend/src/views/model/components/CsvViewerDialog.vue:1-50](file://frontend/src/views/model/components/CsvViewerDialog.vue#L1-L50)
- [frontend/src/views/model/components/EqCacheDialog.vue:1-306](file://frontend/src/views/model/components/EqCacheDialog.vue#L1-L306)
- [frontend/src/views/model/components/PushProgressDialog.vue:1-303](file://frontend/src/views/model/components/PushProgressDialog.vue#L1-L303)
- [frontend/src/views/model/components/PushViewDialog.vue:1-60](file://frontend/src/views/model/components/PushViewDialog.vue#L1-L60)
2026-06-30 14:46:52 +08:00
### 型号数据模型与表单结构
2026-07-09 10:33:19 +08:00
- **数据模型字段**
2026-06-30 14:46:52 +08:00
- 主键:自增整型 ID
- 品牌名称:字符串,最大 100 字符,必填
- 型号名称:字符串,最大 100 字符,必填
- 形式:字符串,最大 100 字符,可空(入耳式/头戴式/耳塞式)
- 阻抗:字符串,最大 100 字符,可空
- 来源:字符串,最大 100 字符,可空
- EQ 键:字符串,最大 255 字符,可空
- 创建时间:日期,默认当前时间
2026-07-09 10:33:19 +08:00
- **表单字段与验证**
2026-06-30 14:46:52 +08:00
- 品牌名称:必填
- 型号名称:必填,长度 1-100
- 形式:可选枚举值
- 阻抗:可选
- 来源:可选
- 频响文件:可选上传,支持 CSV/TXT/JSONTXT 自动转换为 CSV
2026-07-09 10:33:19 +08:00
- **复杂表单处理**
2026-06-30 14:46:52 +08:00
- 文件上传采用 multipart/form-data
- 新增时若品牌不存在,先尝试创建品牌再保存型号
- 文件名解析:优先按品牌接口返回的品牌名进行最长前缀匹配,否则按首个空格拆分
2026-07-09 10:33:19 +08:00
**章节来源**
2026-06-30 14:46:52 +08:00
- [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)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/components/ModelFormDialog.vue:196-214](file://frontend/src/views/model/components/ModelFormDialog.vue#L196-L214)
2026-06-30 14:46:52 +08:00
### 品牌关联与外键约束
2026-07-09 10:33:19 +08:00
- **品牌模型**
2026-06-30 14:46:52 +08:00
- 主键:自增整型 ID
- 名称:唯一、非空、最大 100 字符
2026-07-09 10:33:19 +08:00
- **型号与品牌的关系**
2026-06-30 14:46:52 +08:00
- 前端通过品牌下拉选择型号所属品牌
- 后端在新增/编辑时检查品牌是否存在,不存在则创建
2026-07-09 10:33:19 +08:00
- 当前模型字段为字符串类型的"品牌名称",未建立显式的外键约束
- **级联与一致性**
2026-06-30 14:46:52 +08:00
- 若后续迁移为外键关联,建议在数据库层面添加约束,并在删除品牌时处理级联或阻止删除
2026-07-09 10:33:19 +08:00
**章节来源**
2026-06-30 14:46:52 +08:00
- [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)
### 搜索过滤、排序与分页
2026-07-09 10:33:19 +08:00
- **搜索条件**
2026-06-30 14:46:52 +08:00
- 品牌名称(模糊匹配)
- 型号名称(模糊匹配)
2026-07-09 10:33:19 +08:00
- **排序**
2026-06-30 14:46:52 +08:00
- 支持按 ID 与创建时间排序,升序/降序切换
2026-07-09 10:33:19 +08:00
- **分页**
2026-06-30 14:46:52 +08:00
- 页面大小:10/20/50/100
- 当前页变更时重置为第一页并重新加载
2026-07-09 10:33:19 +08:00
- **后端实现**
2026-06-30 14:46:52 +08:00
- 使用 Sequelize 查询构建 where 条件与 order 排序
- 限制每页最大 1000 条,总数统计用于分页控件
2026-07-09 10:33:19 +08:00
**章节来源**
- [frontend/src/views/model/composables/useModelList.js:18-27](file://frontend/src/views/model/composables/useModelList.js#L18-L27)
- [frontend/src/views/model/composables/useModelList.js:87-111](file://frontend/src/views/model/composables/useModelList.js#L87-L111)
2026-06-30 14:46:52 +08:00
- [backend/src/routes/models.js:133-181](file://backend/src/routes/models.js#L133-L181)
### 批量操作与推送搜索
2026-07-09 10:33:19 +08:00
- **批量复制**
- 支持复制所选项的"品牌+型号"文本
- **推送搜索**
2026-06-30 14:46:52 +08:00
- 校验:对选中型号调用曲线校验服务,返回校验失败项
- 推送:将型号数据批量写入 Meilisearch 索引
- 进度弹窗:显示校验与推送步骤状态、当前处理项与错误明细
2026-07-09 10:33:19 +08:00
- **多媒体资源**
2026-06-30 14:46:52 +08:00
- 查看 EQ 缓存:读取 Redis Hash 字段,支持展开查看 JSON 结构
- 查看 CSV:仅支持来源为特定值的型号,按佩戴方式拼接 S3 Key 并读取
```mermaid
sequenceDiagram
participant U as "用户"
participant V as "型号视图"
2026-07-09 10:33:19 +08:00
participant PP as "PushProgressDialog"
participant API as "API 模块"
2026-06-30 14:46:52 +08:00
participant R as "后端路由"
participant C as "曲线校验服务"
participant MS as "Meilisearch"
2026-07-09 10:33:19 +08:00
U->>V : 选择多个型号并点击"推送搜索"
V->>PP : 打开进度对话框
PP->>API : validatePushToMeilisearch(ids)
API->>R : POST /api/models/push-to-search/validate
2026-06-30 14:46:52 +08:00
R->>C : 校验曲线数据
C-->>R : 校验结果
2026-07-09 10:33:19 +08:00
R-->>API : 校验错误列表或通过
API-->>PP : 显示校验结果
U->>PP : 确认推送
PP->>API : pushToMeilisearch(ids)
API->>R : POST /api/models/push-to-search
2026-06-30 14:46:52 +08:00
R->>MS : 写入索引
MS-->>R : 任务 UID
2026-07-09 10:33:19 +08:00
R-->>API : 推送结果
API-->>PP : 关闭进度弹窗并刷新
2026-06-30 14:46:52 +08:00
```
2026-07-09 10:33:19 +08:00
**图表来源**
- [frontend/src/views/model/index.vue:395-419](file://frontend/src/views/model/index.vue#L395-L419)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/components/PushProgressDialog.vue:117-195](file://frontend/src/views/model/components/PushProgressDialog.vue#L117-L195)
2026-06-30 14:46:52 +08:00
- [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)
2026-07-09 10:33:19 +08:00
**章节来源**
- [frontend/src/views/model/index.vue:395-419](file://frontend/src/views/model/index.vue#L395-L419)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/components/PushProgressDialog.vue:117-195](file://frontend/src/views/model/components/PushProgressDialog.vue#L117-L195)
2026-06-30 14:46:52 +08:00
- [frontend/src/api/model.js:128-150](file://frontend/src/api/model.js#L128-L150)
### 频响文件上传与存储优化
2026-07-09 10:33:19 +08:00
- **支持格式**
2026-06-30 14:46:52 +08:00
- CSV、TXT、JSON
- TXT 自动转换为 CSV(保留频率与幅度列)
2026-07-09 10:33:19 +08:00
- **存储路径**
2026-06-30 14:46:52 +08:00
- S3 Key 规则:autoeq/measurements/{source}/data/{form}/{brandFirstChar}/{brand model}.csv
- 上传成功后将 S3 Key 与型号记录关联
2026-07-09 10:33:19 +08:00
- **读取与展示**
2026-06-30 14:46:52 +08:00
- 仅对特定来源与完整字段的型号允许读取 S3 中的 CSV 内容
- 提供弹窗展示 CSV 文本内容
2026-07-09 10:33:19 +08:00
**章节来源**
2026-06-30 14:46:52 +08:00
- [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)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/components/CsvViewerDialog.vue:1-50](file://frontend/src/views/model/components/CsvViewerDialog.vue#L1-L50)
2026-06-30 14:46:52 +08:00
2026-07-09 10:33:19 +08:00
### EQ缓存查看与动态配置
- **Redis Key 规则**{品牌名称} {型号名称}
- **功能**
2026-06-30 14:46:52 +08:00
- 列出可用的 Hash Key
- 展示指定 Key 的 JSON 值(带层级与图标)
- 支持加载状态指示与空状态提示
2026-07-09 10:33:19 +08:00
- **适用场景**
2026-06-30 14:46:52 +08:00
- 动态配置 EQ 参数、调试频响数据结构
2026-07-09 10:33:19 +08:00
**章节来源**
2026-06-30 14:46:52 +08:00
- [backend/src/services/eqCacheStorage.js:24-66](file://backend/src/services/eqCacheStorage.js#L24-L66)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/components/EqCacheDialog.vue:1-306](file://frontend/src/views/model/components/EqCacheDialog.vue#L1-L306)
2026-06-30 14:46:52 +08:00
### 表单字段解析与文件名智能填充
2026-07-09 10:33:19 +08:00
- **文件名预处理**:去除扩展名、合并多余空格
- **品牌解析策略**
2026-06-30 14:46:52 +08:00
- 优先使用品牌接口返回的品牌名进行最长前缀匹配(支持多词品牌)
2026-07-09 10:33:19 +08:00
- 回退为"第一个空格"左侧为品牌、右侧为型号
- **默认阻抗**:新增时若未填写,按规则自动填充
**章节来源**
- [frontend/src/views/model/components/ModelFormDialog.vue:233-265](file://frontend/src/views/model/components/ModelFormDialog.vue#L233-L265)
### Squig.link外部数据导入
**新增功能**:系统现在支持从squig.link网站导入频响数据。
**工作原理**
- **URL解析**:解析squig.link分享URL,提取基础URL和分享参数
- **清单获取**:获取phone_book.json文件,列出所有可用的测量数据
- **文件匹配**:根据分享参数精确匹配或模糊匹配目标文件
- **数据抓取**:下载TXT频响文件并转换为CSV格式
- **信息提取**:从文件名解析品牌和型号信息
- **自动填充**:自动填充表单字段(品牌、型号、佩戴方式等)
**支持的URL格式**
- `https://theaudiostore.squig.link/?share=Nostalgia_Audio_Camelot`
- `https://squig.link/?share=Moondrop_Chu_2`
2026-06-30 14:46:52 +08:00
2026-07-09 10:33:19 +08:00
**章节来源**
- [frontend/src/api/model.js:157-165](file://frontend/src/api/model.js#L157-L165)
- [backend/src/routes/models.js:307-369](file://backend/src/routes/models.js#L307-L369)
- [backend/src/services/squiglink.js:261-310](file://backend/src/services/squiglink.js#L261-L310)
2026-06-30 14:46:52 +08:00
## 依赖关系分析
2026-07-09 10:33:19 +08:00
- **前端依赖**
2026-06-30 14:46:52 +08:00
- Element Plus UI 组件库
- Axios 请求封装
2026-07-09 10:33:19 +08:00
- Vue 3 Composition API(组合式函数)
- vue-json-pretty JSON展示组件
- @element-plus/icons-vue 图标库
2026-07-09 10:33:19 +08:00
- **后端依赖**
2026-06-30 14:46:52 +08:00
- Express 路由
- Sequelize ORM
- AWS SDKS3
- Redis 客户端
- Meilisearch 客户端
2026-07-09 10:33:19 +08:00
- axios(外部数据抓取)
2026-06-30 14:46:52 +08:00
```mermaid
graph LR
2026-07-09 10:33:19 +08:00
FE_View["前端视图<br/>index.vue"] --> FE_useModelList["组合式函数<br/>useModelList.js"]
FE_useModelList --> FE_API["前端 API<br/>model.js/brand.js"]
2026-06-30 14:46:52 +08:00
FE_API --> FE_Request["请求封装<br/>request.js"]
FE_API --> BE_Routes["后端路由<br/>models.js/brands.js"]
BE_Routes --> BE_Models["数据模型<br/>Model.js/Brand.js"]
2026-07-09 10:33:19 +08:00
BE_Routes --> BE_Services["服务层<br/>measurementStorage.js/eqCacheStorage.js/squiglink.js"]
2026-06-30 14:46:52 +08:00
BE_Routes --> S3["S3 存储"]
BE_Routes --> Redis["Redis 缓存"]
BE_Routes --> MS["Meilisearch"]
```
2026-07-09 10:33:19 +08:00
**图表来源**
- [frontend/src/views/model/index.vue:218-424](file://frontend/src/views/model/index.vue#L218-L424)
2026-07-09 10:33:19 +08:00
- [frontend/src/views/model/composables/useModelList.js:1-191](file://frontend/src/views/model/composables/useModelList.js#L1-L191)
- [frontend/src/api/model.js:1-165](file://frontend/src/api/model.js#L1-L165)
- [backend/src/routes/models.js:1-659](file://backend/src/routes/models.js#L1-L659)
2026-06-30 14:46:52 +08:00
2026-07-09 10:33:19 +08:00
**章节来源**
2026-06-30 14:46:52 +08:00
- [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)
## 性能考虑
2026-07-09 10:33:19 +08:00
- **分页与排序**
2026-06-30 14:46:52 +08:00
- 后端限制每页最大 1000 条,避免一次性传输大量数据
- 排序字段限定为 ID 与创建时间,减少复杂索引需求
2026-07-09 10:33:19 +08:00
- **文件上传**
2026-06-30 14:46:52 +08:00
- 仅允许特定格式,TXT 自动转换降低客户端处理成本
- S3 上传采用内存存储,注意控制文件大小与并发
2026-07-09 10:33:19 +08:00
- **缓存与索引**
2026-06-30 14:46:52 +08:00
- EQ 缓存仅列出 Hash Key,避免一次性返回大体积 JSON
- 推送搜索采用异步任务与进度弹窗,提升用户体验
2026-07-09 10:33:19 +08:00
- **squig.link抓取**
- 使用内存缓存squigsites.json,减少外部请求频率
- 并行处理多项操作,提高响应速度
- **UI性能优化**
- 圆形图标按钮减少DOM复杂度,提升渲染性能
- 工具提示按需显示,避免不必要的重绘
2026-07-09 10:33:19 +08:00
**章节来源**
- [backend/src/services/squiglink.js:33-48](file://backend/src/services/squiglink.js#L33-L48)
2026-06-30 14:46:52 +08:00
## 故障排查指南
2026-07-09 10:33:19 +08:00
- **登录与鉴权**
2026-06-30 14:46:52 +08:00
- 401:令牌失效或缺失,自动跳转登录页
- 403:无权限执行操作
2026-07-09 10:33:19 +08:00
- **网络与超时**
2026-06-30 14:46:52 +08:00
- 请求超时:检查后端服务与网络连通性
- 响应错误:查看控制台日志与消息提示
2026-07-09 10:33:19 +08:00
- **品牌与型号**
2026-06-30 14:46:52 +08:00
- 品牌名称重复:确保品牌唯一性
- 型号重复:同一品牌下型号名称唯一
2026-07-09 10:33:19 +08:00
- **文件上传**
2026-06-30 14:46:52 +08:00
- 不支持的文件格式:确认扩展名为 CSV/TXT/JSON
- TXT 转换失败:检查文件内容格式是否符合预期
2026-07-09 10:33:19 +08:00
- **S3 与 Redis**
2026-06-30 14:46:52 +08:00
- 读取失败:确认 S3 Key 是否正确、对象是否存在
- 缓存为空:确认型号 EQ 缓存是否已生成
2026-07-09 10:33:19 +08:00
- **squig.link导入**
- URL格式错误:确认使用标准的squig.link分享链接
- 数据抓取失败:检查网络连接和目标网站可用性
- 文件匹配失败:确认分享参数与目标文件名匹配
- **UI组件问题**
- 图标不显示:检查@element-plus/icons-vue包是否正确安装
- 工具提示异常:确认title属性设置正确
2026-06-30 14:46:52 +08:00
2026-07-09 10:33:19 +08:00
**章节来源**
2026-06-30 14:46:52 +08:00
- [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)
2026-07-09 10:33:19 +08:00
- [backend/src/routes/models.js:371-499](file://backend/src/routes/models.js#L371-L499)
2026-06-30 14:46:52 +08:00
- [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)
2026-07-09 10:33:19 +08:00
- [backend/src/services/squiglink.js:261-310](file://backend/src/services/squiglink.js#L261-L310)
2026-06-30 14:46:52 +08:00
## 结论
型号管理页面经过重构后,现已成为一个功能完整、架构清晰的现代化管理系统。通过useModelList组合式函数实现了状态管理的统一化,通过5个专用对话框组件提供了丰富的用户交互体验,通过squig.link导入功能扩展了数据来源的多样性,并通过标准化的圆形图标按钮设计提升了整体界面的一致性和用户体验。
2026-07-09 10:33:19 +08:00
系统的主要优势包括:
- **模块化设计**:组合式函数和对话框组件的分离提高了代码的可维护性
- **用户体验优化**:完整的进度跟踪和错误处理提升了用户满意度
- **数据来源多样化**:支持本地文件上传和外部网站数据导入
- **UI设计标准化**:统一的圆形图标按钮设计增强了界面一致性
2026-07-09 10:33:19 +08:00
- **扩展性强**:基于Vue 3 Composition API的设计便于功能扩展
建议在后续版本中继续完善:
- 添加更多外部数据源的支持
- 增强数据验证和错误恢复机制
- 优化大数据量场景下的性能表现
- 进一步丰富图标库的使用,提升界面美观度
2026-06-30 14:46:52 +08:00
## 附录
2026-07-09 10:33:19 +08:00
- **API 一览**
2026-06-30 14:46:52 +08:00
- 获取型号列表: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
- 查看频响 CSVGET /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
2026-07-09 10:33:19 +08:00
- **新增**squig.link数据抓取:POST /api/models/squiglink-fetch
2026-06-30 14:46:52 +08:00
2026-07-09 10:33:19 +08:00
**章节来源**
- [frontend/src/api/model.js:1-165](file://frontend/src/api/model.js#L1-L165)
2026-06-30 14:46:52 +08:00
- [frontend/src/api/brand.js:1-66](file://frontend/src/api/brand.js#L1-L66)
2026-07-09 10:33:19 +08:00
- [backend/src/routes/models.js:133-659](file://backend/src/routes/models.js#L133-L659)
2026-06-30 14:46:52 +08:00
- [backend/src/routes/brands.js:14-147](file://backend/src/routes/brands.js#L14-L147)