Files
PartsInquiry/doc/数据库设计文档-核心业务表.md
2025-10-08 19:15:20 +08:00

998 lines
36 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 配件查询系统 - 数据库设计文档(核心业务表)
**版本**: 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 | | 店铺ID0=全局) |
| 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 | | 店铺ID0=全局) |
| 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` 脚本