准备上传
This commit is contained in:
@@ -1,28 +0,0 @@
|
||||
## 管理端开发说明(当前实现)
|
||||
|
||||
### 1. 模块概览
|
||||
- **VIP 系统**:`/vip/system` 管理统一售价与充值记录,`/vip/list` 维护店铺会员状态。价格管理页面引用 `/api/admin/vip/system/price`,充值列表读取 `/api/admin/vip/system/recharges`。
|
||||
- **公告管理**:`/notice/list` 支持公告检索、创建、编辑、发布与下线,对应接口 `/api/admin/notices` 及其子路径。
|
||||
- **咨询回复**:`/consult` 基于 `/api/admin/consults` 完成列表、单次回复、标记已解决。
|
||||
- **用户/配件/供应商**:`/users`、`/parts`、`/supplier` 依次调用 `/api/admin/users`、`/api/admin/parts`、`/api/suppliers` 进行检索与维护。
|
||||
- **附件与图片**:图片上传统一走 `/api/attachments`,列表页展示时需通过 `withBaseUrl()` 处理相对路径。
|
||||
|
||||
### 2. 认证与上下文
|
||||
- 后端默认启用 `AdminAuthInterceptor`,优先校验 Bearer Token;未登录情况下回退到请求头 `X-Admin-Id` 与 `X-User-Id`。
|
||||
- 管理端前端目前仍使用本地存储写入 `USER_ID`/`ADMIN_ID`(详见 `admin/src/api/http.ts`);接入登录页时需改为在登录成功后写入 Token 并移除默认 ID。
|
||||
- 所有请求必须附带 `X-Shop-Id`(默认 1,可在本地存储或环境变量覆盖),以匹配租户范围。
|
||||
|
||||
### 3. 接口要点
|
||||
- **VIP 列表**:`GET /api/admin/vips` 已落地;`POST /api/admin/vips` 需要传入 `shopId` 与 `userId` 才能成功创建。
|
||||
- **VIP 价格**:`GET/PUT /api/admin/vip/system/price` 会清空 `vip_price` 再写入单条记录,不允许并行修改;可考虑后续改为 `UPDATE` 语句。
|
||||
- **VIP 充值**:`GET /api/admin/vip/system/recharges` 支持关键字(姓名/手机号)过滤,默认按创建时间倒序。
|
||||
- **公告管理**:创建与更新均支持标签、置顶、时间窗,未填写时间默认为即时生效/长期有效。
|
||||
- **附件上传**:上传成功返回 `url` 与元信息,若需要落库请在业务表维持引用;多次上传同一文件会复用记录(按 hash 去重)。
|
||||
|
||||
### 4. 条码识别接入
|
||||
- 管理端不提供扫码入口,仅用户端调用 `/api/barcode/scan`。
|
||||
- 后端代理服务会将图片转发至 Python TXM(FastAPI)并返回首个匹配条码,需保持 Java 与 Python 两侧的 `PY_BARCODE_MAX_UPLOAD_MB` 一致。
|
||||
- 部署时应通过环境变量配置:
|
||||
- `PY_BARCODE_HOST`/`PY_BARCODE_PORT`:Python 服务地址,默认 `127.0.0.1:8000`。
|
||||
- `PY_BARCODE_MAX_UPLOAD_MB`:上传大小限制,默认 8MB。
|
||||
- 小程序端调用扫码接口需将后端域名加入“request 合法域名”并启用 HTTPS。
|
||||
@@ -1,26 +0,0 @@
|
||||
# 管理端需求文档
|
||||
|
||||
## 1. 页面结构
|
||||
- **VIP 系统**:含价格配置、充值记录与会员列表三块;价格修改需立即生效并同步到前端 `VIP_PRICE` 显示;列表支持手机号模糊检索。
|
||||
- **公告管理**:支持公告的新增、编辑、发布、下线、置顶,字段包括标题、内容、标签、有效期、生效状态。
|
||||
- **咨询回复**:列出店铺咨询,管理员可单次回复并标记已解决。
|
||||
- **用户管理**:展示用户基本信息,支持编辑、启停(黑名单)。
|
||||
- **用户配件管理**:适配用户提交的配件数据,允许管理员编辑品牌/型号/规格与图片链接。
|
||||
- **供应商管理**:列表检索、创建、编辑供应商信息,含欠款字段展示。
|
||||
- **主数据字典**:主单位、主类别维护入口,仅平台管理员可用。
|
||||
|
||||
## 2. 认证约束
|
||||
- 所有接口通过 `AdminAuthInterceptor` 鉴权:优先 Bearer Token,其次 `X-Admin-Id`/`X-User-Id`。
|
||||
- 请求必须携带 `X-Shop-Id`,缺省取 1;多租户数据严格隔离。
|
||||
- 登录功能正在开发中,当前临时通过本地存储写入管理员 ID。
|
||||
|
||||
## 3. 功能约束
|
||||
- 禁止硬编码配置值,价格、库存等需从后端接口读取。
|
||||
- 上传图片统一调用 `/api/attachments`,返回的 `url` 需落库或直接引用。
|
||||
- 所有列表接口支持分页(默认 `page=1&size=20`);前端需预留分页扩展点。
|
||||
- 删除功能未启用,均以启停或逻辑状态位代替。
|
||||
|
||||
## 4. 未完成功能
|
||||
- 管理端登录页与权限粒度控制尚未上线。
|
||||
- 配件审核流仅完成基础编辑,驳回/通过流程待接入。
|
||||
- 公告板目前缺少多语言与富文本支持。
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2869,7 +2869,6 @@ components:
|
||||
model: { type: string }
|
||||
spec: { type: string }
|
||||
categoryId: { type: integer, format: int64, nullable: true }
|
||||
unitId: { type: integer, format: int64 }
|
||||
safeMin: { type: number, nullable: true }
|
||||
safeMax: { type: number, nullable: true }
|
||||
purchasePrice: { type: number }
|
||||
@@ -2891,7 +2890,6 @@ components:
|
||||
model: { type: string, nullable: true }
|
||||
spec: { type: string, nullable: true }
|
||||
categoryId: { type: integer, format: int64, nullable: true }
|
||||
unitId: { type: integer, format: int64 }
|
||||
safeMin: { type: number, nullable: true }
|
||||
safeMax: { type: number, nullable: true }
|
||||
prices:
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
# 货品功能扩展需求文档(草案)
|
||||
|
||||
## 1. 当前实现概览
|
||||
|
||||
### 1.1 用户端(uni-app)
|
||||
- `pages/product/list.vue`:支持关键字与按类别筛选、下拉分页、查看详情并跳转编辑;展示“平台推荐/我的提交”标签。
|
||||
- `pages/product/form.vue`:可创建/编辑货品,字段涵盖名称、条码、品牌、型号、规格、产地、单位、类别、安全库存、四列售价、初始库存、图片与备注;提供图片识码能力;图片上传走 `/api/attachments`。
|
||||
- **`pages/product/submit.vue`**:新增配件提交入口,支持型号唯一校验、多图上传、参数 JSON、备注、安全库存等字段,提交成功跳转“我的提交”。
|
||||
- **`pages/product/submissions.vue`、`pages/product/submission-detail.vue`**:新增提交列表与详情页,支持状态筛选、滚动分页、驳回重新提交、图片/参数展示。
|
||||
- 字典:调用 `/api/product-units`、`/api/product-categories` 读取全局单位/类别,并缓存到本地。
|
||||
|
||||
### 1.2 管理端(Vue3 + Element Plus)
|
||||
- **`admin/src/views/parts/Submissions.vue`**:已上线配件审核模块,提供筛选、详情、编辑、通过/驳回、Excel 导出能力。
|
||||
- 其它模块:VIP 系统、公告管理、咨询回复、用户管理、配件管理、供应商管理、主数据字典。
|
||||
- 待迭代:登录页、角色权限细分、操作日志可视化。
|
||||
|
||||
### 1.3 后端(Spring Boot)
|
||||
- `ProductSubmissionController` + `ProductSubmissionService`:完成用户提交、用户查看、管理员审核/驳回、导出全链路;审批通过时同步 `products`、`product_images`、`source_submission_id` 等字段。
|
||||
- OpenAPI 已新增 `/api/products/submissions*` 与 `/api/admin/parts/submissions*` 路径,并标记为 ✅ Fully Implemented。
|
||||
- 数据模型:`products`、`product_prices`、`inventories`、`product_images` 已投产;`part_submissions` 已扩展 JSON、状态、审核信息等字段。
|
||||
- 图片存储:统一走 `attachments`,提交与商品共享资源。
|
||||
|
||||
## 2. 差距分析
|
||||
|
||||
| 需求点 | 现状 | 差距 |
|
||||
| --- | --- | --- |
|
||||
| 用户提交配件待审核 | 用户端新增提交/列表/详情页面,与后台接口打通 | 持续跟踪型号唯一范围(店铺或全局);补充并发校验测试 |
|
||||
| 审核管理 | 管理端已上线审核列表、详情编辑、通过/驳回、导出 | 后续可扩展批量操作、导出更大数据量的异步方案 |
|
||||
| 数据查询增强 | 后端支持多条件、返回 total;前端列表分页同步 | 可继续优化查询性能(索引/缓存)与前端展示字段 |
|
||||
| 图片管理 | 提交端与审核端均支持多图显示、预览、排序 | 可根据需求补充图片备注、AI 识别等增强能力 |
|
||||
| 上架逻辑 | 审核通过自动写入 `products` 并关联 `source_submission_id`、`global_sku_id` | 待确认产品图片、参数同步策略是否满足后续拓展(如平台库) |
|
||||
| 导出 | 管理端支持按筛选条件导出 Excel(2000 条以内同步导出) | 后续可评估异步导出/下载中心、导出模板自定义 |
|
||||
|
||||
## 3. 设计方案
|
||||
|
||||
> 项目采用方案 A(基于 `part_submissions` + `products` 双轨流程),方案 B 已放弃,不再纳入考虑。
|
||||
|
||||
### 方案 A:基于现有 `part_submissions` + `products` 双轨流程(已确认)
|
||||
1. **用户提交**
|
||||
- 新增用户端页面 `pages/product/submit.vue`,字段:型号(model,唯一必填)、配件名称(name)、配件参数(parameters:自由文本/JSON 字段)、图片(多图,最多 9 张)、备注。
|
||||
- 调用 `POST /api/products/submissions`,写入 `part_submissions`:`shop_id`、`user_id`、`model_unique`、`status=pending`、`images JSON`、`extra_attrs`、`created_at`。
|
||||
- 验证规则:
|
||||
- `model_unique` 同一店铺 + 全局唯一(需确认范围)。
|
||||
- 图片通过 `attachments` 保存,限制尺寸/数量。
|
||||
- 上传成功后展示提交状态(待审核)。
|
||||
2. **管理员审核**
|
||||
- 新增管理端视图 `admin/src/views/parts/Submissions.vue`:
|
||||
- 列表字段:型号、名称、提交人、提交时间、当前状态、备注、图片缩略图。
|
||||
- 过滤项:状态(待审/已审/驳回)、关键字(支持型号/名称/提交人)、提交时间区间、店铺。
|
||||
- 操作:
|
||||
- 查看详情(弹窗):可编辑名称、型号、参数、图片(增删排序)、备注。
|
||||
- 审核按钮:批准/驳回,必须填写备注(驳回)。
|
||||
- 批量导出:选中或按筛选条件导出 Excel。
|
||||
- 审核通过逻辑:
|
||||
- 检测是否存在相同型号产品:
|
||||
- 若没有:创建 `products`(source_submission_id 引用)、初始化库存 0、价格默认 0,关联图片。
|
||||
- 若已有:补充图片、参数(可覆盖或合并),并记录 submission→product 对应关系。
|
||||
- 更新 `part_submissions.status=approved`、`reviewer_id`、`reviewed_at`、`product_id`。
|
||||
- 将产品显示给提交用户(若产品属于平台库,可关联 `global_sku_id`)。
|
||||
- 审核驳回:状态=reject,记录 `remark`、`reviewer_id`、`reviewed_at`。
|
||||
3. **数据查询**
|
||||
- `GET /api/products` 增强:支持 `brand`、`model`、`status`(是否审核通过)、`createdStart/End` 等参数;返回 `{ list, total }`。
|
||||
- `GET /api/admin/parts/submissions` 支持分页+多条件,默认按创建时间倒序。
|
||||
- Excel 导出:`GET /api/admin/parts/submissions/export`,返回文件下载,支持当前过滤条件。
|
||||
4. **图片管理**
|
||||
- 提交阶段:图片存储 `attachments`,ownerType=submission,路径按 hash 去重。
|
||||
- 审核详情弹窗内使用 `el-image` + preview 功能查看大图;允许删除/新增(调用 `/api/attachments` 上传)。
|
||||
- 审核通过时同步图片至 `product_images`(可重用 attachment URL,无需复制物理文件),根据排序保存 `sort_order`。
|
||||
5. **上架逻辑**
|
||||
- 平台维护 `global_skus`(可选):
|
||||
- 审核通过界面提供“关联平台配件”下拉,或创建新平台配件,同时写入 `global_skus`。
|
||||
- `products.global_sku_id` 记录来源,供其他店铺引用。
|
||||
- 用户提交的产品通过审核后自动加入其店铺的 `products`,并可在商品列表中展示“平台推荐/自有”区分。
|
||||
|
||||
### 4.1 数据模型变更细节
|
||||
|
||||
#### part_submissions(新增/调整)
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `name` | VARCHAR(120) | 配件名称(用户填写,可用于审核) |
|
||||
| `parameters` | JSON | 结构化参数,如规格、尺寸、材质等 |
|
||||
| `images` | JSON | 图片 URL 列表,提交阶段存储 |
|
||||
| `status` | ENUM('pending','approved','rejected') | 当前审核状态 |
|
||||
| `remark` | VARCHAR(255) | 审核备注(驳回原因等) |
|
||||
| `reviewer_id` | BIGINT | 审核人 ID |
|
||||
| `reviewed_at` | DATETIME | 审核时间 |
|
||||
| `product_id` | BIGINT | 审核通过后关联的产品 ID |
|
||||
| `global_sku_id` | BIGINT | 可选,关联平台配件 ID |
|
||||
| `source_shop_id` | BIGINT | 原提交店铺(若与 shop_id 区分需求明确可保留) |
|
||||
|
||||
> 若原表已有旧字段(如 `compatible`、`size` 等),可迁移到 `parameters` JSON 中或保留以兼容老数据。
|
||||
|
||||
#### products(新增字段)
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `source_submission_id` | BIGINT | 来源提交记录 ID |
|
||||
| `global_sku_id` | BIGINT | 平台配件 ID(可选) |
|
||||
| `platform_status` | ENUM('platform','custom') | 产品来源标识(可选) |
|
||||
|
||||
需要为 `model_unique`、`shop_id` 添加唯一索引,保障型号不可重复提交(规则确定后实施)。
|
||||
|
||||
### 4.2 接口契约摘要
|
||||
|
||||
| 接口 | 方法 | 说明 | 核心入参 | 返回 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `/api/products/submissions` | POST | 用户提交配件 | `{ name, model, parameters?, images[], remark? }` | `{ id, status }` |
|
||||
| `/api/products/submissions` | GET | 用户查看提交记录 | `status?, page, size` | `{ list, total }` |
|
||||
| `/api/admin/parts/submissions` | GET | 管理端列表 | `status?, kw?, shopId?, reviewerId?, startAt?, endAt?, page, size` | `{ list, total }` |
|
||||
| `/api/admin/parts/submissions/{id}` | GET | 查看详情 | - | 详细信息(含图片) |
|
||||
| `/api/admin/parts/submissions/{id}` | PUT | 编辑字段(名称/参数/图片) | `{ name?, parameters?, images?, remark? }` | `{ ok: true }` |
|
||||
| `/api/admin/parts/submissions/{id}/approve` | POST | 审核通过 | `{ remark?, assignGlobalSkuId?, createGlobalSku? }` | `{ ok: true, productId }` |
|
||||
| `/api/admin/parts/submissions/{id}/reject` | POST | 审核驳回 | `{ remark }` | `{ ok: true }` |
|
||||
| `/api/admin/parts/submissions/export` | GET | Excel 导出 | 同列表查询参数 | 二进制文件 |
|
||||
| `/api/products` | GET | 增强查询 | `kw, brand, model, status, categoryId, startAt, endAt, page, size` | `{ list, total }` |
|
||||
|
||||
OpenAPI 需同步更新:新增路径、请求体/响应体、状态标注。
|
||||
|
||||
### 4.3 前端/后端任务拆分
|
||||
|
||||
**后端**
|
||||
1. 数据库迁移脚本(新增字段、索引、默认值)。
|
||||
2. 提交接口实现:存储提交记录、处理图片、型号唯一校验。
|
||||
3. 审核接口实现:
|
||||
- 获取详情、编辑提交记录。
|
||||
- 批准流程(创建/更新产品、同步图片、记录审计)。
|
||||
- 驳回流程。
|
||||
4. 列表查询与导出(注意权限:仅管理员)。
|
||||
5. 产品查询增强(支持多条件和 total)。
|
||||
6. 单元测试/集成测试:审核通过/驳回、重复型号、导出大数据量。
|
||||
|
||||
**管理端前端**
|
||||
1. 新建 `Submissions.vue` 页面:
|
||||
- 列表 + 搜索表单 + 分页。
|
||||
- Excel 导出按钮。
|
||||
2. 审核详情弹窗组件:
|
||||
- 多图预览/排序(Element Plus `el-image` + `el-upload` 或复用现有 `ImageUploader` 组件)。
|
||||
- 字段编辑与保存。
|
||||
- 审核通过/驳回按钮及确认弹窗。
|
||||
3. 上架结果联动:审批通过后刷新列表,提示成功。
|
||||
|
||||
**用户端前端**
|
||||
1. 新增 `pages/product/submit.vue`:
|
||||
- 表单输入 + 多图上传 + 校验(型号唯一、本地格式校验)。
|
||||
- 提交成功提示与跳转。
|
||||
2. 新增“我的提交”页面或在现有列表中添加状态指示。
|
||||
3. 货品列表/详情展示新字段(如“平台配件”标签、审核状态)。
|
||||
|
||||
## 5. 开发计划建议
|
||||
1. **第一阶段:后端改造**
|
||||
- 数据库变更(通过 MysqlMCP):更新 `part_submissions`、`products`、`global_skus` 相关字段与索引。
|
||||
- 新增接口实现(提交、审核、导出、多条件查询)。
|
||||
- 扩展 `ProductService` 支持 total、更多筛选。
|
||||
- 调整 OpenAPI,标注实现状态。
|
||||
2. **第二阶段:管理端前端**
|
||||
- 新建审核模块页面,集成组合查询 + 分页 + 导出。
|
||||
- 审核详情对话框支持多图预览/编辑、字段修改、审核按钮。
|
||||
3. **第三阶段:用户端前端**
|
||||
- 新增“提交配件”入口(从货品列表或我的模块进入)。
|
||||
- 提交表单 + 多图上传(复用 ImageUploader)。
|
||||
- 提交记录列表(待审/已通过/驳回)与状态提示。
|
||||
- 审核通过后自动同步到货品列表(带标签)。
|
||||
4. **第四阶段:测试与文档**
|
||||
- 定义审批流程测试用例:提交->审批->列表刷新->导出。
|
||||
- 验证图片上传、重复型号、并发审批场景。
|
||||
- 更新需求文档、开发文档、用户操作指引。
|
||||
|
||||
## 6. 验收标准
|
||||
- 用户端可提交配件:型号唯一校验、上传多图成功、提交后状态为“待审核”。
|
||||
- 管理端待审核列表能根据筛选条件展示结果,并支持详情查看(含大图预览、编辑字段)。
|
||||
- 管理端可对单条记录审核通过/驳回:
|
||||
- 通过:在 `products` 中生成或更新商品;提交用户在商品列表中可见;状态变更为“已通过”。
|
||||
- 驳回:状态变更为“已驳回”,记录审核备注。
|
||||
- 导出功能可按筛选条件导出 Excel,至少包含 2000 条数据测试无超时;生成文件名避免冲突(时间戳+操作人)。
|
||||
- 数据查询支持组合条件,返回总数;前后端分页一致。
|
||||
- 图片管理:审核详情中可预览大图、删除、重新上传;重复文件自动识别 hash,避免冲突。
|
||||
- 上线后数据库结构、OpenAPI、开发文档同步更新,无遗漏。
|
||||
|
||||
## 7. 风险与注意事项
|
||||
- 型号唯一性需统一标准化(去空格、大小写)并考虑跨店铺冲突策略。
|
||||
- 审核通过时同步到 `products`,需明确库存与价格的初始值(建议默认 0,提醒用户自行编辑)。
|
||||
- Excel 导出需加限流或异步处理,防止长时间请求阻塞。
|
||||
- 图片引用避免重复占用存储;可直接引用同一 URL,而非复制文件。
|
||||
- 若需消息通知(如审核结束提醒),需要后续补充通知机制。
|
||||
- 需要回顾 `global_skus` 与 `products` 的关系,明确平台配件库与用户私有货品的边界,以免数据混乱。
|
||||
|
||||
---
|
||||
> 本文档结合现状与新增需求整理。请确认方案后,可进一步拆解任务并排期执行。
|
||||
@@ -1,176 +0,0 @@
|
||||
* ### **配件查询App需求规格说明书**
|
||||
|
||||
#### 1.0 项目概述
|
||||
本项目旨在开发一款面向小微商户的移动端进销存管理应用,命名为“配件查询”。该应用核心功能是帮助用户高效管理商品、库存、销售、采购、客户、供应商及财务收支,并通过数据报表提供经营状况分析,助力商户实现数字化经营。
|
||||
参考的小程序“智慧记进销存”,但是多了一个配件查询功能,以下所罗列的内容大多也参考至该小程序,如有歧义可优先参照这个小程序,拿不准优先问。
|
||||
当前交付内容:移动端已实现基础的登录、VIP 开通、用户/客户/供应商管理、下单与报表入口;管理端完成会员、公告、咨询、配件、字典维护模块。
|
||||
|
||||
#### 2.0 功能模块需求
|
||||
|
||||
**2.1 首页 (Dashboard)**
|
||||
|
||||
* **2.1.1 核心数据概览:** 首页需直观展示当日、当月的核心经营数据。
|
||||
> 已实现基础销量/库存统计,利润汇总需依赖真实成本数据完善。
|
||||
|
||||
* 今日销售额
|
||||
* 本月销售额
|
||||
* 本月利润
|
||||
* 库存商品数量
|
||||
|
||||
**2.1.2 广告位:** 在首页区域提供一个展示广告的区域。
|
||||
> 待设计,当前保留静态占位图。
|
||||
|
||||
* **2.1.3 快捷功能入口:** 提供一个快捷功能区域,方便用户快速访问常用功能。
|
||||
* 默认应包含:客户管理、销售开单、账户管理、供应商管理、进货开单、其他支出、VIP会员、报表统计等。
|
||||
* 现状:移动端 Tab 首页已集成常用入口,后续需根据配置扩展。
|
||||
|
||||
* **2.1.4 在线客服:** 提供一个悬浮的“咨询”或“在线客服”入口,方便用户随时获取帮助。
|
||||
* 当前通过“我的-咨询”入口触达,悬浮入口尚未实现。
|
||||
|
||||
**2.2 货品管理模块**
|
||||
|
||||
* **2.2.1 货品列表与库存:**
|
||||
* 展示所有货品的列表,包含名称、库存等基本信息。
|
||||
* 支持按“全部类别”或指定类别筛选货品。
|
||||
* 提供搜索功能,支持通过货品名称或条形码进行模糊查找。
|
||||
* 列表底部显示总货品种类数量。
|
||||
* 当库存为空时,应有明显的空状态提示,并引导用户“点击右上角‘+’录入货品信息”。
|
||||
* **2.2.2 新增/编辑货品:**
|
||||
* 支持添加商品图片。
|
||||
* App端支持录入或扫描商品条形码;小程序端仅支持手动录入,不支持扫码。
|
||||
* **货品名称**为必填项。
|
||||
* 可为货品选择**类别**和**主单位**。
|
||||
* 支持自定义扩展货品属性(如品牌、型号、产地、保质期等)。
|
||||
* 货品图片支持多图上传,支持拖拽排序,支持图片放大预览。
|
||||
* 可录入**当前库存**、**安全库存**(一个数值区间,用于库存预警)。
|
||||
* 需分别录入四种价格,**进货价**、**批发价**、**大单报价**和**零售价**。
|
||||
* 提供**备注**字段,用于记录额外信息。
|
||||
* 保存后,可选择“继续新增”或返回列表。
|
||||
* **2.2.3 货品设置:**
|
||||
* 支持自定义**货品类别**管理。
|
||||
* 支持自定义**货品单位**管理。
|
||||
* 提供开关选项,允许用户选择是否“隐藏零库存商品”和“隐藏进货价”。
|
||||
|
||||
**2.3 开单(交易)模块**
|
||||
* **2.3.1 核心功能:** 该模块是应用的核心操作区,整合了销售、进货和财务记账功能。
|
||||
* **2.3.2 销售开单:**
|
||||
* **出货单:**
|
||||
* 自动记录开单**时间**,并支持手动修改。
|
||||
* 可选择**客户**,默认为“零售客户”。
|
||||
* 通过“+”号从货品列表中选择商品,自动计算**合计金额**。
|
||||
* 支持在订单中对单个商品进行操作(如修改数量、价格等)。
|
||||
* **退货单:** 用于处理客户退货业务。
|
||||
* **收款单:** 用于处理销售单的后续收款或直接创建收款记录。
|
||||
* **2.3.3 进货开单:** 用于记录从供应商处采购商品的业务流程。
|
||||
* **2.3.4 其他收入/支出:**
|
||||
* **其他收入:**
|
||||
* 支持对收入进行分类,如“销售收入”、“经营所得”、“利息收入”等。
|
||||
* 可选择**往来单位**和**结算账户**(如现金、银行等)。
|
||||
* 可添加备注并选择日期。
|
||||
* **其他支出:**
|
||||
* 支持对支出进行分类,如“经营支出”、“办公用品”、“房租”等。
|
||||
* 同样支持选择**往来单位**和**结算账户**。
|
||||
|
||||
**2.4 明细查询模块**
|
||||
* **2.4.1 维度筛选:**
|
||||
* 提供按时间维度(自定义、本周、今日、本月、本年)快速筛选单据。
|
||||
* 提供按业务类型(销售、进货、收银、资金、盘点)进行分类查看。
|
||||
* **2.4.2 单据列表:**
|
||||
* 在选定维度下,以列表形式展示所有相关单据。
|
||||
* 提供搜索功能,支持通过单据号、客户/供应商名、品名、备注等关键字查询。
|
||||
* 显示当前筛选条件下的总金额。
|
||||
* 当无数据时,提供清晰的空状态提示。
|
||||
* 提供“+”号,支持在当前分类下快速新建单据。
|
||||
|
||||
**2.5 报表统计模块**
|
||||
* **2.5.1 资金报表:**
|
||||
* **利润统计:** 分析指定时间范围内的收入、支出和利润。
|
||||
* **营业员统计:** 按销售人员维度统计销售业绩。
|
||||
* **经营业绩:** 提供综合性的经营状况分析。
|
||||
* **导入导出模块:** 提供导入导出功能方便用户切换手机或账号后仍能将旧数据导入。
|
||||
* **2.5.2 进销存报表:**
|
||||
* **销售统计:** 按商品、客户、时间等维度分析销售数据。
|
||||
* **进货统计:** 按商品、供应商、时间等维度分析采购数据。
|
||||
* **库存统计:** 提供当前库存成本、数量及分布情况的报告。
|
||||
* **应收/应付对账单:** 生成与客户和供应商的对账单据。
|
||||
|
||||
**2.6 “我的”(用户中心)模块**
|
||||
* **2.6.1 用户信息:** 显示用户头像、店铺名称、注册手机号及“老板”身份标识。
|
||||
> 个人信息读取 `/api/user/me` 已上线。
|
||||
* **2.6.2 会员与订单:**
|
||||
* 提供**VIP会员**入口,展示会员特权。
|
||||
> `/pages/my/vip` 已接入 `/api/vip/status`,开通调用 `/api/vip/pay`。
|
||||
* 提供**我的订单**入口,可能用于查看应用内服务订单。
|
||||
> 入口预留,服务订单接口尚未上线。
|
||||
* **2.6.3 基础管理:**
|
||||
* **供应商管理**
|
||||
* **客户管理**
|
||||
* **客户报价**
|
||||
* **店铺管理**
|
||||
* **2.6.4 设置中心:**
|
||||
* **账号与安全:**
|
||||
* 修改个人信息(头像、姓名)。
|
||||
* 修改登录密码。
|
||||
* **商品设置:**
|
||||
* **系统参数:**
|
||||
* 提供多种业务逻辑开关,如:“销售价低于进货价时提示”、“销售单默认全部收款”、“启用单行折扣”、“启用客户/供应商双身份”。
|
||||
* **关于与协议:** 包含“关于我们”、“隐私协议”、“个人信息安全投诉”等静态页面。
|
||||
* **账号操作:** 提供“账号注销”和“退出登录”功能。
|
||||
|
||||
#### 3.0 全局性需求
|
||||
|
||||
* **3.1 导航:** 采用底部Tab栏导航,包含“首页”、“货品”、“开单”、“明细”、“我的”五个主要模块。
|
||||
> uni-app 端已实现,管理端采用侧栏导航。
|
||||
* **3.2 统一的UI/UX:** 应用整体风格简洁、清晰,操作流程符合移动端使用习惯。
|
||||
* **3.3 空状态页面:** 在列表、报表等数据为空的页面,需提供友好的空状态提示图和引导性文字。
|
||||
* **3.4 数据同步:** 应用数据应在云端同步,保证用户更换设备或多设备使用时数据一致性。
|
||||
* **3.5 多租户数据隔离:** 所有业务数据按店铺(租户)隔离,用户不可访问他人数据。
|
||||
* 所有业务表需包含`user_id`并在读取/写入中强制按`user_id`过滤。
|
||||
* 支持租户内角色与权限控制;导出仅限本租户数据。
|
||||
* **3.6 公共SKU(全局商品库)众包与审核:** 全体用户共同补充、纠错SKU,经审核发布为全局可选SKU。
|
||||
* 用户可提交“新增SKU/编辑建议”,进入审核流(草稿/待审/驳回/发布/下架)。
|
||||
* 全局SKU字段:名称、品牌、规格、条码、主单位、图片、别名、分类标签等。
|
||||
* 各用户通过“本地商品”引用全局SKU,并保留本地私有字段(价格、库存、分类、单位换算、条码别名等)。
|
||||
* **3.7 商品模糊查询(增强):** 在货品列表、开单选品、对账等场景支持多字段模糊匹配。
|
||||
* 支持名称/条码/别名/拼音/品牌/规格模糊匹配,并高亮命中片段。
|
||||
* 支持全局SKU与本地商品联合检索,优先展示本地商品;结果可分页。
|
||||
* 需满足大规模SKU下的性能目标;可通过系统参数配置匹配策略。
|
||||
|
||||
* **3.8 客户端平台:** 提供移动App与小程序;小程序不支持商品条形码扫描功能。
|
||||
> HBuilderX 打包的 App 版本与微信小程序版本已具备扫描差异处理;条码识别仅用户端调用。
|
||||
|
||||
* **3.9 多列销售价格:** 销售价格分四列,即同一种商品有四个销售价格
|
||||
|
||||
### 配件查询
|
||||
|
||||
1. **数据查询功能**
|
||||
- 多参数组合查询(分类、尺寸、型号等)
|
||||
- 模糊匹配关键字
|
||||
- 分页展示查询结果
|
||||
- 一键导出Excel数据
|
||||
2. **数据提交系统**
|
||||
- 用户提交新配件数据
|
||||
- 型号为唯一必填项
|
||||
- 支持图片上传
|
||||
- 提交后等待管理员审核
|
||||
3. **审核管理系统**
|
||||
- 管理员查看待审核列表
|
||||
- 可编辑所有字段
|
||||
- 支持图片更新和删除
|
||||
- 一键批准或拒绝提交
|
||||
4. **图片管理系统**
|
||||
- 每条数据可关联多张图片
|
||||
- 点击图片可放大查看
|
||||
- 管理员可管理所有图片
|
||||
- 自动处理文件名冲突
|
||||
|
||||
## 全局说明(必看)
|
||||
|
||||
由于这个文档写的还不是很完善,目前有存疑的部分先行参考小程序小程序“智慧记进销存”(功能和按钮可以参考,界面样式除外),管理端文档目前待定。
|
||||
|
||||
客户要求的是做双端应用(app端+小程序端),需要考虑兼容性相关问题。
|
||||
|
||||
本程序和“智慧记进销存”大多一致,主要的区别在于客户有配件查询要求,即在产品页面中要额外加一个配件查询按钮或入口,且要求一个产品要有四个销售价格(先按零售价 分销价 批发价 大客户价),且要求能自定义添加各种规格(尺寸,孔径等)。
|
||||
|
||||
有疑惑的部分一定要及时沟通(如未提及的页面和功能需要确认的时候)
|
||||
|
||||
@@ -1,331 +0,0 @@
|
||||
### VIP 功能开发文档
|
||||
|
||||
#### 1. 范围与目标
|
||||
- 目标:为“配件查询”应用提供面向店铺(租户)的会员体系(VIP),支持会员开通、审核、生效与到期管理,并为后续增值能力(如数据永久存储、高级报表、优先审核等)提供统一的权限判定入口。
|
||||
- 范围:后端服务与管理端优先落地;移动端展示会员状态与开通入口,后续再接入支付与自动续期。
|
||||
|
||||
#### 2. 现状与差距
|
||||
- 前端 App:`frontend/pages/my/vip.vue` 当前为静态演示页,读取 `VIP_PRICE_PER_MONTH` 展示,未接入后端状态与支付。
|
||||
- 管理端:已存在页面
|
||||
- `admin/src/views/vip/VipList.vue`:查询、编辑、启停。
|
||||
- `admin/src/views/vip/VipReview.vue`:列出待启用(审核)并提供通过/驳回。
|
||||
- 后端:`AdminVipController` 提供基础接口:列表、创建、更新、审核通过/驳回(部分实现)。依赖表 `vip_users`。
|
||||
- OpenAPI:`/doc/openapi.yaml` 已定义管理端 VIP 接口,标注为「❌ Partially Implemented」。
|
||||
- 数据库:本地 `backend/db/db.sql` 尚未创建 `vip_users` 表;而远程数据库文档 `/doc/database_documentation.md` 已包含该表结构。这是“脚本未对齐线上库”的差距,需要弥合(见实施计划)。
|
||||
|
||||
#### 3. 业务与权限
|
||||
- 归属维度:VIP 为“用户级”。每个用户仅归属一个店铺(无店员概念)。
|
||||
- 状态定义:
|
||||
- `isVip`:是否为会员标记(1/0)。
|
||||
- `status`:启用状态(1=生效,0=未启用/停用)。
|
||||
- `expireAt`:到期时间(为空代表永久或未设置)。
|
||||
|
||||
#### 4. 数据模型设计(多方案)
|
||||
- 方案A:单表 `vip_users`
|
||||
- 字段:`id, shop_id, user_id, is_vip, status, expire_at, remark, reviewer_id, reviewed_at, created_at, updated_at`
|
||||
- 优点:简单直观,满足当前开通/续期/停用/审核的核心需求。
|
||||
- 局限:后续若需要等级(gold/platinum)、付费订单、优惠券、权益包等,需要再扩展新表。
|
||||
- 方案B:三表拆分(推荐用于中长期)
|
||||
- `vip_users`(会员资格)、`vip_levels`(等级/权益配置)、`vip_orders`(开通/续费订单记录)。
|
||||
- 优点:扩展性好,可平滑引入支付渠道、对账、活动定价。
|
||||
- 初期实施成本更高。可采用“增量演进”:先落地方案A,同步预留 `vip_orders` 的接口草案与库表蓝图,待支付接入时启用。
|
||||
|
||||
当前建议:首期采用方案A,满足“开通-审核-生效-到期”的MVP;同时在配置中预留价格与时长,便于后续衔接 `vip_orders`。
|
||||
|
||||
#### 5. 配置与价格策略(严禁硬编码)
|
||||
- 前端价格:已通过 `frontend/common/config.js` 的 `VIP_PRICE_PER_MONTH` 从环境变量/本地存储读取,默认 15 元/月。
|
||||
- 后端价格与时长建议:通过 `system_parameters` 表维护,键建议:
|
||||
- `vip.price`(单位:元/月,number)
|
||||
- `vip.durationDays`(开通/续费时长,默认 30)
|
||||
- 可选:`vip.trialDays`(试用天数,默认 0)
|
||||
- 后端读取优先级:系统参数 > 环境变量(如 `VIP_PRICE`,`VIP_DURATION_DAYS`)> 安全默认值;并通过管理端配置面板维护参数(后续迭代)。
|
||||
|
||||
管理员端价格设置(新增):
|
||||
- 平台统一价,存储于表 `vip_price`(仅一条记录)。
|
||||
- 在管理端“VIP管理”新增“价格设置”入口:读取/修改 `vip_price.price`。
|
||||
- 修改保存后立即生效;前端价格展示以后端返回为准(避免前后端不一致)。
|
||||
|
||||
#### 6. 接口契约(与 openapi.yaml 对齐)
|
||||
- 管理端:
|
||||
- GET `/api/admin/vips`(列表)
|
||||
- POST `/api/admin/vips`(新增)
|
||||
- PUT `/api/admin/vips/{id}`(更新 isVip/status/expireAt/remark)
|
||||
- 审核流程已取消(approve/reject 已移除);统一由用户端一键开通或管理员直接设置。
|
||||
- App(建议新增,未在 openapi.yaml 中登记,待一方开工后再登记):
|
||||
- GET `/api/vip/status`:返回当前用户 VIP 状态与到期时间。
|
||||
- POST `/api/vip/pay`:一键支付并立即开通(临时方案:点击即视为支付成功,直接写入/更新 `vip_users`,置 `status=1,isVip=1,expireAt=now+durationDays`;后续接入真实支付将替换该接口实现)。
|
||||
- 说明:上述 App 接口仅为“建议方案”,在前端或后端开始实现后再将其写入 `/doc/openapi.yaml` 并标注实现状态,避免“仅设计未实现”的文档污染。
|
||||
|
||||
示例返回(状态查询):
|
||||
```json
|
||||
{
|
||||
"isVip": true,
|
||||
"status": 1,
|
||||
"expireAt": "2025-12-31T23:59:59Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### 7. 前后端对接要点
|
||||
- Header:管理端接口需要 `X-User-Id`(用于写入审核人);多租户场景下优先根据用户解析 `shop_id`,或显式传递 `X-Shop-Id`。
|
||||
- 列表过滤:`phone` 模糊匹配 `users.phone`,`status` 精确匹配 `vip_users.status`。
|
||||
- 审核流:通过/驳回接口必须记录 `reviewer_id` 与 `reviewed_at`,便于审计。
|
||||
- App 端状态展示:进入“我的-会员”页时调用 `GET /api/vip/status`,根据返回值展示“已激活/有效期至/立即开通”。
|
||||
|
||||
##### 7.1 数据可见性与留存策略(关键新增)
|
||||
- 规则:
|
||||
- VIP 用户:可查看“所有历史数据”(不做时间裁剪)。
|
||||
- 普通用户:仅显示“最近两个月内”的数据,早于两个月的数据不显示。
|
||||
- 配置项(严禁硬编码):
|
||||
- `vip.dataRetentionDaysForNonVip`(默认 60,单位:天)写入 `system_parameters`;也可通过环境变量 `VIP_NONVIP_RETENTION_DAYS` 覆盖。
|
||||
- 当该值小于等于 0 时,视为“非VIP也不做裁剪”(便于灰度/应急)。
|
||||
- 后端落地建议:
|
||||
- 在列表/查询型接口(如 `/api/orders`, `/api/purchase-orders`, `/api/payments`, `/api/inventories/logs`, `/api/other-transactions` 等)统一增加“非VIP数据时间窗”约束:
|
||||
- 通过当前用户的 VIP 状态与 `expireAt` 判断是否 VIP;非VIP则在 SQL WHERE 中增加 `tx_time/order_time >= NOW() - INTERVAL retentionDays DAY` 等条件。
|
||||
- 采用服务层统一拦截/拼接过滤,避免各控制器重复实现。
|
||||
- 在导出/报表接口同样应用该约束,确保口径一致。
|
||||
- 前端落地建议:
|
||||
- 当非VIP进行跨越两个月以上的日期筛选时,给出轻提示:“普通用户仅显示近两个月数据,开通VIP可查看全部历史”。
|
||||
- 页面不做本地硬裁剪,一切以后端约束为准,前端仅用于用户沟通与引导开通。
|
||||
|
||||
#### 8. 业务流程(Graphviz)
|
||||
```dot
|
||||
digraph G {
|
||||
rankdir=LR;
|
||||
node [shape=box, style=rounded];
|
||||
start [label="用户进入VIP页"];
|
||||
pay [label="一键支付开通\n(POST /api/vip/pay)"];
|
||||
active [label="生效: status=1, isVip=1\n设置expireAt=now+durationDays"];
|
||||
expire [label="到期: 定时任务或登录判定\n自动置 isVip=0 / 提示续期"];
|
||||
|
||||
start -> pay -> active -> expire;
|
||||
}
|
||||
```
|
||||
|
||||
#### 9. 实施计划(MVP)
|
||||
1) 数据库脚本对齐(仅通过 MysqlMCP 执行)
|
||||
- 若目标库缺失 `vip_users`:按 `/doc/database_documentation.md` 定义创建,并补充必要索引与外键。
|
||||
- 备注:执行后同步更新 `/doc/database_documentation.md` 中的更新时间与差异说明(保持与线上一致)。
|
||||
2) 后端接口完备
|
||||
- 补齐 `AdminVipController` 的参数校验、店铺隔离、分页 total 统计(可选)。
|
||||
- 新增 App 侧接口:`GET /api/vip/status` 与 `POST /api/vip/pay`(点击即开通临时方案)。当开始实现后,将路径登记至 `/doc/openapi.yaml` 并标注状态。
|
||||
- 配置读取:接入 `system_parameters` 的 `vip.price`/`vip.durationDays`。
|
||||
3) 管理端接入
|
||||
- `VipList.vue` 与 `VipReview.vue` 接口字段对齐;在创建/编辑时透传 `shopId`(或后端根据用户解析)。
|
||||
- 在“VIP管理”中新增“价格设置”对话框:读取/修改 `vip.price`(走系统参数接口或新增专用接口)。
|
||||
4) App 接入
|
||||
- `pages/my/vip.vue` 调用 `GET /api/vip/status`;“立即开通”改为调用 `POST /api/vip/pay`(临时:点击即开通)。
|
||||
5) 定时/登录时到期检查
|
||||
- 每日定时任务或用户登录时,对已到期记录置 `isVip=0` 并提示续期(可由查询接口实时判断并回写)。
|
||||
|
||||
#### 10. 测试用例(核心)
|
||||
- 列表:无过滤/按手机号/按状态返回正确集合;分页稳定。
|
||||
- 新增:缺少 `shopId`/`userId` 报错;完整入参成功写入,`status=0` 待启用。
|
||||
- 更新:仅更新传入字段,`updated_at` 变更。
|
||||
- 审核:通过后 `status=1` 且记录 `reviewer_id/reviewed_at`;驳回后 `status=0`。
|
||||
- 到期:`expireAt < now()` 时,状态查询返回 `isVip=false`(或提示续期),符合设计。
|
||||
- 数据可见性:
|
||||
- 非VIP:订单/支付/库存流水/其他收支等查询接口,返回记录的最早时间不早于“当前时间-60天”(默认值);当调整 `vip.dataRetentionDaysForNonVip` 后行为随之变化。
|
||||
- VIP:在同样条件下可查询到两个月前的历史记录。
|
||||
- 前端在选择超窗的日期范围时出现轻提示,不影响接口正常返回。
|
||||
- 一键支付开通:
|
||||
- 点击开通后接口返回成功,`vip_users` 写入/更新,`status=1,isVip=1,expireAt=now+durationDays`。
|
||||
- 再次点击在有效期内应提示“已是VIP/延长有效期”,并将 `expireAt` 顺延 `durationDays`(若设计为续期)。
|
||||
- 管理端价格设置:
|
||||
- 读取当前价格成功显示;修改后保存成功,重新读取为新值;前端展示同步更新(以接口返回为准)。
|
||||
|
||||
#### 11. 非功能性要求
|
||||
- 审计:记录审核人与审核时间。
|
||||
- 性能:常用过滤列建索引(`shop_id,status`)。
|
||||
- 安全:所有接口在租户维度强制鉴权与隔离;仅店主/平台管理员可审核。
|
||||
|
||||
#### 12. 验收标准
|
||||
- 管理端可增改查 VIP,支持启停与审核通过/驳回。
|
||||
- App 可正确显示会员状态与有效期,支持提交开通申请。
|
||||
- 配置可通过参数调整价格与时长,无任何硬编码常量。
|
||||
- OpenAPI 中 VIP 路径状态标注准确,接口字段与实现一致。
|
||||
- 数据可见性:非VIP仅显示近两个月数据;VIP显示全部历史;可通过系统参数动态调整非VIP留存天数。
|
||||
- 一键支付:点击立即开通可直接成为VIP并设置到期时间;有效期内再次开通实现续期(如有设计)。
|
||||
- 价格设置:管理员可在“VIP管理”中读取/修改VIP价格,保存后前端价格展示与后端一致。
|
||||
|
||||
#### 13. 普通管理员(Admin-Lite)与申请机制(新增需求)
|
||||
|
||||
- 背景:在现有平台管理员(`admins` 表)之外,新增“普通管理员(Normal Admin)”,供用户端的 VIP 用户申请成为普通管理员后,登录一个精简的普通管理端(admin-lite)。
|
||||
- 目标:
|
||||
- 普通管理端仅包含“配件审核”与“我的”两个功能。
|
||||
- 普通管理员使用“用户端账号(邮箱 + 密码)”登录普通管理端。
|
||||
- 申请资格:仅限 VIP(且建议要求处于有效期内)。
|
||||
|
||||
##### 13.1 业务规则
|
||||
- 申请前置:用户必须为 VIP 用户(建议校验 `vip_users.status=1` 且 `expire_at>now()`)。
|
||||
- 审批策略(多方案):
|
||||
- 方案A(推荐)平台审核:提交申请→平台管理员审核→通过后赋予“普通管理员”权限。
|
||||
- 方案B 自动通过:成为 VIP 后点击“申请”即自动获取权限(适合早期冷启动)。
|
||||
- 方案C 店主审核:若后续引入“店主/员工”角色体系,可由店主审批本店普通管理员。
|
||||
- 有效性约束(推荐):普通管理员权限与 VIP 状态绑定;当 VIP 过期则自动失去普通管理员权限(或进入“受限”状态,仅保留查看)。
|
||||
- 范围隔离:普通管理员仅可访问其所属店铺 `shop_id` 范围内的资源(含配件提交与审核)。
|
||||
|
||||
##### 13.2 数据模型(多方案)
|
||||
- 方案A:复用 `users.role`,并新增审计表(快速落地)
|
||||
- `users.role` 可写入 `normal_admin` 作为标识;新增 `normal_admin_audits` 记录申请、审批与撤销流水。
|
||||
- 优点:改动小,落地快。
|
||||
- 风险:`role` 单值扩展性差,后续多角色并存不便。
|
||||
- 方案B:新增 `user_roles`(推荐中长期)
|
||||
- 结构:`id, user_id, role, status, created_at, updated_at`,可并存多个角色;配套 `user_role_audits` 留痕。
|
||||
- 优点:扩展性强,便于细粒度权限。
|
||||
- 成本:需要通用角色判定与拦截器改造。
|
||||
- 方案C:新增 `normal_admins`
|
||||
- 结构:`id, shop_id, user_id, status, expire_at(可选), remark, reviewer_id, reviewed_at, created_at, updated_at`
|
||||
- 优点:语义清晰;可直接与 VIP 绑定。
|
||||
- 成本:专用表+专用逻辑,通用性略弱。
|
||||
|
||||
当前建议:MVP 采用方案A或C(二选一),优先保证上线速度;后续演进到方案B以支撑更多角色与权限。
|
||||
|
||||
配置项(严禁硬编码,写入 `system_parameters` 或全局参数表):
|
||||
- `normalAdmin.autoApprove`:是否自动通过申请(默认 false)。
|
||||
- `normalAdmin.requiredVipActive`:是否要求 VIP 有效期内(默认 true)。
|
||||
|
||||
##### 13.3 接口契约(开始实现任一侧后同步登记至 `/doc/openapi.yaml` 并标注状态)
|
||||
- 用户端(App/小程序):
|
||||
- POST `/api/normal-admin/apply`:提交申请。需要登录且满足 VIP 条件;根据 `normalAdmin.autoApprove` 决定是否即时生效。
|
||||
- GET `/api/normal-admin/application/status`:查询本人申请状态与生效情况。
|
||||
- 平台管理端:
|
||||
- GET `/api/admin/normal-admin/applications`:申请列表(支持状态/关键词/时间范围)。
|
||||
- POST `/api/admin/normal-admin/applications/{id}/approve`:审批通过。
|
||||
- POST `/api/admin/normal-admin/applications/{id}/reject`:审批驳回(需备注)。
|
||||
- 普通管理端鉴权(见 13.4):
|
||||
- 登录沿用用户侧认证:`POST /api/auth/email/login` 或现有登录接口,后端签发 Token 时加入 `scope`/`role` 标识(如 `normal_admin`)。
|
||||
|
||||
示例返回(申请状态):
|
||||
```json
|
||||
{ "status": "approved", "isVip": true, "vipExpireAt": "2025-12-31T23:59:59Z" }
|
||||
```
|
||||
|
||||
##### 13.4 鉴权与拦截(Admin-Lite)
|
||||
- 新增拦截器 `NormalAdminAuthInterceptor`(或等效过滤器):
|
||||
- 校验登录 Token 为用户侧 Token;读取 `role/scope` 含 `normal_admin`。
|
||||
- 若启用 `normalAdmin.requiredVipActive`:同时校验 `vip_users` 有效。
|
||||
- 强制多租户隔离:将 `shop_id` 固化为当前用户所属店铺,杜绝越权访问。
|
||||
- 路由命名建议:`/api/normal-admin/**` 与平台 `/api/admin/**` 区隔;服务层可复用同一业务逻辑。
|
||||
- 兼容方案:若短期沿用现有 `/api/admin/parts/submissions*`,需在后端根据 Token 类型与 `shop_id` 自动收敛到本店数据(不建议长期共用)。
|
||||
|
||||
##### 13.5 普通管理端(admin-lite)前端
|
||||
- 技术栈:Vue3 + Vite + Element Plus,与现管理端一致;新建 `normal-admin/` 工程或在现有 `admin/` 下以独立入口构建。
|
||||
- 模块:
|
||||
- 配件审核:复制 `admin/src/views/parts/Submissions.vue`,仅保留必要字段与操作;HTTP 基址指向 `/api/normal-admin/...`(或复用后端别名);列表限定为本店数据。
|
||||
- 我的:展示账户信息、VIP 状态、普通管理员状态、退出登录;若未获批且为 VIP,显示“申请成为普通管理员”按钮(调用 `/api/normal-admin/apply`)。
|
||||
- 路由示例:
|
||||
- `/` → 重定向 `/parts/submissions`
|
||||
- `/parts/submissions` → 审核页
|
||||
- `/my` → 我的
|
||||
- 配置(环境变量,不得硬编码):
|
||||
- `VITE_APP_TITLE=配件审核(普通管理端)`
|
||||
- `VITE_API_BASE=/api`(与部署网关一致)
|
||||
- `VITE_ENABLE_EXPORT=true/false`(是否开启导出)
|
||||
|
||||
##### 13.6 流程图(Graphviz)
|
||||
```dot
|
||||
digraph G {
|
||||
rankdir=LR;
|
||||
node [shape=box, style=rounded];
|
||||
a[label="成为VIP\n(GET /api/vip/status)"];
|
||||
b[label="申请普通管理员\n(POST /api/normal-admin/apply)"];
|
||||
c[label="平台审批/自动通过\n(根据 normalAdmin.autoApprove)"];
|
||||
d[label="获得 normal_admin 权限\n(Token 含 scope)"];
|
||||
e[label="登录普通管理端\n(邮箱+密码)"];
|
||||
f[label="配件审核\n(/api/normal-admin/parts/submissions*)"];
|
||||
|
||||
a -> b -> c -> d -> e -> f;
|
||||
}
|
||||
```
|
||||
|
||||
##### 13.7 验收标准(Admin-Lite)
|
||||
- 登录:使用用户邮箱+密码成功登录普通管理端;非普通管理员登录被拒绝并提示申请。
|
||||
- 资格:非 VIP 点击“申请”提示需先成为 VIP;VIP 点击“申请”按配置自动通过或进入待审;审批通过后刷新权限可访问。
|
||||
- 范围:仅能查看与操作本店 `shop_id` 范围内的配件提交;越权访问被拦截。
|
||||
- 审核:通过/驳回、备注、图片管理、参数编辑等操作与现管理端一致;操作成功刷新列表。
|
||||
- 导出(可选):按配置开放导出功能,文件名与权限口径与现实现一致。
|
||||
- 退化:当 VIP 失效时,若配置为强绑定,应在下一次鉴权时移除 `normal_admin` 访问权限(或降级为只读)。
|
||||
|
||||
##### 13.8 实施计划(补充)
|
||||
1) 后端:
|
||||
- 新增 `NormalAdminAuthInterceptor` 与 `/api/normal-admin/**` 路由;实现申请接口与(可选)平台审批接口;复用配件审核服务,默认按当前用户 `shop_id` 限定范围。
|
||||
- Token 扩展:在用户侧登录成功时,根据数据库角色写入 `role/scope=normal_admin`。
|
||||
- 配置读取:接入 `normalAdmin.autoApprove`、`normalAdmin.requiredVipActive`(来自 `system_parameters` 或全局参数表)。
|
||||
2) 前端(admin-lite):
|
||||
- 建立最小可用工程,复制并精简 `Submissions.vue`;新增 `My.vue`;完善登录页与路由守卫(未授权跳转登录)。
|
||||
- “我的”页集成申请按钮与状态显示;成功后刷新权限并跳转审核页。
|
||||
3) 文档与 OpenAPI:
|
||||
- 任一侧开工后,将上述接口登记至 `/doc/openapi.yaml` 并标注实现状态(❌/✅)。
|
||||
|
||||
##### 13.9 风险与注意事项
|
||||
- 权限收敛:严禁普通管理员访问跨店铺数据;所有查询/导出在服务层统一追加 `shop_id=当前用户.shop_id` 条件。
|
||||
- 身份冲突:若同一用户既是平台管理员又是普通管理员,需优先以平台后台入口登录对应端;两个端的 Token/域名/路由需区分。
|
||||
- 续期与降级:明确 VIP 失效后的权限处理策略与用户提示文案,避免误用。
|
||||
- 审计留痕:申请/审批/撤销必须入审计表;审核操作记录操作人与时间。
|
||||
|
||||
##### 13.10 选型落地(方案A)
|
||||
- 选型结论:
|
||||
- 审批策略采用「方案A(平台审核)」:提交申请→平台管理员审核→通过后赋予“普通管理员”权限。
|
||||
- 数据模型采用「方案A(复用 `users.role` + 审计表)」:当前生效权限以 `users.role` 为准,申请/审批/撤销全量留痕于审计表。
|
||||
|
||||
- 审计表 DDL(提交后通过 MysqlMCP 执行;此处为权威定义,禁止硬编码):
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS normal_admin_audits (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
shop_id BIGINT UNSIGNED NOT NULL,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
action ENUM('apply','approve','reject','revoke','expire') NOT NULL,
|
||||
remark VARCHAR(255) NULL,
|
||||
operator_admin_id BIGINT UNSIGNED NULL COMMENT '平台管理员ID(apply时可空)',
|
||||
previous_role VARCHAR(32) NULL,
|
||||
new_role VARCHAR(32) NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_naudit_shop_time (shop_id, created_at),
|
||||
KEY idx_naudit_user_time (user_id, created_at),
|
||||
CONSTRAINT fk_naudit_shop FOREIGN KEY (shop_id) REFERENCES shops(id),
|
||||
CONSTRAINT fk_naudit_user FOREIGN KEY (user_id) REFERENCES users(id),
|
||||
CONSTRAINT fk_naudit_admin FOREIGN KEY (operator_admin_id) REFERENCES admins(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='普通管理员申请/审批审计日志';
|
||||
```
|
||||
|
||||
- 状态判定与待办列表(基于审计流,不单独建申请表):
|
||||
- 当前状态 = 按 `user_id` 取最后一条审计记录的 `action`。
|
||||
- 待审批 = 最后一条为 `apply` 且其后没有 `approve/reject`。
|
||||
- 失效处理 = 定时或登录时检测 VIP 过期,若配置 `normalAdmin.requiredVipActive=true`,写入 `expire` 审计并触发降级(见下)。
|
||||
|
||||
- 接口约定细化(开始实现任一侧后再登记至 `/doc/openapi.yaml` 并标注状态):
|
||||
- 用户申请:POST `/api/normal-admin/apply`
|
||||
- 校验:已登录 + VIP 有效(当 `requiredVipActive=true`)。
|
||||
- 行为:写入 `normal_admin_audits(action='apply')`;若 `autoApprove=true` 则转调用审批通过流程。
|
||||
- 审批列表:GET `/api/admin/normal-admin/applications`
|
||||
- 规则:按照审计记录推导“当前为 apply 且未被approve/reject”的记录;支持关键词与时间过滤;返回 `{ list, total }`。
|
||||
- 审批通过:POST `/api/admin/normal-admin/applications/{userId}/approve`
|
||||
- 行为:读取当前 `users.role` 记为 `previous_role`;更新 `users.role='normal_admin'`;写入审计 `approve`(含 `previous_role/new_role`)。
|
||||
- 审批驳回:POST `/api/admin/normal-admin/applications/{userId}/reject`
|
||||
- 行为:写入审计 `reject`(需 remark)。
|
||||
- 撤销权限:POST `/api/admin/normal-admin/users/{userId}/revoke`
|
||||
- 行为:将 `users.role` 回滚到最近一次 `approve` 的 `previous_role`(若不存在则设为 `'staff'` 或根据 `is_owner` 退回 `'owner'`);写入审计 `revoke`。
|
||||
|
||||
- 鉴权与Token(Admin-Lite):
|
||||
- 登录沿用用户端登录接口(邮箱/密码),签发 Token 时附带 `role` 与 `shopId`;Admin-Lite 入口要求 `role='normal_admin'`。
|
||||
- 在拦截器 `NormalAdminAuthInterceptor` 中:
|
||||
- 校验 `role='normal_admin'`;若 `requiredVipActive=true`,同时校验当前用户 VIP 有效。
|
||||
- 将请求上下文中的 `shop_id` 固化为当前用户 `shop_id`,所有查询自动拼接该条件。
|
||||
|
||||
- 失效与回滚策略:
|
||||
- 当 VIP 过期(检测点:每日任务/登录/接口访问拦截),若启用强绑定则触发降级:
|
||||
- 将 `users.role` 由 `normal_admin` 回滚至上次 `approve` 的 `previous_role`(若无记录:`is_owner=1` 回滚到 `'owner'`,否则 `'staff'`)。
|
||||
- 写入 `expire` 审计(remark 记录触发缘由)。
|
||||
|
||||
- 风险与缓解(方案A局限):
|
||||
- `users.role` 为单值字段,无法并存多角色;短期仅用于识别 Admin-Lite 访问权限,不影响用户侧功能(用户侧权限建议依赖 `is_owner` 与接口授权)。
|
||||
- 后续若需多角色并存,按 13.2 的方案B 迁移至 `user_roles`,并在迁移期间保留写入 `users.role` 的兼容逻辑。
|
||||
|
||||
- 测试要点补充:
|
||||
- 申请→审批通过:审计有 `apply`、`approve` 两条,`users.role` 变为 `normal_admin`,Admin-Lite 可登录访问。
|
||||
- 申请→驳回:审计有 `apply`、`reject`,`users.role` 不变,Admin-Lite 拒绝访问。
|
||||
- 撤销:`users.role` 回滚为 `previous_role`,新增 `revoke` 审计;再次访问被拒绝。
|
||||
- VIP 过期:若强绑定开启,触发降级并写入 `expire`,Admin-Lite 访问被拒绝;关闭强绑定时仅告警不降级。
|
||||
|
||||
—— 本文档为当前功能实现说明与落地细节,不含历史变更记录;如有与数据模型不匹配之处,以 `/doc/database_documentation.md` 为准并及时校准。
|
||||
139
doc/后端使用文档.md
139
doc/后端使用文档.md
@@ -1,139 +0,0 @@
|
||||
https://icons8.com/
|
||||
|
||||
### 后端使用文档(简版)
|
||||
|
||||
本文件用于指导在新电脑上启动 Spring Boot 后端,并直接连接远程 MySQL 数据库。
|
||||
|
||||
### 环境要求
|
||||
- **操作系统**: Windows 10/11(PowerShell)
|
||||
- **JDK**: 17 及以上(`java -version` 应显示 17+)
|
||||
- **网络**: 可访问 `mysql.tonaspace.com:3306`
|
||||
- **构建工具**: 无需单独安装 Maven(项目已提供 `mvnw.cmd`)
|
||||
|
||||
### 快速启动(默认连接远程库)
|
||||
1) 打开 PowerShell,进入项目后端目录:
|
||||
```powershell
|
||||
cd backend
|
||||
```
|
||||
2) 启动后端(使用默认远程数据库配置):
|
||||
```powershell
|
||||
.\mvnw.cmd spring-boot:run -DskipTests
|
||||
```
|
||||
> 说明:`application.properties` 已内置远程库默认值(`DB_URL/DB_USER/DB_PASSWORD`)。除非你的终端已设置了同名环境变量并想覆盖,否则无需再配置。
|
||||
|
||||
### 启动 Python 条码识别服务(可选)
|
||||
|
||||
本项目提供 Python 条码识别服务(FastAPI,目录 `backend/txm`),可与 Java 同时启动或独立启动。
|
||||
|
||||
- 独立启动(推荐先验证):
|
||||
```powershell
|
||||
cd .\backend\txm; python -m pip install -r requirements.txt; python -m app.server.main
|
||||
```
|
||||
|
||||
- 随 Java 一并启动(通过环境变量启用;默认关闭):
|
||||
```powershell
|
||||
$env:PY_BARCODE_ENABLED="true"; $env:PY_BARCODE_WORKDIR=".\txm"; $env:PY_BARCODE_PYTHON="python"; .\mvnw.cmd spring-boot:run -DskipTests
|
||||
```
|
||||
|
||||
可覆盖的相关配置键(同名环境变量可覆盖,括号为默认值):
|
||||
|
||||
```
|
||||
python.barcode.enabled=${PY_BARCODE_ENABLED:false}
|
||||
python.barcode.working-dir=${PY_BARCODE_WORKDIR:./txm}
|
||||
python.barcode.python=${PY_BARCODE_PYTHON:python}
|
||||
python.barcode.app-module=${PY_BARCODE_APP_MODULE:app.server.main}
|
||||
python.barcode.use-module-main=${PY_BARCODE_USE_MODULE:true}
|
||||
python.barcode.host=${PY_BARCODE_HOST:127.0.0.1}
|
||||
python.barcode.port=${PY_BARCODE_PORT:8000}
|
||||
python.barcode.health-path=${PY_BARCODE_HEALTH:/openapi.json}
|
||||
python.barcode.startup-timeout-sec=${PY_BARCODE_TIMEOUT:20}
|
||||
python.barcode.log-file=${PY_BARCODE_LOG:}
|
||||
```
|
||||
|
||||
Java 侧代理接口:`POST /api/barcode/scan`(表单字段名:`file`)。
|
||||
返回:
|
||||
|
||||
```
|
||||
{
|
||||
success: true,
|
||||
barcodeType: 'EAN13' | 'CODE128' | 'QRCODE' | ...,
|
||||
barcode: '字符串',
|
||||
others: [{ type, code }, ...] // 可能为空
|
||||
}
|
||||
```
|
||||
|
||||
说明:优先 EAN-13,否则返回任意码制的第一个结果,并同时返回 others。
|
||||
|
||||
### 可选:显式指定远程数据库(避免被旧环境变量覆盖)
|
||||
如需显式声明一次连接信息(建议在怀疑本机已有旧变量时使用):
|
||||
```powershell
|
||||
$env:DB_URL="jdbc:mysql://mysql.tonaspace.com:3306/partsinquiry?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8mb4&connectionCollation=utf8mb4_0900_ai_ci"; $env:DB_USER="root"; $env:DB_PASSWORD="TONA1234"
|
||||
.\mvnw.cmd spring-boot:run -DskipTests
|
||||
```
|
||||
|
||||
### 启动验证
|
||||
- 浏览器访问:`http://localhost:8080/api/dashboard/overview`
|
||||
- 返回概览数据即表示服务与数据库连接正常
|
||||
|
||||
### 按用户ID登录(用户端快速登录通道)
|
||||
> 仅在调试或特定场景启用。默认关闭。
|
||||
|
||||
1) 启用开关(临时):
|
||||
```powershell
|
||||
$env:AUTH_ID_LOGIN_ENABLED="true"; .\mvnw.cmd spring-boot:run -DskipTests
|
||||
```
|
||||
2) 请求示例:
|
||||
```http
|
||||
POST http://localhost:8080/api/auth/login-by-id
|
||||
Content-Type: application/json
|
||||
|
||||
{ "userId": 2 }
|
||||
```
|
||||
3) 成功返回:`{ token, expiresIn, user:{ userId, shopId, phone? } }`
|
||||
4) 之后在调用业务接口时携带:`Authorization: Bearer <token>`
|
||||
|
||||
### 常见问题
|
||||
- **端口被占用**:更换启动端口
|
||||
```powershell
|
||||
.\mvnw.cmd spring-boot:run -DskipTests -Dserver.port=8081
|
||||
```
|
||||
- **远程库连不通**:检查网络是否放行 `mysql.tonaspace.com:3306`;如在公司网络,确认代理/防火墙策略已放通。
|
||||
- **Java 未安装或版本不符**:安装 JDK 17,并在新开终端内确认 `java -version`。
|
||||
|
||||
### 可选设置
|
||||
- 占位图(非必需):若需启用 `/api/attachments/placeholder`
|
||||
```powershell
|
||||
$env:ATTACHMENTS_PLACEHOLDER_IMAGE="C:\Users\Public\Pictures\placeholder.png"
|
||||
```
|
||||
- 前端联调 CORS(按需):
|
||||
```powershell
|
||||
$env:CORS_ALLOWED_ORIGINS="http://localhost:5173"
|
||||
```
|
||||
|
||||
### 可选:打包为可执行 JAR
|
||||
```powershell
|
||||
cd backend; .\mvnw.cmd clean package -DskipTests; java -jar .\target\demo-0.0.1-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
### SMTP 邮件配置(Windows PowerShell)
|
||||
|
||||
请在启动后端前设置以下环境变量(QQ 邮箱):
|
||||
|
||||
```powershell
|
||||
$env:MAIL_HOST="smtp.qq.com"; $env:MAIL_PORT="465"; $env:MAIL_PROTOCOL="smtps"; $env:MAIL_USERNAME="sdssds@163.com"; $env:MAIL_PASSWORD="NQLihrab8vGiAjiE"; $env:MAIL_FROM="sdssds@163.com"; $env:MAIL_SUBJECT_PREFIX="[配件查询]"
|
||||
```
|
||||
|
||||
说明:
|
||||
- MAIL_USERNAME/MAIL_FROM:发件邮箱地址
|
||||
- MAIL_PASSWORD:SMTP 授权码
|
||||
- 采用 465 + SMTPS + SSL;若使用 587,请改为 `MAIL_PORT=587` 并设置 `spring.mail.properties.mail.smtp.starttls.enable=true`。
|
||||
|
||||
### 邮箱验证码接口
|
||||
- POST `/api/auth/email/send`:请求体 `{ email, scene? }`,成功返回 `{ ok, cooldownSec }`
|
||||
- POST `/api/auth/email/login`:请求体 `{ email, code }`,成功返回 `{ token, expiresIn, user }`
|
||||
|
||||
返回的 JWT 通过 `Authorization: Bearer <token>` 使用,解析后包含 `userId/shopId/email/provider` 等声明。
|
||||
|
||||
以上即为在新电脑上启动后端并连接远程数据库的最小步骤。
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
## 当前开发进度概览(2025-09-27)
|
||||
|
||||
### 一、后端(Spring Boot)
|
||||
- **会员体系**:已实现 `vip_users`、`vip_price`、`vip_recharges` CRUD 及接口 `/api/vip/*`、`/api/admin/vip/*`。
|
||||
- **公告管理**:`/api/admin/notices` 完整可用,支持创建/编辑/发布/下线。
|
||||
- **附件系统**:`/api/attachments` 支持本地存储、hash 去重与 URL 校验;用户与管理端均在使用。
|
||||
- **条码代理**:`/api/barcode/scan` 代理 Python TXM 服务,需人工启动 Python 端。
|
||||
- **鉴权机制**:管理员接口仍依赖 `X-Admin-Id` 兼容头;JWT 登录接口已实现但尚未前端集成。
|
||||
|
||||
### 二、管理端(Vue 3 + Element Plus)
|
||||
- 已上线模块:VIP 系统、VIP 列表、公告管理、咨询回复、用户管理、配件管理、主数据字典、**配件审核(新增 Submissions 页面,支持筛选/详情/通过/驳回/导出)**。
|
||||
- 尚缺模块:登录页、角色权限细分、操作日志可视化。
|
||||
- 交互问题:表格分页统一使用后端分页参数,个别页面(如 VIP 列表)暂未展示 total,需要补齐。
|
||||
|
||||
### 三、移动端(uni-app)
|
||||
- **主流程**:商品、订单、客户、供应商、报表等基础功能可用。
|
||||
- **登录/注册**:`pages/auth/login.vue` 新增邮箱密码登录、验证码注册、忘记密码三合一页面,调用 `/api/auth/password/login`、`/api/auth/email/register`、`/api/auth/email/reset-password`;验证码发送支持 register/reset 场景。
|
||||
- **配件提交(新增)**:`pages/product/submit.vue`、`pages/product/submissions.vue`、`pages/product/submission-detail.vue` 已接入配件提交、列表、详情;支持多图上传、参数 JSON、驳回重新提交,与后端 `/api/products/submissions*` 系列接口对齐。
|
||||
- **VIP 页面**:`pages/my/vip.vue` 已接入状态查询与一键开通,待接续续费提示与权益引导。
|
||||
- **咨询入口**:请求与管理端对接正常,尚缺悬浮入口。
|
||||
- **扫码**:仅 App 端调用条码识别,小程序端提示不支持扫码。
|
||||
|
||||
### 四、数据库
|
||||
- 远程库包含 VIP、附件等新增表,本地脚本 `backend/db/db.sql` 尚未同步;执行结构变更需通过 MysqlMCP 并手动更新脚本。
|
||||
- 需追加的建表脚本:`vip_users`、`vip_price`、`vip_recharges`、`attachments` 等。
|
||||
|
||||
### 五、待解决问题
|
||||
1. **管理员登录上线**:前端需接入 `/api/admin/auth/login` 并替换本地 ADMIN_ID 写死逻辑。
|
||||
2. **VIP 续期逻辑**:`/api/vip/pay` 当前覆盖式设置到期时间,需确认是否改为顺延有效期并记录 `expire_from`。
|
||||
3. **公告富文本**:现为纯文本,若需富文本需评估安全策略。
|
||||
4. **前端分页补充**:管理端表格统一展示 total 并接入分页控件。
|
||||
5. **数据库脚本同步**:更新 `backend/db/db.sql` 与 doc 文档保持一致,避免新环境缺表。
|
||||
6. **条码服务部署**:需编写部署说明,确定 Python TXM 服务是否随 Java 进程自动启动。
|
||||
7. **登录方式文档同步**:OpenAPI 已新增 `/api/auth/email/reset-password`,前端登录页三流程已实现,需对外文档同步展示入口与约束。
|
||||
8. **配件提交流程验收**:需补充测试用例(提交→审核→导出),并确认型号唯一策略是否支持多店共享或全局唯一。
|
||||
997
doc/数据库设计文档-核心业务表.md
Normal file
997
doc/数据库设计文档-核心业务表.md
Normal file
@@ -0,0 +1,997 @@
|
||||
# 配件查询系统 - 数据库设计文档(核心业务表)
|
||||
|
||||
**版本**: 1.0
|
||||
**更新时间**: 2025-10-01
|
||||
**数据库**: MySQL 8.0
|
||||
**字符集**: utf8mb4 / utf8mb4_0900_ai_ci
|
||||
|
||||
---
|
||||
|
||||
## 一、租户与用户体系
|
||||
|
||||
### 1.1 shops(店铺/租户)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| name | VARCHAR(100) | NO | | 店铺名称 |
|
||||
| status | TINYINT UNSIGNED | NO | 1 | 1=启用 0=停用 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_shops_status` (`status`)
|
||||
|
||||
**说明**:多租户隔离的核心表,所有业务数据必须关联shop_id。
|
||||
|
||||
---
|
||||
|
||||
### 1.2 users(用户)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 所属店铺 |
|
||||
| phone | VARCHAR(32) | YES | NULL | 手机号(全局唯一) |
|
||||
| email | VARCHAR(128) | YES | NULL | 邮箱(全局唯一) |
|
||||
| avatar_url | VARCHAR(512) | YES | NULL | 头像URL |
|
||||
| name | VARCHAR(64) | NO | | 用户姓名 |
|
||||
| role | VARCHAR(32) | NO | 'staff' | 角色:owner/staff/normal_admin |
|
||||
| password_hash | VARCHAR(255) | YES | NULL | 密码哈希 |
|
||||
| status | TINYINT UNSIGNED | NO | 1 | 1=启用 0=停用 |
|
||||
| is_owner | TINYINT(1) | NO | 0 | 是否店主 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_users_shop` (`shop_id`)
|
||||
- UNIQUE: `uk_users_phone` (`phone`)
|
||||
- UNIQUE: `ux_users_email` (`email`)
|
||||
|
||||
**外键**:
|
||||
- `fk_users_shop`: `shop_id` → `shops(id)`
|
||||
|
||||
**说明**:支持手机号、邮箱双登录方式;role字段支持普通管理员权限标识。
|
||||
|
||||
---
|
||||
|
||||
### 1.3 admins(平台管理员)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| username | VARCHAR(64) | NO | | 登录名 |
|
||||
| phone | VARCHAR(32) | YES | NULL | 手机号 |
|
||||
| password_hash | VARCHAR(255) | YES | NULL | 密码哈希 |
|
||||
| status | TINYINT UNSIGNED | NO | 1 | 1=启用 0=停用 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- UNIQUE: `ux_admins_username` (`username`)
|
||||
- UNIQUE: `ux_admins_phone` (`phone`)
|
||||
|
||||
**说明**:平台管理员不归属任何店铺,可跨租户管理数据。
|
||||
|
||||
---
|
||||
|
||||
## 二、商品与库存体系
|
||||
|
||||
### 2.1 products(商品)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 所属店铺 |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| name | VARCHAR(120) | NO | | 商品名称 |
|
||||
| category_id | BIGINT UNSIGNED | YES | NULL | 类别ID |
|
||||
| template_id | BIGINT UNSIGNED | YES | NULL | 配件模板ID |
|
||||
| brand | VARCHAR(64) | YES | NULL | 品牌 |
|
||||
| model | VARCHAR(64) | YES | NULL | 型号 |
|
||||
| spec | VARCHAR(128) | YES | NULL | 规格 |
|
||||
| origin | VARCHAR(64) | YES | NULL | 产地 |
|
||||
| barcode | VARCHAR(32) | YES | NULL | 条码 |
|
||||
| dedupe_key | VARCHAR(512) | YES | NULL | 去重键 |
|
||||
| alias | VARCHAR(120) | YES | NULL | 别名 |
|
||||
| is_blacklisted | TINYINT(1) | NO | 0 | 黑名单标记 |
|
||||
| description | TEXT | YES | NULL | 描述 |
|
||||
| global_sku_id | BIGINT UNSIGNED | YES | NULL | 全局SKU ID |
|
||||
| source_submission_id | BIGINT UNSIGNED | YES | NULL | 来源提交ID |
|
||||
| attributes_json | JSON | YES | NULL | 扩展属性JSON |
|
||||
| safe_min | DECIMAL(18,3) | YES | NULL | 安全库存下限 |
|
||||
| safe_max | DECIMAL(18,3) | YES | NULL | 安全库存上限 |
|
||||
| search_text | TEXT | YES | NULL | 全文检索聚合字段 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
| is_active | TINYINT | YES | | 计算字段:deleted_at IS NULL |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_products_shop` (`shop_id`)
|
||||
- KEY: `idx_products_category` (`category_id`)
|
||||
- KEY: `idx_products_template` (`template_id`)
|
||||
- KEY: `idx_products_dedupe` (`dedupe_key`)
|
||||
- KEY: `idx_products_shop_blacklist` (`shop_id`, `is_blacklisted`)
|
||||
- FULLTEXT: `ft_products_search` (`name`, `brand`, `model`, `spec`, `search_text`)
|
||||
- UNIQUE: `ux_products_shop_barcode` (`shop_id`, `barcode`)
|
||||
- UNIQUE: `ux_products_template_name_model` (`template_id`, `name`, `model`)
|
||||
|
||||
**外键**:
|
||||
- `fk_products_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_products_user`: `user_id` → `users(id)`
|
||||
- `fk_products_category`: `category_id` → `product_categories(id)`
|
||||
- `fk_products_template`: `template_id` → `part_templates(id)`
|
||||
- `fk_products_globalsku`: `global_sku_id` → `global_skus(id)`
|
||||
|
||||
**说明**:核心商品表,支持模板化参数、全文检索、去重和黑名单管理。
|
||||
|
||||
---
|
||||
|
||||
### 2.2 product_prices(商品价格)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| product_id | BIGINT UNSIGNED | NO | | 商品ID(主键) |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 最后修改人 |
|
||||
| purchase_price | DECIMAL(18,2) | NO | 0.00 | 进货价 |
|
||||
| retail_price | DECIMAL(18,2) | NO | 0.00 | 零售价 |
|
||||
| wholesale_price | DECIMAL(18,2) | NO | 0.00 | 批发价 |
|
||||
| big_client_price | DECIMAL(18,2) | NO | 0.00 | 大客户价 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `product_id`
|
||||
- KEY: `idx_prices_shop` (`shop_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_prices_product`: `product_id` → `products(id)` ON DELETE CASCADE
|
||||
- `fk_prices_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_prices_user`: `user_id` → `users(id)`
|
||||
|
||||
**约束**:所有价格字段 >= 0
|
||||
|
||||
**说明**:四列销售价格支持不同客户等级定价策略。
|
||||
|
||||
---
|
||||
|
||||
### 2.3 inventories(库存)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| product_id | BIGINT UNSIGNED | NO | | 商品ID(主键) |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 最后修改人 |
|
||||
| quantity | DECIMAL(18,3) | NO | 0.000 | 库存数量 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `product_id`
|
||||
- KEY: `idx_inventories_shop` (`shop_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_inv_product`: `product_id` → `products(id)` ON DELETE CASCADE
|
||||
- `fk_inv_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_inv_user`: `user_id` → `users(id)`
|
||||
|
||||
**约束**:quantity >= 0
|
||||
|
||||
**说明**:支持小数精度(3位),适配多种计量单位。
|
||||
|
||||
---
|
||||
|
||||
### 2.4 product_categories(商品类别)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID(0=全局) |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| name | VARCHAR(64) | NO | | 类别名称 |
|
||||
| parent_id | BIGINT UNSIGNED | YES | NULL | 父类别ID |
|
||||
| sort_order | INT | NO | 0 | 排序 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_categories_shop` (`shop_id`)
|
||||
- KEY: `idx_categories_parent` (`parent_id`)
|
||||
- UNIQUE: `ux_categories_shop_name` (`shop_id`, `name`)
|
||||
|
||||
**外键**:
|
||||
- `fk_categories_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_categories_user`: `user_id` → `users(id)`
|
||||
- `fk_categories_parent`: `parent_id` → `product_categories(id)`
|
||||
|
||||
**说明**:shop_id=0为全局字典,所有租户共享。
|
||||
|
||||
---
|
||||
|
||||
### 2.5 product_units(商品单位)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID(0=全局) |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| name | VARCHAR(16) | NO | | 单位名称 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_units_shop` (`shop_id`)
|
||||
- UNIQUE: `ux_units_shop_name` (`shop_id`, `name`)
|
||||
|
||||
**外键**:
|
||||
- `fk_units_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_units_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:shop_id=0为全局字典,所有租户共享。
|
||||
|
||||
---
|
||||
|
||||
### 2.6 product_images(商品图片)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 上传人 |
|
||||
| product_id | BIGINT UNSIGNED | NO | | 商品ID |
|
||||
| url | VARCHAR(512) | NO | | 图片URL |
|
||||
| hash | VARCHAR(64) | YES | NULL | 内容哈希(去重) |
|
||||
| sort_order | INT | NO | 0 | 排序 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_product_images_product` (`product_id`)
|
||||
- UNIQUE: `ux_product_image_hash` (`product_id`, `hash`)
|
||||
|
||||
**外键**:
|
||||
- `fk_pimg_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_pimg_user`: `user_id` → `users(id)`
|
||||
- `fk_pimg_product`: `product_id` → `products(id)` ON DELETE CASCADE
|
||||
|
||||
**说明**:通过hash实现图片去重。
|
||||
|
||||
---
|
||||
|
||||
### 2.7 product_aliases(商品别名)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| product_id | BIGINT UNSIGNED | NO | | 商品ID |
|
||||
| alias | VARCHAR(120) | NO | | 别名 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_product_alias_product` (`product_id`)
|
||||
- UNIQUE: `ux_product_alias` (`product_id`, `alias`)
|
||||
|
||||
**外键**:
|
||||
- `fk_alias_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_alias_user`: `user_id` → `users(id)`
|
||||
- `fk_alias_product`: `product_id` → `products(id)`
|
||||
|
||||
**说明**:支持商品多别名检索,触发器自动同步到search_text。
|
||||
|
||||
---
|
||||
|
||||
## 三、配件审核与模板体系
|
||||
|
||||
### 3.1 part_submissions(配件提交)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 提交店铺 |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 提交用户 |
|
||||
| name | VARCHAR(120) | YES | NULL | 配件名称 |
|
||||
| external_code | VARCHAR(64) | YES | NULL | 外部编码 |
|
||||
| model_unique | VARCHAR(128) | NO | | 规范化型号(唯一) |
|
||||
| brand | VARCHAR(64) | YES | NULL | 品牌 |
|
||||
| spec | VARCHAR(128) | YES | NULL | 规格 |
|
||||
| unit_id | BIGINT UNSIGNED | YES | NULL | 单位 |
|
||||
| category_id | BIGINT UNSIGNED | YES | NULL | 类别 |
|
||||
| template_id | BIGINT UNSIGNED | YES | NULL | 模板 |
|
||||
| tags | JSON | YES | NULL | 标签 |
|
||||
| attributes | JSON | YES | NULL | 参数JSON |
|
||||
| images | JSON | YES | NULL | 图片URL数组 |
|
||||
| size | VARCHAR(64) | YES | NULL | 尺寸(兼容) |
|
||||
| aperture | VARCHAR(64) | YES | NULL | 孔径(兼容) |
|
||||
| compatible | TEXT | YES | NULL | 适配信息 |
|
||||
| barcode | VARCHAR(64) | YES | NULL | 条码 |
|
||||
| dedupe_key | VARCHAR(512) | YES | NULL | 去重键 |
|
||||
| remark | TEXT | YES | NULL | 备注 |
|
||||
| status | ENUM('pending','approved','rejected') | NO | 'pending' | 审核状态 |
|
||||
| reviewer_id | BIGINT UNSIGNED | YES | NULL | 审核人 |
|
||||
| product_id | BIGINT UNSIGNED | YES | NULL | 关联商品ID |
|
||||
| global_sku_id | BIGINT UNSIGNED | YES | NULL | 关联全局SKU |
|
||||
| reviewed_at | DATETIME | YES | NULL | 审核时间 |
|
||||
| review_remark | VARCHAR(255) | YES | NULL | 审核备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_ps_shop` (`shop_id`)
|
||||
- KEY: `idx_ps_user` (`user_id`)
|
||||
- KEY: `idx_ps_brand` (`brand`)
|
||||
- KEY: `idx_ps_status` (`status`)
|
||||
- KEY: `idx_ps_template` (`template_id`)
|
||||
- KEY: `idx_ps_dedupe` (`dedupe_key`)
|
||||
- KEY: `idx_ps_created_at` (`created_at`)
|
||||
- UNIQUE: `ux_part_model_unique` (`model_unique`)
|
||||
- UNIQUE: `ux_ps_template_name_model` (`template_id`, `name`, `model_unique`)
|
||||
|
||||
**外键**:
|
||||
- `fk_ps_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_ps_user`: `user_id` → `users(id)`
|
||||
- `fk_ps_reviewer`: `reviewer_id` → `admins(id)`
|
||||
- `fk_ps_product`: `product_id` → `products(id)`
|
||||
- `fk_ps_global_sku`: `global_sku_id` → `global_skus(id)`
|
||||
- `fk_ps_template`: `template_id` → `part_templates(id)`
|
||||
|
||||
**说明**:用户提交配件数据,审核通过后生成products记录。model_unique全局唯一。
|
||||
|
||||
---
|
||||
|
||||
### 3.2 part_templates(配件模板)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| category_id | BIGINT UNSIGNED | NO | | 绑定类别 |
|
||||
| name | VARCHAR(120) | NO | | 配件名 |
|
||||
| model_rule | VARCHAR(255) | YES | NULL | 型号规则说明 |
|
||||
| status | TINYINT UNSIGNED | NO | 1 | 1=启用 0=停用 |
|
||||
| created_by_admin_id | BIGINT UNSIGNED | YES | NULL | 创建管理员 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_pt_category` (`category_id`)
|
||||
- KEY: `idx_pt_status` (`status`)
|
||||
- KEY: `idx_pt_admin` (`created_by_admin_id`)
|
||||
- KEY: `idx_part_templates_deleted_at` (`deleted_at`)
|
||||
|
||||
**外键**:
|
||||
- `fk_pt_category`: `category_id` → `product_categories(id)`
|
||||
- `fk_pt_admin`: `created_by_admin_id` → `admins(id)`
|
||||
|
||||
**说明**:配件模板定义,关联多个参数字段。
|
||||
|
||||
---
|
||||
|
||||
### 3.3 part_template_params(模板参数)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| template_id | BIGINT UNSIGNED | NO | | 所属模板 |
|
||||
| field_key | VARCHAR(64) | NO | | 参数键 |
|
||||
| field_label | VARCHAR(120) | NO | | 参数名(展示) |
|
||||
| type | ENUM('string','number','boolean','enum','date') | NO | | 参数类型 |
|
||||
| required | TINYINT(1) | NO | 0 | 是否必填 |
|
||||
| unit | VARCHAR(32) | YES | NULL | 单位 |
|
||||
| enum_options | JSON | YES | NULL | 枚举选项 |
|
||||
| searchable | TINYINT(1) | NO | 0 | 参与检索 |
|
||||
| fuzzy_searchable | TINYINT(1) | NO | 0 | 可模糊查询(数值) |
|
||||
| fuzzy_tolerance | DECIMAL(18,6) | YES | NULL | 容差(NULL=平台默认) |
|
||||
| dedupe_participate | TINYINT(1) | NO | 0 | 参与去重 |
|
||||
| sort_order | INT | NO | 0 | 排序 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_ptp_template` (`template_id`)
|
||||
- KEY: `idx_ptp_sort` (`template_id`, `sort_order`)
|
||||
- UNIQUE: `ux_ptp_field_key` (`template_id`, `field_key`)
|
||||
|
||||
**外键**:
|
||||
- `fk_ptp_template`: `template_id` → `part_templates(id)` ON DELETE CASCADE
|
||||
|
||||
**说明**:定义模板的参数字段,支持类型化、验证和模糊搜索。
|
||||
|
||||
---
|
||||
|
||||
### 3.4 global_skus(全局SKU)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| name | VARCHAR(120) | NO | | SKU名称 |
|
||||
| brand | VARCHAR(64) | YES | NULL | 品牌 |
|
||||
| model | VARCHAR(64) | YES | NULL | 型号 |
|
||||
| spec | VARCHAR(128) | YES | NULL | 规格 |
|
||||
| barcode | VARCHAR(32) | YES | NULL | 条码 |
|
||||
| unit_id | BIGINT UNSIGNED | YES | NULL | 单位 |
|
||||
| tags | JSON | YES | NULL | 标签 |
|
||||
| status | ENUM('published','offline') | NO | 'published' | 状态 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_global_skus_brand_model` (`brand`, `model`)
|
||||
- UNIQUE: `ux_global_skus_barcode` (`barcode`)
|
||||
|
||||
**外键**:
|
||||
- `fk_globalsku_unit`: `unit_id` → `product_units(id)`
|
||||
|
||||
**说明**:全局共享的商品库,供各租户引用。
|
||||
|
||||
---
|
||||
|
||||
## 四、客户与供应商
|
||||
|
||||
### 4.1 customers(客户)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| name | VARCHAR(120) | NO | | 客户名称 |
|
||||
| contact_name | VARCHAR(64) | YES | NULL | 联系人 |
|
||||
| mobile | VARCHAR(32) | YES | NULL | 手机 |
|
||||
| phone | VARCHAR(32) | YES | NULL | 座机 |
|
||||
| address | VARCHAR(255) | YES | NULL | 送货地址 |
|
||||
| price_level | ENUM('零售价','批发价','大单报价') | NO | '零售价' | 默认价格等级 |
|
||||
| status | TINYINT UNSIGNED | NO | 1 | 1=启用 0=停用 |
|
||||
| ar_opening | DECIMAL(18,2) | NO | 0.00 | 期初应收 |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_customers_shop` (`shop_id`)
|
||||
- KEY: `idx_customers_phone` (`phone`)
|
||||
- KEY: `idx_customers_mobile` (`mobile`)
|
||||
|
||||
**外键**:
|
||||
- `fk_customers_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_customers_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:price_level关联product_prices的四列价格之一。
|
||||
|
||||
---
|
||||
|
||||
### 4.2 suppliers(供应商)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| name | VARCHAR(120) | NO | | 供应商名称 |
|
||||
| contact_name | VARCHAR(64) | YES | NULL | 联系人 |
|
||||
| mobile | VARCHAR(32) | YES | NULL | 手机 |
|
||||
| phone | VARCHAR(32) | YES | NULL | 电话 |
|
||||
| address | VARCHAR(255) | YES | NULL | 经营地址 |
|
||||
| status | TINYINT UNSIGNED | NO | 1 | 1=启用 0=停用 |
|
||||
| ap_opening | DECIMAL(18,2) | NO | 0.00 | 期初应付 |
|
||||
| ap_payable | DECIMAL(18,2) | NO | 0.00 | 当前应付(实时) |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_suppliers_shop` (`shop_id`)
|
||||
- KEY: `idx_suppliers_phone` (`phone`)
|
||||
- KEY: `idx_suppliers_mobile` (`mobile`)
|
||||
|
||||
**外键**:
|
||||
- `fk_suppliers_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_suppliers_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:ap_payable由订单和付款记录联动维护。
|
||||
|
||||
---
|
||||
|
||||
### 4.3 accounts(结算账户)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| name | VARCHAR(64) | NO | | 账户名称 |
|
||||
| type | ENUM('cash','bank','alipay','wechat','other') | NO | 'cash' | 账户类型 |
|
||||
| bank_name | VARCHAR(64) | YES | NULL | 银行名称 |
|
||||
| bank_account | VARCHAR(64) | YES | NULL | 银行账号 |
|
||||
| balance | DECIMAL(18,2) | NO | 0.00 | 账户余额 |
|
||||
| status | TINYINT UNSIGNED | NO | 1 | 1=启用 0=停用 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_accounts_shop` (`shop_id`)
|
||||
- UNIQUE: `ux_accounts_shop_name` (`shop_id`, `name`)
|
||||
|
||||
**外键**:
|
||||
- `fk_accounts_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_accounts_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:支持现金、银行、支付宝、微信等多种结算方式。
|
||||
|
||||
---
|
||||
|
||||
## 五、订单与财务
|
||||
|
||||
### 5.1 sales_orders(销售单)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| customer_id | BIGINT UNSIGNED | YES | NULL | 客户ID |
|
||||
| order_no | VARCHAR(32) | NO | | 订单号 |
|
||||
| order_time | DATETIME | NO | | 订单时间 |
|
||||
| status | ENUM('draft','approved','returned','void') | NO | 'draft' | 单据状态 |
|
||||
| amount | DECIMAL(18,2) | NO | 0.00 | 应收合计 |
|
||||
| paid_amount | DECIMAL(18,2) | NO | 0.00 | 已收合计 |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_sales_shop_time` (`shop_id`, `order_time`)
|
||||
- KEY: `idx_sales_customer` (`customer_id`)
|
||||
- UNIQUE: `ux_sales_order_no` (`shop_id`, `order_no`)
|
||||
|
||||
**外键**:
|
||||
- `fk_sales_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_sales_user`: `user_id` → `users(id)`
|
||||
- `fk_sales_customer`: `customer_id` → `customers(id)`
|
||||
|
||||
**说明**:approved后自动扣减库存;付款记录关联payments表。
|
||||
|
||||
---
|
||||
|
||||
### 5.2 sales_order_items(销售单明细)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| order_id | BIGINT UNSIGNED | NO | | 订单ID |
|
||||
| product_id | BIGINT UNSIGNED | NO | | 商品ID |
|
||||
| quantity | DECIMAL(18,3) | NO | | 数量 |
|
||||
| unit_price | DECIMAL(18,2) | NO | | 单价 |
|
||||
| discount_rate | DECIMAL(5,2) | NO | 0.00 | 折扣率(0-100) |
|
||||
| cost_price | DECIMAL(18,2) | NO | 0.00 | 成本单价 |
|
||||
| cost_amount | DECIMAL(18,2) | NO | 0.00 | 成本金额 |
|
||||
| amount | DECIMAL(18,2) | NO | | 行金额 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_soi_order` (`order_id`)
|
||||
- KEY: `idx_soi_product` (`product_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_soi_order`: `order_id` → `sales_orders(id)` ON DELETE CASCADE
|
||||
- `fk_soi_product`: `product_id` → `products(id)`
|
||||
|
||||
**约束**:
|
||||
- quantity > 0
|
||||
- unit_price >= 0
|
||||
- discount_rate >= 0 AND <= 100
|
||||
|
||||
**说明**:记录开单时的成本价,用于利润分析。
|
||||
|
||||
---
|
||||
|
||||
### 5.3 purchase_orders(进货单)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| supplier_id | BIGINT UNSIGNED | YES | NULL | 供应商ID |
|
||||
| order_no | VARCHAR(32) | NO | | 订单号 |
|
||||
| order_time | DATETIME | NO | | 订单时间 |
|
||||
| status | ENUM('draft','approved','void','returned') | NO | 'draft' | 单据状态 |
|
||||
| amount | DECIMAL(18,2) | NO | 0.00 | 应付合计 |
|
||||
| paid_amount | DECIMAL(18,2) | NO | 0.00 | 已付合计 |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_purchase_shop_time` (`shop_id`, `order_time`)
|
||||
- KEY: `idx_purchase_supplier` (`supplier_id`)
|
||||
- UNIQUE: `ux_purchase_order_no` (`shop_id`, `order_no`)
|
||||
|
||||
**外键**:
|
||||
- `fk_purchase_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_purchase_user`: `user_id` → `users(id)`
|
||||
- `fk_purchase_supplier`: `supplier_id` → `suppliers(id)`
|
||||
|
||||
**说明**:approved后自动增加库存。
|
||||
|
||||
---
|
||||
|
||||
### 5.4 purchase_order_items(进货单明细)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| order_id | BIGINT UNSIGNED | NO | | 订单ID |
|
||||
| product_id | BIGINT UNSIGNED | NO | | 商品ID |
|
||||
| quantity | DECIMAL(18,3) | NO | | 数量 |
|
||||
| unit_price | DECIMAL(18,2) | NO | | 单价 |
|
||||
| amount | DECIMAL(18,2) | NO | | 行金额 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_poi_order` (`order_id`)
|
||||
- KEY: `idx_poi_product` (`product_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_poi_order`: `order_id` → `purchase_orders(id)` ON DELETE CASCADE
|
||||
- `fk_poi_product`: `product_id` → `products(id)`
|
||||
|
||||
**约束**:
|
||||
- quantity > 0
|
||||
- unit_price >= 0
|
||||
|
||||
---
|
||||
|
||||
### 5.5 payments(收付款记录)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 操作人 |
|
||||
| biz_type | ENUM('sale','purchase','other') | NO | | 业务类型 |
|
||||
| biz_id | BIGINT UNSIGNED | YES | NULL | 业务单据ID |
|
||||
| account_id | BIGINT UNSIGNED | NO | | 结算账户 |
|
||||
| direction | ENUM('in','out') | NO | | 收款/付款 |
|
||||
| amount | DECIMAL(18,2) | NO | | 金额 |
|
||||
| pay_time | DATETIME | NO | | 付款时间 |
|
||||
| category | VARCHAR(64) | YES | NULL | 分类key(其他收支) |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_payments_shop_time` (`shop_id`, `pay_time`)
|
||||
- KEY: `idx_payments_biz` (`biz_type`, `biz_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_payments_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_payments_user`: `user_id` → `users(id)`
|
||||
- `fk_payments_account`: `account_id` → `accounts(id)`
|
||||
|
||||
**约束**:amount > 0
|
||||
|
||||
**说明**:统一管理销售收款、进货付款和其他收支。
|
||||
|
||||
---
|
||||
|
||||
### 5.6 other_transactions(其他收支)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| type | ENUM('income','expense') | NO | | 收入/支出 |
|
||||
| category | VARCHAR(64) | NO | | 分类key |
|
||||
| counterparty_type | VARCHAR(32) | YES | NULL | customer/supplier/other |
|
||||
| counterparty_id | BIGINT UNSIGNED | YES | NULL | 往来单位ID |
|
||||
| account_id | BIGINT UNSIGNED | NO | | 结算账户 |
|
||||
| amount | DECIMAL(18,2) | NO | | 金额 |
|
||||
| tx_time | DATETIME | NO | | 交易时间 |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_ot_shop_time` (`shop_id`, `tx_time`)
|
||||
- KEY: `idx_ot_account` (`account_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_ot_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_ot_user`: `user_id` → `users(id)`
|
||||
- `fk_ot_account`: `account_id` → `accounts(id)`
|
||||
|
||||
**约束**:amount > 0
|
||||
|
||||
**说明**:记录非进销业务的其他收入和支出。
|
||||
|
||||
---
|
||||
|
||||
### 5.7 inventory_movements(库存流水)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 操作人 |
|
||||
| product_id | BIGINT UNSIGNED | NO | | 商品ID |
|
||||
| source_type | VARCHAR(32) | NO | | 来源:sale/purchase/return/adjust/audit |
|
||||
| source_id | BIGINT UNSIGNED | YES | NULL | 来源单据ID |
|
||||
| qty_delta | DECIMAL(18,3) | NO | | 数量增减(+/-) |
|
||||
| amount_delta | DECIMAL(18,2) | YES | NULL | 金额增减 |
|
||||
| cost_price | DECIMAL(18,2) | YES | NULL | 成本单价 |
|
||||
| cost_amount | DECIMAL(18,2) | YES | NULL | 成本金额 |
|
||||
| reason | VARCHAR(64) | YES | NULL | 原因/类别 |
|
||||
| tx_time | DATETIME | NO | | 业务时间 |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_im_shop_time` (`shop_id`, `tx_time`)
|
||||
- KEY: `idx_im_product` (`product_id`)
|
||||
|
||||
**说明**:所有库存变动的审计日志,出库为负,入库为正。
|
||||
|
||||
---
|
||||
|
||||
## 六、销售退货
|
||||
|
||||
### 6.1 sales_return_orders(销售退货单)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| customer_id | BIGINT UNSIGNED | YES | NULL | 客户ID |
|
||||
| order_no | VARCHAR(32) | NO | | 订单号 |
|
||||
| order_time | DATETIME | NO | | 订单时间 |
|
||||
| status | ENUM('approved','void') | NO | 'approved' | 单据状态 |
|
||||
| amount | DECIMAL(18,2) | NO | 0.00 | 退货金额合计 |
|
||||
| paid_amount | DECIMAL(18,2) | NO | 0.00 | 已退/已收合计 |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_sr_shop_time` (`shop_id`, `order_time`)
|
||||
- UNIQUE: `ux_sr_order_no` (`shop_id`, `order_no`)
|
||||
|
||||
**外键**:
|
||||
- `fk_sr_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_sr_user`: `user_id` → `users(id)`
|
||||
- `fk_sr_customer`: `customer_id` → `customers(id)`
|
||||
|
||||
**说明**:approved后增加库存。
|
||||
|
||||
---
|
||||
|
||||
### 6.2 sales_return_order_items(销售退货明细)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| order_id | BIGINT UNSIGNED | NO | | 订单ID |
|
||||
| product_id | BIGINT UNSIGNED | NO | | 商品ID |
|
||||
| quantity | DECIMAL(18,3) | NO | | 数量 |
|
||||
| unit_price | DECIMAL(18,2) | NO | | 单价 |
|
||||
| discount_rate | DECIMAL(5,2) | NO | 0.00 | 折扣率 |
|
||||
| cost_price | DECIMAL(18,2) | NO | 0.00 | 成本单价 |
|
||||
| cost_amount | DECIMAL(18,2) | NO | 0.00 | 成本金额 |
|
||||
| amount | DECIMAL(18,2) | NO | | 行金额 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_sroi_order` (`order_id`)
|
||||
- KEY: `idx_sroi_product` (`product_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_sroi_order`: `order_id` → `sales_return_orders(id)` ON DELETE CASCADE
|
||||
- `fk_sroi_product`: `product_id` → `products(id)`
|
||||
|
||||
---
|
||||
|
||||
### 6.3 purchase_return_orders(进货退货单)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建人 |
|
||||
| supplier_id | BIGINT UNSIGNED | YES | NULL | 供应商ID |
|
||||
| order_no | VARCHAR(32) | NO | | 订单号 |
|
||||
| order_time | DATETIME | NO | | 订单时间 |
|
||||
| status | ENUM('approved','void') | NO | 'approved' | 单据状态 |
|
||||
| amount | DECIMAL(18,2) | NO | 0.00 | 退货金额合计 |
|
||||
| paid_amount | DECIMAL(18,2) | NO | 0.00 | 已付合计 |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_pr_shop_time` (`shop_id`, `order_time`)
|
||||
- UNIQUE: `ux_pr_order_no` (`shop_id`, `order_no`)
|
||||
|
||||
**外键**:
|
||||
- `fk_pr_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_pr_user`: `user_id` → `users(id)`
|
||||
- `fk_pr_supplier`: `supplier_id` → `suppliers(id)`
|
||||
|
||||
**说明**:approved后减少库存。
|
||||
|
||||
---
|
||||
|
||||
### 6.4 purchase_return_order_items(进货退货明细)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| order_id | BIGINT UNSIGNED | NO | | 订单ID |
|
||||
| product_id | BIGINT UNSIGNED | NO | | 商品ID |
|
||||
| quantity | DECIMAL(18,3) | NO | | 数量 |
|
||||
| unit_price | DECIMAL(18,2) | NO | | 单价 |
|
||||
| amount | DECIMAL(18,2) | NO | | 行金额 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_proi_order` (`order_id`)
|
||||
- KEY: `idx_proi_product` (`product_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_proi_order`: `order_id` → `purchase_return_orders(id)` ON DELETE CASCADE
|
||||
- `fk_proi_product`: `product_id` → `products(id)`
|
||||
|
||||
---
|
||||
|
||||
## 七、触发器
|
||||
|
||||
### 7.1 products.search_text 维护触发器
|
||||
|
||||
**trg_products_ai** (AFTER INSERT)
|
||||
```sql
|
||||
UPDATE products
|
||||
SET search_text = CONCAT_WS(' ', NEW.name, NEW.brand, NEW.model, NEW.spec)
|
||||
WHERE id = NEW.id;
|
||||
```
|
||||
|
||||
**trg_products_au** (BEFORE UPDATE)
|
||||
```sql
|
||||
SET NEW.search_text = CONCAT_WS(' ', NEW.name, NEW.brand, NEW.model, NEW.spec);
|
||||
```
|
||||
|
||||
### 7.2 product_aliases 同步触发器
|
||||
|
||||
**trg_palias_ai** (AFTER INSERT)
|
||||
```sql
|
||||
-- 聚合所有别名到products.search_text
|
||||
UPDATE products p
|
||||
JOIN (
|
||||
SELECT pa.product_id, GROUP_CONCAT(pa.alias SEPARATOR ' ') AS aliases
|
||||
FROM product_aliases pa
|
||||
WHERE pa.product_id = NEW.product_id AND pa.deleted_at IS NULL
|
||||
GROUP BY pa.product_id
|
||||
) a ON a.product_id = p.id
|
||||
SET p.search_text = CONCAT_WS(' ', p.name, p.brand, p.model, p.spec, a.aliases)
|
||||
WHERE p.id = NEW.product_id;
|
||||
```
|
||||
|
||||
**trg_palias_au** (AFTER UPDATE)、**trg_palias_ad** (AFTER DELETE) - 类似逻辑
|
||||
|
||||
### 7.3 consults 回复状态触发器
|
||||
|
||||
**trg_consult_replies_ai** (AFTER INSERT)
|
||||
```sql
|
||||
UPDATE consults
|
||||
SET status = 'resolved', updated_at = NOW()
|
||||
WHERE id = NEW.consult_id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、数据完整性约束
|
||||
|
||||
### 8.1 CHECK约束
|
||||
|
||||
- `products`: `safe_min <= safe_max`
|
||||
- `product_prices`: 所有价格 >= 0
|
||||
- `inventories`: `quantity >= 0`
|
||||
- `sales_order_items`: `quantity > 0, unit_price >= 0, discount_rate BETWEEN 0 AND 100`
|
||||
- `purchase_order_items`: `quantity > 0, unit_price >= 0`
|
||||
- `payments`: `amount > 0`
|
||||
- `other_transactions`: `amount > 0`
|
||||
|
||||
### 8.2 唯一性约束
|
||||
|
||||
- `shops`: 无业务层面唯一约束
|
||||
- `users`: `phone` 全局唯一、`email` 全局唯一
|
||||
- `products`: `(shop_id, barcode)` 唯一、`(template_id, name, model)` 唯一
|
||||
- `part_submissions`: `model_unique` 全局唯一、`(template_id, name, model_unique)` 唯一
|
||||
- `customers/suppliers`: 无强制唯一约束(允许同名)
|
||||
- `accounts`: `(shop_id, name)` 唯一
|
||||
- `sales_orders/purchase_orders`: `(shop_id, order_no)` 唯一
|
||||
|
||||
---
|
||||
|
||||
## 九、设计说明
|
||||
|
||||
### 9.1 多租户隔离
|
||||
|
||||
- 所有业务表必须包含 `shop_id`
|
||||
- 全局字典表(单位、类别)使用 `shop_id=0` 表示平台共享
|
||||
- 查询必须强制按 `shop_id` 过滤
|
||||
- VIP数据可见性:非VIP用户仅显示最近60天(可配置)数据
|
||||
|
||||
### 9.2 软删除策略
|
||||
|
||||
- 主要业务表使用 `deleted_at` 字段标记软删除
|
||||
- 查询默认过滤 `deleted_at IS NULL`
|
||||
- 部分关联表(如订单明细)采用级联删除
|
||||
|
||||
### 9.3 审计与追踪
|
||||
|
||||
- 所有表包含 `created_at`, `updated_at` 时间戳
|
||||
- 审核表(part_submissions、vip_users)记录审核人和审核时间
|
||||
- 库存变动通过 `inventory_movements` 完整留痕
|
||||
- 普通管理员申请通过 `normal_admin_audits` 留痕
|
||||
|
||||
### 9.4 性能优化
|
||||
|
||||
- 高频查询字段建立复合索引(如 `shop_id + order_time`)
|
||||
- `products.search_text` 使用FULLTEXT索引支持全文检索
|
||||
- 价格和库存表采用主键为业务主键(product_id)的设计
|
||||
- 合理使用外键约束,但不过度使用以避免性能损失
|
||||
|
||||
### 9.5 扩展性设计
|
||||
|
||||
- 商品属性通过 `attributes_json` 支持动态扩展
|
||||
- 配件模板系统支持类型化参数定义
|
||||
- 财务分类通过配置表 `finance_categories` 动态管理
|
||||
- 预留 `global_sku_id` 支持平台级商品库
|
||||
|
||||
---
|
||||
|
||||
**文档维护说明**:
|
||||
- 任何数据库结构变更必须同步更新本文档
|
||||
- 执行DDL操作后需标注更新时间
|
||||
- 新增表需补充完整的字段说明和索引信息
|
||||
- 变更需同步更新 `backend/db/db.sql` 脚本
|
||||
|
||||
584
doc/数据库设计文档-辅助配置表.md
Normal file
584
doc/数据库设计文档-辅助配置表.md
Normal file
@@ -0,0 +1,584 @@
|
||||
# 配件查询系统 - 数据库设计文档(辅助配置表)
|
||||
|
||||
**版本**: 1.0
|
||||
**更新时间**: 2025-10-01
|
||||
**数据库**: MySQL 8.0
|
||||
**字符集**: utf8mb4 / utf8mb4_0900_ai_ci
|
||||
|
||||
---
|
||||
|
||||
## 一、VIP会员体系
|
||||
|
||||
### 1.1 vip_users(会员用户)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 用户ID |
|
||||
| is_vip | TINYINT(1) | NO | 1 | 是否VIP(1是 0否) |
|
||||
| status | TINYINT UNSIGNED | NO | 0 | 启用状态:1启用 0停用 |
|
||||
| expire_at | DATETIME | YES | NULL | 到期时间 |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注/审核说明 |
|
||||
| reviewer_id | BIGINT UNSIGNED | YES | NULL | 审核人 |
|
||||
| reviewed_at | DATETIME | YES | NULL | 审核时间 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_vu_shop_user` (`shop_id`, `user_id`)
|
||||
- KEY: `idx_vu_shop_status` (`shop_id`, `status`)
|
||||
|
||||
**外键**:
|
||||
- `fk_vu_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_vu_user`: `user_id` → `users(id)`
|
||||
- `fk_vu_reviewer`: `reviewer_id` → `users(id)`
|
||||
|
||||
**说明**:
|
||||
- VIP状态判定:`status=1 AND is_vip=1 AND (expire_at IS NULL OR expire_at >= NOW())`
|
||||
- 非VIP用户数据可见性:最近60天(可配置)
|
||||
- VIP用户:查看全部历史数据
|
||||
|
||||
---
|
||||
|
||||
### 1.2 vip_price(VIP价格)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| price | DECIMAL(10,2) | NO | | 单月价格(元) |
|
||||
|
||||
**索引**:无
|
||||
|
||||
**说明**:
|
||||
- 全局配置表,仅一条记录
|
||||
- 表示平台统一VIP单月价格
|
||||
- 管理端可读取和修改
|
||||
|
||||
---
|
||||
|
||||
### 1.3 vip_recharges(VIP充值记录)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 用户ID |
|
||||
| price | DECIMAL(10,2) | NO | | 本次充值价格(元) |
|
||||
| duration_days | INT | NO | | 本次续期天数 |
|
||||
| expire_from | DATETIME | YES | NULL | 生效前到期时间 |
|
||||
| expire_to | DATETIME | NO | | 生效后到期时间 |
|
||||
| channel | VARCHAR(32) | NO | 'oneclick' | 渠道(oneclick/...) |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_vr_shop` (`shop_id`)
|
||||
- KEY: `idx_vr_user` (`user_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_vr_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_vr_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:记录每次VIP开通/续费的历史,支持对账和查询。
|
||||
|
||||
---
|
||||
|
||||
## 二、普通管理员体系
|
||||
|
||||
### 2.1 normal_admin_audits(普通管理员审计)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 用户ID |
|
||||
| action | ENUM('apply','approve','reject','revoke','expire') | NO | | 操作类型 |
|
||||
| remark | VARCHAR(255) | YES | NULL | 备注 |
|
||||
| operator_admin_id | BIGINT UNSIGNED | YES | NULL | 平台管理员ID |
|
||||
| previous_role | VARCHAR(32) | YES | NULL | 变更前角色 |
|
||||
| new_role | VARCHAR(32) | YES | NULL | 变更后角色 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_naudit_shop_time` (`shop_id`, `created_at`)
|
||||
- KEY: `idx_naudit_user_time` (`user_id`, `created_at`)
|
||||
|
||||
**外键**:
|
||||
- `fk_naudit_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_naudit_user`: `user_id` → `users(id)`
|
||||
- `fk_naudit_admin`: `operator_admin_id` → `admins(id)`
|
||||
|
||||
**说明**:
|
||||
- 普通管理员申请、审批、撤销的完整审计日志
|
||||
- 当前状态 = 按user_id取最后一条记录的action
|
||||
- VIP失效触发降级时写入expire审计
|
||||
|
||||
---
|
||||
|
||||
## 三、身份与认证
|
||||
|
||||
### 3.1 user_identities(第三方身份映射)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 用户ID |
|
||||
| provider | ENUM('wechat_mp','wechat_app') | NO | | 身份提供方 |
|
||||
| openid | VARCHAR(64) | NO | | 微信openid |
|
||||
| unionid | VARCHAR(64) | YES | NULL | 微信unionid |
|
||||
| nickname | VARCHAR(64) | YES | NULL | 昵称 |
|
||||
| avatar_url | VARCHAR(512) | YES | NULL | 头像URL |
|
||||
| last_login_at | DATETIME | YES | NULL | 最后登录时间 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_identity_user` (`user_id`)
|
||||
- KEY: `idx_identity_shop` (`shop_id`)
|
||||
- UNIQUE: `ux_identity_provider_openid` (`provider`, `openid`)
|
||||
- UNIQUE: `ux_identity_unionid` (`unionid`)
|
||||
|
||||
**外键**:
|
||||
- `fk_identity_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_identity_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:
|
||||
- 支持微信小程序和APP登录
|
||||
- 短信登录使用users.phone作为全局唯一身份,不创建identity记录
|
||||
|
||||
---
|
||||
|
||||
### 3.2 wechat_sessions(微信会话)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| provider | ENUM('wechat_mp','wechat_app') | NO | | 提供方 |
|
||||
| openid | VARCHAR(64) | NO | | 微信openid |
|
||||
| session_key | VARCHAR(128) | NO | | 会话密钥 |
|
||||
| expires_at | DATETIME | NO | | 过期时间 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_wechat_session_expires` (`expires_at`)
|
||||
- UNIQUE: `ux_wechat_session` (`provider`, `openid`)
|
||||
|
||||
**说明**:临时存储微信会话密钥。
|
||||
|
||||
---
|
||||
|
||||
### 3.3 sms_codes(短信验证码)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| phone | VARCHAR(32) | NO | | 手机号 |
|
||||
| scene | VARCHAR(32) | NO | 'login' | 场景:login/register/... |
|
||||
| code_hash | CHAR(64) | NO | | 验证码哈希(SHA-256) |
|
||||
| salt | CHAR(32) | NO | | 加盐字符串 |
|
||||
| expire_at | DATETIME | NO | | 过期时间 |
|
||||
| status | TINYINT UNSIGNED | NO | 0 | 0=active 1=used 2=expired 3=blocked |
|
||||
| fail_count | TINYINT UNSIGNED | NO | 0 | 错误次数 |
|
||||
| ip | VARCHAR(45) | YES | NULL | 发送IP |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_phone_created_at` (`phone`, `created_at`)
|
||||
- KEY: `idx_phone_scene_status` (`phone`, `scene`, `status`)
|
||||
- KEY: `idx_expire_at` (`expire_at`)
|
||||
- KEY: `idx_ip_created_at` (`ip`, `created_at`)
|
||||
|
||||
**说明**:
|
||||
- 验证码采用哈希+盐存储
|
||||
- 支持多场景(登录、注册、重置密码等)
|
||||
- 记录失败次数防止暴力破解
|
||||
|
||||
---
|
||||
|
||||
### 3.4 email_codes(邮箱验证码)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| email | VARCHAR(128) | NO | | 邮箱 |
|
||||
| scene | VARCHAR(32) | NO | | 场景:login/register/reset |
|
||||
| code_hash | VARCHAR(64) | NO | | 验证码哈希(SHA-256) |
|
||||
| salt | VARCHAR(64) | NO | | 加盐字符串 |
|
||||
| expire_at | DATETIME | NO | | 过期时间 |
|
||||
| status | TINYINT UNSIGNED | NO | 0 | 0=unused 1=used 2=expired |
|
||||
| fail_count | INT | NO | 0 | 错误次数 |
|
||||
| ip | VARCHAR(64) | YES | NULL | 发送IP |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_email_scene_created` (`email`, `scene`, `created_at`)
|
||||
- KEY: `idx_email_expire` (`expire_at`)
|
||||
|
||||
**说明**:与sms_codes类似,用于邮箱验证场景。
|
||||
|
||||
---
|
||||
|
||||
## 四、咨询与公告
|
||||
|
||||
### 4.1 consults(咨询)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 所属店铺 |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 提问用户 |
|
||||
| topic | VARCHAR(120) | NO | | 主题 |
|
||||
| message | TEXT | NO | | 咨询内容 |
|
||||
| status | ENUM('open','resolved','closed') | NO | 'open' | 状态 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_consult_shop_status` (`shop_id`, `status`)
|
||||
- KEY: `fk_consult_user` (`user_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_consult_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_consult_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:
|
||||
- open=未解决,resolved=已解决,closed=关闭
|
||||
- 触发器:有回复时自动标记为resolved
|
||||
|
||||
---
|
||||
|
||||
### 4.2 consult_replies(咨询回复)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| consult_id | BIGINT UNSIGNED | NO | | 所属咨询 |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 回复人(管理员) |
|
||||
| content | TEXT | NO | | 回复内容 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 回复时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_cr_consult` (`consult_id`)
|
||||
- KEY: `fk_cr_user` (`user_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_cr_consult`: `consult_id` → `consults(id)`
|
||||
- `fk_cr_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:管理员对咨询的回复记录。
|
||||
|
||||
---
|
||||
|
||||
### 4.3 notices(公告)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| title | VARCHAR(120) | NO | | 标题 |
|
||||
| content | VARCHAR(500) | NO | | 内容(跑马灯) |
|
||||
| tag | VARCHAR(32) | YES | NULL | 标签(如"活动") |
|
||||
| is_pinned | TINYINT(1) | NO | 0 | 是否置顶 |
|
||||
| starts_at | DATETIME | YES | NULL | 生效开始时间 |
|
||||
| ends_at | DATETIME | YES | NULL | 生效结束时间 |
|
||||
| status | ENUM('draft','published','offline') | NO | 'published' | 状态 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
| deleted_at | DATETIME | YES | NULL | 软删除标记 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_notices_time` (`starts_at`, `ends_at`)
|
||||
|
||||
**说明**:
|
||||
- 平台全局公告,与租户无关
|
||||
- 前台仅显示status='published'且在有效期内的公告
|
||||
- 排序:is_pinned DESC, created_at DESC
|
||||
|
||||
---
|
||||
|
||||
## 五、系统配置
|
||||
|
||||
### 5.1 system_parameters(系统参数)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID |
|
||||
| user_id | BIGINT UNSIGNED | NO | | 创建/修改人 |
|
||||
| key | VARCHAR(64) | NO | | 参数键 |
|
||||
| value | JSON | NO | | 参数值(JSON) |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_sysparams_shop` (`shop_id`)
|
||||
- UNIQUE: `ux_sysparams_shop_key` (`shop_id`, `key`)
|
||||
|
||||
**外键**:
|
||||
- `fk_sysparams_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_sysparams_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:
|
||||
- 租户级配置,支持JSON格式存储复杂配置
|
||||
- 常用配置键:
|
||||
- `vip.dataRetentionDaysForNonVip`: 非VIP数据保留天数(默认60)
|
||||
- `normalAdmin.autoApprove`: 普通管理员自动审批(默认false)
|
||||
- `normalAdmin.requiredVipActive`: 要求VIP有效(默认true)
|
||||
|
||||
---
|
||||
|
||||
### 5.2 finance_categories(财务分类)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | NO | | 店铺ID(0=全局) |
|
||||
| type | ENUM('income','expense') | NO | | 收入/支出 |
|
||||
| key | VARCHAR(64) | NO | | 分类key |
|
||||
| label | VARCHAR(120) | NO | | 分类名称 |
|
||||
| sort_order | INT | NO | 0 | 排序 |
|
||||
| status | TINYINT UNSIGNED | NO | 1 | 1=启用 0=停用 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_fc_shop_type` (`shop_id`, `type`)
|
||||
- UNIQUE: `ux_fc_shop_key` (`shop_id`, `key`)
|
||||
|
||||
**说明**:
|
||||
- 管理其他收入/支出的分类
|
||||
- shop_id=0为平台默认分类
|
||||
- 读取优先级:finance_categories表 → system_parameters → application.properties
|
||||
|
||||
---
|
||||
|
||||
## 六、附件管理
|
||||
|
||||
### 6.1 attachments(通用附件)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| shop_id | BIGINT UNSIGNED | YES | NULL | 店铺ID(全局资源可空) |
|
||||
| user_id | BIGINT UNSIGNED | YES | NULL | 上传人 |
|
||||
| owner_type | VARCHAR(32) | NO | | 归属类型:product/part_submission/... |
|
||||
| owner_id | BIGINT UNSIGNED | NO | | 归属ID |
|
||||
| url | VARCHAR(512) | NO | | 文件URL |
|
||||
| hash | VARCHAR(64) | YES | NULL | 内容哈希(SHA-256) |
|
||||
| meta | JSON | YES | NULL | 元数据 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_attachments_owner` (`owner_type`, `owner_id`)
|
||||
- UNIQUE: `ux_attachments_hash` (`hash`)
|
||||
|
||||
**外键**:
|
||||
- `fk_att_shop`: `shop_id` → `shops(id)`
|
||||
- `fk_att_user`: `user_id` → `users(id)`
|
||||
|
||||
**说明**:
|
||||
- 通过hash实现文件去重
|
||||
- 支持多种归属类型(商品、配件提交、全局SKU等)
|
||||
- meta字段存储文件元信息(大小、类型等)
|
||||
|
||||
---
|
||||
|
||||
## 七、配件参数字典(扩展)
|
||||
|
||||
### 7.1 part_attribute_dictionary(参数字典)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| attribute_name | VARCHAR(64) | NO | | 参数名称 |
|
||||
| attribute_unit | VARCHAR(16) | YES | NULL | 单位 |
|
||||
| attribute_type | ENUM('numeric','text','enum') | NO | 'text' | 类型 |
|
||||
| enum_values | JSON | YES | NULL | 枚举值 |
|
||||
| is_searchable | TINYINT(1) | NO | 1 | 是否可搜索 |
|
||||
| sort_order | INT | NO | 0 | 排序 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- UNIQUE: `ux_pad_name` (`attribute_name`)
|
||||
|
||||
**说明**:全局参数字典,定义可用的配件参数。
|
||||
|
||||
---
|
||||
|
||||
### 7.2 part_categories(配件分类)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| name | VARCHAR(64) | NO | | 分类名称 |
|
||||
| parent_id | BIGINT UNSIGNED | YES | NULL | 父分类 |
|
||||
| sort_order | INT | NO | 0 | 排序 |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_pc_parent` (`parent_id`)
|
||||
- UNIQUE: `ux_pc_name` (`name`)
|
||||
|
||||
**说明**:配件专用分类,支持层级结构。
|
||||
|
||||
---
|
||||
|
||||
### 7.3 part_category_attributes(分类参数关联)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| category_id | BIGINT UNSIGNED | NO | | 分类ID |
|
||||
| attribute_id | BIGINT UNSIGNED | NO | | 参数ID |
|
||||
| is_required | TINYINT(1) | NO | 0 | 是否必填 |
|
||||
| sort_order | INT | NO | 0 | 排序 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_pca_category` (`category_id`)
|
||||
- UNIQUE: `ux_pca_cat_attr` (`category_id`, `attribute_id`)
|
||||
|
||||
**外键**:
|
||||
- `fk_pca_category`: `category_id` → `part_categories(id)` ON DELETE CASCADE
|
||||
- `fk_pca_attribute`: `attribute_id` → `part_attribute_dictionary(id)` ON DELETE CASCADE
|
||||
|
||||
**说明**:定义每个配件分类应包含哪些参数。
|
||||
|
||||
---
|
||||
|
||||
### 7.4 part_attribute_templates(参数模板)
|
||||
|
||||
| 字段 | 类型 | 空值 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| id | BIGINT UNSIGNED | NO | AUTO_INCREMENT | 主键 |
|
||||
| template_name | VARCHAR(64) | NO | | 模板名称 |
|
||||
| category_id | BIGINT UNSIGNED | YES | NULL | 关联分类 |
|
||||
| attributes | JSON | NO | | 参数定义JSON |
|
||||
| created_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | NO | CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
**索引**:
|
||||
- PRIMARY KEY: `id`
|
||||
- KEY: `idx_pat_category` (`category_id`)
|
||||
- UNIQUE: `ux_pat_name` (`template_name`)
|
||||
|
||||
**说明**:预定义的参数模板,快速应用到配件。
|
||||
|
||||
---
|
||||
|
||||
## 八、配置参数说明
|
||||
|
||||
### 8.1 VIP相关配置
|
||||
|
||||
| 配置键 | 类型 | 默认值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| vip.dataRetentionDaysForNonVip | number | 60 | 非VIP数据保留天数 |
|
||||
| vip.price | number | 15 | VIP单月价格(元) |
|
||||
| vip.durationDays | number | 30 | 开通时长(天) |
|
||||
|
||||
### 8.2 普通管理员配置
|
||||
|
||||
| 配置键 | 类型 | 默认值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| normalAdmin.autoApprove | boolean | false | 是否自动通过申请 |
|
||||
| normalAdmin.requiredVipActive | boolean | true | 是否要求VIP有效 |
|
||||
|
||||
### 8.3 财务分类配置
|
||||
|
||||
**收入分类**(income_categories):
|
||||
- operation_income: 经营所得
|
||||
- interest_income: 利息收入
|
||||
- other_income: 其它收入
|
||||
- deposit_ar_income: 收订金/欠款
|
||||
- investment_income: 投资收入
|
||||
- sale_income: 销售收入
|
||||
- account_operation: 账户操作
|
||||
- fund_transfer_in: 资金转账转入
|
||||
|
||||
**支出分类**(expense_categories):
|
||||
- operation_expense: 经营支出
|
||||
- office_supplies: 办公用品
|
||||
- rent: 房租
|
||||
- interest_expense: 利息支出
|
||||
- other_expense: 其它支出
|
||||
- account_operation: 账户操作
|
||||
- fund_transfer_out: 资金转账转出
|
||||
|
||||
---
|
||||
|
||||
## 九、数据安全与性能
|
||||
|
||||
### 9.1 敏感数据加密
|
||||
|
||||
- 密码:SHA-256哈希存储(password_hash)
|
||||
- 验证码:SHA-256哈希+盐(code_hash + salt)
|
||||
- 第三方token:加密存储(wechat_sessions.session_key)
|
||||
|
||||
### 9.2 索引策略
|
||||
|
||||
- 高频查询字段:shop_id, user_id, status, created_at
|
||||
- 唯一性约束:email, phone, openid, hash
|
||||
- 复合索引:(shop_id, status), (user_id, created_at)
|
||||
- 全文索引:仅用于products.search_text
|
||||
|
||||
### 9.3 数据清理
|
||||
|
||||
**定期清理**:
|
||||
- sms_codes/email_codes:清理7天前expired记录
|
||||
- wechat_sessions:清理过期会话
|
||||
- inventory_movements:归档6个月前数据(可选)
|
||||
|
||||
**软删除**:
|
||||
- 业务表采用deleted_at标记
|
||||
- 查询默认过滤deleted_at IS NULL
|
||||
- 定期归档软删除数据
|
||||
|
||||
---
|
||||
|
||||
## 十、扩展性设计
|
||||
|
||||
### 10.1 JSON字段应用
|
||||
|
||||
- products.attributes_json: 扩展商品属性
|
||||
- part_submissions.attributes/images/tags: 灵活配件数据
|
||||
- attachments.meta: 文件元信息
|
||||
- system_parameters.value: 动态配置
|
||||
|
||||
### 10.2 ENUM类型管理
|
||||
|
||||
- 新增枚举值需要ALTER TABLE
|
||||
- 重要状态采用ENUM确保数据一致性
|
||||
- 次要分类采用VARCHAR + 配置表
|
||||
|
||||
### 10.3 多语言支持预留
|
||||
|
||||
- 公告内容可扩展为JSON:{zh: "中文", en: "English"}
|
||||
- 财务分类label可支持多语言
|
||||
- 当前版本仅支持简体中文
|
||||
|
||||
---
|
||||
|
||||
**文档维护说明**:
|
||||
- 辅助表主要用于系统配置、认证、审计和扩展功能
|
||||
- 任何结构变更必须同步更新本文档和`backend/db/db.sql`
|
||||
- 配置参数变更需同时更新application.properties默认值
|
||||
- 新增表需评估是否属于核心业务表或辅助表,放入对应文档
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
## 模板参数可模糊查询(±容差)功能需求文档
|
||||
|
||||
### 1. 背景与目标
|
||||
当前用户端「按模板参数查询」要求参数值与数据库完全相同才能命中,实际使用中数值类参数(如内径、外径、长度等)存在测量/录入微小误差,严格等值导致命中率偏低。新增能力:在管理端创建模板时,为每个参数提供「可模糊查询」选项;开启后,用户搜索该参数时按数值区间匹配(±容差);未开启的参数继续精确等值。
|
||||
|
||||
### 2. 业务范围
|
||||
- 场景:用户端/管理端的商品列表查询(含「按模板参数查询」模式)。
|
||||
- 对象:模板参数定义(仅限数值型参数生效)。
|
||||
- 不影响:名称/品牌/型号/规格关键字搜索逻辑;非数值类型参数的等值匹配逻辑。
|
||||
|
||||
### 3. 术语与约束
|
||||
- 模板参数类型:string/number/boolean/enum/date。
|
||||
- 模糊查询仅对 type=number 生效;其他类型不展示该选项或忽略配置。
|
||||
- 容差(tolerance):对搜索入参 v,匹配区间为 \[v - tolerance, v + tolerance](闭区间)。默认容差为 1(见配置项),可在参数层级单独覆盖。
|
||||
- 组合关系:多参数为 AND 关系;每个参数根据其「可模糊查询」与容差独立计算。
|
||||
|
||||
### 4. 交互与流程
|
||||
- 管理端-模板配置:
|
||||
- 新建/编辑模板参数时,新增选项:
|
||||
- 可模糊查询(开关,仅当类型为 number 显示)
|
||||
- 容差值(number,>0,显示单位提示,同 `unit` 字段;当开关开启时必填,否则置空)
|
||||
- 校验:
|
||||
- type≠number 时禁止开启;
|
||||
- 容差必须为正数,支持小数;
|
||||
- 可保存为“使用平台默认容差”,当字段留空时后端落默认(见配置)。
|
||||
- 用户端/管理端-按模板参数查询:
|
||||
- 入参与现状一致:仍以 `templateId` + 多个 `param_*` 传参;
|
||||
- 行为变化:
|
||||
- 对应参数若开启可模糊查询:按区间 \[v - tol, v + tol] 比较;
|
||||
- 否则:仍为精确等值比较。
|
||||
|
||||
### 5. 数据模型变更(待实施)
|
||||
- 表:`part_template_params`
|
||||
- 新增列:
|
||||
- `fuzzy_searchable` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否允许模糊查询(仅数值型)'
|
||||
- `fuzzy_tolerance` DECIMAL(18,6) NULL COMMENT '容差;NULL 表示使用平台默认容差'
|
||||
- 说明:
|
||||
- 仅当 `type='number' AND fuzzy_searchable=1` 时才使用容差;
|
||||
- 初始迁移将全部历史记录置为 `fuzzy_searchable=0, fuzzy_tolerance=NULL`,保持现有行为不变。
|
||||
|
||||
### 6. 配置项(后端)
|
||||
- `search.fuzzy.enabled`(bool,默认 true):是否启用模糊查询全局开关;
|
||||
- `search.fuzzy.defaultTolerance`(decimal,默认 1.0):当参数未设置 `fuzzy_tolerance` 时使用;
|
||||
- 读取途径:Spring 配置(application.properties/yaml)或环境变量。禁止在代码中硬编码数字 1。
|
||||
- 仅全局配置,不支持租户级(`system_parameters`)覆盖;无需设置小数精度上限/最大容差限制。
|
||||
|
||||
### 7. 接口协议与兼容性
|
||||
- 查询接口:`GET /api/products`(已存在)
|
||||
- 入参保持不变:`templateId`、`param_*`。
|
||||
- 语义扩展(无须 `templateId` 也启用模糊):后端将基于商品行的 `template_id` 与参数定义逐行判定某个 `param_*` 是否启用 ±容差;若该参数在对应模板中未开启模糊或非数值型,则对该条件执行等值匹配。
|
||||
- 模板接口:`POST /api/admin/part-templates`、`PUT /api/admin/part-templates/{id}`(已存在)
|
||||
- 参数定义对象新增字段:
|
||||
- `fuzzySearchable`(boolean)
|
||||
- `fuzzyTolerance`(number,nullable)
|
||||
- 若前端暂未改造,后端默认按 `fuzzySearchable=false` 处理,兼容旧请求体。
|
||||
|
||||
(根据「接口规范生效条件」,待功能开发完成后更新 `doc/openapi.yaml` 中对应 schema 与描述,并在 summary/description 标注实现状态)
|
||||
|
||||
### 8. 后端实现要点(建议方案)
|
||||
当前实现(精确匹配),示意:
|
||||
```sql
|
||||
-- 现状(等值):
|
||||
AND JSON_UNQUOTE(JSON_EXTRACT(p.attributes_json, '$.内径')) = '10'
|
||||
```
|
||||
|
||||
推荐实现:
|
||||
- 行级判定方案(支持无 `templateId` 也启用模糊):
|
||||
- 对每个传入的 `param_<key>=v`:
|
||||
- 以 `EXISTS` 子查询或 `JOIN part_template_params ptp ON ptp.template_id=p.template_id AND ptp.field_key='<key>'` 获取参数定义;
|
||||
- 若 `ptp.type='number' AND ptp.fuzzy_searchable=1`:对 `v` 解析为数值,计算 `tol = COALESCE(ptp.fuzzy_tolerance, :defaultTolerance)`;
|
||||
- 下限截断:`lower = GREATEST(0, v - tol)`;
|
||||
- 条件:
|
||||
```sql
|
||||
CAST(JSON_UNQUOTE(JSON_EXTRACT(p.attributes_json, '$.<key>')) AS DECIMAL(18,6)) BETWEEN :lower AND :upper
|
||||
```
|
||||
- 否则:执行等值匹配:
|
||||
```sql
|
||||
JSON_UNQUOTE(JSON_EXTRACT(p.attributes_json, '$.<key>')) = :val
|
||||
```
|
||||
- 快路径(可选):当请求携带 `templateId` 时,可先一次性加载该模板参数定义映射到内存,按映射决定每个条件构造,以减少 `JOIN/EXISTS` 次数。
|
||||
- 容差取值:优先 `ptp.fuzzy_tolerance`,否则全局 `search.fuzzy.defaultTolerance`。
|
||||
|
||||
性能建议:
|
||||
- 初期:允许全表扫描 + JSON_EXTRACT;观察真实 QPS 与延迟;
|
||||
- 进阶(可选):对热点参数引入“生成列 + 索引”(Generated Column),例如:
|
||||
- 在 `products` 增加 `attr_<key> DECIMAL(18,6) GENERATED ALWAYS AS (CAST(JSON_UNQUOTE(JSON_EXTRACT(attributes_json, '$.<key>')) AS DECIMAL(18,6))) STORED` 并建索引,以支持范围查询;
|
||||
- 仅对访问量高的少数参数启用,避免列爆炸。
|
||||
|
||||
### 9. 管理端实现要点(UI/校验)
|
||||
- `admin/src/views/parts/Templates.vue`:
|
||||
- 参数编辑行新增:
|
||||
- 开关:可模糊查询(仅 type=number 显示)
|
||||
- 数值输入:容差(显示单位,>0,支持小数;留空表示使用平台默认)
|
||||
- 保存/加载兼容:与后端新增字段映射,历史数据默认显示为关闭态。
|
||||
- 校验:当参数开启模糊时,对应值在 UI 侧仅允许数字输入;单位提示与 `unit` 一致。
|
||||
|
||||
### 10. 验收标准(Test Cases)
|
||||
- 单参数-模糊:模板字段 `内径`(number,fuzzy=true,tolerance=1);商品 A/B/C 分别取值 9/10/11;搜索 `param_内径=10` 命中 A/B/C。
|
||||
- 单参数-精确:同上但 fuzzy=false;搜索 `param_内径=10` 仅命中 B。
|
||||
- 多参数组合:`内径`(fuzzy=true, tol=0.5)、`长度`(fuzzy=false);搜索 `param_内径=10`、`param_长度=20` 仅命中满足区间与等值的交集。
|
||||
- 无 templateId:也启用模糊;后端逐行按 `p.template_id` 与参数定义判定是否应用容差。
|
||||
- 容差来源:当 `fuzzy_tolerance=NULL` 时,生效平台默认容差;覆盖值生效优先级高于默认。
|
||||
- 非数值参数:即使请求携带 `param_颜色=黑`,也严格等值。
|
||||
- 下限截断:当 `v - tol < 0` 时,以 `0` 作为下限;不支持负数参数匹配。
|
||||
- 非法输入:当参数在模板中开启模糊但请求值非数字时,返回 400(Bad Request)。
|
||||
|
||||
### 11. 兼容与回退
|
||||
- 不改动现有请求入参与返回体,历史客户端无需升级亦可按原精确逻辑使用;
|
||||
- 新能力由模板参数配置显式开启,可随时在模板中关闭;
|
||||
- 如需全局关闭,可通过 `search.fuzzy.enabled=false` 临时禁用(后端配置)。
|
||||
|
||||
### 12. 风险与注意事项
|
||||
- 数据质量:历史 `attributes_json` 中数值可能以字符串存储;需统一以 `CAST(JSON_UNQUOTE(...))` 解析。
|
||||
- 单位与容差:UI 需提示单位;容差与单位一一对应,避免“毫米 vs 厘米”误解。
|
||||
- 性能:范围查询较等值更难走索引;必要时引入“生成列+索引”优化热点字段。
|
||||
- 负数与边界:不支持负数参数;区间采用闭区间,且下限截断为 `0`。
|
||||
|
||||
### 13. 实施清单(参考)
|
||||
1) 数据库:为 `part_template_params` 增列 `fuzzy_searchable`、`fuzzy_tolerance`;(变更需通过 MysqlMCP,成功后同步更新 `doc/database_documentation.md` 与 `backend/db/db.sql`)
|
||||
2) 配置:新增 `search.fuzzy.*` 配置项并给出默认值(全局生效,无租户级覆盖);
|
||||
3) 管理端:模板参数编辑 UI 新增开关与容差输入;
|
||||
4) 后端:按 8 节改造查询 SQL 构建逻辑(无 `templateId` 也启用模糊,行级按模板判定);
|
||||
5) 文档:在功能开发完成后更新 `doc/openapi.yaml` 中模板参数 schema 与 `GET /api/products` 的查询规则说明,并标注实现状态;
|
||||
6) 发布:前后端同步上线;无需灰度与回滚开关;
|
||||
7) 验收:按 10 节用例覆盖单测/集成测试与手工回归。
|
||||
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
## 货品删除功能开发文档(软删方案)
|
||||
|
||||
### 1. 背景与目标
|
||||
- 将“与货品相关”的删除行为统一为软删除,避免历史引用断裂,支持后续恢复与审计。
|
||||
- 用户仅保留“拉黑/恢复”,订单维持“作废 void”,不做删除。
|
||||
|
||||
### 2. 范围
|
||||
- 货品主表:`products`
|
||||
- 关联信息:`product_images`、`product_prices`、`inventories`、`product_aliases`
|
||||
- 相关查询接口:商品搜索、详情、导出(如有)
|
||||
|
||||
### 2.1 父子级联关系(必须遵守)
|
||||
- 分类(`product_categories`) → 模板(`part_templates`) → 商品(`products`)
|
||||
- 规则:
|
||||
- 删除分类 ⇒ 级联软删该分类下所有模板;再级联软删由这些模板创建的所有商品;并同时软删所有 `category_id=该分类` 的商品(包括未通过模板创建的商品)。
|
||||
- 删除模板 ⇒ 仅软删该模板下的商品,不影响同分类其它模板的商品。
|
||||
- 订单不可删除,仅允许作废(void),因此采用“软删”是必要前提,避免历史订单断裂。
|
||||
- 恢复:当前不提供任何恢复入口;如未来开放,恢复不做级联,需逐层独立恢复以避免误恢复。
|
||||
|
||||
### 3. 设计要点
|
||||
- 软删标记:使用 `products.deleted_at DATETIME NULL`(已存在)。被软删即视为“不对外可见”。
|
||||
- 恢复:当前不提供恢复入口。若未来开放,语义为将 `deleted_at=NULL`。
|
||||
- 查询默认过滤:所有列表/搜索默认附加 `deleted_at IS NULL`(当前搜索已实现)。
|
||||
- 详情访问:若记录被软删,返回 404(或通过 `includeDeleted=true` 显式读取)。
|
||||
- 关联表处理:软删商品时不物理删除图片/价格/库存/别名(均按商品引用读取,详情被 404 屏蔽即可)。
|
||||
|
||||
- 模板软删标记统一:为 `part_templates` 引入 `deleted_at DATETIME NULL` 以统一软删标记;`status` 字段保留为启停用,不代表软删。所有查询需同时过滤 `deleted_at IS NULL AND status=1`(按需)。
|
||||
|
||||
- 字典与作用域:分类与单位属于 `shop_id=0` 的全局字典。删除分类会影响所有店铺下此分类的模板与商品;此操作需平台管理员权限并要求二次确认。
|
||||
|
||||
- 报表与搜索:默认排除软删记录;不提供“含回收站”开关。
|
||||
|
||||
- 数据保留与清理:支持配置项 `SOFT_DELETE_RETENTION_DAYS`(默认永久保留,仅清理无引用对象)。
|
||||
|
||||
- 单位删除校验:移除对已废弃 `products.unit_id` 的校验逻辑。
|
||||
|
||||
### 4. 数据库与索引
|
||||
现状:`products` 存在唯一约束 `UNIQUE(shop_id, barcode)`。软删后可能需要“同店铺、同条码”重新建商品。
|
||||
|
||||
- 目标:唯一约束仅作用于“活动记录”(未软删)。
|
||||
- 做法:增加生成列 `is_active` 并重建唯一索引(MySQL 8)。
|
||||
|
||||
DDL(上线脚本草案)
|
||||
```sql
|
||||
-- 仅对生产环境执行一次;如已存在请跳过对应步骤
|
||||
ALTER TABLE products
|
||||
ADD COLUMN is_active TINYINT AS (CASE WHEN deleted_at IS NULL THEN 1 ELSE 0 END) STORED,
|
||||
ADD INDEX idx_products_deleted_at (deleted_at);
|
||||
|
||||
-- 重建唯一索引,使其仅约束未软删记录
|
||||
DROP INDEX ux_products_shop_barcode ON products; -- 若不存在请忽略
|
||||
CREATE UNIQUE INDEX ux_products_shop_barcode_live ON products(shop_id, barcode, is_active);
|
||||
```
|
||||
|
||||
风险与说明
|
||||
- “条码为空”不会受唯一约束影响(MySQL 对 NULL 不唯一);符合预期。
|
||||
- 老数据不受影响;后续删除改为软删即可。
|
||||
- 若未来需要“永久删除”,可新增仅限平台运维的强删脚本,先清理关联,再物理删除目标商品。
|
||||
- 如未来开放“恢复”,当恢复商品与现存“活动记录”在 `(shop_id, barcode)` 上冲突时,恢复应返回 `409 Conflict` 并附带冲突商品信息。
|
||||
|
||||
模板表 DDL(新增软删标记)
|
||||
```sql
|
||||
ALTER TABLE part_templates
|
||||
ADD COLUMN deleted_at DATETIME NULL,
|
||||
ADD INDEX idx_part_templates_deleted_at (deleted_at);
|
||||
```
|
||||
|
||||
### 5. 接口设计(OpenAPI 约定)
|
||||
说明:按规范,等后端开始开发即补充到 `/doc/openapi.yaml` 并标注实现状态;本方案不新增任何“恢复”接口。
|
||||
|
||||
1) 软删商品(行为不变,明确语义)
|
||||
- Method/Path: `DELETE /api/products/{id}`
|
||||
- 语义:软删,将 `deleted_at=NOW()`。
|
||||
- 返回:`200 {}`
|
||||
- 鉴权:需要 `X-Shop-Id`/`X-User-Id` 或 Token,且仅允许同店铺数据。
|
||||
|
||||
2) 商品详情(行为调整)
|
||||
- Method/Path: `GET /api/products/{id}`
|
||||
- 默认:若 `deleted_at IS NOT NULL` 返回 `404`。
|
||||
- 可选:`includeDeleted=true` 时允许读取已软删详情(仅管理端使用)。
|
||||
|
||||
3) 恢复接口
|
||||
- 不同意新增以下恢复接口:`PUT /api/admin/dicts/categories/{id}/restore`、`PUT /api/admin/part-templates/{id}/restore`、`PUT /api/products/{id}/restore`。
|
||||
|
||||
### 6. 后端实现说明
|
||||
- Controller 改动(示意)
|
||||
- `ProductController.delete(id, shopId)`:保持现有调用,内部执行软删。
|
||||
- `GET /api/products/{id}`:调用 `productService.findDetail(id)` 前,先判断 `deleted_at`,若非空且未显式 `includeDeleted` → `404`。
|
||||
|
||||
- Service 改动(核心)
|
||||
- 移除/不提供任何恢复相关方法。
|
||||
- `findDetail(id)`:若被软删且无 `includeDeleted` 参数 → 返回空 Optional。
|
||||
- 模板表采用 `deleted_at` 表示软删,`status` 表示启停用;查询需同时过滤 `deleted_at IS NULL` 与必要的 `status` 条件。
|
||||
|
||||
#### 6.1 级联软删伪代码
|
||||
```java
|
||||
// 分类软删
|
||||
void deleteCategorySoft(Long categoryId) {
|
||||
// 1) 标记分类 deleted_at
|
||||
UPDATE product_categories SET deleted_at=NOW() WHERE id=? AND deleted_at IS NULL;
|
||||
// 2) 级联模板软删(统一使用 deleted_at)
|
||||
UPDATE part_templates SET deleted_at=NOW() WHERE category_id=? AND deleted_at IS NULL;
|
||||
// 3) 级联商品软删:模板创建的商品 + 直接挂在分类下的商品
|
||||
UPDATE products SET deleted_at=NOW() WHERE (
|
||||
template_id IN (SELECT id FROM part_templates WHERE category_id=?)
|
||||
OR category_id=?
|
||||
) AND deleted_at IS NULL;
|
||||
}
|
||||
|
||||
// 模板软删(不波及其它模板)
|
||||
void deleteTemplateSoft(Long templateId) {
|
||||
// 1) 模板标记为软删
|
||||
UPDATE part_templates SET deleted_at=NOW() WHERE id=? AND deleted_at IS NULL;
|
||||
// 2) 级联商品软删(仅该模板下)
|
||||
UPDATE products SET deleted_at=NOW() WHERE template_id=? AND deleted_at IS NULL;
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 前端改动
|
||||
- 列表页:保持不显示软删项(现已过滤)。
|
||||
- 详情页:若接口返回 404,提示“已被删除或无权限”。
|
||||
- 管理端:不提供“回收站/恢复”入口;删除按钮提示:该操作为软删除,对前台不可见,当前无恢复入口。
|
||||
|
||||
### 8. 权限与审计
|
||||
- 鉴权:沿用现有用户/店铺头部识别;仅同店铺商品可操作。
|
||||
- 权限边界:
|
||||
- 普通用户:仅可删除本用户的货品;无权删除模板与分类;无恢复权限。
|
||||
- 店铺管理员:仅有审核功能;无删除模板/分类与恢复权限。
|
||||
- 平台管理员:可删除货品、模板、分类;删除全局分类需二次确认;无恢复权限。
|
||||
- 审计:不记录操作日志(操作者、时间、来源 IP、对象 ID 与名称),以简化开发。
|
||||
|
||||
### 9. 测试用例
|
||||
- 删除后搜索不可见;`GET /api/products/{id}` 返回 404。
|
||||
- 条码唯一:软删后允许同店铺同条码新建。
|
||||
- (如未来开放恢复)恢复时如与现有活动记录冲突,返回 409 并附带冲突商品信息。
|
||||
|
||||
### 10. 发布与回滚
|
||||
- 发布顺序:
|
||||
1) 执行数据库 DDL(生成列与索引)。
|
||||
2) 上线后端(调整 detail 行为,移除/不提供恢复逻辑)。
|
||||
3) 上线前端(不提供回收站/恢复入口)。
|
||||
- 回滚:
|
||||
- 后端回滚到旧版本;DDL 不需要回退(生成列与新索引向前兼容)。
|
||||
|
||||
### 11. FAQ / 风险
|
||||
- 问:软删后图片与价格是否清理?
|
||||
- 答:不清理,保持数据可恢复;若永久删除再统一清理关联。
|
||||
- 问:库存与统计是否包含软删商品?
|
||||
- 答:常规统计应排除软删;如需包含,增加显式参数。
|
||||
- 问:条码冲突如何处理?
|
||||
- 答:按“活动记录”唯一;如未来开放恢复,发现冲突则返回 409,并指明冲突商品。
|
||||
- 问:字典(分类/单位)是否为全局维度?删除是否影响所有店铺?
|
||||
- 答:是,`shop_id=0` 全局字典;删除全局分类会影响所有店铺下该分类的模板与商品,需平台管理员二次确认。
|
||||
- 问:是否保留“强删”入口?
|
||||
- 答:保留仅限平台运维的强删入口(默认关闭)。分类/模板强删前需校验无订单关联商品后再执行。
|
||||
- 问:为何不做物理删除?
|
||||
- 答:订单/流水等历史记录必须可追溯;物理删除会破坏外键与统计。软删能满足“前台不可见、后台可恢复”的业务诉求。
|
||||
|
||||
|
||||
### 12. 任务拆解(实施)
|
||||
- 后端:
|
||||
- [ ] `GET /api/products/{id}` 软删返回 404 / 支持 `includeDeleted`
|
||||
- [ ] 分类删除级联扩展:同时软删 `category_id=该分类` 的商品(含未走模板创建)
|
||||
- [ ] 模板表引入 `deleted_at`;查询同时过滤 `deleted_at IS NULL` 与必要的 `status`
|
||||
- [ ] 移除“单位删除校验检查 products.unit_id”的逻辑
|
||||
- 数据库:
|
||||
- [ ] 为 `products` 增加 `is_active` 与唯一索引(见 DDL)
|
||||
- [ ] 为 `part_templates` 增加 `deleted_at` 与索引
|
||||
- 前端管理端:
|
||||
- [ ] 删除按钮文案更新(软删除,对前台不可见,当前无恢复入口)
|
||||
- [ ] 不提供“回收站/恢复”入口
|
||||
|
||||
(本文件为技术方案与实施指引,变更上线后请同步 `/doc/openapi.yaml` 与 `/doc/database_documentation.md`)
|
||||
|
||||
|
||||
793
doc/项目开发文档.md
Normal file
793
doc/项目开发文档.md
Normal file
@@ -0,0 +1,793 @@
|
||||
# 配件查询系统 - 项目开发文档
|
||||
|
||||
**项目名称**:配件查询App
|
||||
**版本**:v1.0
|
||||
**更新时间**:2025-10-01
|
||||
**技术栈**:Spring Boot 3 + MySQL 8.0 + Vue 3 + uni-app
|
||||
|
||||
---
|
||||
|
||||
## 一、项目概述
|
||||
|
||||
### 1.1 项目定位
|
||||
|
||||
面向小微商户的移动端进销存管理应用,核心功能包括:
|
||||
- 商品管理(库存、价格、类别)
|
||||
- 进销存业务(销售开单、进货开单、退货处理)
|
||||
- 客户与供应商管理
|
||||
- 财务管理(账户、收支、报表)
|
||||
- **配件查询**:支持配件参数化查询、用户提交、审核上架
|
||||
|
||||
### 1.2 系统架构
|
||||
|
||||
```
|
||||
前端层:
|
||||
├── 移动端(uni-app): 用户端App + 微信小程序
|
||||
├── 管理端(Vue3 + Element Plus): 平台管理后台
|
||||
└── 普通管理端(Vue3 + Element Plus): 精简审核后台
|
||||
|
||||
后端层:
|
||||
├── Spring Boot 3.x:RESTful API服务
|
||||
├── MySQL 8.0:数据持久化
|
||||
├── JWT:用户认证
|
||||
└── Python FastAPI(可选):条码识别服务
|
||||
|
||||
部署层:
|
||||
├── 数据库:mysql.tonaspace.com:3306
|
||||
├── 后端:Java应用服务器
|
||||
└── 前端:静态资源 + CDN
|
||||
```
|
||||
|
||||
### 1.3 多租户模型
|
||||
|
||||
- **租户隔离**:所有业务数据必须关联shop_id,严格按租户隔离
|
||||
- **全局字典**:类别、单位使用shop_id=0作为平台共享字典
|
||||
- **权限体系**:
|
||||
- 平台管理员(admins表):跨租户管理
|
||||
- 店主(users.is_owner=1):店铺所有权限
|
||||
- 员工(users.role=staff):基础操作权限
|
||||
- 普通管理员(users.role=normal_admin):配件审核权限
|
||||
|
||||
---
|
||||
|
||||
## 二、核心功能需求
|
||||
|
||||
### 2.1 用户端功能(移动App + 小程序)
|
||||
|
||||
#### 2.1.1 首页Dashboard
|
||||
- ✅ **数据概览**:今日/本月销售额、本月利润、库存数量
|
||||
- ✅ **快捷入口**:客户管理、销售开单、账户管理、供应商管理、进货开单、其他支出、VIP会员、报表统计
|
||||
- ⚠️ **在线客服**:咨询入口已实现,悬浮按钮待添加
|
||||
|
||||
#### 2.1.2 货品管理
|
||||
**列表功能**:
|
||||
- ✅ 按类别筛选、关键字搜索(名称/条码/别名)
|
||||
- ✅ 显示库存数量、零库存提示
|
||||
- ✅ 总货品种类统计
|
||||
|
||||
**新增/编辑**:
|
||||
- ✅ 商品图片上传(多图、排序、预览)
|
||||
- ✅ 扫描条形码(App支持,小程序不支持)
|
||||
- ✅ 必填项:商品名称
|
||||
- ✅ 可选项:类别、品牌、型号、规格、产地、条码、描述
|
||||
- ✅ 价格:进货价、零售价、批发价、大客户价(四列)
|
||||
- ✅ 库存:当前库存、安全库存上下限
|
||||
- ✅ 支持模板化参数录入
|
||||
|
||||
**货品设置**:
|
||||
- ✅ 类别管理(读取全局字典)
|
||||
- ✅ 单位管理(读取全局字典)
|
||||
- ⚠️ 隐藏零库存商品、隐藏进货价:前端功能待实现
|
||||
|
||||
#### 2.1.3 配件查询与提交
|
||||
- ✅ **配件搜索**:多参数组合查询、模糊匹配、分页展示
|
||||
- ✅ **配件提交**:
|
||||
- 型号唯一校验
|
||||
- 多图上传(最多9张)
|
||||
- 参数JSON录入
|
||||
- 备注、安全库存
|
||||
- 提交后进入待审核状态
|
||||
- ✅ **提交记录**:查看pending/approved/rejected状态
|
||||
- ✅ **提交详情**:查看审核结果、驳回原因
|
||||
|
||||
#### 2.1.4 开单模块
|
||||
**销售单**:
|
||||
- ✅ 出货单:选择客户、添加商品、计算合计、收款
|
||||
- ✅ 退货单:客户退货处理
|
||||
- ✅ 收款单:后续收款记录
|
||||
|
||||
**进货单**:
|
||||
- ✅ 进货开单:选择供应商、添加商品、付款
|
||||
- ✅ 进货退货:向供应商退货
|
||||
|
||||
**其他收支**:
|
||||
- ✅ 其他收入:分类、往来单位、结算账户、备注
|
||||
- ✅ 其他支出:分类、往来单位、结算账户、备注
|
||||
- ✅ 财务分类动态配置
|
||||
|
||||
#### 2.1.5 明细查询
|
||||
- ✅ 时间维度筛选:自定义、本周、今日、本月、本年
|
||||
- ✅ 业务类型筛选:销售、进货、收银、资金、盘点
|
||||
- ✅ 关键字搜索:单据号、客户/供应商名、品名、备注
|
||||
- ✅ 总金额统计
|
||||
- ✅ 快速新建单据
|
||||
|
||||
#### 2.1.6 报表统计
|
||||
**资金报表**:
|
||||
- ✅ 利润统计:按时间分析收入/支出/利润
|
||||
- ✅ 销售报表:按客户或按货品维度聚合
|
||||
- ⚠️ 营业员统计:待实现
|
||||
- ⚠️ 导入导出:待实现
|
||||
|
||||
**进销存报表**:
|
||||
- ✅ 销售统计:按商品/客户/时间维度
|
||||
- ✅ 进货统计:按商品/供应商/时间维度
|
||||
- ✅ 库存统计:当前库存、成本、分布
|
||||
- ⚠️ 应收应付对账单:待实现
|
||||
|
||||
#### 2.1.7 我的(用户中心)
|
||||
**个人信息**:
|
||||
- ✅ 查看头像、姓名、手机号、邮箱
|
||||
- ✅ 修改头像、姓名
|
||||
- ✅ 修改密码
|
||||
|
||||
**VIP会员**:
|
||||
- ✅ VIP状态查询(is_vip、expire_at、status)
|
||||
- ✅ 一键开通VIP(点击即开通,临时方案)
|
||||
- ✅ 充值记录查询
|
||||
- ✅ 数据可见性:
|
||||
- VIP用户:查看全部历史数据
|
||||
- 普通用户:仅显示最近60天数据(可配置)
|
||||
|
||||
**基础管理**:
|
||||
- ✅ 客户管理:新增、编辑、查询、默认价格等级
|
||||
- ✅ 供应商管理:新增、编辑、查询、欠款管理
|
||||
|
||||
**登录与注册**:
|
||||
- ✅ 手机号注册/登录
|
||||
- ✅ 邮箱+密码登录
|
||||
- ✅ 邮箱验证码注册
|
||||
- ✅ 忘记密码(邮箱验证码重置)
|
||||
- ⚠️ 短信验证码登录:后端已实现,前端待接入
|
||||
- ⚠️ 微信登录:预留接口,待接入
|
||||
|
||||
**账号与安全**:
|
||||
- ✅ 修改个人信息
|
||||
- ✅ 修改登录密码
|
||||
- ⚠️ 账号注销、退出登录:待实现
|
||||
|
||||
---
|
||||
|
||||
### 2.2 管理端功能(平台管理后台)
|
||||
|
||||
#### 2.2.1 用户管理
|
||||
- ✅ 用户列表:按shop_id/关键字/分页查询
|
||||
- ✅ 编辑用户:姓名、手机、角色、状态
|
||||
- ✅ 拉黑/解除拉黑:置用户status=0/1
|
||||
|
||||
#### 2.2.2 用户配件管理
|
||||
- ✅ 配件列表:按shop_id/关键字查询,显示模板信息
|
||||
- ✅ 编辑配件:品牌、型号、规格、图片
|
||||
- ✅ 配件恢复:取消软删除
|
||||
|
||||
#### 2.2.3 配件审核
|
||||
- ✅ 提交列表:按状态/关键字/时间/店铺筛选
|
||||
- ✅ 审核详情:查看完整信息、图片预览
|
||||
- ✅ 编辑提交:修改名称、参数、图片、备注
|
||||
- ✅ 审核通过:生成products记录、关联图片、记录审核人
|
||||
- ✅ 审核驳回:记录驳回原因、审核人、审核时间
|
||||
- ✅ Excel导出:按筛选条件导出(限2000条)
|
||||
|
||||
#### 2.2.4 配件模板管理
|
||||
- ✅ 模板列表:查看所有模板
|
||||
- ✅ 模板详情:查看参数定义
|
||||
- ⚠️ 创建模板:后端接口已实现,前端待接入
|
||||
- ⚠️ 更新模板:后端接口已实现,前端待接入
|
||||
- ✅ 删除模板:软删除(status=0)或强制删除
|
||||
|
||||
#### 2.2.5 VIP管理
|
||||
- ✅ 会员列表:按手机号/分页查询
|
||||
- ✅ 价格设置:读取/修改vip_price表
|
||||
- ✅ 价格配置接口:`GET/PUT /api/admin/vip/price`
|
||||
- ⚠️ 新增会员:后端接口已实现,前端待接入
|
||||
- ⚠️ 更新会员:后端接口已实现,前端待接入
|
||||
|
||||
#### 2.2.6 公告管理
|
||||
- ✅ 公告列表:按状态/关键字查询
|
||||
- ✅ 创建公告:标题、内容、标签、有效期、状态
|
||||
- ⚠️ 编辑公告:后端接口已实现,前端待接入
|
||||
- ⚠️ 发布/下线:后端接口已实现,前端待接入
|
||||
|
||||
#### 2.2.7 咨询回复
|
||||
- ✅ 咨询列表:按shop_id/状态/关键字查询
|
||||
- ✅ 回复咨询:单次回复并自动标记已解决
|
||||
- ✅ 查看历史:查看用户历史咨询与回复
|
||||
|
||||
#### 2.2.8 主数据字典
|
||||
- ✅ 主单位维护:新增、编辑、删除(shop_id=0)
|
||||
- ✅ 主类别维护:新增、编辑、删除(shop_id=0)
|
||||
|
||||
#### 2.2.9 普通管理员审批
|
||||
- ⚠️ 申请列表:查看待审核申请
|
||||
- ⚠️ 审批通过:赋予normal_admin权限
|
||||
- ⚠️ 审批驳回:记录驳回原因
|
||||
- ⚠️ 撤销权限:移除normal_admin权限
|
||||
|
||||
#### 2.2.10 管理员登录
|
||||
- ⚠️ 登录接口:后端已实现JWT签发,前端待接入
|
||||
- 当前方案:本地存储写入ADMIN_ID临时方案
|
||||
|
||||
---
|
||||
|
||||
### 2.3 普通管理端功能(Admin-Lite)
|
||||
|
||||
#### 2.3.1 定位
|
||||
- 面向VIP用户申请成为普通管理员后使用
|
||||
- 仅包含"配件审核"与"我的"两个功能
|
||||
- 使用用户端账号(邮箱+密码)登录
|
||||
|
||||
#### 2.3.2 配件审核(复用平台管理端逻辑)
|
||||
- ⚠️ 提交列表:限定为本店数据
|
||||
- ⚠️ 审核详情:查看、编辑、图片管理
|
||||
- ⚠️ 通过/驳回:操作权限限定本店
|
||||
- ⚠️ 导出(可选):按配置开放
|
||||
|
||||
#### 2.3.3 我的
|
||||
- ⚠️ 账户信息:展示VIP状态、普通管理员状态
|
||||
- ⚠️ 申请入口:未获批VIP显示"申请成为普通管理员"按钮
|
||||
- ⚠️ 退出登录
|
||||
|
||||
#### 2.3.4 权限规则
|
||||
- 申请资格:必须为VIP用户(可配置是否要求有效期内)
|
||||
- 审批策略:
|
||||
- 方案A(当前采用):平台审核
|
||||
- 方案B:自动通过(通过配置normalAdmin.autoApprove控制)
|
||||
- 有效性约束:普通管理员权限与VIP状态绑定(可配置)
|
||||
- 范围隔离:仅可访问所属shop_id的数据
|
||||
|
||||
---
|
||||
|
||||
## 三、技术实现
|
||||
|
||||
### 3.1 后端技术栈
|
||||
|
||||
**框架与依赖**:
|
||||
- Spring Boot 3.x
|
||||
- Spring Data JPA
|
||||
- Spring Security(JWT)
|
||||
- MySQL Connector
|
||||
- Apache POI(Excel导出)
|
||||
- Java Mail(邮件验证码)
|
||||
|
||||
**项目结构**:
|
||||
```
|
||||
src/main/java/com/example/demo/
|
||||
├── account/ # 账户管理
|
||||
├── admin/ # 管理端控制器
|
||||
├── attachment/ # 附件服务
|
||||
├── auth/ # 认证服务(JWT、邮箱、短信、密码)
|
||||
├── barcode/ # 条码识别代理
|
||||
├── common/ # 公共组件(拦截器、异常处理、配置)
|
||||
├── consult/ # 咨询管理
|
||||
├── customer/ # 客户管理
|
||||
├── dashboard/ # 首页概览
|
||||
├── notice/ # 公告管理
|
||||
├── order/ # 订单管理
|
||||
├── product/ # 商品管理(含配件提交、模板)
|
||||
├── report/ # 报表服务
|
||||
├── supplier/ # 供应商管理
|
||||
├── user/ # 用户管理
|
||||
└── vip/ # VIP管理
|
||||
```
|
||||
|
||||
**配置管理**(application.properties):
|
||||
- 数据库连接:通过环境变量`DB_URL/DB_USER/DB_PASSWORD`注入
|
||||
- JWT配置:`jwt.secret`、`jwt.expiresIn`
|
||||
- 邮件SMTP:`spring.mail.*`
|
||||
- 附件存储:`attachments.upload.storage-dir`
|
||||
- VIP配置:`vip.dataRetentionDaysForNonVip`(默认60天)
|
||||
- 普通管理员:`normalAdmin.autoApprove`(默认false)
|
||||
- ⚠️ 禁止硬编码:所有配置值必须通过环境变量或配置文件注入
|
||||
|
||||
**认证与鉴权**:
|
||||
- JWT Token:用户登录后签发,包含userId、shopId、role
|
||||
- AdminAuthInterceptor:平台管理端鉴权,支持Bearer Token和X-Admin-Id头
|
||||
- NormalAdminAuthInterceptor:普通管理端鉴权,校验role=normal_admin且VIP有效
|
||||
|
||||
---
|
||||
|
||||
### 3.2 前端技术栈
|
||||
|
||||
#### 3.2.1 移动端(uni-app)
|
||||
**技术选型**:
|
||||
- HBuilderX
|
||||
- Vue 2
|
||||
- uni-ui组件库
|
||||
|
||||
**目录结构**:
|
||||
```
|
||||
frontend/
|
||||
├── pages/ # 页面
|
||||
│ ├── auth/ # 登录注册
|
||||
│ ├── index/ # 首页
|
||||
│ ├── product/ # 货品管理(含配件提交)
|
||||
│ ├── order/ # 开单
|
||||
│ ├── detail/ # 明细
|
||||
│ ├── my/ # 我的
|
||||
│ ├── customer/ # 客户
|
||||
│ ├── supplier/ # 供应商
|
||||
│ ├── account/ # 账户
|
||||
│ └── report/ # 报表
|
||||
├── components/ # 组件
|
||||
│ ├── tabs/ # Tab组件
|
||||
│ ├── layout/ # 布局组件
|
||||
│ └── ImageUploader/ # 图片上传
|
||||
└── common/ # 公共文件
|
||||
├── config.js # 配置(API_BASE_URL、VIP_PRICE等)
|
||||
├── http.js # HTTP封装
|
||||
├── constants.js # 常量
|
||||
└── navigation.js # 导航
|
||||
```
|
||||
|
||||
**配置管理**(common/config.js):
|
||||
- API_BASE_URL:优先级:环境变量 > 本地存储 > 默认值
|
||||
- SHOP_ID:店铺ID配置
|
||||
- ENABLE_DEFAULT_USER:开发模式开关
|
||||
- VIP_PRICE_PER_MONTH:VIP价格(默认15元)
|
||||
- ⚠️ 所有配置禁止硬编码,必须支持环境变量覆盖
|
||||
|
||||
#### 3.2.2 管理端(Vue 3 + Element Plus)
|
||||
**技术选型**:
|
||||
- Vue 3 + Vite
|
||||
- Element Plus
|
||||
- Axios
|
||||
|
||||
**目录结构**:
|
||||
```
|
||||
admin/
|
||||
├── src/
|
||||
│ ├── views/ # 页面
|
||||
│ │ ├── admin/ # 用户管理
|
||||
│ │ ├── card/ # 卡片
|
||||
│ │ ├── consult/ # 咨询
|
||||
│ │ ├── dict/ # 字典
|
||||
│ │ ├── normal-admin/ # 普通管理员审批
|
||||
│ │ ├── notice/ # 公告
|
||||
│ │ ├── parts/ # 配件管理(含审核Submissions.vue)
|
||||
│ │ ├── supplier/ # 供应商
|
||||
│ │ ├── users/ # 用户
|
||||
│ │ └── vip/ # VIP管理
|
||||
│ ├── api/ # API封装
|
||||
│ ├── router/ # 路由
|
||||
│ └── styles/ # 样式
|
||||
└── vite.config.ts # Vite配置
|
||||
```
|
||||
|
||||
**HTTP配置**(src/api/http.ts):
|
||||
- 自动注入X-Shop-Id、X-Admin-Id、X-User-Id头
|
||||
- 优先级:localStorage > 环境变量 > 默认值
|
||||
|
||||
#### 3.2.3 普通管理端(Vue 3 + Element Plus)
|
||||
**项目位置**:`normal-admin/`
|
||||
|
||||
**功能**:
|
||||
- 复制admin项目结构,精简为配件审核+我的两个模块
|
||||
- 登录沿用用户端认证接口
|
||||
- 鉴权要求:role=normal_admin且VIP有效
|
||||
|
||||
⚠️ **当前状态**:项目框架已建立,核心功能待实现
|
||||
|
||||
---
|
||||
|
||||
### 3.3 数据库设计
|
||||
|
||||
**核心设计原则**:
|
||||
1. 多租户隔离:所有业务表包含shop_id
|
||||
2. 软删除:使用deleted_at标记,查询时过滤
|
||||
3. 审计追踪:记录创建人、修改人、时间戳
|
||||
4. 外键约束:合理使用,避免过度影响性能
|
||||
5. 索引优化:高频查询字段建立复合索引
|
||||
|
||||
**表分类**:
|
||||
- 核心业务表(30个):见《数据库设计文档-核心业务表.md》
|
||||
- 辅助配置表(16个):见《数据库设计文档-辅助配置表.md》
|
||||
|
||||
**重要约束**:
|
||||
- products.barcode:(shop_id, barcode)唯一
|
||||
- part_submissions.model_unique:全局唯一
|
||||
- users.phone/email:全局唯一
|
||||
- accounts.name:(shop_id, name)唯一
|
||||
- orders.order_no:(shop_id, order_no)唯一
|
||||
|
||||
---
|
||||
|
||||
### 3.4 接口设计
|
||||
|
||||
**接口文档**:`doc/openapi.yaml`
|
||||
|
||||
**实现状态标注**:
|
||||
- ✅ Fully Implemented:前后端均已实现并联调通过
|
||||
- ❌ Partially Implemented:仅一方实现或未完全联调
|
||||
|
||||
**核心接口组**:
|
||||
1. 认证:`/api/auth/*`
|
||||
2. 用户端:`/api/user/*`、`/api/products/*`、`/api/orders/*`、`/api/vip/*`
|
||||
3. 平台管理端:`/api/admin/*`
|
||||
4. 普通管理端:`/api/normal-admin/*`
|
||||
5. 公共:`/api/notices`、`/api/attachments`、`/api/finance/categories`
|
||||
|
||||
**Header约定**:
|
||||
- X-Shop-Id:店铺ID(默认1)
|
||||
- X-User-Id:用户ID(用户端接口必传)
|
||||
- X-Admin-Id:管理员ID(管理端接口必传)
|
||||
- Authorization:Bearer Token(JWT方案,逐步迁移)
|
||||
|
||||
---
|
||||
|
||||
## 四、开发状态
|
||||
|
||||
### 4.1 已完成功能
|
||||
|
||||
**后端**:
|
||||
- ✅ 用户认证体系(邮箱、密码、JWT)
|
||||
- ✅ 商品管理(CRUD、价格、库存、图片)
|
||||
- ✅ 配件提交与审核(用户提交、管理员审核、导出)
|
||||
- ✅ 配件模板管理(CRUD、参数定义)
|
||||
- ✅ 客户与供应商管理
|
||||
- ✅ 订单管理(销售、进货、退货、付款)
|
||||
- ✅ 财务管理(账户、其他收支、分类配置)
|
||||
- ✅ 库存流水记录
|
||||
- ✅ VIP状态查询与一键开通
|
||||
- ✅ VIP充值记录查询
|
||||
- ✅ 公告管理(CRUD、发布、下线)
|
||||
- ✅ 咨询与回复
|
||||
- ✅ 主数据字典维护
|
||||
- ✅ 附件上传与校验
|
||||
- ✅ 首页概览统计
|
||||
- ✅ 销售报表(按客户/货品维度)
|
||||
- ✅ 条码识别代理
|
||||
|
||||
**移动端(uni-app)**:
|
||||
- ✅ 登录注册(邮箱密码、邮箱验证码)
|
||||
- ✅ 首页概览
|
||||
- ✅ 商品列表、详情、新增、编辑
|
||||
- ✅ 配件提交、列表、详情
|
||||
- ✅ 开单(销售、进货、退货、其他收支)
|
||||
- ✅ 客户与供应商管理
|
||||
- ✅ VIP状态查询与开通
|
||||
- ✅ 用户信息查看与修改
|
||||
|
||||
**管理端(Vue3)**:
|
||||
- ✅ 用户管理(列表、编辑、拉黑)
|
||||
- ✅ 用户配件管理(列表、编辑、恢复)
|
||||
- ✅ 配件审核(列表、详情、通过、驳回、导出)
|
||||
- ✅ 模板列表、详情、删除
|
||||
- ✅ VIP列表、价格设置
|
||||
- ✅ 公告列表、创建
|
||||
- ✅ 咨询列表、回复、历史
|
||||
- ✅ 主数据字典维护
|
||||
|
||||
---
|
||||
|
||||
### 4.2 待完成功能
|
||||
|
||||
**高优先级**:
|
||||
- ⚠️ 管理员登录页(前端)
|
||||
- ⚠️ 普通管理员审批流程(前后端)
|
||||
- ⚠️ 普通管理端核心功能(前端)
|
||||
- ⚠️ 短信验证码登录(前端接入)
|
||||
- ⚠️ 数据库脚本同步(backend/db/db.sql缺少多个表)
|
||||
|
||||
**中优先级**:
|
||||
- ⚠️ 公告编辑、发布、下线(前端)
|
||||
- ⚠️ VIP新增、更新(前端)
|
||||
- ⚠️ 配件模板创建、更新(前端)
|
||||
- ⚠️ 账号注销、退出登录
|
||||
- ⚠️ 货品设置(隐藏零库存、隐藏进货价)
|
||||
- ⚠️ 悬浮客服入口
|
||||
- ⚠️ 应收应付对账单
|
||||
- ⚠️ 营业员统计
|
||||
|
||||
**低优先级**:
|
||||
- ⚠️ 微信登录(第三方认证)
|
||||
- ⚠️ 数据导入导出
|
||||
- ⚠️ 多语言支持
|
||||
- ⚠️ 公告富文本编辑
|
||||
- ⚠️ 操作日志可视化
|
||||
|
||||
---
|
||||
|
||||
### 4.3 已知问题
|
||||
|
||||
#### 4.3.1 严重问题
|
||||
1. **数据库脚本不一致**:
|
||||
- backend/db/db.sql缺少:admins、vip_users、vip_price、vip_recharges、sms_codes、email_codes、normal_admin_audits、consults、consult_replies、notices等表
|
||||
- 新环境部署时无法初始化
|
||||
- **建议**:立即同步db.sql与线上数据库结构
|
||||
|
||||
2. **密码默认值泄露**:
|
||||
- application.properties第14行硬编码数据库密码默认值
|
||||
- **建议**:移除默认值,强制要求环境变量
|
||||
|
||||
3. **unitId字段不一致**:
|
||||
- Product实体无unitId字段(已移除)
|
||||
- ProductDtos仍保留unitId
|
||||
- OpenAPI文档中ProductDetail包含unitId
|
||||
- **建议**:统一移除所有unitId引用
|
||||
|
||||
#### 4.3.2 中等问题
|
||||
1. **身份验证混乱**:
|
||||
- 后端支持JWT和X-Admin-Id两种方式
|
||||
- 前端仍使用X-Admin-Id
|
||||
- **建议**:统一迁移到JWT Bearer Token
|
||||
|
||||
2. **OpenAPI状态不准确**:
|
||||
- 多个已实现接口仍标记为"Partially Implemented"
|
||||
- **建议**:逐一验证并更新状态
|
||||
|
||||
3. **配置硬编码**:
|
||||
- 前端存在多处硬编码fallback值(http://127.0.0.1:8080)
|
||||
- **建议**:通过配置文件统一管理
|
||||
|
||||
---
|
||||
|
||||
## 五、部署与运维
|
||||
|
||||
### 5.1 环境要求
|
||||
|
||||
**生产环境**:
|
||||
- JDK 17+
|
||||
- MySQL 8.0+
|
||||
- Node.js 16+(前端构建)
|
||||
- Python 3.8+(可选,条码识别服务)
|
||||
|
||||
**开发环境**:
|
||||
- IntelliJ IDEA / VS Code
|
||||
- HBuilderX(uni-app开发)
|
||||
- Maven 3.8+
|
||||
- Git
|
||||
|
||||
---
|
||||
|
||||
### 5.2 环境变量配置
|
||||
|
||||
**后端必需**:
|
||||
```bash
|
||||
# 数据库
|
||||
DB_URL=jdbc:mysql://mysql.tonaspace.com:3306/partsinquiry
|
||||
DB_USER=root
|
||||
DB_PASSWORD=<实际密码>
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=<随机生成的密钥>
|
||||
JWT_EXPIRES_IN=86400
|
||||
|
||||
# 邮件(如需邮箱验证码)
|
||||
MAIL_HOST=smtp.qq.com
|
||||
MAIL_PORT=465
|
||||
MAIL_USERNAME=<邮箱>
|
||||
MAIL_PASSWORD=<授权码>
|
||||
MAIL_FROM=<发件邮箱>
|
||||
|
||||
# 附件存储
|
||||
ATTACHMENTS_DIR=./data/attachments
|
||||
ATTACHMENTS_PLACEHOLDER_IMAGE=<占位图路径>
|
||||
|
||||
# VIP配置
|
||||
VIP_NONVIP_RETENTION_DAYS=60
|
||||
```
|
||||
|
||||
**前端必需**:
|
||||
```bash
|
||||
# 移动端(uni-app)
|
||||
VITE_APP_API_BASE_URL=https://api.example.com
|
||||
VITE_APP_SHOP_ID=1
|
||||
VITE_APP_VIP_PRICE=15
|
||||
|
||||
# 管理端(Vue3)
|
||||
VITE_APP_API_BASE_URL=https://api.example.com
|
||||
VITE_APP_TITLE=配件查询管理端
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.3 部署流程
|
||||
|
||||
**后端部署**:
|
||||
```bash
|
||||
# 1. 打包
|
||||
mvn clean package -DskipTests
|
||||
|
||||
# 2. 上传jar包
|
||||
scp target/demo-0.0.1-SNAPSHOT.jar user@server:/app/
|
||||
|
||||
# 3. 启动服务
|
||||
java -jar demo-0.0.1-SNAPSHOT.jar \
|
||||
--spring.profiles.active=prod \
|
||||
--server.port=8080
|
||||
```
|
||||
|
||||
**前端部署**:
|
||||
```bash
|
||||
# 移动端(uni-app)
|
||||
# HBuilderX: 发行 → 原生App-云打包 / 小程序-微信
|
||||
|
||||
# 管理端(Vue3)
|
||||
cd admin
|
||||
npm run build
|
||||
# 将dist目录上传到Nginx/CDN
|
||||
```
|
||||
|
||||
**数据库初始化**:
|
||||
```bash
|
||||
# 首次部署执行
|
||||
mysql -h mysql.tonaspace.com -u root -p partsinquiry < backend/db/db.sql
|
||||
|
||||
# ⚠️ 注意:当前db.sql不完整,需先同步结构
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.4 监控与日志
|
||||
|
||||
**日志配置**:
|
||||
- 路径:`./logs/application.log`
|
||||
- 级别:生产环境INFO,开发环境DEBUG
|
||||
- 轮转:按日期分割,保留30天
|
||||
|
||||
**监控指标**:
|
||||
- 应用健康检查:`/actuator/health`
|
||||
- JVM内存:通过Spring Boot Actuator暴露
|
||||
- 数据库连接池:Hikari监控
|
||||
- 接口响应时间:Logback日志记录
|
||||
|
||||
**告警规则**:
|
||||
- 数据库连接失败
|
||||
- 磁盘空间<10%
|
||||
- 内存使用>90%
|
||||
- 接口5xx错误率>1%
|
||||
|
||||
---
|
||||
|
||||
## 六、开发规范
|
||||
|
||||
### 6.1 代码规范
|
||||
|
||||
**后端(Java)**:
|
||||
- 遵循阿里巴巴Java开发手册
|
||||
- 统一使用Lombok简化代码
|
||||
- 异常处理:GlobalExceptionHandler统一捕获
|
||||
- 日志:使用SLF4J + Logback
|
||||
- 事务:@Transactional注解,只读操作标记readOnly=true
|
||||
|
||||
**前端(JavaScript/TypeScript)**:
|
||||
- ESLint规则:推荐配置
|
||||
- 组件命名:PascalCase
|
||||
- 变量命名:camelCase
|
||||
- 常量命名:UPPER_SNAKE_CASE
|
||||
|
||||
---
|
||||
|
||||
### 6.2 Git工作流
|
||||
|
||||
**分支策略**:
|
||||
- main:生产环境
|
||||
- develop:开发环境
|
||||
- feature/*:功能分支
|
||||
- hotfix/*:紧急修复
|
||||
|
||||
**提交规范**:
|
||||
```
|
||||
feat: 新功能
|
||||
fix: 修复bug
|
||||
docs: 文档更新
|
||||
style: 代码格式调整
|
||||
refactor: 重构
|
||||
test: 测试相关
|
||||
chore: 构建/工具配置
|
||||
```
|
||||
|
||||
**禁止操作**:
|
||||
- ❌ 直接push到main分支
|
||||
- ❌ 提交时跳过hooks(--no-verify)
|
||||
- ❌ force push到main/master
|
||||
- ❌ 提交大文件(>10MB)
|
||||
- ❌ 提交敏感信息(密码、密钥)
|
||||
|
||||
---
|
||||
|
||||
### 6.3 数据库变更流程
|
||||
|
||||
1. **本地测试**:在开发环境验证DDL
|
||||
2. **更新文档**:同步修改`doc/数据库设计文档-*.md`
|
||||
3. **更新脚本**:同步修改`backend/db/db.sql`
|
||||
4. **执行变更**:通过MysqlMCP执行线上变更
|
||||
5. **验证结果**:查询information_schema确认结构
|
||||
6. **更新代码**:修改Entity、DTO、Service
|
||||
7. **更新接口**:修改`doc/openapi.yaml`
|
||||
|
||||
⚠️ **禁止直接在生产环境手动执行DDL**
|
||||
|
||||
---
|
||||
|
||||
## 七、测试策略
|
||||
|
||||
### 7.1 单元测试
|
||||
|
||||
**覆盖率要求**:
|
||||
- Service层:>80%
|
||||
- Controller层:>60%
|
||||
- Util工具类:>90%
|
||||
|
||||
**测试框架**:
|
||||
- JUnit 5
|
||||
- Mockito
|
||||
- Spring Boot Test
|
||||
|
||||
### 7.2 集成测试
|
||||
|
||||
**关键场景**:
|
||||
- 配件提交 → 审核 → 生成商品
|
||||
- 销售开单 → 库存扣减 → 收款
|
||||
- VIP开通 → 数据可见性变化
|
||||
- 普通管理员申请 → 审批 → 权限生效
|
||||
|
||||
### 7.3 性能测试
|
||||
|
||||
**压测指标**:
|
||||
- 商品列表查询:<200ms(1000并发)
|
||||
- 订单创建:<500ms(100并发)
|
||||
- 配件搜索:<300ms(支持全文检索)
|
||||
|
||||
**工具**:
|
||||
- JMeter
|
||||
- Apache Bench
|
||||
|
||||
---
|
||||
|
||||
## 八、后续规划
|
||||
|
||||
### 8.1 短期(1-2月)
|
||||
|
||||
1. 完成普通管理员审批流程
|
||||
2. 前端统一迁移到JWT认证
|
||||
3. 同步数据库脚本(db.sql)
|
||||
4. 补充缺失的前端功能(公告编辑、VIP管理等)
|
||||
5. 完善单元测试覆盖率
|
||||
|
||||
### 8.2 中期(3-6月)
|
||||
|
||||
1. 微信登录集成
|
||||
2. 数据导入导出功能
|
||||
3. 高级报表(利润分析、库龄分析)
|
||||
4. 消息通知系统(审核结果、VIP到期提醒)
|
||||
5. 多语言支持(国际化)
|
||||
|
||||
### 8.3 长期(6月+)
|
||||
|
||||
1. 移动端原生性能优化
|
||||
2. 大数据量优化(分库分表)
|
||||
3. 多角色权限体系(RBAC)
|
||||
4. 第三方支付集成(微信支付、支付宝)
|
||||
5. 数据分析与BI看板
|
||||
6. API开放平台(OAuth2.0)
|
||||
|
||||
---
|
||||
|
||||
## 九、联系方式
|
||||
|
||||
**技术支持**:
|
||||
- 项目地址:C:\Users\21826\Desktop\wj\PartsInquiry
|
||||
- 数据库:mysql.tonaspace.com:3306
|
||||
- 文档路径:doc/
|
||||
|
||||
**文档维护**:
|
||||
- 数据库变更后必须更新数据库设计文档
|
||||
- 接口变更后必须更新openapi.yaml
|
||||
- 新功能上线后必须更新本开发文档
|
||||
|
||||
---
|
||||
|
||||
**文档修订历史**:
|
||||
- 2025-10-01:初始版本,整合现有需求与开发状态
|
||||
|
||||
Reference in New Issue
Block a user