408 lines
19 KiB
Markdown
408 lines
19 KiB
Markdown
|
|
# 型号管理页面
|
|||
|
|
|
|||
|
|
<cite>
|
|||
|
|
**本文档引用的文件**
|
|||
|
|
- [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)
|
|||
|
|
</cite>
|
|||
|
|
|
|||
|
|
## 目录
|
|||
|
|
1. [简介](#简介)
|
|||
|
|
2. [项目结构](#项目结构)
|
|||
|
|
3. [核心组件](#核心组件)
|
|||
|
|
4. [架构总览](#架构总览)
|
|||
|
|
5. [详细组件分析](#详细组件分析)
|
|||
|
|
6. [依赖关系分析](#依赖关系分析)
|
|||
|
|
7. [性能考虑](#性能考虑)
|
|||
|
|
8. [故障排查指南](#故障排查指南)
|
|||
|
|
9. [结论](#结论)
|
|||
|
|
10. [附录](#附录)
|
|||
|
|
|
|||
|
|
## 简介
|
|||
|
|
本文件面向“型号管理页面”的技术实现与使用说明,覆盖以下关键能力:
|
|||
|
|
- 型号列表展示、搜索过滤、排序与分页
|
|||
|
|
- 型号详情查看与参数配置
|
|||
|
|
- 型号表单的数据结构、字段验证与复杂表单处理(含频响文件上传)
|
|||
|
|
- 型号与品牌的关联关系、级联数据管理与外键约束处理
|
|||
|
|
- 型号参数的动态配置、数据格式验证与存储优化
|
|||
|
|
- 批量操作(复制、推送搜索)的实现方案
|
|||
|
|
|
|||
|
|
## 项目结构
|
|||
|
|
型号管理页面位于前端单页应用中,后端提供 REST 接口与数据模型支撑,前端通过 API 模块与后端交互。
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph TB
|
|||
|
|
subgraph "前端"
|
|||
|
|
FE_Model["型号视图<br/>frontend/src/views/model/index.vue"]
|
|||
|
|
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"]
|
|||
|
|
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"]
|
|||
|
|
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 "型号视图<br/>index.vue"
|
|||
|
|
participant A as "API 模块<br/>model.js/brand.js"
|
|||
|
|
participant R as "后端路由<br/>models.js/brands.js"
|
|||
|
|
participant M as "模型<br/>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["前端视图<br/>index.vue"] --> FE_API["前端 API<br/>model.js/brand.js"]
|
|||
|
|
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"]
|
|||
|
|
BE_Routes --> BE_Services["服务层<br/>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)
|