Files
zhiyin/docs/SHARE-FEATURE.md
T

254 lines
6.7 KiB
Markdown
Raw 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.
# 分享功能设计方案
## 1. 概述
**目标**:用户可通过分享面试/简历等给好友或微信群,每次有效分享获得积分奖励,积分可抵扣面试/简历优化次数,形成用户增长闭环。
**核心逻辑**:分享者 A → 生成分享链接 → 非 A 的其他用户点击 → 计入有效分享一次 → A 获得 1 个「分享积分」,每 3 次有效分享可兑换 1 次面试或简历优化次数。
---
## 2. 数据模型
### User 新增字段
```
shareCredits: number // 分享积分,默认 0
```
- 1 个 shareCredit 可兑换 1 次 面试 或 1 次 简历优化
- 在 QuotaService 中作为兜底:当 interviewCredits / resumeOptimizeCredits 为 0 时尝试消耗 shareCredits
### ShareRecord 集合
```
@Schema({ timestamps: true })
ShareRecord {
_id: ObjectId
userId: ObjectId // 分享者
shareCode: string // 8位唯一短码 (hex),用于分享链接
type: 'interview' | 'resume' | 'app'
refId: string // 关联的面试/简历ID(可选)
title: string // 分享标题
description: string // 分享描述
visitCount: number // 总访问次数
creditedCount: number // 已计为有效的访问次数
isActive: boolean // 链接是否有效
createdAt: Date // timestamps
updatedAt: Date
}
index: { shareCode: 1 } unique
index: { userId: 1, createdAt: -1 }
```
### ShareVisit 集合(访问记录)
```
@Schema({ timestamps: true })
ShareVisit {
_id: ObjectId
shareId: ObjectId // 关联的 ShareRecord
sharerId: ObjectId // 分享者 userId(冗余,便于查询)
visitorId: string // 访问者标识(openId 或 匿名ID)
visitorUserId: ObjectId // 访问者 userId(如果已注册/登录)
credited: boolean // 是否已为此访问发积分
creditedAt: Date
createdAt: Date // timestamps
}
index: { shareId: 1, visitorId: 1 } unique // 同一人只计一次
index: { sharerId: 1, createdAt: -1 }
```
---
## 3. API 设计
| 方法 | 路径 | 权限 | 说明 |
|------|------|------|------|
| POST | /api/share/create | JWT | 生成分享链接,返回 shareCode + URL |
| GET | /api/share/visit/:shareCode | Public | 访问分享链接,记录访问+判定发放积分 |
| GET | /api/share/stats | JWT | 获取我的分享统计(总分享次数、总积分、今日积分) |
| GET | /api/share/records | JWT | 获取我的分享记录列表(分页) |
| GET | /api/share/visitors | JWT | 获取访问过我分享的用户列表(分页) |
### POST /api/share/create
Request:
```json
{
"type": "interview" | "resume" | "app",
"refId": "xxx",
"title": "我在职引完成了AI模拟面试",
"description": "快来和我一起练习面试吧"
}
```
Response:
```json
{
"shareCode": "a1b2c3d4",
"shareUrl": "https://zhiyin.app/share/a1b2c3d4",
"wechatShareInfo": {
"title": "...",
"description": "...",
"path": "/pages/share/share?code=a1b2c3d4"
}
}
```
### GET /api/share/visit/:shareCode
- 如果来自微信小程序:记录 `visitorId = openId`
- 如果来自 H5 链接:记录 `visitorId = 匿名设备ID`(可选)
- 判定条件:
- `visitorId !== sharer.openId`(自己点自己不算)
-`visitorId` 之前未在该 shareId 下领过积分
- 当日该分享者已获得积分 < 3(日上限)
- 满足条件 → `credited = true`shareCredits + 1
- 返回重定向或展示落地页
### GET /api/share/stats
```json
{
"totalShares": 15,
"totalVisits": 43,
"creditedCount": 12,
"todayCredited": 2,
"shareCredits": 4
}
```
### GET /api/share/records
```json
[
{
"shareCode": "a1b2c3d4",
"type": "interview",
"title": "我在职引完成了AI模拟面试",
"visitCount": 5,
"creditedCount": 3,
"createdAt": "2026-06-12T10:00:00Z"
}
]
```
### GET /api/share/visitors
```json
[
{
"visitor": { "nickname": "张三", "avatar": "..." },
"credited": true,
"creditedAt": "2026-06-12T10:30:00Z"
}
]
```
---
## 4. 积分兜底机制
`QuotaService.checkAndDeductInterview()``checkAndDeductOptimize()` 中增加兜底:
```
if (interviewCredits <= 0 && shareCredits > 0) {
shareCredits -= 1
return // 用分享积分抵扣
}
```
同时新增 `useShareCredit(userId, type)` 方法由前端显式调用,或自动在抵扣链中完成。
---
## 5. 前端实现
### 5.1 分享入口
**进入点 1:面试报告页**`pages/report/report.vue`
- 在"生成分享卡片"按钮旁增加"分享给好友"按钮
- 点击后调用 `POST /api/share/create` 生成 shareCode
- 微信小程序内直接调 `wx.shareAppMessage`
- H5 环境复制分享链接到剪贴板
**进入点 2:简历优化结果页**`pages/result/result.vue`
- 同上
**进入点 3:应用首页**`pages/index/index.vue`
- "邀请好友"入口,固定分享 app 类型
### 5.2 我的分享页
**页面位置**`/pages/share/share.vue`
**进入方式**:用户「我的」页面 → "我的分享" 菜单项
页面内容:
- 顶部统计卡片:总收益积分、今日收益、总分享次数
- "分享给好友"主按钮
- Tab 切换:「分享记录」/ 「访问记录」
- 分享记录列表:分享类型、标题、访问数、有效数、时间
- 访问记录列表:访客昵称、访问时间、是否已积分
### 5.3 微信分享
使用 uni-app `onShareAppMessage` 生命周期:
```javascript
// 在页面中定义
onShareAppMessage() {
return {
title: '我在职引完成了AI模拟面试',
path: `/pages/share/share?code=${this.shareCode}`,
imageUrl: '...'
}
}
```
### 5.4 H5 分享链接
分享链接格式:`https://zhiyin.app/share/{shareCode}`
H5 落地页展示:
- 分享者信息
- 分享内容预览
- "打开小程序" / "下载 App" 引导按钮
---
## 6. 风控规则
| 规则 | 说明 |
|------|------|
| 日上限 | 同一用户每日最多获 3 个分享积分 |
| 自分享过滤 | 自己点自己的链接不计数 |
| 同人去重 | 同一访客对同一链接只计一次 |
| 链接有效期 | 分享链接 30 天有效期 |
| 频率限制 | 每分钟最多创建 5 次分享(前端控制) |
---
## 7. 存储方案
- **ShareRecord**MongoDB 集合 `sharerecords`
- **ShareVisit**MongoDB 集合 `sharevisits`
- 积分字段 `shareCredits` 存储在 User 文档上,`$inc` 原子操作确保并发安全
---
## 8. 依赖模块
- `QuotaService`(来自 UserModule- 积分发放与抵扣
- `UserModule`(获取 User 信息、校验身份)
- `PricingModule`@Global 已有,无需额外导入)
---
## 9. 未纳入 MVP 的内容
- 分享链接落地页(H5 路由 `/share/:code`)— 第一期直接返回 JSON
- 分享数据可视化图表
- 积分兑换商城
- 排行榜 / 邀请竞赛