Files
zhiyin/docs/SHARE-FEATURE.md
T

6.7 KiB
Raw Blame History

分享功能设计方案

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:

{
  "type": "interview" | "resume" | "app",
  "refId": "xxx",
  "title": "我在职引完成了AI模拟面试",
  "description": "快来和我一起练习面试吧"
}

Response:

{
  "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 = trueshareCredits + 1
  • 返回重定向或展示落地页

GET /api/share/stats

{
  "totalShares": 15,
  "totalVisits": 43,
  "creditedCount": 12,
  "todayCredited": 2,
  "shareCredits": 4
}

GET /api/share/records

[
  {
    "shareCode": "a1b2c3d4",
    "type": "interview",
    "title": "我在职引完成了AI模拟面试",
    "visitCount": 5,
    "creditedCount": 3,
    "createdAt": "2026-06-12T10:00:00Z"
  }
]

GET /api/share/visitors

[
  {
    "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 生命周期:

// 在页面中定义
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. 存储方案

  • ShareRecordMongoDB 集合 sharerecords
  • ShareVisitMongoDB 集合 sharevisits
  • 积分字段 shareCredits 存储在 User 文档上,$inc 原子操作确保并发安全

8. 依赖模块

  • QuotaService(来自 UserModule)- 积分发放与抵扣
  • UserModule(获取 User 信息、校验身份)
  • PricingModule@Global 已有,无需额外导入)

9. 未纳入 MVP 的内容

  • 分享链接落地页(H5 路由 /share/:code)— 第一期直接返回 JSON
  • 分享数据可视化图表
  • 积分兑换商城
  • 排行榜 / 邀请竞赛