Files
wx_service/docs/reading/PRD.md
T

34 KiB
Raw Blame History

阅读打卡小程序 - 产品需求文档 (PRD)

1. 产品概述

1.1 产品定位

一款阅读打卡小程序,通过 AI 预生成每本书的分日阅读计划(含导读、预估阅读时长、理解问题),引导用户按计划阅读并每日打卡,培养持续阅读习惯。

1.2 核心价值

  • AI 阅读计划:AI 预先为每本书拆分每日阅读导读,预估阅读时长,后台可人工调整
  • 引导式阅读:每天展示导读内容 + 预估阅读时长 + 理解问题,降低阅读门槛
  • 打卡激励:读完当日内容后回答问题、写读书感悟,完成打卡
  • 分享传播:生成精美分享宣传图,展示阅读成果

1.3 目标用户

  • 想养成阅读习惯但缺乏计划性的用户
  • 读书会/学习社群成员
  • 家长引导孩子阅读

2. 功能范围

2.1 核心功能(MVP

书单与书籍

  • 浏览书单列表(按分类/主题组织)
  • 查看书单下的书籍列表
  • 查看书籍详情和阅读计划概览

AI 阅读计划

  • AI 预生成每本书的分日阅读导读(后台触发)
  • 每日导读包含:导读内容、阅读范围(页码/章节)、AI 预估阅读时长、理解问题
  • 后台管理员可编辑调整 AI 生成的计划内容

每日打卡

  • 展示今日导读内容和 AI 预估阅读时长(用户无需手动填写时长)
  • 用户阅读完成后回答理解问题
  • 提交打卡 + 选填读书感悟
  • 打卡日历展示连续打卡记录

分享宣传图

  • 生成分享海报(连续打卡天数、已读书籍数、累计阅读时长等)
  • 支持多种海报模板

阅读统计

  • 连续打卡天数 / 最长连续天数
  • 已读完书籍数
  • 累计阅读时长(由 AI 预估时长按打卡天数累加)
  • 阅读趋势图

2.2 暂不实现(后续迭代)

  • 用户自建书单
  • 社区互动(评论/点赞感悟)
  • 阅读排行榜
  • 订阅消息推送提醒
  • 书籍推荐算法

3. 页面结构

3.1 页面清单与 TabBar

TabBar:
  ├── 今日阅读 (pages/home/index)        - 首页,展示今日任务与打卡入口
  ├── 书单 (pages/book-lists/index)       - 浏览书单和书籍
  ├── 统计 (pages/stats/index)            - 阅读数据统计
  └── 我的 (pages/profile/index)          - 个人中心

非 Tab 页:
  ├── 书籍详情 (pages/book-detail/index)  - 书籍信息 + 阅读计划预览
  ├── 阅读打卡 (pages/reading/index)      - 今日导读 + 问题 + 打卡
  ├── 感悟列表 (pages/reflections/index)  - 某本书的感悟记录
  └── 分享海报 (pages/poster/index)       - 生成/预览分享图

3.2 首页 — 今日阅读 (home)

核心目标:一目了然展示今日阅读任务,快速进入打卡

元素 说明 数据来源
打卡日历条 近 7 天打卡状态(圆点标记) GET /reading/my/stats
在读书籍卡片 书名、封面、进度(第 X/Y 天) GET /reading/my/books
今日任务预览 导读标题 + AI 预估阅读时长 GET /reading/my/books/:id/today
打卡按钮 "开始今日阅读" / "今日已打卡 " 根据 daily_status 判断
空状态引导 未选书时展示 "去选一本书开始吧" 跳转书单页

首页布局示意

┌─────────────────────────────┐
│  📖 今日阅读                 │
│  ─────────────────────────  │
│  [日 一 二 三 四 五 六]      │
│   ●  ●  ●  ○  ○  ○  ○      │
│  连续打卡 3 天               │
│  ─────────────────────────  │
│  ┌───────────────────────┐  │
│  │ 📕 《人类简史》        │  │
│  │ 第 5/30 天             │  │
│  │ ████████░░░ 17%        │  │
│  └───────────────────────┘  │
│  ─────────────────────────  │
│  今日导读:第三章 农业革命   │
│  ⏱ 预估阅读 25 分钟         │
│  📝 3 道理解问题             │
│  ─────────────────────────  │
│  [ 🟢 开始今日阅读 ]        │
└─────────────────────────────┘

3.3 书单页 (book-lists)

核心目标:浏览和选择想读的书

元素 说明
书单卡片列表 书单封面、标题、描述、书籍数量
点击书单 展开书单下的书籍列表
书籍卡片 书名、作者、封面、计划天数、"开始阅读"按钮

3.4 书籍详情页 (book-detail)

核心目标:了解书籍信息和阅读计划,决定是否开始阅读

元素 说明
书籍封面大图 封面、书名、作者
书籍简介 内容简介
阅读计划概览 共 X 天、AI 预估总阅读时长
每日计划预览 可展开查看每天的导读标题和预估时长
操作按钮 "开始阅读"(未开始)/ "继续阅读"(进行中)/ "已读完"(已完成)

3.5 阅读打卡页 (reading)

核心目标:完成今日阅读任务并打卡

┌─────────────────────────────┐
│  ← 返回     第 5/30 天      │
│  ─────────────────────────  │
│  📖 今日导读                 │
│  第三章 农业革命 (P45-P62)   │
│  ─────────────────────────  │
│  ⏱ 预估阅读时长: 25 分钟    │
│  ─────────────────────────  │
│  [导读内容区域]              │
│  "农业革命是人类历史上最具    │
│   争议的转折点之一。作者认为  │
│   农业并非进步,而是..."     │
│  ─────────────────────────  │
│  📝 阅读理解 (读完后作答)    │
│  ─────────────────────────  │
│  Q1: 作者为什么认为农业革命  │
│      是"史上最大的骗局"?    │
│  [文本输入框]                │
│                             │
│  Q2: 采集社会与农业社会相比  │
│      各有什么优劣?          │
│  [文本输入框]                │
│                             │
│  Q3: 你是否同意作者的观点?  │
│      为什么?                │
│  [文本输入框]                │
│  ─────────────────────────  │
│  💭 读书感悟 (选填)          │
│  [多行文本输入框]            │
│  ─────────────────────────  │
│  [ ✅ 完成今日打卡 ]         │
└─────────────────────────────┘

交互规则

  • 理解问题至少回答 1 道才能提交打卡
  • 读书感悟为选填项
  • 打卡成功后展示鼓励动画 + 连续打卡天数
  • 当天最后一天打卡 → 弹出"恭喜读完全书" + 引导生成分享图

3.6 统计页 (stats)

元素 说明
核心数据卡片 连续打卡天数、已读完书籍数、累计阅读时长
打卡日历 月度日历视图,标记已打卡日期
阅读趋势 周/月维度的每日阅读时长趋势图(来自 AI 预估时长)
已读书籍列表 已完成的书籍及完成日期

3.7 个人中心 (profile)

元素 说明
用户信息 头像、昵称
在读书籍 当前正在阅读的书籍列表
已读书籍 已完成的书籍列表
我的感悟 所有读书感悟汇总
分享成就 进入海报生成页

3.8 分享海报页 (poster)

元素 说明
海报预览 实时预览生成的宣传图
模板选择 多种海报风格可选
展示字段 连续打卡天数、已读书籍数、累计阅读时长、当前在读书名
操作按钮 "保存到相册" / "分享给好友"

4. 数据模型

4.1 书单表 (fa_reading_book_list)

字段 类型 必填 说明
id bigint PK 主键
title varchar(100) 书单标题
description varchar(500) 书单描述
cover_image varchar(500) 书单封面图 URL
sort_order int 排序权重(越小越靠前,默认 0
status varchar(20) 状态:active / inactive
created_at timestamp 自动 创建时间
updated_at timestamp 自动 更新时间
deleted_at timestamp 自动 软删除时间

4.2 书籍表 (fa_reading_book)

字段 类型 必填 说明
id bigint PK 主键
book_list_id bigint 所属书单 ID
title varchar(200) 书名
author varchar(100) 作者
cover_image varchar(500) 书籍封面图 URL
description text 内容简介
isbn varchar(20) ISBN 编号
total_pages int 总页数(用于 AI 生成计划)
total_plan_days int 计划总天数
sort_order int 排序权重(默认 0
status varchar(20) 状态:active / inactive
created_at timestamp 自动 创建时间
updated_at timestamp 自动 更新时间
deleted_at timestamp 自动 软删除时间

索引

  • idx_book_list_id (book_list_id)
  • idx_status (status)

4.3 阅读计划表 (fa_reading_plan)

字段 类型 必填 说明
id bigint PK 主键
book_id bigint 关联书籍 ID(唯一)
total_days int 计划总天数
total_estimated_minutes int AI 预估总阅读时长(分钟,所有天数累加)
ai_generated tinyint(1) 是否 AI 生成(1=是,0=否)
ai_model varchar(50) 生成时使用的 AI 模型
status varchar(20) 状态:draft / published
created_at timestamp 自动 创建时间
updated_at timestamp 自动 更新时间
deleted_at timestamp 自动 软删除时间

索引

  • uidx_book_id (book_id) UNIQUE

4.4 每日导读表 (fa_reading_plan_day)

字段 类型 必填 说明
id bigint PK 主键
plan_id bigint 关联阅读计划 ID
day_number int 第几天(从 1 开始)
title varchar(200) 导读标题(如"第三章 农业革命")
guide_content text 导读正文(AI 生成的阅读引导)
reading_range varchar(100) 阅读范围(如"P45-P62"或"第三章"
estimated_minutes int AI 预估阅读时长(分钟)
questions_json json 理解问题数组 [{"q":"问题内容","hint":"提示"}]
sort_order int 排序(默认等于 day_number
created_at timestamp 自动 创建时间
updated_at timestamp 自动 更新时间
deleted_at timestamp 自动 软删除时间

索引

  • uidx_plan_day (plan_id, day_number) UNIQUE
  • idx_plan_id (plan_id)

questions_json 结构

[
  {
    "q": "作者为什么认为农业革命是'史上最大的骗局'",
    "hint": "可以从人类生活质量、劳动强度等角度思考"
  },
  {
    "q": "采集社会与农业社会相比各有什么优劣?",
    "hint": ""
  }
]

4.5 用户阅读进度表 (fa_reading_user_book)

字段 类型 必填 说明
id bigint PK 主键
uid bigint 用户 ID
book_id bigint 书籍 ID
plan_id bigint 阅读计划 ID
current_day int 当前进度(已完成到第几天,默认 0
total_days int 计划总天数(冗余,方便查询)
status varchar(20) 状态:reading / completed / dropped
started_at timestamp 开始阅读时间
completed_at timestamp 读完时间
created_at timestamp 自动 创建时间
updated_at timestamp 自动 更新时间
deleted_at timestamp 自动 软删除时间

索引

  • uidx_uid_book (uid, book_id) UNIQUE
  • idx_uid_status (uid, status)

4.6 每日打卡表 (fa_reading_daily_checkin)

字段 类型 必填 说明
id bigint PK 主键
uid bigint 用户 ID
user_book_id bigint 关联用户阅读进度 ID
plan_day_id bigint 关联每日导读 ID
day_number int 第几天
date date 打卡自然日
estimated_minutes int AI 预估阅读时长(冗余自 plan_day)
answers_json json 问题回答 [{"q":"问题","a":"回答"}]
reflection text 读书感悟
status varchar(20) 状态:checked_in / missed
checked_in_at timestamp 打卡时间
created_at timestamp 自动 创建时间
updated_at timestamp 自动 更新时间
deleted_at timestamp 自动 软删除时间

索引

  • uidx_uid_date (uid, date) UNIQUE
  • idx_uid_user_book (uid, user_book_id)
  • idx_user_book_day (user_book_id, day_number)

answers_json 结构

[
  {
    "q": "作者为什么认为农业革命是'史上最大的骗局'",
    "a": "因为农业让人类的劳动量大幅增加,饮食更加单一,但总人口的增长又让人们无法回到采集社会..."
  }
]

4.7 分享记录表 (fa_reading_share)

字段 类型 必填 说明
id bigint PK 主键
uid bigint 用户 ID
share_type varchar(20) 分享类型:daily / book_complete / streak_milestone
template_code varchar(50) 海报模板编码
data_json json 海报数据快照
image_url varchar(500) 生成的海报图片 URL
created_at timestamp 自动 创建时间
updated_at timestamp 自动 更新时间
deleted_at timestamp 自动 软删除时间

索引

  • idx_uid (uid)

5. API 设计

5.1 路由前缀与鉴权

前缀 鉴权 用途
/api/reading 部分公开 小程序主接口
/api/admin/reading Admin JWT 管理后台

5.2 书单与书籍(公开接口)

获取书单列表

GET /api/reading/book-lists

Response:
{
  "code": 0,
  "data": {
    "items": [
      {
        "id": 1,
        "title": "经典必读书单",
        "description": "精选 10 本改变思维方式的经典作品",
        "cover_image": "https://...",
        "book_count": 10
      }
    ]
  }
}

获取书单下的书籍列表

GET /api/reading/book-lists/:id/books

Response:
{
  "code": 0,
  "data": {
    "book_list": { "id": 1, "title": "经典必读书单" },
    "items": [
      {
        "id": 1,
        "title": "人类简史",
        "author": "尤瓦尔·赫拉利",
        "cover_image": "https://...",
        "total_plan_days": 30,
        "total_estimated_minutes": 750,
        "description": "..."
      }
    ]
  }
}

获取书籍详情(含计划概览)

GET /api/reading/books/:id

Response:
{
  "code": 0,
  "data": {
    "book": {
      "id": 1,
      "title": "人类简史",
      "author": "尤瓦尔·赫拉利",
      "cover_image": "https://...",
      "description": "...",
      "total_pages": 440
    },
    "plan": {
      "id": 1,
      "total_days": 30,
      "total_estimated_minutes": 750,
      "status": "published",
      "days_preview": [
        {
          "day_number": 1,
          "title": "序章 - 人类的三大革命",
          "reading_range": "P1-P15",
          "estimated_minutes": 20
        },
        {
          "day_number": 2,
          "title": "第一章 - 人类:一种也没什么特别的动物",
          "reading_range": "P16-P32",
          "estimated_minutes": 25
        }
      ]
    }
  }
}

5.3 用户阅读(需登录)

开始阅读一本书

POST /api/reading/books/:id/start

Response:
{
  "code": 0,
  "data": {
    "user_book_id": 1,
    "book_id": 1,
    "book_title": "人类简史",
    "current_day": 0,
    "total_days": 30,
    "status": "reading",
    "started_at": "2026-03-21T10:00:00+08:00"
  }
}

业务规则

  • 同一本书不能重复开始(返回 409
  • 同时只能在读一本书(可配置,MVP 先限制 1 本)

获取我的阅读列表

GET /api/reading/my/books
Query:
  - status: string (reading/completed/dropped/all,默认 all)

Response:
{
  "code": 0,
  "data": {
    "items": [
      {
        "user_book_id": 1,
        "book_id": 1,
        "book_title": "人类简史",
        "book_cover": "https://...",
        "author": "尤瓦尔·赫拉利",
        "current_day": 5,
        "total_days": 30,
        "progress_percent": 17,
        "status": "reading",
        "started_at": "2026-03-15T10:00:00+08:00"
      }
    ]
  }
}

获取某本书的阅读进度详情

GET /api/reading/my/books/:user_book_id

Response:
{
  "code": 0,
  "data": {
    "user_book": {
      "user_book_id": 1,
      "book_id": 1,
      "book_title": "人类简史",
      "author": "尤瓦尔·赫拉利",
      "current_day": 5,
      "total_days": 30,
      "status": "reading"
    },
    "checkin_history": [
      {
        "day_number": 5,
        "date": "2026-03-20",
        "title": "第三章 农业革命",
        "estimated_minutes": 25,
        "has_reflection": true,
        "checked_in_at": "2026-03-20T21:30:00+08:00"
      }
    ]
  }
}

5.4 每日打卡(需登录)

获取今日阅读任务

GET /api/reading/my/books/:user_book_id/today

Response:
{
  "code": 0,
  "data": {
    "daily_status": "pending",          // pending / checked_in
    "day_number": 6,
    "total_days": 30,
    "plan_day": {
      "id": 6,
      "title": "第三章 农业革命(续)",
      "guide_content": "上一节我们了解了农业革命的起源...",
      "reading_range": "P63-P80",
      "estimated_minutes": 25,
      "questions": [
        {
          "q": "农业社会带来了哪些社会结构的变化?",
          "hint": "可以从私有制、阶级分化等角度思考"
        },
        {
          "q": "作者认为小麦'驯化'了人类,你怎么理解?",
          "hint": ""
        }
      ]
    },
    "checkin": null                     // 已打卡时返回打卡详情
  }
}

提交今日打卡

POST /api/reading/my/books/:user_book_id/checkin
Body:
{
  "answers": [
    {
      "q": "农业社会带来了哪些社会结构的变化?",
      "a": "农业带来了定居生活,随之产生了私有制和社会阶级分化..."
    },
    {
      "q": "作者认为小麦'驯化'了人类,你怎么理解?",
      "a": "从小麦的角度看,它成功地让人类为它服务..."
    }
  ],
  "reflection": "今天读到农业革命的部分很有启发,原来我们以为的进步..."
}

Response:
{
  "code": 0,
  "data": {
    "checkin_id": 10,
    "day_number": 6,
    "date": "2026-03-21",
    "estimated_minutes": 25,
    "status": "checked_in",
    "checked_in_at": "2026-03-21T22:00:00+08:00",
    "summary": {
      "current_streak_days": 6,
      "max_streak_days": 6,
      "total_reading_minutes": 145,
      "total_books_completed": 0,
      "book_progress_percent": 20,
      "is_book_completed": false
    }
  }
}

业务规则

  • 同一天同一本书只能打卡一次(返回 409)
  • answers 数组至少包含 1 条非空回答
  • reflection 选填
  • 打卡成功后 user_book.current_day 自增 1
  • current_day == total_days,自动将 user_book.status 更新为 completed
  • 当天未打卡自然过期后标记为 missed(可通过定时任务或下次请求时回填)

获取打卡记录列表

GET /api/reading/my/books/:user_book_id/checkins
Query:
  - page: int (默认 1)
  - page_size: int (默认 20)

Response:
{
  "code": 0,
  "data": {
    "items": [
      {
        "id": 10,
        "day_number": 6,
        "date": "2026-03-21",
        "title": "第三章 农业革命(续)",
        "estimated_minutes": 25,
        "answers_count": 2,
        "has_reflection": true,
        "checked_in_at": "2026-03-21T22:00:00+08:00"
      }
    ],
    "total": 6,
    "page": 1,
    "page_size": 20
  }
}

5.5 读书感悟(需登录)

获取某本书的感悟列表

GET /api/reading/my/books/:user_book_id/reflections
Query:
  - page: int (默认 1)
  - page_size: int (默认 20)

Response:
{
  "code": 0,
  "data": {
    "items": [
      {
        "day_number": 6,
        "date": "2026-03-21",
        "title": "第三章 农业革命(续)",
        "reflection": "今天读到农业革命的部分很有启发..."
      }
    ],
    "total": 3,
    "page": 1,
    "page_size": 20
  }
}

5.6 阅读统计(需登录)

获取统计概览

GET /api/reading/my/stats

Response:
{
  "code": 0,
  "data": {
    "current_streak_days": 6,
    "max_streak_days": 6,
    "total_reading_minutes": 145,
    "total_books_completed": 0,
    "total_checkin_days": 6,
    "current_book": {
      "book_title": "人类简史",
      "progress_percent": 20,
      "current_day": 6,
      "total_days": 30
    },
    "recent_checkins": [
      { "date": "2026-03-21", "status": "checked_in", "estimated_minutes": 25 },
      { "date": "2026-03-20", "status": "checked_in", "estimated_minutes": 20 },
      { "date": "2026-03-19", "status": "checked_in", "estimated_minutes": 30 }
    ]
  }
}

5.7 分享海报(需登录)

获取海报预览数据

GET /api/reading/poster/data
Query:
  - template_code: string (默认 "reading_1")

Response:
{
  "code": 0,
  "data": {
    "nickname": "读书人",
    "streak_days": 6,
    "total_books_completed": 2,
    "total_reading_minutes": 1450,
    "current_book_title": "人类简史",
    "current_book_progress": "6/30",
    "template_code": "reading_1",
    "share_title": "我已连续阅读打卡 6 天"
  }
}

生成分享海报

POST /api/reading/poster/generate
Body:
{
  "template_code": "reading_1",
  "show_fields": ["streak_days", "total_books_completed", "total_reading_minutes"]
}

Response:
{
  "code": 0,
  "data": {
    "template_code": "reading_1",
    "image_url": "https://static.nepiedg.top/reading/posters/...",
    "share_title": "我已连续阅读打卡 6 天"
  }
}

5.8 管理后台 API

方法 路径 说明
书单管理
GET /api/admin/reading/book-lists 书单列表(支持分页)
POST /api/admin/reading/book-lists 创建书单
PUT /api/admin/reading/book-lists/:id 更新书单
DELETE /api/admin/reading/book-lists/:id 删除书单
书籍管理
GET /api/admin/reading/books 书籍列表(支持按书单筛选)
POST /api/admin/reading/books 创建书籍
PUT /api/admin/reading/books/:id 更新书籍
DELETE /api/admin/reading/books/:id 删除书籍
阅读计划管理
GET /api/admin/reading/plans/:book_id 获取书籍的阅读计划
POST /api/admin/reading/plans/:book_id/generate AI 生成阅读计划
PUT /api/admin/reading/plans/:plan_id 更新阅读计划状态
导读内容管理
GET /api/admin/reading/plan-days?plan_id=X 获取某计划的所有导读
PUT /api/admin/reading/plan-days/:id 编辑单日导读内容

6. 核心业务流程

6.1 用户打卡流程

用户进入"今日阅读"首页
  │
  ├── 未选书 → 展示空状态 → 引导去"书单"页选书
  │                              │
  │                              ↓
  │                         点击书籍 → 书籍详情页
  │                              │
  │                              ↓
  │                         点击"开始阅读"
  │                              │
  │                         POST /books/:id/start
  │                              │
  │                              ↓
  │                         返回首页(展示在读书籍)
  │
  └── 有在读书 → GET /my/books/:id/today
       │
       ├── 今日已打卡 (daily_status = checked_in)
       │   → 展示"今日已完成 ✅"
       │   → 展示打卡记录(时长、回答、感悟)
       │
       └── 今日未打卡 (daily_status = pending)
            → 展示今日导读内容
            → 展示 AI 预估阅读时长(如"预估 25 分钟"
            → 用户阅读完成后:
                 │
                 ├── 1) 回答理解问题(至少 1 题)
                 ├── 2) 写读书感悟(选填)
                 └── 3) 点击"完成打卡"
                      │
                      POST /my/books/:id/checkin
                      │
                      ├── 普通天 → 打卡成功
                      │   → current_day + 1
                      │   → 展示鼓励动画 + 连续天数
                      │
                      └── 最后一天 (current_day == total_days)
                           → user_book.status = completed
                           → 弹出"🎉 恭喜读完全书!"
                           → 引导生成分享宣传图

6.2 AI 阅读计划生成流程(后台)

管理员在后台创建书籍
  │
  ↓
点击"AI 生成阅读计划"
  │
  ↓
POST /admin/reading/plans/:book_id/generate
  │
  ├── 输入给 AI:
  │   - 书名、作者、简介、总页数
  │   - 期望计划天数(如 30 天)
  │
  ├── AI 返回(结构化 JSON):
  │   - 每日导读标题 (title)
  │   - 导读正文 (guide_content)
  │   - 阅读范围 (reading_range)
  │   - 预估阅读时长 (estimated_minutes)
  │   - 理解问题 (questions)
  │
  ├── 写入 fa_reading_plan 表
  │   - ai_generated = true
  │   - status = draft
  │
  └── 写入 fa_reading_plan_day 表(逐日)
      │
      ↓
管理员逐日审核/编辑导读内容、时长、问题
      │
      ↓
将计划状态改为 published → 前端可见

AI Prompt 参考

你是一位资深阅读导师,请为以下书籍制定一个 {total_days} 天的阅读计划:

书名:{title}
作者:{author}
简介:{description}
总页数:{total_pages}

要求:
1. 将全书合理拆分为 {total_days} 天的阅读任务
2. 每天包含:导读标题、导读正文(200-300字,引导读者关注重点)、阅读范围(页码)、预估阅读时长(分钟)、2-3 道理解问题
3. 预估阅读时长应考虑该部分的难度和信息密度
4. 理解问题应引导深度思考,而非简单的信息检索

请以 JSON 数组格式返回,每个元素包含:
{
  "day_number": 1,
  "title": "导读标题",
  "guide_content": "导读正文",
  "reading_range": "P1-P15",
  "estimated_minutes": 20,
  "questions": [
    {"q": "问题内容", "hint": "思考提示"}
  ]
}

6.3 分享宣传图流程

用户点击"分享成就"
  │
  ↓
GET /reading/poster/data → 获取海报数据
  │
  ↓
选择海报模板(多种风格)
  │
  ↓
POST /reading/poster/generate → 生成海报图片
  │
  ↓
预览海报
  │
  ├── "保存到相册" → wx.saveImageToPhotosAlbum
  └── "分享给好友" → open-type="share"

7. 后端模块结构

遵循现有 wx_service 的 Handler → Service → Model 分层架构:

wx_service/internal/reading/
├── handler/
│   └── handler.go              # HTTP 接口处理(入参校验、调用 Service、返回 JSON
├── model/
│   ├── book_list.go            # 书单模型 (fa_reading_book_list)
│   ├── book.go                 # 书籍模型 (fa_reading_book)
│   ├── reading_plan.go         # 阅读计划模型 (fa_reading_plan)
│   ├── plan_day.go             # 每日导读模型 (fa_reading_plan_day)
│   ├── user_book.go            # 用户阅读进度模型 (fa_reading_user_book)
│   ├── daily_checkin.go        # 每日打卡模型 (fa_reading_daily_checkin)
│   └── share.go                # 分享记录模型 (fa_reading_share)
└── service/
    └── service.go              # 业务逻辑(打卡、统计、计划生成、海报)

7.1 接入 main.go 的步骤

// 1. 在 AutoMigrate 中注册所有 Model
database.AutoMigrate(
    // ... 现有模型 ...
    &readingmodel.BookList{},
    &readingmodel.Book{},
    &readingmodel.ReadingPlan{},
    &readingmodel.PlanDay{},
    &readingmodel.UserBook{},
    &readingmodel.DailyCheckin{},
    &readingmodel.Share{},
)

// 2. 创建 Service
readingService := readingservice.NewService(database.DB, config.AppConfig.AI)

// 3. 创建 Handler
readingHandler := readinghandler.NewHandler(readingService)

// 4. 传入 routes.Register 并注册路由

7.2 路由注册

// routes.go 中新增
readingAPI := router.Group("/api/reading")
{
    // 公开接口
    readingAPI.GET("/book-lists", readingHandler.ListBookLists)
    readingAPI.GET("/book-lists/:id/books", readingHandler.ListBooksByList)
    readingAPI.GET("/books/:id", readingHandler.GetBookDetail)

    // 需登录接口
    readingProtected := readingAPI.Group("")
    readingProtected.Use(middleware.AuthMiddleware(db, sessionCache))
    readingProtected.Use(middleware.RequireUserMiddleware())
    {
        readingProtected.POST("/books/:id/start", readingHandler.StartReading)
        readingProtected.GET("/my/books", readingHandler.ListMyBooks)
        readingProtected.GET("/my/books/:id", readingHandler.GetMyBookDetail)
        readingProtected.GET("/my/books/:id/today", readingHandler.GetTodayTask)
        readingProtected.POST("/my/books/:id/checkin", readingHandler.Checkin)
        readingProtected.GET("/my/books/:id/checkins", readingHandler.ListCheckins)
        readingProtected.GET("/my/books/:id/reflections", readingHandler.ListReflections)
        readingProtected.GET("/my/stats", readingHandler.Stats)
        readingProtected.GET("/poster/data", readingHandler.PosterData)
        readingProtected.POST("/poster/generate", readingHandler.GeneratePoster)
    }
}

8. 前端项目结构

apps/reading-checkin/
├── src/
│   ├── api/
│   │   ├── auth.js              # 微信登录(复用现有模式)
│   │   ├── request.js           # 请求封装(Bearer Token + 401 重试)
│   │   ├── book.js              # 书单/书籍相关 API
│   │   ├── checkin.js           # 打卡相关 API
│   │   └── poster.js            # 海报相关 API
│   ├── components/
│   │   ├── book-card/           # 书籍卡片组件
│   │   ├── checkin-calendar/    # 打卡日历组件
│   │   ├── progress-bar/        # 阅读进度条
│   │   └── question-card/       # 问题回答卡片
│   ├── pages/
│   │   ├── home/index.vue       # 今日阅读(首页)
│   │   ├── book-lists/index.vue # 书单列表
│   │   ├── book-detail/index.vue# 书籍详情
│   │   ├── reading/index.vue    # 阅读打卡页
│   │   ├── stats/index.vue      # 统计
│   │   ├── profile/index.vue    # 我的
│   │   └── poster/index.vue     # 分享海报
│   ├── stores/
│   │   ├── index.js             # Pinia store 入口
│   │   └── user.js              # 用户状态
│   ├── utils/
│   │   ├── format.js            # 时长、日期格式化
│   │   └── storage.js           # reading_checkin_ 前缀存储
│   ├── config/
│   │   └── index.js             # mini_program_id, baseUrl 配置
│   ├── App.vue                  # 应用入口(onLaunch 登录)
│   ├── main.js
│   ├── manifest.json
│   ├── pages.json               # 页面路由 + TabBar 配置
│   └── uni.scss                 # 全局样式
├── package.json
└── vite.config.js

8.1 关键配置

config/index.js:

const config = {
  mini_program_id: '<reading_checkin_mp_id>',
  baseUrl: {
    dev: 'http://localhost:8080/api',
    prod: 'https://wx.nepiedg.top/api'
  }
}

utils/storage.js 存储前缀: reading_checkin_


9. 实施计划

阶段 内容 优先级
P0: 后端基础 Model 定义 + AutoMigrate + Service 骨架 + Handler + Routes 接入
P0: 前端脚手架 基于 quit-checkin 创建项目骨架、登录、请求封装
P1: 书单与书籍 后台 CRUD + 前端展示
P1: AI 阅读计划 后台 AI 生成 + 导读编辑
P1: 打卡核心流程 今日任务获取 + 回答问题 + 提交打卡 + 进度更新
P2: 统计页面 连续天数、日历、趋势图
P2: 分享海报 海报数据 + 模板 + 生成
P3: 优化体验 打卡动画、空状态引导、错误处理
P3: 联调测试 前后端联调 + 微信真机测试

10. 与现有系统的关系

复用项 说明
用户表 (users) 共用,通过 mini_program_id 区分小程序
微信登录 (AuthService) 完全复用
鉴权中间件 (AuthMiddleware) 完全复用
七牛上传 (QiniuService) 复用(书籍封面、海报图片上传)
Redis 缓存 (SessionUserCache) 复用
管理后台框架 (admin) 复用 JWT 鉴权和管理员体系
AI 配置 (config.AI) 复用 AI 调用配置(参照 smoke 模块的 AI 集成)