topfans/docs/PRD-activity.md
2026-04-07 22:28:50 +08:00

230 lines
6.8 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.

# 运营活动功能实现计划
## 背景
用户希望添加一个运营活动功能:
- 用户可以进入运营活动界面
- 通过水晶购买道具推进活动进程
- 购买道具可获得贡献点
- 后台统计贡献点排名
- 运营活动有时间限制
- 不同阶段展示不同界面效果
**现有代码基础**
- 前端已有应援活动页面 (`frontend/pages/support-activity/`)
- 已有活动配置 (`frontend/utils/activity-config.js`)
- 已有排行榜服务可作为参考 (`backend/services/assetService/service/ranking_service.go`)
- 水晶余额在 `fan_profiles.crystal_balance`
---
## 实现方案
### 1. 数据库设计
**✅ 已确认: 道具配置使用数据库方式**
新建表:`activities`, `activity_items`, `activity_contributions`, `activity_user_stats`
```sql
-- 运营活动表
CREATE TABLE IF NOT EXISTS activities (
id BIGSERIAL PRIMARY KEY,
activity_type VARCHAR(50) NOT NULL, -- 活动类型: birthday/concert/bus
title VARCHAR(100) NOT NULL, -- 活动标题
description TEXT, -- 活动描述
star_id BIGINT NOT NULL, -- 所属明星
start_time BIGINT NOT NULL, -- 开始时间
end_time BIGINT NOT NULL, -- 结束时间
target_progress BIGINT NOT NULL DEFAULT 1000, -- 目标进度
current_progress BIGINT NOT NULL DEFAULT 0, -- 当前进度
status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/active/completed/expired
stage_configs JSONB, -- 阶段配置 (不同进度的背景图等)
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
-- 活动道具表 (数据库配置,支持运营平台动态调整)
CREATE TABLE IF NOT EXISTS activity_items (
id BIGSERIAL PRIMARY KEY,
activity_id BIGINT NOT NULL,
item_type VARCHAR(50) NOT NULL, -- 道具类型: firework/megaphone/love
item_name VARCHAR(50) NOT NULL, -- 道具名称
icon_url VARCHAR(500), -- 道具图标
crystal_cost INTEGER NOT NULL, -- 水晶消耗
contribution_points INTEGER NOT NULL, -- 贡献点奖励
sort_order INTEGER NOT NULL DEFAULT 0,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
-- 用户活动贡献记录表
CREATE TABLE IF NOT EXISTS activity_contributions (
id BIGSERIAL PRIMARY KEY,
activity_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
item_id BIGINT NOT NULL,
item_type VARCHAR(50) NOT NULL,
quantity INTEGER NOT NULL DEFAULT 1,
crystal_spent BIGINT NOT NULL,
contribution_points BIGINT NOT NULL,
created_at BIGINT NOT NULL
);
-- 用户活动贡献汇总表 (用于排行榜)
CREATE TABLE IF NOT EXISTS activity_user_stats (
id BIGSERIAL PRIMARY KEY,
activity_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
star_id BIGINT NOT NULL,
total_contribution BIGINT NOT NULL DEFAULT 0,
total_crystal_spent BIGINT NOT NULL DEFAULT 0,
total_items INTEGER NOT NULL DEFAULT 0,
last_contribute_at BIGINT NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
CONSTRAINT uk_activity_user_star UNIQUE (activity_id, user_id, star_id)
);
```
### 2. Proto 定义
新建 `backend/proto/activity.proto`
```protobuf
// 活动相关消息定义
message Activity {
int64 id = 1;
string activity_type = 2;
string title = 3;
string description = 4;
int64 star_id = 5;
int64 start_time = 6;
int64 end_time = 7;
int64 target_progress = 8;
int64 current_progress = 9;
string status = 10;
string current_stage = 11; // 当前阶段: early/mid/late/completed
repeated ActivityItem items = 12;
}
message ActivityItem {
int64 id = 1;
string item_type = 2;
string item_name = 3;
string icon_url = 4;
int32 crystal_cost = 5;
int32 contribution_points = 6;
}
// 贡献购买请求
message PurchaseItemRequest {
int64 activity_id = 1;
string item_type = 2;
int32 quantity = 3;
int64 star_id = 4;
}
// 贡献点排名
message ContributionRankingRequest {
int64 activity_id = 1;
int64 star_id = 2;
int32 page = 3;
int32 page_size = 4;
}
message ContributionRankingItem {
int32 rank = 1;
int64 user_id = 2;
string nickname = 3;
string avatar_url = 4;
int64 total_contribution = 5;
int64 total_crystal_spent = 6;
}
message MyContribution {
int32 rank = 1;
int64 total_contribution = 2;
int64 total_crystal_spent = 3;
string status = 4; // ranked/unranked
}
```
### 3. 后端服务实现
**新建服务**: `backend/services/activityService/`
- `main.go` - 服务入口
- `service/activity_service.go` - 业务逻辑
- `repository/activity_repository.go` - 数据库操作
- `provider/activity_provider.go` - Dubbo provider
**API 端点** (通过 gateway):
- `GET /api/v1/activities/:id` - 获取活动详情
- `GET /api/v1/activities/:id/items` - 获取活动道具列表
- `POST /api/v1/activities/:id/purchase` - 购买道具
- `GET /api/v1/activities/:id/ranking` - 贡献点排名
- `GET /api/v1/activities?star_id=:star_id` - 获取活动列表
**水晶扣减逻辑**:
1. 检查用户水晶余额是否足够
2. 扣减水晶 (`fan_profiles.crystal_balance`)
3. 增加活动进度
4. 记录贡献明细
5. 更新用户贡献汇总
6. 返回结果
### 4. 前端实现
**修改文件**:
- `frontend/utils/activity-config.js` - 添加动态阶段配置
- `frontend/pages/support-activity/index.vue` - 接入后端 API
- `frontend/pages/support-activity/components/ActionBar.vue` - 购买道具交互
- `frontend/utils/api.js` - 添加活动 API
**阶段展示逻辑**:
```
- 0-25%: 初期 (early) - 初始背景
- 26-50%: 中期 (mid) - 中期背景
- 51-75%: 后期 (late) - 后期背景
- 76-100%: 完成 (completed) - 完成背景 + 特效动画
```
**时间限制显示**:
- 活动未开始: 显示"距开始还有 X 天"
- 活动进行中: 显示"还剩 X 天 X 小时"
- 活动已结束: 显示"活动已结束"
---
## 关键文件路径
| 组件 | 文件路径 |
|------|----------|
| 数据库初始化 | `backend/scripts/init_database.sql` |
| Proto 定义 | `backend/proto/activity.proto` (新建) |
| 活动服务 | `backend/services/activityService/` (新建) |
| Gateway 路由 | `backend/gateway/controller/` (新增) |
| 前端活动配置 | `frontend/utils/activity-config.js` |
| 前端活动页面 | `frontend/pages/support-activity/index.vue` |
| 前端 API | `frontend/utils/api.js` |
---
## 验证方案
1. **数据库**: 确认表创建成功,索引正确
2. **后端 API**:
- 创建活动,验证返回
- 购买道具,验证水晶扣减和贡献点增加
- 获取排名,验证排序正确
3. **前端**:
- 活动页面加载正常
- 购买道具交互正常
- 不同阶段背景切换正常
- 倒计时显示正常
4. **整体流程**: 完整流程测试 - 购买道具 -> 贡献点增加 -> 排名更新