Files
rent/database/skills.md
T
2026-05-08 20:16:34 +08:00

28 KiB
Raw Blame History

数据库 Skills

数据库信息

  • 数据库名: rent_platform
  • 字符集: utf8mb4
  • 排序规则: utf8mb4_unicode_ci
  • 时区: +08:00

表结构总览

表名 说明 核心字段
admins 平台管理员表 id, username, name, role, status
users 用户表 id, phone, nickname, status
user_oauth 第三方账号绑定 user_id, provider, openid
sellers 商家账户表 id, phone, password, contact_name, status
merchants 商家表 seller_id, shop_name, status, rating
rooms 房源表 merchant_id, name, type, price, status, audit_status
room_calendar 房量房价日历 room_id, date, price, stock, status
room_calendar_logs 房态变更日志 room_id, operator_id, change_type
orders 订单表 order_no, user_id, merchant_id, room_id, pay_amount, service_fee, merchant_income, status, payment_method, payment_no, paid_at, confirmed_at, checkin_at, checkout_at, cancelled_at, refund_amount, refund_at, source
reviews 评价表 order_id, user_id, rating, content
favorites 收藏表 user_id, room_id
coupons 优惠券模板 name, type, value, scope
user_coupons 用户优惠券 user_id, coupon_id, status
promotions 促销活动 merchant_id, name, type, rules
member_levels 会员等级 level, name, min_points, discount
user_members 用户会员信息 user_id, level_id, points, growth_value
settlements 结算对账单 merchant_id, settlement_no, period_start, period_end, status
settlement_items 对账单明细 settlement_id, order_id, order_no, order_amount
withdrawals 提现记录 merchant_id, settlement_ids, amount, status
notifications 消息通知 user_id, type, title, content
advertisements 广告位 position, image, link_type
platform_configs 平台配置 config_key, config_value
operation_logs 操作日志 user_id, module, action, detail
mkt_activities 营销活动总表 name, type, enabled, config
mkt_invitations 邀请关系 activity_id, inviter_id, invitee_id, invite_code
mkt_cashbacks 返现记录 activity_id, inviter_id, order_id, amount, status
mkt_user_invite_stats 用户邀请统计 activity_id, user_id, invite_code, available_balance
mkt_invite_withdrawals 邀请提现申请 activity_id, user_id, amount, status

核心关系

users (1) ──── (n) orders
  │
  └── (n) ──── (n) coupons (user_coupons)
  │
  └── (n) ──── (n) rooms (favorites)

sellers (1) ──── (1) merchants ──── (n) rooms ──── (n) room_calendar
                                │
                                └── (n) orders

orders (1) ──── (1) reviews
orders (1) ──── (1) settlements

状态枚举

管理员状态 (admins.status)

  • active - 正常
  • frozen - 冻结

管理员角色 (admins.role)

  • super_admin - 超级管理员
  • admin - 管理员
  • operator - 运营人员

用户状态 (users.status)

  • active - 正常
  • frozen - 冻结
  • deleted - 已注销

商家账户状态 (sellers.status)

  • active - 正常
  • frozen - 冻结
  • deleted - 已注销

商家状态 (merchants.status)

  • pending - 待审核
  • approved - 已通过
  • rejected - 已拒绝
  • frozen - 已冻结

订单状态 (orders.status)

  • pending_pay - 待支付
  • pending_confirm - 待确认
  • pending_checkin - 待入住
  • checked_in - 已入住
  • completed - 已完成
  • cancelled - 已取消
  • refunding - 退款中
  • refunded - 已退款

订单状态流转

待支付 ──支付成功──> 待确认 ──商家确认──> 待入住 ──入住──> 已入住 ──自动离店──> 已完成
   │                  │                    │
   └──超时/取消──> 已取消   └──商家拒绝──> 已取消    └──用户退款──> 退款中
                                              │
                                              ├──商家通过──> 已退款(恢复房量)
                                              └──商家拒绝──> 已取消

待确认 ──用户退款──> 退款中 ──商家通过──> 已退款(恢复房量)

