Files
dashboard/.qoder/repowiki/zh/content/核心功能模块/品牌管理.md
T

362 lines
19 KiB
Markdown
Raw Normal View History

2026-06-30 14:46:52 +08:00
# 品牌管理
<cite>
**本文引用的文件**
- [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)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本章节面向“品牌管理”功能,系统性阐述品牌 CRUD 操作、数据验证规则、与型号模型的关联关系以及缓存策略的实现细节。文档通过后端路由、模型定义、前端视图与 API 调用的联动,结合错误处理与日志记录,帮助初学者快速上手,同时为有经验的开发者提供足够的技术深度。
## 项目结构
品牌管理功能涉及前后端协作:前端负责用户交互与分页搜索;后端提供认证中间件、统一响应格式、品牌路由与模型持久化;型号模型与品牌存在逻辑上的关联;此外还包含 EQ 缓存服务用于读取型号 EQ 数据。
```mermaid
graph TB
subgraph "前端"
FE_View["品牌视图<br/>frontend/src/views/brand/index.vue"]
FE_API["品牌 API 封装<br/>frontend/src/api/brand.js"]
end
subgraph "后端"
APP["应用入口<br/>backend/src/app.js"]
ROUTES_IDX["路由汇总<br/>backend/src/routes/index.js"]
AUTH_MW["认证中间件<br/>backend/src/middleware/auth.js"]
BRAND_ROUTE["品牌路由<br/>backend/src/routes/brands.js"]
BRAND_MODEL["品牌模型<br/>backend/src/models/Brand.js"]
MODEL_MODEL["型号模型<br/>backend/src/models/Model.js"]
RESP_UTIL["统一响应工具<br/>backend/src/utils/response.js"]
EQ_CACHE["EQ 缓存服务<br/>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 "前端视图<br/>brand/index.vue"
participant API as "前端 API<br/>brand.js"
participant APP as "应用入口<br/>app.js"
participant MW as "认证中间件<br/>auth.js"
participant RT as "品牌路由<br/>brands.js"
participant MD as "品牌模型<br/>Brand.js"
participant UT as "响应工具<br/>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 "品牌视图<br/>index.vue"
participant API as "品牌 API<br/>brand.js"
participant ModelView as "型号视图<br/>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<br/>品牌名称+空格+型号名称"] --> 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 缓存读取失败进行降级处理,保证核心功能可用。
[本节为通用建议,不直接分析具体文件,故无“章节来源”]