409 lines
11 KiB
Markdown
409 lines
11 KiB
Markdown
---
|
||
slug: tech-v1-1-extension
|
||
---
|
||
|
||
# 「伴享」技术方案 V1.1 — 扩展架构
|
||
|
||
**版本**: V1.1
|
||
**对应PRD**: PRD-V1.1-体验优化版
|
||
**更新日期**: 2026-02-16
|
||
|
||
---
|
||
|
||
## 1. 架构变更概述
|
||
|
||
V1.1在V1.0基础上新增:社区队长、会员订阅、家政服务、日常消费。无架构层面重大变更,主要是新增数据表和API端点。
|
||
|
||
### 1.1 变更影响矩阵
|
||
|
||
| 层级 | 变更 | 影响范围 |
|
||
|------|------|----------|
|
||
| 数据库 | 新增6张表 | 队长/会员/服务商/服务人员/商品/购物车 |
|
||
| API | 新增4组端点 | /captains, /membership, /services, /products |
|
||
| Flutter | 新增4个Feature模块 | captain/, membership/, housekeeping/, shopping/ |
|
||
| 第三方 | 无新增 | - |
|
||
| 部署 | 无变更 | 同V1.0 Docker Compose |
|
||
|
||
---
|
||
|
||
## 2. 新增数据库表
|
||
|
||
### 2.1 增量DDL
|
||
|
||
```sql
|
||
-- ===========================
|
||
-- V1.1 增量DDL
|
||
-- ===========================
|
||
|
||
-- 1. 队长相关
|
||
CREATE TABLE captain_applications (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
user_id BIGINT REFERENCES users(id),
|
||
bio TEXT,
|
||
specialties TEXT[],
|
||
serving_area VARCHAR(50),
|
||
contact_info JSONB,
|
||
status VARCHAR(20) DEFAULT 'pending'
|
||
CHECK (status IN ('pending', 'approved', 'rejected')),
|
||
reviewer_note TEXT,
|
||
reviewed_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE TABLE captains (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
user_id BIGINT UNIQUE REFERENCES users(id),
|
||
level VARCHAR(20) DEFAULT 'trainee'
|
||
CHECK (level IN ('trainee', 'silver', 'gold', 'honor')),
|
||
bio TEXT,
|
||
specialties TEXT[],
|
||
serving_area VARCHAR(50),
|
||
total_activities INTEGER DEFAULT 0,
|
||
total_participants INTEGER DEFAULT 0,
|
||
total_new_users INTEGER DEFAULT 0,
|
||
avg_rating DECIMAL(2,1) DEFAULT 0,
|
||
monthly_subsidy DECIMAL(10,2) DEFAULT 0,
|
||
status VARCHAR(20) DEFAULT 'active',
|
||
approved_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
updated_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- 2. 会员
|
||
CREATE TABLE memberships (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
user_id BIGINT REFERENCES users(id),
|
||
plan VARCHAR(20) NOT NULL CHECK (plan IN ('monthly', 'yearly')),
|
||
price DECIMAL(10,2) NOT NULL,
|
||
paid_by_user_id BIGINT REFERENCES users(id),
|
||
starts_at TIMESTAMP NOT NULL,
|
||
expires_at TIMESTAMP NOT NULL,
|
||
auto_renew BOOLEAN DEFAULT FALSE,
|
||
status VARCHAR(20) DEFAULT 'active'
|
||
CHECK (status IN ('active', 'expired', 'cancelled')),
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
CREATE INDEX idx_membership_user ON memberships(user_id, status);
|
||
|
||
-- 用户表新增字段
|
||
ALTER TABLE users ADD COLUMN is_member BOOLEAN DEFAULT FALSE;
|
||
ALTER TABLE users ADD COLUMN member_expires_at TIMESTAMP;
|
||
ALTER TABLE users ADD COLUMN is_captain BOOLEAN DEFAULT FALSE;
|
||
ALTER TABLE users ADD COLUMN captain_level VARCHAR(20);
|
||
|
||
-- 3. 服务商
|
||
CREATE TABLE service_providers (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
company_name VARCHAR(100),
|
||
category VARCHAR(50),
|
||
contact_phone VARCHAR(20),
|
||
license_no VARCHAR(50),
|
||
address TEXT,
|
||
lat DECIMAL(10,7),
|
||
lng DECIMAL(10,7),
|
||
rating DECIMAL(2,1) DEFAULT 5.0,
|
||
status VARCHAR(20) DEFAULT 'active',
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- 4. 服务人员
|
||
CREATE TABLE service_workers (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
provider_id BIGINT REFERENCES service_providers(id),
|
||
name VARCHAR(50),
|
||
avatar_url TEXT,
|
||
skills TEXT[],
|
||
rating DECIMAL(2,1) DEFAULT 5.0,
|
||
service_count INTEGER DEFAULT 0,
|
||
hourly_rate DECIMAL(10,2),
|
||
status VARCHAR(20) DEFAULT 'available',
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- 5. 服务订单
|
||
CREATE TABLE service_orders (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
order_no VARCHAR(20) UNIQUE NOT NULL,
|
||
user_id BIGINT REFERENCES users(id),
|
||
worker_id BIGINT REFERENCES service_workers(id),
|
||
service_type VARCHAR(50),
|
||
scheduled_date DATE,
|
||
scheduled_time TIME,
|
||
duration_hours DECIMAL(3,1),
|
||
address TEXT,
|
||
requirements TEXT,
|
||
amount DECIMAL(10,2),
|
||
platform_fee DECIMAL(10,2),
|
||
status VARCHAR(20) DEFAULT 'pending',
|
||
rating INTEGER CHECK (rating BETWEEN 1 AND 5),
|
||
review TEXT,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- 6. 商品
|
||
CREATE TABLE products (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
provider_id BIGINT REFERENCES service_providers(id),
|
||
name VARCHAR(100),
|
||
category VARCHAR(50),
|
||
description TEXT,
|
||
image_url TEXT,
|
||
price DECIMAL(10,2),
|
||
unit VARCHAR(20),
|
||
stock INTEGER DEFAULT 0,
|
||
status VARCHAR(20) DEFAULT 'available',
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- 7. 购物车
|
||
CREATE TABLE cart_items (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
user_id BIGINT REFERENCES users(id),
|
||
product_id BIGINT REFERENCES products(id),
|
||
quantity INTEGER DEFAULT 1,
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
UNIQUE(user_id, product_id)
|
||
);
|
||
|
||
-- 8. 配送订单
|
||
CREATE TABLE delivery_orders (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
order_no VARCHAR(20) UNIQUE NOT NULL,
|
||
user_id BIGINT REFERENCES users(id),
|
||
provider_id BIGINT REFERENCES service_providers(id),
|
||
items JSONB,
|
||
total_amount DECIMAL(10,2),
|
||
delivery_fee DECIMAL(10,2) DEFAULT 0,
|
||
delivery_address TEXT,
|
||
delivery_phone VARCHAR(11),
|
||
estimated_delivery TIMESTAMP,
|
||
status VARCHAR(20) DEFAULT 'pending',
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- 9. 队长排行榜物化视图
|
||
CREATE MATERIALIZED VIEW captain_monthly_ranking AS
|
||
SELECT
|
||
c.user_id,
|
||
u.nickname,
|
||
u.avatar_url,
|
||
c.level,
|
||
COUNT(a.id) AS monthly_activities,
|
||
c.avg_rating
|
||
FROM captains c
|
||
JOIN users u ON c.user_id = u.id
|
||
LEFT JOIN activities a ON a.creator_id = c.user_id
|
||
AND a.start_time >= date_trunc('month', CURRENT_DATE)
|
||
WHERE c.status = 'active'
|
||
GROUP BY c.user_id, u.nickname, u.avatar_url, c.level, c.avg_rating
|
||
ORDER BY monthly_activities DESC;
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 新增API端点
|
||
|
||
### 3.1 队长模块 `/captains`
|
||
|
||
| 方法 | 路径 | 描述 |
|
||
|------|------|------|
|
||
| POST | /captains/apply | 申请成为队长 |
|
||
| GET | /captains/application-status | 查看申请状态 |
|
||
| GET | /captains/me/dashboard | 队长数据面板 |
|
||
| GET | /captains/ranking | 队长排行榜 |
|
||
| GET | /captains/:userId | 查看队长主页 |
|
||
|
||
**管理端(内部)**:
|
||
| 方法 | 路径 | 描述 |
|
||
|------|------|------|
|
||
| GET | /admin/captains/applications | 待审核列表 |
|
||
| POST | /admin/captains/applications/:id/approve | 审核通过 |
|
||
| POST | /admin/captains/applications/:id/reject | 审核拒绝 |
|
||
|
||
### 3.2 会员模块 `/membership`
|
||
|
||
| 方法 | 路径 | 描述 |
|
||
|------|------|------|
|
||
| GET | /membership/plans | 会员方案列表 |
|
||
| GET | /membership/status | 当前会员状态 |
|
||
| POST | /membership/subscribe | 开通会员 |
|
||
| POST | /membership/generate-pay-link | 生成子女代付链接 |
|
||
| GET | /membership/pay/:token | 子女代付页面数据 |
|
||
| POST | /membership/pay/:token/confirm | 子女确认支付 |
|
||
|
||
### 3.3 家政服务 `/services/housekeeping`
|
||
|
||
| 方法 | 路径 | 描述 |
|
||
|------|------|------|
|
||
| GET | /services/housekeeping/workers | 服务人员列表 |
|
||
| GET | /services/housekeeping/workers/:id | 人员详情 |
|
||
| POST | /services/housekeeping/orders | 预约下单 |
|
||
| GET | /services/housekeeping/orders | 我的服务订单 |
|
||
| POST | /services/housekeeping/orders/:id/cancel | 取消 |
|
||
| POST | /services/housekeeping/orders/:id/review | 评价 |
|
||
|
||
### 3.4 日常消费 `/shopping`
|
||
|
||
| 方法 | 路径 | 描述 |
|
||
|------|------|------|
|
||
| GET | /shopping/providers | 商家列表 |
|
||
| GET | /shopping/products | 商品列表 |
|
||
| GET | /shopping/cart | 购物车 |
|
||
| POST | /shopping/cart/add | 加入购物车 |
|
||
| PUT | /shopping/cart/:id | 修改数量 |
|
||
| DELETE | /shopping/cart/:id | 删除 |
|
||
| POST | /shopping/orders | 配送下单 |
|
||
| GET | /shopping/orders | 配送订单列表 |
|
||
|
||
---
|
||
|
||
## 4. Flutter新增模块
|
||
|
||
### 4.1 新增Feature模块
|
||
|
||
```
|
||
features/
|
||
├── captain/ # 社区队长
|
||
│ ├── captain_apply_page.dart
|
||
│ ├── captain_dashboard_page.dart
|
||
│ ├── captain_ranking_page.dart
|
||
│ └── captain_profile_page.dart
|
||
├── membership/ # 会员中心
|
||
│ ├── membership_page.dart
|
||
│ ├── pay_link_page.dart
|
||
│ └── widgets/
|
||
├── housekeeping/ # 家政服务
|
||
│ ├── worker_list_page.dart
|
||
│ ├── worker_detail_page.dart
|
||
│ ├── booking_page.dart
|
||
│ └── widgets/
|
||
├── shopping/ # 日常消费
|
||
│ ├── provider_list_page.dart
|
||
│ ├── product_list_page.dart
|
||
│ ├── cart_page.dart
|
||
│ ├── checkout_page.dart
|
||
│ └── widgets/
|
||
└── onboarding/ # 新手引导
|
||
├── onboarding_page.dart
|
||
└── guide_overlay.dart
|
||
```
|
||
|
||
### 4.2 微信分享集成
|
||
|
||
```dart
|
||
// 使用 fluwx 插件
|
||
dependencies:
|
||
fluwx: ^4.x
|
||
|
||
// 活动分享
|
||
Future<void> shareActivity(Activity activity) async {
|
||
await fluwx.shareToWeChat(
|
||
WeChatShareWebPageModel(
|
||
webPage: 'https://h5.banxiang.com/activity/${activity.id}',
|
||
title: activity.title,
|
||
description: '来「伴享」一起参加吧!还剩${activity.remainingSlots}个名额',
|
||
thumbnail: WeChatImage.network(activity.coverImage),
|
||
scene: WeChatScene.session,
|
||
),
|
||
);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 队长等级自动计算
|
||
|
||
```javascript
|
||
// 定时任务:每日凌晨更新队长等级
|
||
async function updateCaptainLevels() {
|
||
const captains = await db.query('SELECT * FROM captains WHERE status = $1', ['active']);
|
||
|
||
for (const captain of captains.rows) {
|
||
let newLevel = 'trainee';
|
||
|
||
if (captain.total_activities >= 50 && captain.avg_rating >= 4.75 && captain.total_new_users >= 100) {
|
||
newLevel = 'gold';
|
||
} else if (captain.total_activities >= 20 && captain.avg_rating >= 4.5 && captain.total_new_users >= 20) {
|
||
newLevel = 'silver';
|
||
}
|
||
|
||
if (newLevel !== captain.level) {
|
||
await db.query('UPDATE captains SET level = $1, updated_at = NOW() WHERE id = $2', [newLevel, captain.id]);
|
||
// 发送升级通知
|
||
await sendNotification(captain.user_id, 'CAPTAIN_LEVEL_UP', { newLevel });
|
||
}
|
||
}
|
||
|
||
// 刷新排行榜
|
||
await db.query('REFRESH MATERIALIZED VIEW captain_monthly_ranking');
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 会员权限中间件
|
||
|
||
```javascript
|
||
// middleware/membership.js
|
||
function requireMembership(req, res, next) {
|
||
if (!req.user.is_member || new Date(req.user.member_expires_at) < new Date()) {
|
||
return res.status(403).json({
|
||
success: false,
|
||
error: {
|
||
code: 'MEMBERSHIP_REQUIRED',
|
||
message: '此功能需要开通会员',
|
||
upgrade_url: '/membership/plans'
|
||
}
|
||
});
|
||
}
|
||
next();
|
||
}
|
||
|
||
// 免费用户限额检查
|
||
function checkFreeLimit(type) {
|
||
return async (req, res, next) => {
|
||
if (req.user.is_member) return next();
|
||
|
||
const limits = {
|
||
ai_chat: 20, // 每天20条
|
||
activity_join: 3, // 每月3次
|
||
};
|
||
|
||
const count = await getUsageCount(req.user.id, type);
|
||
if (count >= limits[type]) {
|
||
return res.status(403).json({
|
||
success: false,
|
||
error: {
|
||
code: 'FREE_LIMIT_EXCEEDED',
|
||
message: type === 'ai_chat'
|
||
? '今日AI对话次数已用完,开通会员享无限对话'
|
||
: '本月活动次数已用完,开通会员享无限参与',
|
||
upgrade_url: '/membership/plans'
|
||
}
|
||
});
|
||
}
|
||
next();
|
||
};
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 子女代付H5页面
|
||
|
||
```
|
||
技术栈:Vue 3 + Vant(H5页面,微信内置浏览器打开)
|
||
|
||
流程:
|
||
1. 父母端生成代付链接 → 分享到微信
|
||
2. 子女点击链接 → 打开H5页面
|
||
3. H5页面展示:父母信息 + 会员方案 + 价格
|
||
4. 子女点击支付 → 调起微信支付JSAPI
|
||
5. 支付成功 → 后端更新会员状态 → Push通知父母
|
||
```
|
||
|
||
---
|
||
|
||
**文档结束**
|