自动完成机制

  • 定时任务每天凌晨 1 点执行(OrderSchedule.completeExpiredOrders
  • 自动将"已入住"且"离店日期为前一天"的订单标记为"已完成"
  • 记录 checkout_at 字段为当前时间
  • 用户可在订单完成后进行评价

商家手动确认离店

  • 商家可在订单详情页点击"确认离店"按钮
  • 需满足条件:订单状态为"已入住"且当前日期 >= 离店日期
  • 确认后订单立即变为"已完成",无需等待自动任务
  • 适用场景:客人提前离店或商家需要立即完成订单

订单取消/退款规则

操作 适用状态 说明
用户取消 pending_pay 直接取消,无退款
用户取消 pending_confirm 取消并退款,恢复房量
用户退款申请 pending_confirm, pending_checkin 状态变为 refunding,等待商家审核
商家通过退款 refunding 状态变为 refunded,恢复房量日历库存
商家拒绝退款 refunding 状态变为 cancelled

订单时间字段说明

字段 类型 说明
created_at datetime 订单创建时间
paid_at datetime 支付完成时间(支付成功后记录)
confirmed_at datetime 商家确认时间(商家确认订单后记录)
checkin_at datetime 实际入住时间(商家办理入住后记录)
checkout_at datetime 实际离店时间(自动完成或手动离店时记录)
cancelled_at datetime 取消时间(订单取消时记录)
refund_at datetime 退款时间(退款成功时记录)

订单来源 (orders.source)

  • miniapp - 小程序下单
  • web - 网页下单
  • third_party - 第三方平台(如美团、携程)

支付方式 (orders.payment_method)

  • wechat - 微信支付
  • alipay - 支付宝
  • balance - 余额支付

房源状态 (rooms.status)

  • on_sale - 在售
  • off_sale - 已下架

房源审核状态 (rooms.audit_status)

  • pending - 待审核
  • approved - 已通过
  • rejected - 已拒绝

房源类型 (rooms.type)

  • hotel - 酒店
  • homestay - 民宿
  • apartment - 公寓
  • hostel - 青旅

优惠券类型 (coupons.type)

  • fixed - 固定金额
  • percent - 百分比折扣

关键索引

-- 高频查询索引
idx_users_phone (phone)
idx_sellers_phone (phone)
idx_merchants_status (status)
idx_merchants_city (city)
idx_rooms_merchant_id (merchant_id)
idx_rooms_status_price (status, price)
idx_rooms_audit_status (audit_status)
idx_orders_user_id (user_id)
idx_orders_merchant_id (merchant_id)
idx_orders_status (status)
idx_orders_check_in (check_in_date)
idx_room_calendar_room_date (room_id, date)

查询示例

获取在售房源(含商家信息)

SELECT r.*, m.shop_name, m.city, m.rating as merchant_rating
FROM rooms r
JOIN merchants m ON r.merchant_id = m.id
WHERE r.status = 'on_sale' AND m.status = 'approved'
ORDER BY r.rating DESC
LIMIT 10;

获取房源日历

SELECT * FROM room_calendar
WHERE room_id = ? AND date BETWEEN ? AND ?
ORDER BY date;

批量更新房量房价

INSERT INTO room_calendar (room_id, date, price, stock, status)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE price = VALUES(price), stock = VALUES(stock), status = VALUES(status);

获取用户订单

SELECT o.*, r.name as room_name, m.shop_name
FROM orders o
JOIN rooms r ON o.room_id = r.id
JOIN merchants m ON o.merchant_id = m.id
WHERE o.user_id = ?
ORDER BY o.created_at DESC;

更新房量(预订成功)

UPDATE room_calendar
SET sold = sold + 1, stock = stock - 1
WHERE room_id = ? AND date = ? AND stock > 0;

数据迁移

# 初始化数据库
mysql -u root -p < database/migrations/001_init_schema.sql

# 导入种子数据
mysql -u root -p rent_platform < database/seeds/001_init_data.sql

注意事项

  1. 用户手机号、身份证号需加密存储(AES-256)
  2. 密码使用 bcrypt 哈希存储
  3. 金额字段使用 DECIMAL(10,2) 避免精度丢失
  4. JSON 字段用于存储数组/对象(如设施列表、活动规则)
  5. 所有表都有 created_at 字段,核心表有 updated_at
  6. 敏感操作需记录到 operation_logs 表
  7. 订单自动完成:定时任务每天凌晨 1 点执行,将离店日期为前一天的"已入住"订单自动标记为"已完成"

定时任务

订单自动完成任务 (OrderSchedule)

文件位置: apps/server/src/schedule/order.schedule.ts

执行时间: 每天凌晨 1 点(Cron: 0 1 * * *

任务逻辑:

// 将前一天离店且状态为"已入住"的订单自动完成
UPDATE orders 
SET status = 'completed', checkout_at = NOW()
WHERE status = 'checked_in' 
  AND DATE(check_out_date) = DATE(NOW() - INTERVAL 1 DAY)

日志输出: 已自动完成 N 笔过期订单 (YYYY-MM-DD)


平台配置表 (platform_configs)

配置键 默认值 说明
commission_rate 0.10 默认平台佣金比例
service_fee_rate 0.05 软件服务费比例(可配置)
min_deposit 5000 最低保证金金额
auto_cancel_minutes 30 未支付订单自动取消时间
auto_complete_hours 24 入住后自动完成订单时间
sms_enabled true 是否启用短信通知
max_images_per_room 20 每个房源最大图片数
max_images_per_review 9 每条评价最大图片数

服务费计算

  • 软件服务费 = 实付金额 × service_fee_rate
  • 商家预计收入 = 实付金额 - 软件服务费
  • 配置可通过平台管理后台「系统设置」页面调整

商家入驻流程

流程概述

用户点击商家入驻 → 商家注册/登录页面 → 注册商家账户 → 创建店铺 → 提交审核 → 审核通过 → 开始营业

账户体系说明

账户类型 表名 Token存储 路由前缀
C端用户 users token / userInfo /rooms, /orders, /user
商家账户 sellers sellerToken / sellerInfo /merchant/*
平台管理员 admins 管理后台独立存储 /admin/*

注意: 用户和商家是独立的账户体系,一个用户可以同时是商家。

商家注册接口

接口 路径 说明
发送验证码 POST /api/seller-auth/send-code 发送商家验证码(6位数字)
商家注册 POST /api/seller-auth/register 手机号+验证码注册
商家登录 POST /api/seller-auth/login 手机号+验证码或密码登录
刷新令牌 POST /api/seller-auth/refresh 使用refreshToken刷新
获取商家信息 GET /api/seller-auth/profile 需Bearer Token

商家注册参数

interface SellerRegisterParams {
  phone: string; // 手机号(必填,正则:/^1[3-9]\d{9}$/
  code: string; // 验证码(必填,6位数字)
  contactName: string; // 联系人姓名(必填,2-50字)
  email?: string; // 邮箱(选填,需验证格式)
  password?: string; // 密码(选填,6-20位,便于密码登录)
}

商家登录参数

interface SellerLoginParams {
  phone: string; // 手机号(必填)
  code?: string; // 验证码(可选,6位数字)
  password?: string; // 密码(可选,6-20位)
}
// 注:验证码和密码至少填写一种

商家注册响应

interface SellerLoginResult {
  accessToken: string;
  refreshToken: string;
  sellerInfo: {
    id: number;
    phone: string;
    contactName: string;
    email?: string;
    status: "active" | "frozen" | "deleted";
    merchantId?: number; // 有值表示已创建店铺
    merchantStatus?: string; // 店铺状态
  };
}

商家入驻状态判断

sellerInfo.merchantId sellerInfo.merchantStatus 状态说明
无/undefined - 未创建店铺,需引导创建
有值 pending 店铺审核中
有值 approved 已通过审核,可营业
有值 rejected 已拒绝,显示原因
有值 frozen 店铺已冻结

小程序页面路由

页面 路径 说明
个人中心 /pages/mine/index 入口:商家中心、商家入驻按钮
商家注册/登录 /pages/seller-register/index 商家账号注册登录
商家中心 /pages/seller/home 商家管理入口
商家订单列表 /pages/seller/orders 商家订单管理
商家订单详情 /pages/seller/order-detail 商家订单详情
创建店铺 /pages/shop-create/index 填写店铺信息提交审核
修改店铺 /pages/shop-edit/index 修改店铺信息重新审核

Store设计

// useSellerStore (apps/miniapp/src/store/seller.ts)
const sellerToken = ref(uni.getStorageSync("sellerToken") || "");
const sellerInfo = ref<SellerInfo | null>(
  uni.getStorageSync("sellerInfo") || null,
);

// 判断方法
isSellerLoggedIn(); // 是否登录商家账号
hasMerchant(); // 是否已创建店铺

店铺创建功能

创建店铺接口

接口 路径 说明
申请创建店铺 POST /api/merchant/apply 需商家Token,创建后状态为pending
获取我的店铺 GET /api/merchant/mine 需商家Token
更新店铺信息 PUT /api/merchant/update 需商家Token,审核通过/拒绝后修改会重置为pending

创建店铺参数 (ApplyMerchantDto)

字段 类型 必填 校验规则
shopName string 2-100字
phone string 联系电话不能为空
province string
city string
district string
address string 详细地址
businessLicense string 营业执照图片URL
licenseNo string 营业执照编号
legalPerson string 法人姓名
description string 店铺描述

创建店铺流程

商家中心 → 点击"创建店铺" → 填写表单 → 提交申请
    → 调用 POST /merchant/apply
    → 更新 sellerInfo.merchantId 和 merchantStatus
    → 跳转商家中心显示审核中状态

前端 API 模块

文件: apps/miniapp/src/api/merchant.ts

applyMerchant(data); // 申请创建店铺
getMyMerchant(); // 获取我的店铺信息
updateMerchant(data); // 更新店铺信息
getMerchantById(id); // 获取商家详情(公开)

店铺审核状态展示

状态枚举与显示

status 显示文本 颜色 说明
pending 审核中 橙色 等待平台审核,不可修改
approved 营业中 绿色 审核通过,可正常营业
rejected 已拒绝 红色 审核拒绝,显示原因,可修改重新提交
frozen 已冻结 灰色 店铺被冻结,联系客服

商家中心页面状态展示逻辑

审核中 (pending):

  • 显示状态标签"审核中"
  • 显示提示"店铺信息审核中,暂不可修改"
  • 不显示修改按钮
  • 不显示数据概览和功能菜单

审核通过 (approved):

  • 显示状态标签"营业中"
  • 显示店铺信息卡片(电话、地址等)
  • 显示数据概览(订单、房源、收入、评分)
  • 显示"修改店铺信息"按钮
  • 显示功能菜单(订单管理、房源管理)

审核拒绝 (rejected):

  • 显示状态标签"已拒绝"
  • 显示拒绝原因区块(红色背景,包含拒绝原因)
  • 显示店铺信息卡片
  • 显示"修改店铺信息"按钮
  • 不显示数据概览和功能菜单

店铺冻结 (frozen):

  • 显示状态标签"已冻结"
  • 显示提示"店铺已被冻结,请联系平台客服"
  • 不显示修改按钮
  • 不显示数据概览和功能菜单

修改店铺重新审核逻辑

后端逻辑 (merchant.service.ts):

async update(id, dto) {
  const merchant = await this.findById(id);
  // 审核通过或拒绝后修改,重置为pending
  if (merchant.status === 'approved' || merchant.status === 'rejected') {
    await this.merchantRepo.update(id, { ...dto, status: 'pending', rejectReason: null });
  } else {
    await this.merchantRepo.update(id, dto);
  }
  return this.findById(id);
}

修改流程:

点击"修改店铺信息" → 填写表单 → 提交修改
    → 调用 PUT /merchant/update
    → 后端自动将 status 重置为 pending,清空 rejectReason
    → 跳转商家中心显示"审核中"状态

后续迭代事项

  1. 商家管理后台集成: 商家后台跳转入口
  2. 商家实名认证: 身份证上传、银行卡绑定
  3. 图片上传接口: 营业执照真实上传功能

三端分离开发规范

三端定义

说明 前端项目 API路由前缀
用户端 C端普通用户 小程序用户页面 (pages/*) /xxx (无前缀)
商家端 B端商家 小程序商家页面 (pages/seller/*) + 商家管理后台 (merchant-admin) /seller/xxx
平台端 平台管理员 平台管理后台 (platform-admin) /admin/xxx

后端 Controller 文件命名规范

每个模块的控制器按端拆分为独立文件,命名格式:{module}-{端}.controller.ts

modules/merchant/
├── merchant-public.controller.ts    # 用户端 @Controller('merchants')
├── merchant-seller.controller.ts    # 商家端 @Controller('seller/merchant')
├── merchant-admin.controller.ts     # 管理端 @Controller('admin/merchants')
├── merchant.service.ts              # 共享 Service
├── merchant.module.ts               # 模块定义
└── dto/

命名对照

  • *-public.controller.ts → 用户端(公开接口,无Guard或JwtAuthGuard
  • *-seller.controller.ts → 商家端(SellerJwtAuthGuard
  • *-user.controller.ts → 用户端(需登录,JwtAuthGuard
  • *-admin.controller.ts → 管理端(JwtAuthGuard + RolesGuard + @Roles('admin')

小程序 API 文件目录规范

apps/miniapp/src/api/
├── user/                    # 用户端 API
│   ├── auth.ts              # /auth/*, /user/profile
│   ├── merchant.ts          # /merchants/* (公开)
│   ├── room.ts              # /rooms/* (公开)
│   ├── order.ts             # /orders/*
│   ├── review.ts            # /reviews/*
│   └── invite.ts            # /user/activity/invite/*
└── seller/                  # 商家端 API
    ├── auth.ts              # /seller/auth/*
    ├── merchant.ts          # /seller/merchant/*
    ├── room.ts              # /seller/rooms/*
    ├── room-calendar.ts     # /seller/room-calendar/*
    └── order.ts             # /seller/orders/*

Guard 使用对照

Guard Token 装饰器
用户端(公开)
用户端(需登录) JwtAuthGuard Bearer Token @CurrentUser('sub')
商家端 SellerJwtAuthGuard Bearer sellerToken @CurrentSeller('sub')
管理端 JwtAuthGuard + RolesGuard Bearer adminToken @CurrentUser('sub') + @Roles('admin')

新增模块开发清单

新增业务模块时,按以下步骤操作:

  1. 创建 modules/{module}/ 目录
  2. 创建 dto/{module}.dto.ts
  3. 创建 {module}.service.ts
  4. 按需创建控制器文件:{module}-public.controller.ts{module}-seller.controller.ts{module}-admin.controller.ts
  5. 创建 {module}.module.ts,引用所有控制器和共享 Service
  6. app.module.ts 中注册新模块
  7. 小程序端按端创建 API 文件:api/user/{module}.tsapi/seller/{module}.ts
  8. 商家管理后台/平台管理后台按需添加 API 文件

商家订单管理

商家订单接口

接口 路径 说明
订单列表 GET /api/seller/orders 支持状态筛选、订单号搜索
订单详情 GET /api/seller/orders/:id 获取订单详情
确认订单 PUT /api/seller/orders/:id/confirm pending_confirm → pending_checkin
拒绝订单 PUT /api/seller/orders/:id/reject pending_confirm → cancelled
办理入住 PUT /api/seller/orders/:id/checkin pending_checkin → checked_in
确认离店 PUT /api/seller/orders/:id/checkout checked_in → completed(需已到离店日期)
通过退款 PUT /api/seller/orders/:id/approve-refund refunding → refunded,恢复房量
拒绝退款 PUT /api/seller/orders/:id/reject-refund refunding → cancelled

商家订单状态Tab

Tab名称 对应状态
全部 所有状态
待确认 pending_confirm
待入住 pending_checkin
已入住 checked_in
已完成 completed
已取消 cancelled
已退款 refunded, refunding

商家订单操作权限

状态 可操作
pending_confirm 确认、拒绝
pending_checkin 办理入住
checked_in 确认离店(需已到离店日期)
refunding 通过退款、拒绝退款
其他状态 无操作

订单完成方式

方式 触发条件 说明
自动完成 每天凌晨1点定时任务 将离店日期为前一天的"已入住"订单自动完成
商家手动确认 商家点击"确认离店"按钮 需已到离店日期,订单立即完成

文件上传服务

上传接口

接口 路径 说明
用户上传 POST /api/upload 需用户Token
商家上传 POST /api/seller/upload 需商家Token
管理员上传 POST /api/admin/upload 需管理员Token

存储配置

存储方式通过 platform_configs 表配置,支持:

配置键 说明
storage_provider 存储方式:local / tencent_cos / aliyun_oss
storage_local_path 本地存储路径(默认 ./uploads)
storage_cos_bucket 腾讯云COS Bucket
storage_cos_region 腾讯云COS Region
storage_cos_secret_id 腾讯云SecretId
storage_cos_secret_key 腾讯云SecretKey
storage_oss_bucket 阿里云OSS Bucket
storage_oss_region 阿里云OSS Region
storage_oss_access_key_id 阿里云AccessKeyId
storage_oss_access_key_secret 阿里云AccessKeySecret

存储配置接口

接口 路径 说明
获取存储配置 GET /api/admin/config/storage 需管理员Token
更新存储配置 PUT /api/admin/config/storage 需管理员Token

小程序上传工具

文件: apps/miniapp/src/utils/upload.ts

import { chooseAndUpload, uploadFile } from '@/utils/upload';

// 选择并上传图片
const urls = await chooseAndUpload({ count: 1, useSellerToken: true });

// 直接上传文件
const url = await uploadFile(filePath, { useSellerToken: true });

后端上传模块

文件位置: apps/server/src/modules/upload/

  • upload.service.ts — 核心上传逻辑,策略模式支持本地/腾讯云/阿里云
  • upload.controller.ts — 上传接口控制器
  • upload.module.ts — 模块定义

静态文件访问

本地上传的文件通过 /uploads/ 路径访问,例如:

  • 上传返回: { url: "/uploads/abc123.jpg" }
  • 访问地址: http://localhost:3000/uploads/abc123.jpg

OSS SDK 安装

使用腾讯云COS或阿里云OSS时,需安装对应SDK:

# 腾讯云COS
pnpm --filter @rent/server add cos-nodejs-sdk-v5

# 阿里云OSS
pnpm --filter @rent/server add ali-oss