dingdanquanliucheng/开发细节/03-数据库调整设计.md

307 lines
13 KiB
Markdown
Raw Normal View History

2026-05-14 13:51:06 +08:00
# 数据库调整设计
## 1. 调整目标
基于现有 `数据库.sql`,补齐开发总纲中新增或明确的能力:
- 订单状态新增 `cancel_pending`
- 订单固定提成金额
- 订单取消申请与取消前状态记录
- 产品分类独立维护
- 报表分类映射配置
- 欠款生成模式配置
- 阿里云 OSS 文件字段补充
- 司机任务手动创建/分配需要的字段补充
- 工厂下发确认记录
## 2. 状态与枚举调整
### 2.1 订单状态
`sales_order.order_status` 继续使用 `varchar(32)`,业务层限制枚举。
| 状态值 | 说明 |
| --- | --- |
| `draft` | 草稿 |
| `pending_approve` | 待审核 |
| `approved` | 已通过,待生成/确认下发工厂文本 |
| `rejected` | 已退回 |
| `pending_factory` | 已确认下发工厂,待工厂处理 |
| `pending_driver` | 待司机接单 |
| `accepted` | 已接单 |
| `picked_up` | 已揽货 |
| `delivered` | 已送达 |
| `production` | 生产中 |
| `shipped` | 已发货 |
| `completed` | 已完成 |
| `settled` | 已结算 |
| `cancel_pending` | 取消申请中 |
| `canceled` | 已取消 |
### 2.2 欠款生成模式
使用 `system_config` 保存。
| config_key | config_value | 说明 |
| --- | --- | --- |
| `arrears_generate_mode` | `delivered` | 默认,送达后生成欠款 |
| `arrears_generate_mode` | `shipped` | 发货后生成欠款 |
## 3. 表结构调整清单
### 3.1 `sales_order` 调整
新增字段:
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `commission_amount` | decimal(18,2) | 0.00 | 订单固定提成金额 |
| `cancel_requested_by` | bigint | null | 取消申请人 |
| `cancel_requested_at` | datetime | null | 取消申请时间 |
| `cancel_reason` | varchar(255) | null | 取消原因 |
| `cancel_opinion` | varchar(1000) | null | 取消说明 |
| `cancel_previous_status` | varchar(32) | null | 进入 `cancel_pending` 前状态 |
| `supplier_text_confirmed_at` | datetime | null | 确认下发工厂时间 |
| `supplier_text_confirmed_by` | bigint | null | 确认下发人 |
索引:
| 索引 | 字段 | 说明 |
| --- | --- | --- |
| `idx_sales_order_cancel_requested_by` | `cancel_requested_by` | 取消申请查询 |
| `idx_sales_order_supplier_confirmed_at` | `supplier_text_confirmed_at` | 下发确认查询 |
### 3.2 新增 `product_category`
用于管理员维护产品分类,不再将工业品/日用品写死。
| 字段 | 类型 | 约束 | 说明 |
| --- | --- | --- | --- |
| `id` | bigint | PK | 主键 |
| `category_name` | varchar(64) | not null | 分类名称 |
| `category_code` | varchar(64) | not null unique | 分类编码 |
| `sort_no` | int | default 0 | 排序 |
| `status` | tinyint | default 1 | 1 启用0 停用 |
| `remark` | varchar(500) | null | 备注 |
| `created_at` | datetime | default current_timestamp | 创建时间 |
| `updated_at` | datetime | on update current_timestamp | 更新时间 |
| `deleted` | tinyint | default 0 | 逻辑删除 |
### 3.3 `product` 调整
新增字段:
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `category_id` | bigint | null | 产品分类 ID |
保留 `category` 快照/冗余字段,方便历史兼容和展示。
索引:
| 索引 | 字段 |
| --- | --- |
| `idx_product_category_id` | `category_id` |
### 3.4 新增 `order_supplier_text_log`
记录下发工厂文本生成与确认历史。
| 字段 | 类型 | 约束 | 说明 |
| --- | --- | --- | --- |
| `id` | bigint | PK | 主键 |
| `order_id` | bigint | not null | 订单 ID |
| `supplier_id` | bigint | not null | 工厂/供应商 ID |
| `template_type` | varchar(64) | null | 模板类型 |
| `text_content` | longtext | not null | 下发文本 |
| `confirmed` | tinyint | default 0 | 是否确认下发 |
| `confirmed_by` | bigint | null | 确认人 |
| `confirmed_at` | datetime | null | 确认时间 |
| `created_by` | bigint | null | 生成人 |
| `created_at` | datetime | default current_timestamp | 创建时间 |
索引:
| 索引 | 字段 |
| --- | --- |
| `idx_supplier_text_order_id` | `order_id` |
| `idx_supplier_text_supplier_id` | `supplier_id` |
### 3.5 `logistics_task` 调整
现有字段基本满足手动创建司机任务。建议补充:
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `created_by` | bigint | null | 任务创建人 |
| `canceled_at` | datetime | null | 任务取消时间 |
| `canceled_by` | bigint | null | 任务取消人 |
| `cancel_reason` | varchar(500) | null | 任务取消原因 |
### 3.6 `file_attachment` 调整
为阿里云 OSS 图片、视频和附件补充元数据。
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `storage_provider` | varchar(32) | `aliyun_oss` | 存储服务商 |
| `bucket_name` | varchar(128) | null | OSS Bucket |
| `object_key` | varchar(1000) | null | OSS Object Key |
| `content_type` | varchar(128) | null | MIME 类型 |
| `file_ext` | varchar(32) | null | 扩展名 |
| `file_category` | varchar(32) | null | image/video/document/export/import |
索引:
| 索引 | 字段 |
| --- | --- |
| `idx_file_attachment_category` | `file_category` |
| `idx_file_attachment_object_key` | `object_key` |
### 3.7 `customer_arrears` 调整
补充结算关闭字段:
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `generated_mode` | varchar(32) | null | `shipped``delivered` |
| `settled_at` | datetime | null | 结算时间 |
| `settled_by` | bigint | null | 结算操作人 |
| `closed_at` | datetime | null | 关闭时间 |
### 3.8 `system_config` 初始化配置
建议初始化以下配置:
| config_key | config_value | config_name |
| --- | --- | --- |
| `arrears_generate_mode` | `delivered` | 欠款生成模式 |
| `logistics_timeout_hours` | `48` | 物流超时小时数 |
| `inactive_customer_days` | `90` | 沉默客户周期 |
| `inactive_customer_amount_threshold` | `1000` | 沉默客户金额阈值 |
| `report_category_mapping` | `{}` | 报表分类映射 |
| `aliyun_oss_bucket` | 空 | 阿里云 OSS Bucket |
| `aliyun_oss_endpoint` | 空 | 阿里云 OSS Endpoint |
| `aliyun_ai_region` | 空 | 阿里云 AI/OCR 地域 |
敏感凭证不写入数据库明文字段,使用环境变量或安全配置。
## 4. 建议迁移 SQL
以下 SQL 是基于现有 `数据库.sql` 的增量调整示例,实际执行应通过 Alembic 迁移管理。
```sql
CREATE TABLE IF NOT EXISTS `product_category` (
`id` bigint NOT NULL COMMENT '主键',
`category_name` varchar(64) NOT NULL COMMENT '分类名称',
`category_code` varchar(64) NOT NULL COMMENT '分类编码',
`sort_no` int NOT NULL DEFAULT 0 COMMENT '排序号',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态1启用 0停用',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint NOT NULL DEFAULT 0 COMMENT '逻辑删除0否 1是',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_product_category_code` (`category_code`),
KEY `idx_product_category_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品分类表';
ALTER TABLE `product`
ADD COLUMN `category_id` bigint DEFAULT NULL COMMENT '产品分类ID' AFTER `category`,
ADD KEY `idx_product_category_id` (`category_id`);
ALTER TABLE `sales_order`
ADD COLUMN `commission_amount` decimal(18,2) NOT NULL DEFAULT 0.00 COMMENT '订单固定提成金额' AFTER `profit_rate`,
ADD COLUMN `cancel_requested_by` bigint DEFAULT NULL COMMENT '取消申请人' AFTER `canceled_at`,
ADD COLUMN `cancel_requested_at` datetime DEFAULT NULL COMMENT '取消申请时间' AFTER `cancel_requested_by`,
ADD COLUMN `cancel_reason` varchar(255) DEFAULT NULL COMMENT '取消原因' AFTER `cancel_requested_at`,
ADD COLUMN `cancel_opinion` varchar(1000) DEFAULT NULL COMMENT '取消说明' AFTER `cancel_reason`,
ADD COLUMN `cancel_previous_status` varchar(32) DEFAULT NULL COMMENT '取消前状态' AFTER `cancel_opinion`,
ADD COLUMN `supplier_text_confirmed_at` datetime DEFAULT NULL COMMENT '确认下发工厂时间' AFTER `cancel_previous_status`,
ADD COLUMN `supplier_text_confirmed_by` bigint DEFAULT NULL COMMENT '确认下发人' AFTER `supplier_text_confirmed_at`,
ADD KEY `idx_sales_order_cancel_requested_by` (`cancel_requested_by`),
ADD KEY `idx_sales_order_supplier_confirmed_at` (`supplier_text_confirmed_at`);
CREATE TABLE IF NOT EXISTS `order_supplier_text_log` (
`id` bigint NOT NULL COMMENT '主键',
`order_id` bigint NOT NULL COMMENT '订单ID',
`supplier_id` bigint NOT NULL COMMENT '工厂/供应商ID',
`template_type` varchar(64) DEFAULT NULL COMMENT '模板类型',
`text_content` longtext NOT NULL COMMENT '下发文本',
`confirmed` tinyint NOT NULL DEFAULT 0 COMMENT '是否确认下发0否 1是',
`confirmed_by` bigint DEFAULT NULL COMMENT '确认人',
`confirmed_at` datetime DEFAULT NULL COMMENT '确认时间',
`created_by` bigint DEFAULT NULL COMMENT '生成人',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_supplier_text_order_id` (`order_id`),
KEY `idx_supplier_text_supplier_id` (`supplier_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工厂下发文本记录表';
ALTER TABLE `logistics_task`
ADD COLUMN `created_by` bigint DEFAULT NULL COMMENT '任务创建人' AFTER `factory_id`,
ADD COLUMN `canceled_at` datetime DEFAULT NULL COMMENT '任务取消时间' AFTER `delivered_at`,
ADD COLUMN `canceled_by` bigint DEFAULT NULL COMMENT '任务取消人' AFTER `canceled_at`,
ADD COLUMN `cancel_reason` varchar(500) DEFAULT NULL COMMENT '任务取消原因' AFTER `canceled_by`;
ALTER TABLE `file_attachment`
ADD COLUMN `storage_provider` varchar(32) NOT NULL DEFAULT 'aliyun_oss' COMMENT '存储服务商' AFTER `file_size`,
ADD COLUMN `bucket_name` varchar(128) DEFAULT NULL COMMENT 'OSS Bucket' AFTER `storage_provider`,
ADD COLUMN `object_key` varchar(1000) DEFAULT NULL COMMENT 'OSS Object Key' AFTER `bucket_name`,
ADD COLUMN `content_type` varchar(128) DEFAULT NULL COMMENT 'MIME类型' AFTER `object_key`,
ADD COLUMN `file_ext` varchar(32) DEFAULT NULL COMMENT '扩展名' AFTER `content_type`,
ADD COLUMN `file_category` varchar(32) DEFAULT NULL COMMENT '文件类别' AFTER `file_ext`,
ADD KEY `idx_file_attachment_category` (`file_category`),
ADD KEY `idx_file_attachment_object_key` (`object_key`(191));
ALTER TABLE `customer_arrears`
ADD COLUMN `generated_mode` varchar(32) DEFAULT NULL COMMENT '欠款生成模式shipped/delivered' AFTER `status`,
ADD COLUMN `settled_at` datetime DEFAULT NULL COMMENT '结算时间' AFTER `reminded_at`,
ADD COLUMN `settled_by` bigint DEFAULT NULL COMMENT '结算操作人' AFTER `settled_at`,
ADD COLUMN `closed_at` datetime DEFAULT NULL COMMENT '关闭时间' AFTER `settled_by`;
```
## 5. 初始化数据建议
### 5.1 产品分类
```sql
INSERT INTO `product_category` (`id`, `category_name`, `category_code`, `sort_no`, `status`)
VALUES
(1, '工业品', 'industry', 1, 1),
(2, '日用品', 'daily', 2, 1);
```
### 5.2 系统配置
```sql
INSERT INTO `system_config` (`id`, `config_key`, `config_value`, `config_name`, `remark`, `status`)
VALUES
(1001, 'arrears_generate_mode', 'delivered', '欠款生成模式', 'shipped=发货后记账delivered=送达后记账', 1),
(1002, 'logistics_timeout_hours', '48', '物流超时小时数', '首个物流节点超过该小时数无流转提醒', 1),
(1003, 'inactive_customer_days', '90', '沉默客户周期', '超过该天数未下单触发检查', 1),
(1004, 'inactive_customer_amount_threshold', '1000', '沉默客户金额阈值', '低于该金额不提醒', 1),
(1005, 'report_category_mapping', '{}', '报表分类映射', '按产品分类配置统计口径', 1);
```
## 6. 数据一致性规则
| 场景 | 规则 |
| --- | --- |
| 客户去重 | `crm_customer.customer_name + mobile` 唯一 |
| 产品快照 | 订单明细保存名称、规格、单位快照,历史订单不随产品变化 |
| 取消审批 | 进入 `cancel_pending` 时保存 `cancel_previous_status`,拒绝取消后恢复 |
| 下发确认 | 确认下发时写 `order_supplier_text_log`,订单状态变为 `pending_factory` |
| 欠款生成 | 按 `arrears_generate_mode``shipped``delivered` 状态生成 |
| 附件存储 | OSS 上传成功后必须写入 `file_attachment` |
| 审计日志 | 所有关键写操作必须写入 `audit_log` |
## 7. Alembic 迁移要求
- 每次表结构变更必须生成独立 migration 文件。
- migration 文件必须包含 upgrade 和 downgrade。
- 初始化数据可以单独 migration避免和结构变更混在一起。
- 生产环境禁止直接手工改表,必须通过迁移执行。
- 敏感配置如 OSS AccessKey、阿里云模型凭证不得写入 migration。