642 lines
22 KiB
Markdown
642 lines
22 KiB
Markdown
# 外卖SaaS系统 - 数据库设计
|
||
|
||
## 1. 数据库设计原则
|
||
|
||
### 1.1 命名规范
|
||
- **表名**:小写字母,下划线分隔,复数形式(如:`orders`, `order_items`)
|
||
- **字段名**:小写字母,下划线分隔(如:`created_at`, `total_amount`)
|
||
- **主键**:统一使用 `id`,类型为 UUID
|
||
- **外键**:`表名_id`(如:`order_id`, `merchant_id`)
|
||
- **索引**:`idx_表名_字段名`(如:`idx_orders_merchant_id`)
|
||
|
||
### 1.2 通用字段
|
||
所有表都包含以下字段:
|
||
- `id`:UUID,主键
|
||
- `created_at`:TIMESTAMP,创建时间
|
||
- `updated_at`:TIMESTAMP,更新时间
|
||
- `deleted_at`:TIMESTAMP,软删除时间(可选)
|
||
- `tenant_id`:UUID,租户ID(多租户隔离)
|
||
|
||
### 1.3 数据类型规范
|
||
- **金额**:DECIMAL(18,2)
|
||
- **时间**:TIMESTAMP WITH TIME ZONE
|
||
- **布尔**:BOOLEAN
|
||
- **枚举**:VARCHAR 或 INTEGER
|
||
- **JSON数据**:JSONB
|
||
|
||
## 2. 核心表结构
|
||
|
||
### 2.1 租户管理
|
||
|
||
#### tenants(租户表)
|
||
```sql
|
||
CREATE TABLE tenants (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
name VARCHAR(100) NOT NULL,
|
||
code VARCHAR(50) UNIQUE NOT NULL,
|
||
contact_name VARCHAR(50),
|
||
contact_phone VARCHAR(20),
|
||
contact_email VARCHAR(100),
|
||
status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:冻结 3:过期
|
||
subscription_plan VARCHAR(50), -- 订阅套餐
|
||
subscription_start_date TIMESTAMP WITH TIME ZONE,
|
||
subscription_end_date TIMESTAMP WITH TIME ZONE,
|
||
max_merchants INTEGER DEFAULT 10, -- 最大商家数
|
||
max_orders_per_day INTEGER DEFAULT 1000, -- 每日订单限额
|
||
settings JSONB, -- 租户配置
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_tenants_code ON tenants(code);
|
||
CREATE INDEX idx_tenants_status ON tenants(status);
|
||
```
|
||
|
||
### 2.2 商家管理
|
||
|
||
#### merchants(商家表)
|
||
```sql
|
||
CREATE TABLE merchants (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
name VARCHAR(100) NOT NULL,
|
||
logo_url VARCHAR(500),
|
||
description TEXT,
|
||
contact_phone VARCHAR(20),
|
||
contact_person VARCHAR(50),
|
||
business_license VARCHAR(100), -- 营业执照号
|
||
status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:休息 3:停业
|
||
rating DECIMAL(3,2) DEFAULT 0, -- 评分
|
||
total_sales INTEGER DEFAULT 0, -- 总销量
|
||
settings JSONB, -- 商家配置
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_merchants_tenant_id ON merchants(tenant_id);
|
||
CREATE INDEX idx_merchants_status ON merchants(status);
|
||
```
|
||
|
||
#### merchant_stores(门店表)
|
||
```sql
|
||
CREATE TABLE merchant_stores (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
merchant_id UUID NOT NULL REFERENCES merchants(id),
|
||
name VARCHAR(100) NOT NULL,
|
||
address VARCHAR(500) NOT NULL,
|
||
latitude DECIMAL(10,7), -- 纬度
|
||
longitude DECIMAL(10,7), -- 经度
|
||
phone VARCHAR(20),
|
||
business_hours JSONB, -- 营业时间 {"monday": {"open": "09:00", "close": "22:00"}}
|
||
delivery_range INTEGER DEFAULT 3000, -- 配送范围(米)
|
||
min_order_amount DECIMAL(18,2) DEFAULT 0, -- 起送价
|
||
delivery_fee DECIMAL(18,2) DEFAULT 0, -- 配送费
|
||
status INTEGER NOT NULL DEFAULT 1,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_merchant_stores_merchant_id ON merchant_stores(merchant_id);
|
||
CREATE INDEX idx_merchant_stores_location ON merchant_stores USING GIST(point(longitude, latitude));
|
||
```
|
||
|
||
### 2.3 菜品管理
|
||
|
||
#### categories(菜品分类表)
|
||
```sql
|
||
CREATE TABLE categories (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
merchant_id UUID NOT NULL REFERENCES merchants(id),
|
||
name VARCHAR(50) NOT NULL,
|
||
sort_order INTEGER DEFAULT 0,
|
||
status INTEGER NOT NULL DEFAULT 1,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_categories_merchant_id ON categories(merchant_id);
|
||
```
|
||
|
||
#### dishes(菜品表)
|
||
```sql
|
||
CREATE TABLE dishes (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
merchant_id UUID NOT NULL REFERENCES merchants(id),
|
||
category_id UUID REFERENCES categories(id),
|
||
name VARCHAR(100) NOT NULL,
|
||
description TEXT,
|
||
image_url VARCHAR(500),
|
||
price DECIMAL(18,2) NOT NULL,
|
||
original_price DECIMAL(18,2), -- 原价
|
||
unit VARCHAR(20) DEFAULT '份', -- 单位
|
||
stock INTEGER, -- 库存(NULL表示不限)
|
||
sales_count INTEGER DEFAULT 0, -- 销量
|
||
rating DECIMAL(3,2) DEFAULT 0, -- 评分
|
||
sort_order INTEGER DEFAULT 0,
|
||
status INTEGER NOT NULL DEFAULT 1, -- 1:上架 2:下架
|
||
tags JSONB, -- 标签 ["热销", "新品"]
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_dishes_merchant_id ON dishes(merchant_id);
|
||
CREATE INDEX idx_dishes_category_id ON dishes(category_id);
|
||
CREATE INDEX idx_dishes_status ON dishes(status);
|
||
```
|
||
|
||
#### dish_specs(菜品规格表)
|
||
```sql
|
||
CREATE TABLE dish_specs (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
dish_id UUID NOT NULL REFERENCES dishes(id),
|
||
name VARCHAR(50) NOT NULL, -- 规格名称(如:大份、小份)
|
||
price DECIMAL(18,2) NOT NULL,
|
||
stock INTEGER,
|
||
status INTEGER NOT NULL DEFAULT 1,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
CREATE INDEX idx_dish_specs_dish_id ON dish_specs(dish_id);
|
||
```
|
||
|
||
### 2.4 用户管理
|
||
|
||
#### users(用户表)
|
||
```sql
|
||
CREATE TABLE users (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
phone VARCHAR(20) UNIQUE NOT NULL,
|
||
nickname VARCHAR(50),
|
||
avatar_url VARCHAR(500),
|
||
gender INTEGER, -- 0:未知 1:男 2:女
|
||
birthday DATE,
|
||
balance DECIMAL(18,2) DEFAULT 0, -- 余额
|
||
points INTEGER DEFAULT 0, -- 积分
|
||
status INTEGER NOT NULL DEFAULT 1,
|
||
last_login_at TIMESTAMP WITH TIME ZONE,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_users_phone ON users(phone);
|
||
```
|
||
|
||
#### user_addresses(用户地址表)
|
||
```sql
|
||
CREATE TABLE user_addresses (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
user_id UUID NOT NULL REFERENCES users(id),
|
||
contact_name VARCHAR(50) NOT NULL,
|
||
contact_phone VARCHAR(20) NOT NULL,
|
||
province VARCHAR(50),
|
||
city VARCHAR(50),
|
||
district VARCHAR(50),
|
||
address VARCHAR(500) NOT NULL,
|
||
house_number VARCHAR(50), -- 门牌号
|
||
latitude DECIMAL(10,7),
|
||
longitude DECIMAL(10,7),
|
||
is_default BOOLEAN DEFAULT FALSE,
|
||
label VARCHAR(20), -- 标签:家、公司等
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_user_addresses_user_id ON user_addresses(user_id);
|
||
```
|
||
|
||
### 2.5 订单管理
|
||
|
||
#### orders(订单表)
|
||
```sql
|
||
CREATE TABLE orders (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
order_no VARCHAR(50) UNIQUE NOT NULL, -- 订单号
|
||
merchant_id UUID NOT NULL REFERENCES merchants(id),
|
||
store_id UUID NOT NULL REFERENCES merchant_stores(id),
|
||
user_id UUID NOT NULL REFERENCES users(id),
|
||
|
||
-- 收货信息
|
||
delivery_address VARCHAR(500) NOT NULL,
|
||
delivery_latitude DECIMAL(10,7),
|
||
delivery_longitude DECIMAL(10,7),
|
||
contact_name VARCHAR(50) NOT NULL,
|
||
contact_phone VARCHAR(20) NOT NULL,
|
||
|
||
-- 金额信息
|
||
dish_amount DECIMAL(18,2) NOT NULL, -- 菜品金额
|
||
delivery_fee DECIMAL(18,2) DEFAULT 0, -- 配送费
|
||
package_fee DECIMAL(18,2) DEFAULT 0, -- 打包费
|
||
discount_amount DECIMAL(18,2) DEFAULT 0, -- 优惠金额
|
||
total_amount DECIMAL(18,2) NOT NULL, -- 总金额
|
||
actual_amount DECIMAL(18,2) NOT NULL, -- 实付金额
|
||
|
||
-- 订单状态
|
||
status INTEGER NOT NULL DEFAULT 1, -- 1:待支付 2:待接单 3:制作中 4:待配送 5:配送中 6:已完成 7:已取消
|
||
payment_status INTEGER DEFAULT 0, -- 0:未支付 1:已支付 2:已退款
|
||
payment_method VARCHAR(20), -- 支付方式
|
||
payment_time TIMESTAMP WITH TIME ZONE,
|
||
|
||
-- 时间信息
|
||
estimated_delivery_time TIMESTAMP WITH TIME ZONE, -- 预计送达时间
|
||
accepted_at TIMESTAMP WITH TIME ZONE, -- 接单时间
|
||
cooking_at TIMESTAMP WITH TIME ZONE, -- 开始制作时间
|
||
delivered_at TIMESTAMP WITH TIME ZONE, -- 送达时间
|
||
completed_at TIMESTAMP WITH TIME ZONE, -- 完成时间
|
||
cancelled_at TIMESTAMP WITH TIME ZONE, -- 取消时间
|
||
|
||
remark TEXT, -- 备注
|
||
cancel_reason TEXT, -- 取消原因
|
||
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
CREATE INDEX idx_orders_tenant_id ON orders(tenant_id);
|
||
CREATE INDEX idx_orders_order_no ON orders(order_no);
|
||
CREATE INDEX idx_orders_merchant_id ON orders(merchant_id);
|
||
CREATE INDEX idx_orders_user_id ON orders(user_id);
|
||
CREATE INDEX idx_orders_status ON orders(status);
|
||
CREATE INDEX idx_orders_created_at ON orders(created_at);
|
||
```
|
||
|
||
#### order_items(订单明细表)
|
||
```sql
|
||
CREATE TABLE order_items (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
order_id UUID NOT NULL REFERENCES orders(id),
|
||
dish_id UUID NOT NULL REFERENCES dishes(id),
|
||
dish_name VARCHAR(100) NOT NULL, -- 冗余字段,防止菜品被删除
|
||
dish_image_url VARCHAR(500),
|
||
spec_id UUID REFERENCES dish_specs(id),
|
||
spec_name VARCHAR(50),
|
||
price DECIMAL(18,2) NOT NULL, -- 单价
|
||
quantity INTEGER NOT NULL, -- 数量
|
||
amount DECIMAL(18,2) NOT NULL, -- 小计
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
|
||
CREATE INDEX idx_order_items_dish_id ON order_items(dish_id);
|
||
```
|
||
|
||
### 2.6 配送管理
|
||
|
||
#### delivery_drivers(配送员表)
|
||
```sql
|
||
CREATE TABLE delivery_drivers (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
merchant_id UUID REFERENCES merchants(id), -- NULL表示平台配送员
|
||
name VARCHAR(50) NOT NULL,
|
||
phone VARCHAR(20) UNIQUE NOT NULL,
|
||
id_card VARCHAR(18), -- 身份证号
|
||
vehicle_type VARCHAR(20), -- 车辆类型:电动车、摩托车
|
||
vehicle_number VARCHAR(20), -- 车牌号
|
||
status INTEGER NOT NULL DEFAULT 1, -- 1:空闲 2:配送中 3:休息 4:离线
|
||
current_latitude DECIMAL(10,7), -- 当前位置
|
||
current_longitude DECIMAL(10,7),
|
||
rating DECIMAL(3,2) DEFAULT 0,
|
||
total_deliveries INTEGER DEFAULT 0, -- 总配送单数
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_delivery_drivers_merchant_id ON delivery_drivers(merchant_id);
|
||
CREATE INDEX idx_delivery_drivers_status ON delivery_drivers(status);
|
||
```
|
||
|
||
#### delivery_tasks(配送任务表)
|
||
```sql
|
||
CREATE TABLE delivery_tasks (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
order_id UUID NOT NULL REFERENCES orders(id),
|
||
driver_id UUID REFERENCES delivery_drivers(id),
|
||
pickup_address VARCHAR(500) NOT NULL, -- 取餐地址
|
||
pickup_latitude DECIMAL(10,7),
|
||
pickup_longitude DECIMAL(10,7),
|
||
delivery_address VARCHAR(500) NOT NULL, -- 送餐地址
|
||
delivery_latitude DECIMAL(10,7),
|
||
delivery_longitude DECIMAL(10,7),
|
||
distance INTEGER, -- 配送距离(米)
|
||
estimated_time INTEGER, -- 预计时长(分钟)
|
||
status INTEGER NOT NULL DEFAULT 1, -- 1:待分配 2:待取餐 3:配送中 4:已送达 5:异常
|
||
assigned_at TIMESTAMP WITH TIME ZONE, -- 分配时间
|
||
picked_at TIMESTAMP WITH TIME ZONE, -- 取餐时间
|
||
delivered_at TIMESTAMP WITH TIME ZONE, -- 送达时间
|
||
delivery_fee DECIMAL(18,2) DEFAULT 0, -- 配送费
|
||
remark TEXT,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
CREATE INDEX idx_delivery_tasks_order_id ON delivery_tasks(order_id);
|
||
CREATE INDEX idx_delivery_tasks_driver_id ON delivery_tasks(driver_id);
|
||
CREATE INDEX idx_delivery_tasks_status ON delivery_tasks(status);
|
||
```
|
||
|
||
### 2.7 支付管理
|
||
|
||
#### payments(支付记录表)
|
||
```sql
|
||
CREATE TABLE payments (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
order_id UUID NOT NULL REFERENCES orders(id),
|
||
user_id UUID NOT NULL REFERENCES users(id),
|
||
payment_no VARCHAR(50) UNIQUE NOT NULL, -- 支付单号
|
||
payment_method VARCHAR(20) NOT NULL, -- 支付方式:wechat、alipay、balance
|
||
amount DECIMAL(18,2) NOT NULL,
|
||
status INTEGER NOT NULL DEFAULT 0, -- 0:待支付 1:支付中 2:成功 3:失败 4:已退款
|
||
third_party_no VARCHAR(100), -- 第三方支付单号
|
||
paid_at TIMESTAMP WITH TIME ZONE,
|
||
callback_data JSONB, -- 回调数据
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
CREATE INDEX idx_payments_order_id ON payments(order_id);
|
||
CREATE INDEX idx_payments_payment_no ON payments(payment_no);
|
||
CREATE INDEX idx_payments_user_id ON payments(user_id);
|
||
```
|
||
|
||
#### refunds(退款记录表)
|
||
```sql
|
||
CREATE TABLE refunds (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
order_id UUID NOT NULL REFERENCES orders(id),
|
||
payment_id UUID NOT NULL REFERENCES payments(id),
|
||
refund_no VARCHAR(50) UNIQUE NOT NULL,
|
||
amount DECIMAL(18,2) NOT NULL,
|
||
reason TEXT,
|
||
status INTEGER NOT NULL DEFAULT 0, -- 0:待审核 1:退款中 2:成功 3:失败
|
||
third_party_no VARCHAR(100),
|
||
refunded_at TIMESTAMP WITH TIME ZONE,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
CREATE INDEX idx_refunds_order_id ON refunds(order_id);
|
||
CREATE INDEX idx_refunds_payment_id ON refunds(payment_id);
|
||
```
|
||
|
||
### 2.8 营销管理
|
||
|
||
#### coupons(优惠券表)
|
||
```sql
|
||
CREATE TABLE coupons (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
merchant_id UUID REFERENCES merchants(id), -- NULL表示平台券
|
||
name VARCHAR(100) NOT NULL,
|
||
type INTEGER NOT NULL, -- 1:满减券 2:折扣券 3:代金券
|
||
discount_type INTEGER NOT NULL, -- 1:固定金额 2:百分比
|
||
discount_value DECIMAL(18,2) NOT NULL, -- 优惠值
|
||
min_order_amount DECIMAL(18,2) DEFAULT 0, -- 最低消费
|
||
max_discount_amount DECIMAL(18,2), -- 最大优惠金额(折扣券用)
|
||
total_quantity INTEGER NOT NULL, -- 总数量
|
||
received_quantity INTEGER DEFAULT 0, -- 已领取数量
|
||
used_quantity INTEGER DEFAULT 0, -- 已使用数量
|
||
valid_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||
valid_end_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||
status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:停用
|
||
description TEXT,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_coupons_merchant_id ON coupons(merchant_id);
|
||
CREATE INDEX idx_coupons_status ON coupons(status);
|
||
```
|
||
|
||
#### user_coupons(用户优惠券表)
|
||
```sql
|
||
CREATE TABLE user_coupons (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
user_id UUID NOT NULL REFERENCES users(id),
|
||
coupon_id UUID NOT NULL REFERENCES coupons(id),
|
||
status INTEGER NOT NULL DEFAULT 1, -- 1:未使用 2:已使用 3:已过期
|
||
used_order_id UUID REFERENCES orders(id),
|
||
received_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
used_at TIMESTAMP WITH TIME ZONE,
|
||
expired_at TIMESTAMP WITH TIME ZONE NOT NULL
|
||
);
|
||
|
||
CREATE INDEX idx_user_coupons_user_id ON user_coupons(user_id);
|
||
CREATE INDEX idx_user_coupons_coupon_id ON user_coupons(coupon_id);
|
||
CREATE INDEX idx_user_coupons_status ON user_coupons(status);
|
||
```
|
||
|
||
### 2.9 评价管理
|
||
|
||
#### reviews(评价表)
|
||
```sql
|
||
CREATE TABLE reviews (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID NOT NULL REFERENCES tenants(id),
|
||
order_id UUID NOT NULL REFERENCES orders(id),
|
||
user_id UUID NOT NULL REFERENCES users(id),
|
||
merchant_id UUID NOT NULL REFERENCES merchants(id),
|
||
rating INTEGER NOT NULL, -- 评分 1-5
|
||
taste_rating INTEGER, -- 口味评分
|
||
package_rating INTEGER, -- 包装评分
|
||
delivery_rating INTEGER, -- 配送评分
|
||
content TEXT,
|
||
images JSONB, -- 评价图片
|
||
is_anonymous BOOLEAN DEFAULT FALSE,
|
||
reply_content TEXT, -- 商家回复
|
||
reply_at TIMESTAMP WITH TIME ZONE,
|
||
status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:隐藏
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
CREATE INDEX idx_reviews_order_id ON reviews(order_id);
|
||
CREATE INDEX idx_reviews_user_id ON reviews(user_id);
|
||
CREATE INDEX idx_reviews_merchant_id ON reviews(merchant_id);
|
||
```
|
||
|
||
### 2.10 系统管理
|
||
|
||
#### system_users(系统用户表)
|
||
```sql
|
||
CREATE TABLE system_users (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID REFERENCES tenants(id), -- NULL表示平台管理员
|
||
merchant_id UUID REFERENCES merchants(id), -- NULL表示租户管理员
|
||
username VARCHAR(50) UNIQUE NOT NULL,
|
||
password_hash VARCHAR(255) NOT NULL,
|
||
real_name VARCHAR(50),
|
||
phone VARCHAR(20),
|
||
email VARCHAR(100),
|
||
role_id UUID REFERENCES roles(id),
|
||
status INTEGER NOT NULL DEFAULT 1,
|
||
last_login_at TIMESTAMP WITH TIME ZONE,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_system_users_username ON system_users(username);
|
||
CREATE INDEX idx_system_users_tenant_id ON system_users(tenant_id);
|
||
```
|
||
|
||
#### roles(角色表)
|
||
```sql
|
||
CREATE TABLE roles (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID REFERENCES tenants(id),
|
||
name VARCHAR(50) NOT NULL,
|
||
code VARCHAR(50) NOT NULL,
|
||
description TEXT,
|
||
permissions JSONB, -- 权限列表
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITH TIME ZONE
|
||
);
|
||
|
||
CREATE INDEX idx_roles_tenant_id ON roles(tenant_id);
|
||
```
|
||
|
||
#### operation_logs(操作日志表)
|
||
```sql
|
||
CREATE TABLE operation_logs (
|
||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||
tenant_id UUID REFERENCES tenants(id),
|
||
user_id UUID,
|
||
user_type VARCHAR(20), -- system_user, merchant_user, customer
|
||
module VARCHAR(50), -- 模块
|
||
action VARCHAR(50), -- 操作
|
||
description TEXT,
|
||
ip_address VARCHAR(50),
|
||
user_agent TEXT,
|
||
request_data JSONB,
|
||
response_data JSONB,
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
CREATE INDEX idx_operation_logs_tenant_id ON operation_logs(tenant_id);
|
||
CREATE INDEX idx_operation_logs_user_id ON operation_logs(user_id);
|
||
CREATE INDEX idx_operation_logs_created_at ON operation_logs(created_at);
|
||
```
|
||
|
||
## 3. 数据库索引策略
|
||
|
||
### 3.1 主键索引
|
||
- 所有表使用UUID作为主键,自动创建主键索引
|
||
|
||
### 3.2 外键索引
|
||
- 所有外键字段创建索引,提升关联查询性能
|
||
|
||
### 3.3 业务索引
|
||
- 订单号、支付单号等唯一业务字段创建唯一索引
|
||
- 状态字段创建普通索引
|
||
- 时间字段(created_at)创建索引,支持时间范围查询
|
||
|
||
### 3.4 复合索引
|
||
```sql
|
||
-- 订单查询常用复合索引
|
||
CREATE INDEX idx_orders_merchant_status_created ON orders(merchant_id, status, created_at DESC);
|
||
|
||
-- 用户订单查询
|
||
CREATE INDEX idx_orders_user_status_created ON orders(user_id, status, created_at DESC);
|
||
```
|
||
|
||
### 3.5 地理位置索引
|
||
```sql
|
||
-- 使用PostGIS扩展支持地理位置查询
|
||
CREATE EXTENSION IF NOT EXISTS postgis;
|
||
|
||
-- 门店位置索引
|
||
CREATE INDEX idx_merchant_stores_location ON merchant_stores
|
||
USING GIST(ST_MakePoint(longitude, latitude));
|
||
```
|
||
|
||
## 4. 数据库优化
|
||
|
||
### 4.1 分区策略
|
||
```sql
|
||
-- 订单表按月分区
|
||
CREATE TABLE orders_2024_01 PARTITION OF orders
|
||
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
|
||
|
||
CREATE TABLE orders_2024_02 PARTITION OF orders
|
||
FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
|
||
```
|
||
|
||
### 4.2 物化视图
|
||
```sql
|
||
-- 商家统计物化视图
|
||
CREATE MATERIALIZED VIEW merchant_statistics AS
|
||
SELECT
|
||
m.id as merchant_id,
|
||
m.name,
|
||
COUNT(DISTINCT o.id) as total_orders,
|
||
SUM(o.actual_amount) as total_revenue,
|
||
AVG(r.rating) as avg_rating
|
||
FROM merchants m
|
||
LEFT JOIN orders o ON m.id = o.merchant_id AND o.status = 6
|
||
LEFT JOIN reviews r ON m.id = r.merchant_id
|
||
GROUP BY m.id, m.name;
|
||
|
||
CREATE UNIQUE INDEX ON merchant_statistics(merchant_id);
|
||
```
|
||
|
||
### 4.3 查询优化建议
|
||
- 避免SELECT *,只查询需要的字段
|
||
- 使用EXPLAIN分析查询计划
|
||
- 合理使用JOIN,避免过多关联
|
||
- 大数据量查询使用分页
|
||
- 使用prepared statement防止SQL注入
|
||
|
||
## 5. 数据备份策略
|
||
|
||
### 5.1 备份方案
|
||
- **全量备份**:每天凌晨2点执行
|
||
- **增量备份**:每4小时执行一次
|
||
- **WAL归档**:实时归档,支持PITR
|
||
|
||
### 5.2 备份脚本示例
|
||
```bash
|
||
#!/bin/bash
|
||
# 全量备份
|
||
pg_dump -h localhost -U postgres -d takeout_saas -F c -f /backup/full_$(date +%Y%m%d).dump
|
||
|
||
# 保留最近30天的备份
|
||
find /backup -name "full_*.dump" -mtime +30 -delete
|
||
```
|
||
|
||
## 6. 数据迁移
|
||
|
||
### 6.1 EF Core Migrations
|
||
```bash
|
||
# 添加迁移
|
||
dotnet ef migrations add InitialCreate --project TakeoutSaaS.Infrastructure
|
||
|
||
# 更新数据库
|
||
dotnet ef database update --project TakeoutSaaS.Infrastructure
|
||
```
|
||
|
||
### 6.2 版本控制
|
||
- 所有数据库变更通过Migration管理
|
||
- Migration文件纳入版本控制
|
||
- 生产环境变更需要审核
|
||
|