diff --git a/docs/产品设计文档.md b/docs/产品设计文档.md new file mode 100644 index 0000000..f114455 --- /dev/null +++ b/docs/产品设计文档.md @@ -0,0 +1,513 @@ +# Doodle Mini 小程序 - 产品设计文档 v2.0 + +> 定位:3-8 岁早教 A4 纸打印资料小程序 +> 版本:v2.0 产品重设计方案 +> 最后更新:2026-03-24 + +--- + +## 一、现状问题诊断 + +### 1.1 内容层面 + +| 问题 | 现状 | 影响 | +|------|------|------| +| 品类单一 | 仅有数学计算、专注力训练、识字、练字四类 | 缺少英语启蒙、科学认知、艺术创造、生活常识等早教核心板块 | +| 题型趋同 | 数学 26 种题型多为数字计算变体,缺少生活化数学 | 用户容易审美疲劳,低龄段(3-5岁)可用内容少 | +| 缺乏体系 | 题型平铺排列,无年龄分级/难度递进 | 家长无法按孩子年龄/水平选择合适内容 | +| 无趣味化 | 缺少迷宫、涂色卡、手工折纸等高趣味性内容 | 与竞品(kiddoworksheets)差距大 | +| 内容静态 | 所有内容均为代码写死,无法动态扩展 | 新增题型需要发版,运营效率低 | + +### 1.2 用户体验层面 + +| 问题 | 现状 | 影响 | +|------|------|------| +| 首页缺吸引力 | 入口卡片列表式排布,无分类筛选 | 题型多时找不到内容,新用户不知从何开始 | +| 无用户体系 | 无登录/收藏/历史记录 | 用户无法追踪使用情况,留存差 | +| 缺少预览图 | 进入题型前看不到最终效果 | 试错成本高 | +| 无批量打印 | 每次只能生成一张 → 保存 → 打印 | 需要多张时操作繁琐 | +| 无打印指引 | 保存到相册后缺少从相册打印的引导 | 用户可能不知道如何打印 | + +### 1.3 技术层面 + +| 问题 | 现状 | 影响 | +|------|------|------| +| 云函数名不一致 | 代码调用 `robotaxi`,目录名 `doodle` | 可能存在线上风险 | +| 无效代码引用 | `index.js` 引用不存在的 `station/area` 等模块 | 部署可能失败 | +| debug 页有死链 | 指向不存在的 `demoPages/shapePrint` | 功能残缺 | +| 无 PDF 导出 | `createPDF` 云函数仅实验性代码 | 缺少直接生成 PDF 的能力 | +| 渲染方案限制 | 全部 Canvas 渲染,交互受限 | 难以实现复杂交互(如拖拽、填写) | + +--- + +## 二、竞品参考与差距分析 + +参考 [kiddoworksheets.com](https://www.kiddoworksheets.com/),对比如下: + +| 维度 | kiddoworksheets | Doodle Mini 现状 | 差距 | +|------|----------------|------------------|------| +| 内容品类 | 30+ 大类(字母、拼写、涂色、迷宫、折纸、找不同、时钟...) | 4 大类 | 严重不足 | +| 年龄覆盖 | 学前 - 5 年级 | 3-8 岁(但内容未分级) | 缺少分级体系 | +| 题目数量 | 每个品类数十到数百张 | 每种题型动态生成(无限但变化有限) | 模板多样性不够 | +| 下载方式 | 直接 PDF 下载 | 保存 PNG 到相册 | 体验略差 | +| 视觉风格 | 彩色卡通插画 | 简约线条风格 | 视觉吸引力弱 | +| 内容更新 | 持续更新 | 代码写死 | 运营效率差距大 | +| SEO/分享 | 独立网页,搜索引擎友好 | 小程序,依赖微信生态 | 获客渠道不同 | + +--- + +## 三、产品重设计方案 + +### 3.1 全新信息架构 + +``` +┌──────────────────────────────────────────────────────────────┐ +│ 首页(重设计) │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐ │ +│ │ 数学 │ │ 语文 │ │ 英语 │ │ 益智 │ │ 创意 │ │ +│ │ 启蒙 │ │ 启蒙 │ │ 启蒙 │ │ 游戏 │ │ 手工 │ │ +│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └───┬────┘ │ +├───────┼──────────┼──────────┼──────────┼─────────────┼──────┤ +│ ▼ ▼ ▼ ▼ ▼ │ +│ 数字认知 识字卡 字母学习 迷宫 涂色卡 │ +│ 计数练习 练字帖 自然拼读 找不同 折纸 │ +│ 加减运算 看图说话 词汇练习 连线题 手工 │ +│ 时钟练习 成语接龙 闪卡 拼图 贴纸 │ +│ 形状认知 笔顺练习 描红 数独 ... │ +│ ... ... ... ... │ +└──────────────────────────────────────────────────────────────┘ +``` + +### 3.2 新 TabBar 设计 + +| Tab | 名称 | 说明 | +|-----|------|------| +| 1 | 发现 | 首页,分类浏览所有可打印资料,含推荐/热门/最新 | +| 2 | 分龄 | 按年龄(3-4/4-5/5-6/6-7/7-8)筛选适合的内容 | +| 3 | 收藏 | 收藏的题型、已下载的历史记录 | +| 4 | 我的 | 用户中心、打印指南、设置、意见反馈 | + +--- + +## 四、新增功能规划(按优先级排序) + +### P0 - 核心改进(1-2 周内完成) + +> 低开发成本、高用户价值,优先推进 + +| # | 功能 | 描述 | 开发难度 | 用户价值 | +|---|------|------|---------|---------| +| 1 | **年龄分级体系** | 为所有题型标注适合年龄段(3-4/4-5/5-6/6-7/7-8),首页增加年龄筛选 | ⭐⭐ | ⭐⭐⭐⭐⭐ | +| 2 | **难度标签** | 每个题型标注难度(入门/基础/进阶/挑战),方便家长选择 | ⭐ | ⭐⭐⭐⭐ | +| 3 | **效果预览图** | 入口卡片展示真实的打印效果缩略图,非 icon 风格 | ⭐⭐ | ⭐⭐⭐⭐ | +| 4 | **首页重设计** | 增加分类导航(横向滚动标签)+ 搜索 + 推荐区域 | ⭐⭐ | ⭐⭐⭐⭐⭐ | +| 5 | **打印指南页** | 新增「如何打印」图文引导页(从保存→打印→装订的完整教程) | ⭐ | ⭐⭐⭐⭐ | +| 6 | **修复技术问题** | 清理云函数无效引用、统一函数名、移除死链 | ⭐ | ⭐⭐⭐ | + +### P1 - 内容扩充(2-4 周) + +> 显著丰富产品内容,提升竞争力 + +#### 4.1 数学新增题型 + +| # | 功能 | 描述 | 开发难度 | +|---|------|------|---------| +| 7 | **时钟练习** | 认识钟表、读时间、画时针分针 | ⭐⭐⭐ | +| 8 | **形状分类** | 按形状/大小/颜色分类,圈出不同类 | ⭐⭐ | +| 9 | **规律填空** | 数字/图形规律,找出下一个 | ⭐⭐ | +| 10 | **货币认知** | 认识人民币面值,简单找零练习 | ⭐⭐⭐ | +| 11 | **测量启蒙** | 用尺子量长度、比较长短 | ⭐⭐ | + +#### 4.2 语文新增题型 + +| # | 功能 | 描述 | 开发难度 | +|---|------|------|---------| +| 12 | **拼音练习** | 声母/韵母/整体认读音节描红、拼音组合 | ⭐⭐⭐ | +| 13 | **笔画练习** | 基本笔画(横竖撇捺等)描红练习 | ⭐⭐ | +| 14 | **偏旁部首** | 偏旁部首认知、组字练习 | ⭐⭐ | +| 15 | **看图说话** | 提供图片场景,引导孩子看图说话/写话 | ⭐⭐⭐ | +| 16 | **成语/古诗填空** | 常见成语、古诗的填空练习 | ⭐⭐ | + +#### 4.3 英语启蒙(全新模块) + +| # | 功能 | 描述 | 开发难度 | +|---|------|------|---------| +| 17 | **字母描红** | A-Z 大小写字母描红练习 | ⭐⭐ | +| 18 | **字母闪卡** | 字母+对应单词+插图的闪卡 | ⭐⭐ | +| 19 | **字母找一找** | 在字母方阵中找出目标字母 | ⭐(复用 numberFind) | +| 20 | **单词描红** | 常见英语单词描红(颜色/动物/数字/水果) | ⭐⭐⭐ | +| 21 | **自然拼读练习纸** | CVC 单词拼读、元音辅音分类 | ⭐⭐⭐ | + +### P2 - 益智游戏(4-6 周) + +> 高趣味性内容,显著提升差异化 + +| # | 功能 | 描述 | 开发难度 | +|---|------|------|---------| +| 22 | **走迷宫** | 不同难度的迷宫(简单路径/多分支/主题迷宫) | ⭐⭐⭐⭐ | +| 23 | **找不同** | 两张相似图片找出差异点 | ⭐⭐⭐⭐ | +| 24 | **数独入门** | 4×4 / 6×6 简易数独 | ⭐⭐⭐ | +| 25 | **控笔练习** | 虚线描画(直线/曲线/锯齿/螺旋) | ⭐⭐ | +| 26 | **连线画图** | 按数字/字母顺序连点成画(Dot-to-Dot) | ⭐⭐⭐ | +| 27 | **图形拼图** | 七巧板/图形拼合练习 | ⭐⭐⭐ | +| 28 | **记忆力翻翻卡** | 可打印的配对翻翻卡(打印→剪切→玩) | ⭐⭐ | + +### P3 - 创意手工(6-8 周) + +> 拓展品类边界,吸引更多用户群 + +| # | 功能 | 描述 | 开发难度 | +|---|------|------|---------| +| 29 | **涂色卡** | 卡通主题线稿涂色(动物/交通/节日/恐龙等) | ⭐⭐⭐ | +| 30 | **折纸模板** | 可打印的折纸展开图+步骤说明 | ⭐⭐(主要是素材制作) | +| 31 | **字母/数字手工** | 打印→剪切→粘贴的立体字母/数字 | ⭐⭐ | +| 32 | **主题手工** | 节日手工(春节/中秋/圣诞等)、季节手工 | ⭐⭐⭐ | +| 33 | **贴纸打印** | 可打印的奖励贴纸、装饰贴纸 | ⭐⭐ | +| 34 | **自制绘本** | 打印→装订的简易绘本模板 | ⭐⭐⭐ | + +### P4 - 体验升级(持续迭代) + +> 提升产品专业度和用户粘性 + +| # | 功能 | 描述 | 开发难度 | +|---|------|------|---------| +| 35 | **用户体系** | 微信授权登录 + 用户信息 | ⭐⭐ | +| 36 | **收藏功能** | 收藏喜欢的题型,快速访问 | ⭐⭐ | +| 37 | **下载历史** | 记录每次下载的内容和时间 | ⭐⭐ | +| 38 | **批量生成** | 一次生成多张不同题目的练习纸 | ⭐⭐⭐ | +| 39 | **PDF 导出** | 支持直接生成多页 PDF(需云函数) | ⭐⭐⭐⭐ | +| 40 | **自定义纸张** | 支持 A4/B5/Letter 等纸张尺寸切换 | ⭐⭐ | +| 41 | **打印套餐** | 按周/月推荐「每日一练」打印计划 | ⭐⭐⭐ | +| 42 | **社区分享** | 用户分享打印效果、使用心得 | ⭐⭐⭐⭐ | +| 43 | **数据统计** | 记录孩子使用数据,生成学习报告 | ⭐⭐⭐⭐ | + +--- + +## 五、页面重设计方案 + +### 5.1 首页「发现」页重设计 + +**现状问题**:四个独立的 Tab 页各自为政,用户需要在 Tab 间跳转寻找内容。 + +**改造方案**:合并为统一的「发现」首页 + +``` +┌─────────────────────────────────────┐ +│ 🔍 搜索框 │ +├─────────────────────────────────────┤ +│ [全部] [数学] [语文] [英语] │ +│ [益智] [创意] [手工] │ ← 横向滚动分类标签 +├─────────────────────────────────────┤ +│ │ +│ 📌 今日推荐 │ ← 每日精选 2-3 个内容 +│ ┌────────────────────────────┐ │ +│ │ 🎄 圣诞主题涂色卡 [NEW] │ │ +│ │ [效果预览图] │ │ +│ └────────────────────────────┘ │ +│ │ +│ 🔥 热门下载 │ ← 横向滚动卡片 +│ ┌─────┐ ┌─────┐ ┌─────┐ │ +│ │迷宫 │ │涂色卡│ │加减法│ │ +│ └─────┘ └─────┘ └─────┘ │ +│ │ +│ 📚 数学启蒙 │ ← 按分类展示 +│ ┌─────────┬─────────┬─────────┐ │ +│ │ 数字认知 │ 计数练习 │ 加减运算 │ │ +│ │ [缩略图] │ [缩略图] │ [缩略图] │ │ +│ │ 3-5岁 │ 4-6岁 │ 5-7岁 │ │ +│ └─────────┴─────────┴─────────┘ │ +│ │ +│ ✏️ 语文启蒙 │ +│ ┌─────────┬─────────┬─────────┐ │ +│ │ 识字卡 │ 练字帖 │ 拼音 │ │ +│ └─────────┴─────────┴─────────┘ │ +│ │ +│ 🌈 创意手工 │ +│ ┌─────────┬─────────┬─────────┐ │ +│ │ 涂色卡 │ 折纸 │ 贴纸 │ │ +│ └─────────┴─────────┴─────────┘ │ +│ │ +└─────────────────────────────────────┘ +``` + +### 5.2 分类详情页 + +点击分类标签或「查看更多」进入的二级页面: + +``` +┌─────────────────────────────────────┐ +│ ← 返回 数学启蒙 │ +├─────────────────────────────────────┤ +│ 年龄筛选: │ +│ [全部] [3-4岁] [4-5岁] [5-6岁] │ +│ [6-7岁] [7-8岁] │ +│ │ +│ 难度筛选: │ +│ [全部] [⭐入门] [⭐⭐基础] │ +│ [⭐⭐⭐进阶] [⭐⭐⭐⭐挑战] │ +├─────────────────────────────────────┤ +│ │ +│ ┌────────────────────────────┐ │ +│ │ [效果预览大图] │ │ +│ │ 数字排序 │ │ +│ │ ⭐⭐ 基础 | 适合 4-6 岁 │ │ +│ │ 📥 12.3k 次下载 │ │ +│ │ [立即生成] [❤️ 收藏] │ │ +│ └────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────┐ │ +│ │ [效果预览大图] │ │ +│ │ 凑十法练习 │ │ +│ │ ⭐⭐⭐ 进阶 | 适合 5-7 岁 │ │ +│ └────────────────────────────┘ │ +│ │ +└─────────────────────────────────────┘ +``` + +### 5.3 生成/预览页重设计 + +``` +┌─────────────────────────────────────┐ +│ ← 返回 凑十法练习 ❤️ ··· │ +├─────────────────────────────────────┤ +│ │ +│ ┌────────────────────────────┐ │ +│ │ │ │ +│ │ A4 打印效果预览区 │ │ +│ │ (Canvas 实时渲染) │ │ +│ │ │ │ +│ └────────────────────────────┘ │ +│ │ +│ ⚙️ 参数设置 │ +│ ┌────────────────────────────┐ │ +│ │ 范围:[10以内 ▼] │ │ +│ │ 题数:[12 ▼] │ │ +│ │ 纸张:[A4 ▼] │ │ +│ │ 页眉:[显示 ▼] │ │ +│ └────────────────────────────┘ │ +│ │ +│ ┌──────────┐ ┌──────────────┐ │ +│ │ 🔄 换一批 │ │ 📥 保存并打印 │ │ +│ └──────────┘ └──────────────┘ │ +│ │ +│ ┌──────────┐ ┌──────────────┐ │ +│ │ 📄 存PDF │ │ 📤 分享好友 │ │ +│ └──────────┘ └──────────────┘ │ +│ │ +└─────────────────────────────────────┘ +``` + +### 5.4 「我的」页面(新增) + +``` +┌─────────────────────────────────────┐ +│ 我的 │ +├─────────────────────────────────────┤ +│ ┌─────┐ │ +│ │ 头像 │ 微信用户昵称 │ +│ └─────┘ 已生成 128 张练习纸 │ +├─────────────────────────────────────┤ +│ │ +│ 📥 下载历史 > │ +│ ❤️ 我的收藏 > │ +│ 📋 每日打印计划 > │ +│ 📊 学习统计 > │ +│ │ +├─────────────────────────────────────┤ +│ │ +│ 🖨️ 打印指南 > │ +│ ⚙️ 打印设置 > │ +│ 💬 意见反馈 > │ +│ ℹ️ 关于我们 > │ +│ │ +└─────────────────────────────────────┘ +``` + +--- + +## 六、视觉风格升级建议 + +### 6.1 现状问题 + +- 入口卡片仅为简单的文字+icon,缺少视觉吸引力 +- 配色单一,整体观感不够「儿童友好」 +- 缺少品牌感(Logo、IP形象等) + +### 6.2 改进方向 + +| 维度 | 建议 | +|------|------| +| 主色调 | 采用温暖明亮的渐变色系(橙黄 → 粉紫),传达活力与童趣 | +| 品牌 IP | 设计一个可爱的 IP 形象(如小恐龙/小兔子),贯穿全应用 | +| 卡片风格 | 入口卡片使用真实打印效果预览图 + 圆角卡片 + 柔和阴影 | +| 字体 | 标题使用圆体/手写风格字体,正文保持清晰易读 | +| 图标 | 使用统一的手绘风格图标替代 emoji | +| 动效 | 适度加入微动效(卡片进场、按钮反馈、生成加载) | +| 空状态 | IP 形象配合趣味文案(如「还没有收藏哦,去发现好玩的练习纸吧~」) | + +### 6.3 打印页面风格 + +| 维度 | 建议 | +|------|------| +| 页眉 | 统一品牌 Logo + 小程序码 + 日期 + 孩子姓名(可选) | +| 页脚 | 鼓励语/小贴士(如「做得真棒!」「今天又进步了!」) | +| 装饰 | 页面边角增加可爱装饰元素(星星、花朵、小动物) | +| 排版 | 优化题目间距,确保打印后字体大小适合儿童辨认(≥14pt) | + +--- + +## 七、技术改造建议 + +### 7.1 架构优化 + +| 改造项 | 现状 | 目标 | 优先级 | +|--------|------|------|--------| +| 内容配置化 | 题型硬编码 | JSON 配置 + 云端下发,新增题型无需发版 | P0 | +| 模板引擎 | 各题型独立 Draw Service | 抽象通用模板引擎,减少重复代码 | P1 | +| 云端渲染 | 本地 Canvas 导出 PNG | 云函数生成 PDF,支持多页/高清 | P2 | +| 素材管理 | 素材随代码打包 | CDN + 按需下载,减少包体积 | P1 | +| 数据埋点 | 基础 tracker | 完善用户行为分析(使用频率、下载量、题型偏好) | P1 | + +### 7.2 分包优化 + +``` +当前分包结构: 建议优化后: +├── 主包 ├── 主包 +│ ├── mathIndex │ ├── home (发现首页) +│ ├── focusIndex │ ├── category (分类页) +│ ├── index (识字) │ ├── profile (我的) +│ └── copyBook (练字) │ └── guide (打印指南) +├── mathPages ├── mathPages (数学相关) +└── focusPages ├── chinesPages (语文相关) + ├── englishPages (英语相关) + ├── puzzlePages (益智相关) + └── craftPages (创意手工) +``` + +### 7.3 数据模型扩展 + +```typescript +interface WorksheetType { + id: string; + page: string; + title: string; + desc: string; + + // 新增字段 + category: 'math' | 'chinese' | 'english' | 'puzzle' | 'craft'; + subcategory: string; + ageRange: [number, number]; // [minAge, maxAge] + difficulty: 1 | 2 | 3 | 4; // 入门/基础/进阶/挑战 + previewImage: string; // 真实效果预览图 + downloadCount: number; // 下载次数(可云端维护) + tags: string[]; // 搜索标签 + isNew: boolean; // 新上线标记 + sortOrder: number; // 排序权重 +} +``` + +--- + +## 八、实施路线图 + +``` +Phase 1(第 1-2 周) ← 夯实基础 +├── 修复技术问题(云函数/死链) +├── 增加年龄分级和难度标签 +├── 首页重设计(分类导航 + 搜索) +├── 新增打印指南页 +└── 效果预览图优化 + +Phase 2(第 3-4 周) ← 内容扩充 +├── 新增:控笔练习 +├── 新增:时钟练习 +├── 新增:拼音练习 +├── 新增:字母描红 +├── 新增:字母闪卡 +└── 新增:笔画练习 + +Phase 3(第 5-6 周) ← 趣味内容 +├── 新增:走迷宫 +├── 新增:涂色卡(引入线稿素材) +├── 新增:折纸模板 +├── 新增:找不同 +├── 新增:控笔练习升级版 +└── 新增:记忆力翻翻卡 + +Phase 4(第 7-8 周) ← 体验升级 +├── 用户体系(登录/收藏/历史) +├── PDF 导出功能 +├── 批量生成 +├── 每日打印计划 +└── 数据统计与学习报告 + +Phase 5(持续迭代) ← 生态建设 +├── 更多主题手工内容 +├── 节日/季节限定内容 +├── 社区分享 +├── 内容创作者入驻 +└── 会员体系(免费内容 + 高级内容) +``` + +--- + +## 九、商业化思路 + +| 模式 | 说明 | +|------|------| +| **免费 + 广告** | 基础内容免费,展示原生广告(现有模式) | +| **会员订阅** | 月/年会员,解锁高级内容、去广告、批量导出 PDF | +| **内容付费** | 特定高级内容包(如「幼升小全套」「暑假特训」)单独购买 | +| **打印服务** | 接入云打印平台,用户一键下单,直接邮寄打印成品 | + +--- + +## 十、关键指标(KPI) + +| 指标 | 当前预估 | Phase 2 目标 | 长期目标 | +|------|---------|-------------|---------| +| 内容品类 | 4 类 | 8 类 | 15+ 类 | +| 可打印题型 | 41 种 | 60+ 种 | 150+ 种 | +| 日均使用 UV | - | 500 | 5,000 | +| 人均停留时长 | - | 3 min | 8 min | +| 日均下载量 | - | 1,000 张 | 10,000 张 | +| 用户次日留存 | - | 25% | 40% | +| 分享率 | - | 10% | 20% | + +--- + +## 附录 A:竞品功能对照表 + +| 功能 | kiddoworksheets | Doodle Mini 现有 | Doodle Mini v2.0 规划 | +|------|----------------|-----------------|---------------------| +| 字母描红 | ✅ | ❌ | ✅ P1 | +| 草书练习 | ✅ | ❌ | ❌(非目标用户需求) | +| 缺失字母 | ✅ | ❌ | ✅ P1(字母找一找) | +| 数字描红 | ✅ | ✅ 看数字写一写 | ✅ | +| 缺失数字 | ✅ | ✅ 填上缺少的数字 | ✅ | +| 闪卡 | ✅ | ❌ | ✅ P1 | +| 形状练习 | ✅ | ✅ 识别形状 | ✅ | +| 规律练习 | ✅ | ✅ 颜色找规律 | ✅ 扩展数字/图形规律 | +| 涂色页 | ✅ | ❌ | ✅ P2 | +| 画画教程 | ✅ | ❌ | ❌(优先级低) | +| 点连线 | ✅ | ✅ 数字点连线 | ✅ 扩展字母连线 | +| 加法 | ✅ | ✅ 多种加法题型 | ✅ | +| 减法 | ✅ | ✅ 多种减法题型 | ✅ | +| 乘法 | ✅ | ✅ 九九乘法表 | ✅ | +| 计数 | ✅ | ✅ 多种计数题型 | ✅ | +| 英语练习 | ✅ | ❌ | ✅ P1 | +| 高频词 | ✅ | ❌ | ✅ P2 | +| 词汇拼写 | ✅ | ❌ | ✅ P2 | +| 字谜 | ✅ | ❌ | ✅ P3 | +| 填字游戏 | ✅ | ❌ | ✅ P3 | +| 常识问答 | ✅ | ❌ | ❌(优先级低) | +| 描线练习 | ✅ | ✅ 线条识别 | ✅ 控笔练习 | +| 配对连线 | ✅ | ✅ 连连看/连线 | ✅ | +| 找相同 | ✅ | ❌ | ✅ P2 | +| 人体部位 | ✅ | ❌ | ❌(优先级低) | +| 时钟 | ✅ | ❌ | ✅ P1 | +| 贴纸 | ✅ | ❌ | ✅ P3 | +| 滑动拼图 | ✅(在线游戏) | ❌ | ❌(非打印类) | +| 找不同 | ✅ | ❌ | ✅ P2 | +| 折纸 | ✅ | ❌ | ✅ P2 | +| 迷宫 | ✅ | ❌ | ✅ P2 | diff --git a/docs/技术架构设计文档.md b/docs/技术架构设计文档.md new file mode 100644 index 0000000..9814d2a --- /dev/null +++ b/docs/技术架构设计文档.md @@ -0,0 +1,928 @@ +# Doodle Mini - 技术架构设计文档 + +> 版本:v2.0 +> 最后更新:2026-03-24 +> 配套文档:[现有功能清单](./现有功能清单.md) | [产品设计文档](./产品设计文档.md) + +--- + +## 一、技术决策总览 + +### 1.1 核心原则 + +| 原则 | 说明 | +|------|------| +| **成本优先** | 优先使用微信云开发,避免自建服务器的运维和费用 | +| **渐进增强** | 先小程序跑通,后续再扩展 PC Web,不为未来过度设计 | +| **前端为主** | Canvas 渲染、随机生成等核心逻辑保持前端执行,后端仅做必要的数据存储和服务 | +| **可迁移** | 核心绘制逻辑与平台 API 解耦,为将来迁移 Web 做准备 | + +### 1.2 后端方案决策 + +#### 需要后端的场景 vs 不需要的场景 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 不需要后端(前端完成) │ +├─────────────────────────────────────────────────────────┤ +│ ✅ Canvas 绘制所有题型 │ +│ ✅ 随机题目生成算法 │ +│ ✅ A4 排版与打印预览 │ +│ ✅ PNG 导出 → 保存相册 │ +│ ✅ 题型配置数据(可前端内置 JSON) │ +│ ✅ 分享功能 │ +│ ✅ 本地收藏/历史(wx.Storage) │ +└─────────────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────────────┐ +│ 需要后端(轻量级) │ +├─────────────────────────────────────────────────────────┤ +│ 📦 内容配置远程下发(热更新题型/分类,无需发版) │ +│ 📦 静态素材存储与 CDN 分发(涂色卡线稿、折纸模板等) │ +│ 📦 用户数据同步(收藏、历史记录跨设备) │ +│ 📦 下载统计 / 热度排名 │ +│ 📦 PDF 多页合并导出 │ +│ 📦 未来 PC Web 端的 API 服务 │ +└─────────────────────────────────────────────────────────┘ +``` + +#### 方案对比与选择 + +| 维度 | 微信云开发 | 自建云服务器 | 决策 | +|------|-----------|-------------|------| +| 接入成本 | ⭐ 极低(已有基础) | ⭐⭐⭐ 需搭建部署 | 云开发 ✅ | +| 运维成本 | ⭐ 免运维 | ⭐⭐⭐ 需监控/维护 | 云开发 ✅ | +| 费用 | 免费额度足够早期(数据库 2GB/存储 5GB/云函数 10万次/月) | 最低约 ¥50-100/月 | 云开发 ✅ | +| 小程序集成 | ⭐ 原生集成,鉴权零成本 | ⭐⭐ 需对接登录/鉴权 | 云开发 ✅ | +| PC Web 支持 | ⭐⭐ 需通过 HTTP API 桥接 | ⭐ 天然支持 | 自建 ✅ | +| 灵活性 | ⭐⭐ 受限于云开发 SDK | ⭐ 完全自由 | 自建 ✅ | +| 数据迁移 | ⭐⭐ 可导出但不方便 | ⭐ 标准数据库 | 自建 ✅ | + +**最终决策:近期使用微信云开发,远期按需引入轻量后端** + +``` +Phase 1-3(当前~8周):100% 微信云开发 + └── 云数据库 + 云存储 + 云函数,零服务器成本 + +Phase 4+(需要 PC Web 时):引入轻量后端 + └── 方案 A(推荐):云开发 HTTP API + PC Web 直接调用 + └── 方案 B:Cloudflare Workers / Vercel Serverless 做 API 代理层 + └── 方案 C:轻量 Node.js 服务(仅在流量大时考虑) +``` + +--- + +## 二、系统架构总图 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ 用户端 │ +│ │ +│ ┌──────────────────────┐ ┌──────────────────────┐ │ +│ │ 微信小程序 (当前) │ │ PC Web (未来) │ │ +│ │ │ │ │ │ +│ │ ┌────────────────┐ │ │ ┌────────────────┐ │ │ +│ │ │ UI 层 (WXML) │ │ │ │ UI 层 (React) │ │ │ +│ │ │ Skyline 渲染 │ │ │ │ Tailwind CSS │ │ │ +│ │ └───────┬────────┘ │ │ └───────┬────────┘ │ │ +│ │ │ │ │ │ │ │ +│ │ ┌───────▼────────┐ │ │ ┌───────▼────────┐ │ │ +│ │ │ 业务逻辑层 (TS) │ │ │ │ 业务逻辑层 (TS) │ │ │ +│ │ │ Page + Mixin │ │ │ │ Hooks + Store │ │ │ +│ │ └───────┬────────┘ │ │ └───────┬────────┘ │ │ +│ │ │ │ │ │ │ │ +│ │ ┌───────▼────────┐ │ │ ┌───────▼────────┐ │ │ +│ │ │ 共享核心层 │◄─┼─────────┼──► 共享核心层 │ │ │ +│ │ │ @doodle/core │ │ │ │ @doodle/core │ │ │ +│ │ │ ┌─────────────┐ │ │ │ │ (同一套代码) │ │ │ +│ │ │ │ DrawService │ │ │ │ └───────┬────────┘ │ │ +│ │ │ │ DataModels │ │ │ │ │ │ │ +│ │ │ │ Generators │ │ │ │ │ │ │ +│ │ │ │ Utils │ │ │ │ │ │ │ +│ │ │ └─────────────┘ │ │ │ │ │ │ +│ │ └───────┬────────┘ │ │ │ │ │ +│ │ │ │ │ │ │ │ +│ │ ┌───────▼────────┐ │ │ ┌───────▼────────┐ │ │ +│ │ │ 平台适配层 │ │ │ │ 平台适配层 │ │ │ +│ │ │ wx.* API │ │ │ │ Web API │ │ │ +│ │ │ wx.cloud.* │ │ │ │ HTTP Client │ │ │ +│ │ │ Canvas 2D │ │ │ │ Canvas 2D │ │ │ +│ │ └───────┬────────┘ │ │ └───────┬────────┘ │ │ +│ └──────────┼──────────┘ └──────────┼──────────┘ │ +└──────────────┼───────────────────────────────┼──────────────────┘ + │ │ + ▼ ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ 后端服务层 │ +│ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ 微信云开发 (Phase 1-3) │ │ +│ │ │ │ +│ │ ┌─────────────┐ ┌──────────┐ ┌────────────┐ │ │ +│ │ │ 云数据库 │ │ 云存储 │ │ 云函数 │ │ │ +│ │ │ (MongoDB) │ │ (COS) │ │ (Node.js) │ │ │ +│ │ │ │ │ │ │ │ │ │ +│ │ │ • 用户数据 │ │ • 涂色卡 │ │ • getOpenId│ │ │ +│ │ │ • 收藏记录 │ │ • 折纸图 │ │ • genPDF │ │ │ +│ │ │ • 下载统计 │ │ • 手工图 │ │ • syncData │ │ │ +│ │ │ • 内容配置 │ │ • 预览图 │ │ • stats │ │ │ +│ │ │ • 反馈数据 │ │ • 字体 │ │ │ │ │ +│ │ └─────────────┘ └──────────┘ └────────────┘ │ │ +│ └─────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ 轻量 API 层 (Phase 4+, 仅 PC Web) │ │ +│ │ │ │ +│ │ 方案 A: 云开发 HTTP API (推荐,零额外成本) │ │ +│ │ 方案 B: Cloudflare Workers (极低成本) │ │ +│ │ 方案 C: Vercel Serverless Functions │ │ +│ └─────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ CDN (腾讯云) │ │ +│ │ 素材图片 / 字体文件 / 预览图 / 分享图 │ │ +│ └─────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 三、前端架构详细设计 + +### 3.1 现有架构问题 + +``` +当前代码组织: +miniprogram/ +├── pages/ ← 主包页面,各自直接引用 mixin +├── mathPages/ ← 数学分包,每个页面有自己的 Draw 服务 +│ └── shared/ ← 数学共用(service、templates、assets) +├── focusPages/ ← 专注力分包,结构同上 +│ └── shared/ +├── service/ ← 识字/练字的 Draw 服务 +├── base/ ← pageMixin、callCloud 等基础层 +├── components/ ← UI 组件 +├── constants/ ← 静态配置数据 +└── utils/ ← 工具函数 +``` + +**问题分析:** + +| 问题 | 详情 | +|------|------| +| Mixin 模式笨重 | `pageMixin` 通过对象展开合并,无类型安全,难以追踪数据流 | +| Draw 服务分散 | 每个分包下各有 `shared/service/`,大量重复的绘制工具方法 | +| 平台耦合严重 | Draw 服务直接使用 `wx.createImage`、`canvas.createImage` 等 API | +| 模板重复 | `mathPages` 和 `focusPages` 的 `canvas-page-template.wxml` 内容相同 | +| 无共享核心 | 数据模型、生成算法与 UI 逻辑混在一起,无法跨平台复用 | +| 状态管理原始 | 纯 `setData`,无统一的状态管理方案 | + +### 3.2 目标架构 + +``` +miniprogram/ +├── core/ ← 🆕 共享核心层(平台无关) +│ ├── models/ ← 数据模型定义 +│ │ ├── worksheet.ts ← WorksheetType 统一模型 +│ │ ├── category.ts ← 分类模型 +│ │ ├── user.ts ← 用户数据模型 +│ │ └── print-config.ts ← 打印配置模型 +│ ├── generators/ ← 题目生成算法(纯逻辑) +│ │ ├── math/ ← 数学题目生成器 +│ │ │ ├── addition.ts +│ │ │ ├── subtraction.ts +│ │ │ ├── number-sequence.ts +│ │ │ └── ... +│ │ ├── focus/ ← 专注力题目生成器 +│ │ ├── chinese/ ← 语文题目生成器 +│ │ └── english/ ← 英语题目生成器 +│ ├── draw/ ← 绘制服务(Canvas 2D API,平台无关) +│ │ ├── base-draw.ts ← 基础绘制(纸面、页眉、网格等) +│ │ ├── math-draw/ ← 数学绘制服务 +│ │ ├── focus-draw/ ← 专注力绘制服务 +│ │ ├── chinese-draw/ ← 语文绘制服务 +│ │ ├── english-draw/ ← 英语绘制服务 +│ │ └── craft-draw/ ← 手工/涂色绘制服务 +│ ├── data/ ← 内容配置数据 +│ │ ├── worksheets.ts ← 所有题型定义(本地兜底) +│ │ ├── categories.ts ← 分类定义 +│ │ ├── words.ts ← 词库 +│ │ └── difficulty.ts ← 难度与年龄映射 +│ └── utils/ ← 纯工具函数(无平台依赖) +│ ├── random.ts +│ ├── math-utils.ts +│ └── format.ts +│ +├── platform/ ← 🆕 平台适配层 +│ ├── canvas-adapter.ts ← Canvas API 适配(wx ↔ Web) +│ ├── storage-adapter.ts ← 存储适配(wxStorage ↔ localStorage) +│ ├── cloud-adapter.ts ← 云服务适配(wx.cloud ↔ HTTP) +│ ├── image-adapter.ts ← 图片加载适配 +│ └── share-adapter.ts ← 分享能力适配 +│ +├── services/ ← 🆕 业务服务层 +│ ├── worksheet-service.ts ← 题型数据加载(本地 + 远程兜底) +│ ├── user-service.ts ← 用户数据管理 +│ ├── favorite-service.ts ← 收藏管理 +│ ├── history-service.ts ← 下载历史管理 +│ ├── print-service.ts ← 打印/导出统一入口 +│ ├── stats-service.ts ← 统计上报 +│ └── ad-service.ts ← 广告管理 +│ +├── store/ ← 🆕 状态管理 +│ ├── app-store.ts ← 全局状态(用户/配置/主题) +│ └── page-store.ts ← 页面级状态工具 +│ +├── pages/ ← 重构后的主包页面 +│ ├── home/ ← 发现首页(合并原 4 个 Tab 入口) +│ ├── category/ ← 分类详情页 +│ ├── worksheet/ ← 统一的题型生成/预览页 +│ ├── profile/ ← 我的 +│ ├── guide/ ← 打印指南 +│ ├── favorites/ ← 收藏列表 +│ ├── history/ ← 下载历史 +│ └── settings/ ← 设置 +│ +├── subpackages/ ← 🆕 按品类分包 +│ ├── math/ ← 数学题型页面 +│ ├── chinese/ ← 语文题型页面 +│ ├── english/ ← 英语题型页面 +│ ├── puzzle/ ← 益智游戏页面 +│ └── craft/ ← 创意手工页面 +│ +├── components/ ← UI 组件 +│ ├── shared/ ← 通用组件 +│ │ ├── worksheet-card/ ← 题型卡片(带预览图) +│ │ ├── category-tabs/ ← 分类标签栏 +│ │ ├── age-filter/ ← 年龄筛选器 +│ │ ├── difficulty-badge/ ← 难度标签 +│ │ ├── canvas-preview/ ← Canvas 预览区 +│ │ ├── action-bar/ ← 底部操作栏(保存/分享/换一批) +│ │ ├── print-header/ ← 打印页眉配置 +│ │ └── empty-state/ ← 空状态 +│ └── business/ ← 业务组件 +│ ├── worksheet-list/ ← 题型列表 +│ ├── param-panel/ ← 参数设置面板 +│ └── ... +│ +├── config/ ← 配置 +├── assets/ ← 静态资源 +└── style/ ← 全局样式 +``` + +### 3.3 分层职责 + +``` +┌──────────────────────────────────────────────────────┐ +│ UI 层 │ +│ pages/ + components/ (WXML + WXSS + 页面 TS) │ +│ 职责:界面渲染、用户交互、调用 services │ +├──────────────────────────────────────────────────────┤ +│ 业务服务层 │ +│ services/ + store/ │ +│ 职责:组合 core 能力,管理状态,对接平台 API │ +├──────────────────────────────────────────────────────┤ +│ 平台适配层 │ +│ platform/ │ +│ 职责:抹平 wx.* 和 Web API 差异 │ +├──────────────────────────────────────────────────────┤ +│ 共享核心层 │ +│ core/ (纯 TypeScript,零平台依赖) │ +│ 职责:绘制服务、生成算法、数据模型 │ +│ 🔑 可直接在 Web 项目中 import 使用 │ +└──────────────────────────────────────────────────────┘ +``` + +--- + +## 四、共享核心层设计(@doodle/core) + +这是未来跨平台复用的关键。所有与 `wx.*` 无关的逻辑都应该放在这一层。 + +### 4.1 Canvas 适配器接口 + +```typescript +/** + * 平台无关的 Canvas 上下文接口 + * 微信小程序和 Web 的 Canvas 2D API 基本一致, + * 但图片加载、字体加载等需要适配 + */ +interface ICanvasAdapter { + getContext(): CanvasRenderingContext2D; + setSize(width: number, height: number): void; + loadImage(src: string): Promise; + toDataURL(type?: string, quality?: number): Promise; + toBlob(): Promise; // Web 专用 + toTempFilePath(): Promise; // 小程序专用 +} +``` + +### 4.2 绘制服务基类(平台无关) + +```typescript +abstract class BaseDrawService { + protected ctx: CanvasRenderingContext2D; + protected paperWidth: number; + protected paperHeight: number; + + // 这些方法仅使用标准 Canvas 2D API,不依赖任何平台 + protected drawGrid(rows: number, cols: number): void { /* ... */ } + protected drawText(text: string, x: number, y: number, options: TextOptions): void { /* ... */ } + protected drawLine(x1: number, y1: number, x2: number, y2: number): void { /* ... */ } + protected drawHeader(config: PrintConfig): void { /* ... */ } + protected drawRoundedRect(x: number, y: number, w: number, h: number, r: number): void { /* ... */ } + + abstract draw(params: DrawParams): Promise; +} +``` + +### 4.3 题目生成器模式 + +```typescript +/** + * 所有题目生成器实现此接口 + * 输入配置参数,输出与平台无关的题目数据 + * 绘制服务消费这些数据来渲染 Canvas + */ +interface IWorksheetGenerator { + generate(config: TConfig): TData; + getDefaultConfig(): TConfig; +} + +// 示例:加法题生成器 +class AdditionGenerator implements IWorksheetGenerator { + generate(config: AdditionConfig): AdditionData { + const questions = []; + for (let i = 0; i < config.count; i++) { + const a = randomInt(0, config.maxNumber); + const b = randomInt(0, config.maxNumber - a); + questions.push({ a, b, answer: a + b }); + } + return { questions, config }; + } +} +``` + +--- + +## 五、后端(云开发)详细设计 + +### 5.1 云数据库集合设计 + +``` +云数据库 Collections: +┌─────────────────────────────────────────────────┐ +│ │ +│ worksheets (题型配置表) │ +│ ┌─────────────────────────────────────┐ │ +│ │ _id: string │ │ +│ │ category: string │ │ +│ │ subcategory: string │ │ +│ │ title: string │ │ +│ │ desc: string │ │ +│ │ ageRange: [number, number] │ │ +│ │ difficulty: 1|2|3|4 │ │ +│ │ previewImage: string │ │ +│ │ page: string │ │ +│ │ tags: string[] │ │ +│ │ isNew: boolean │ │ +│ │ isHot: boolean │ │ +│ │ sortOrder: number │ │ +│ │ downloadCount: number │ │ +│ │ status: 'active'|'draft'|'hidden' │ │ +│ │ createdAt: Date │ │ +│ │ updatedAt: Date │ │ +│ └─────────────────────────────────────┘ │ +│ │ +│ categories (分类表) │ +│ ┌─────────────────────────────────────┐ │ +│ │ _id: string │ │ +│ │ name: string │ │ +│ │ icon: string │ │ +│ │ color: string │ │ +│ │ sortOrder: number │ │ +│ │ parentId: string | null │ │ +│ └─────────────────────────────────────┘ │ +│ │ +│ users (用户表) │ +│ ┌─────────────────────────────────────┐ │ +│ │ _id: string (openid) │ │ +│ │ uuid: string │ │ +│ │ nickName: string │ │ +│ │ avatarUrl: string │ │ +│ │ totalDownloads: number │ │ +│ │ createdAt: Date │ │ +│ │ lastActiveAt: Date │ │ +│ └─────────────────────────────────────┘ │ +│ │ +│ favorites (收藏表) │ +│ ┌─────────────────────────────────────┐ │ +│ │ _id: string │ │ +│ │ _openid: string │ │ +│ │ worksheetId: string │ │ +│ │ createdAt: Date │ │ +│ └─────────────────────────────────────┘ │ +│ │ +│ download_logs (下载日志表) │ +│ ┌─────────────────────────────────────┐ │ +│ │ _id: string │ │ +│ │ _openid: string │ │ +│ │ worksheetId: string │ │ +│ │ params: object (生成参数快照) │ │ +│ │ createdAt: Date │ │ +│ └─────────────────────────────────────┘ │ +│ │ +│ feedback (用户反馈表) │ +│ ┌─────────────────────────────────────┐ │ +│ │ _id: string │ │ +│ │ _openid: string │ │ +│ │ content: string │ │ +│ │ contact: string │ │ +│ │ createdAt: Date │ │ +│ └─────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────┘ +``` + +### 5.2 云函数设计 + +``` +cloudfunctions/ +└── doodle/ + ├── index.js ← 统一入口(action 路由) + ├── package.json + ├── src/ + │ ├── user/ + │ │ ├── getOpenId.js ← ✅ 已有,保留 + │ │ └── updateProfile.js ← 🆕 更新用户信息 + │ ├── worksheet/ + │ │ ├── getList.js ← 🆕 获取题型列表(支持分类/筛选) + │ │ ├── getDetail.js ← 🆕 获取题型详情 + │ │ └── incrementDownload.js← 🆕 下载计数+1 + │ ├── favorite/ + │ │ ├── add.js ← 🆕 添加收藏 + │ │ ├── remove.js ← 🆕 取消收藏 + │ │ └── list.js ← 🆕 我的收藏列表 + │ ├── history/ + │ │ └── list.js ← 🆕 下载历史 + │ ├── feedback/ + │ │ └── submit.js ← 🆕 提交反馈 + │ └── pdf/ + │ └── generate.js ← 🆕 PDF 生成(Phase 4) + └── common/ + ├── responseMiddleware.js ← ✅ 已有,保留 + └── auth.js ← 🆕 鉴权中间件 +``` + +### 5.3 云函数调用策略 + +``` +┌────────────────────────────────────────────────────────────┐ +│ 数据加载策略 │ +│ │ +│ 题型配置数据 (worksheets/categories) │ +│ ┌────────────────────────────────────────┐ │ +│ │ 优先级 1: 本地缓存(wx.Storage) │ │ +│ │ 优先级 2: 云数据库查询 │ │ +│ │ 优先级 3: 前端内置兜底数据 │ ← 保证离线可用 │ +│ └────────────────────────────────────────┘ │ +│ │ +│ 缓存策略: │ +│ • 首次启动:云端拉取 → 写入本地缓存 │ +│ • 后续启动:先用缓存渲染 → 后台静默更新 │ +│ • 缓存有效期:24 小时 │ +│ • 无网络:使用本地缓存或内置兜底 │ +│ │ +│ 用户数据 (favorites/history) │ +│ ┌────────────────────────────────────────┐ │ +│ │ 本地优先写入 → 后台同步云端 │ │ +│ │ 冲突策略:以云端为准(云端时间戳更新) │ │ +│ └────────────────────────────────────────┘ │ +│ │ +│ 统计数据 (download count) │ +│ ┌────────────────────────────────────────┐ │ +│ │ 批量上报:本地累计 → 退出时/定时上报 │ │ +│ │ 非关键路径,允许丢失 │ │ +│ └────────────────────────────────────────┘ │ +└────────────────────────────────────────────────────────────┘ +``` + +### 5.4 云存储规划 + +``` +云存储目录结构: +cloud://doodle-xxx.xxxx/ +├── assets/ +│ ├── previews/ ← 题型效果预览图 +│ │ ├── math/ +│ │ ├── chinese/ +│ │ ├── english/ +│ │ ├── puzzle/ +│ │ └── craft/ +│ ├── coloring/ ← 涂色卡线稿(SVG/PNG) +│ │ ├── animals/ +│ │ ├── vehicles/ +│ │ ├── holidays/ +│ │ └── ... +│ ├── origami/ ← 折纸展开图 +│ ├── stickers/ ← 贴纸素材 +│ ├── maze-templates/ ← 迷宫模板数据(JSON) +│ └── craft-templates/ ← 手工模板 +├── fonts/ ← 字体文件 +│ ├── SimHei.ttf +│ └── handwriting.ttf +└── share/ ← 分享图 + └── default-share.png +``` + +--- + +## 六、关键技术方案 + +### 6.1 Canvas 渲染架构(改进) + +**现有问题**:预览区尺寸初始化和 A4 导出尺寸是两阶段,`setPaper()` 会重设 Canvas 尺寸。 + +**改进方案**: + +``` +┌─────────────────────────────────────────────────────┐ +│ Canvas 渲染管线 │ +│ │ +│ ① 逻辑坐标系统(所有 Draw 服务统一使用) │ +│ 固定使用 A4 逻辑坐标: 595 × 842 │ +│ 所有绘制操作都在这个坐标系下 │ +│ │ +│ ② 预览渲染 │ +│ Canvas 物理尺寸 = 容器宽度 × dpr │ +│ ctx.scale(容器宽度/595 × dpr, ...) │ +│ → 绘制服务使用 A4 坐标 → 自动缩放到预览区 │ +│ │ +│ ③ 导出渲染 │ +│ Canvas 物理尺寸 = 1240 × 1754 (150DPI A4) │ +│ ctx.scale(1240/595, 1754/842) │ +│ → 同一套绘制代码 → 导出高清图 │ +│ │ +│ 好处: │ +│ • Draw 服务完全不感知预览/导出差异 │ +│ • 同一套代码在小程序和 Web 上直接可用 │ +│ • 预览和导出结果 100% 一致 │ +└─────────────────────────────────────────────────────┘ +``` + +### 6.2 图片加载适配 + +```typescript +// platform/image-adapter.ts + +// 小程序实现 +class WxImageAdapter implements IImageAdapter { + async loadImage(canvas: WechatMiniprogram.Canvas, src: string) { + const img = canvas.createImage(); + return new Promise((resolve, reject) => { + img.onload = () => resolve(img); + img.onerror = reject; + img.src = src; + }); + } +} + +// Web 实现(未来) +class WebImageAdapter implements IImageAdapter { + async loadImage(_canvas: HTMLCanvasElement, src: string) { + const img = new Image(); + img.crossOrigin = 'anonymous'; + return new Promise((resolve, reject) => { + img.onload = () => resolve(img); + img.onerror = reject; + img.src = src; + }); + } +} +``` + +### 6.3 PDF 导出方案(Phase 4) + +``` +方案对比: + +A. 云函数生成 PDF(推荐) + 云函数接收绘制参数 JSON → 服务端用 pdfkit 生成 → 上传云存储 → 返回下载链接 + 优点:不受客户端限制,可生成多页 + 缺点:云函数有执行时间限制(60s),复杂图形渲染较慢 + +B. 客户端多页 Canvas 拼接 + 前端生成多张 PNG → 云函数用 pdfkit 合并为 PDF + 优点:渲染在客户端,云函数只做拼接 + 缺点:需上传多张图片到云存储,流量开销大 + +C. Web 端直接使用 jsPDF + 仅适用于 PC Web 版本 + 优点:零服务器成本 + 缺点:小程序不可用 + +推荐路径: + 小程序:方案 B(客户端渲染 + 云端拼接) + PC Web:方案 C(jsPDF 纯前端) +``` + +### 6.4 涂色卡/迷宫等素材型内容方案 + +``` +┌──────────────────────────────────────────────────────┐ +│ 两类内容的技术方案差异 │ +│ │ +│ 类型 A:算法生成型(现有主力) │ +│ ┌──────────────────────────────────────┐ │ +│ │ 前端算法随机生成题目数据 │ │ +│ │ → DrawService 渲染到 Canvas │ │ +│ │ → 导出图片 │ │ +│ │ │ │ +│ │ 适用:数学题、专注力题、字母练习等 │ │ +│ │ 优点:无限变化、零存储成本 │ │ +│ │ 开发方式:写 Generator + DrawService │ │ +│ └──────────────────────────────────────┘ │ +│ │ +│ 类型 B:素材模板型(需扩展) │ +│ ┌──────────────────────────────────────┐ │ +│ │ 设计师制作 SVG/PNG 线稿 │ │ +│ │ → 上传到云存储 │ │ +│ │ → 前端加载 + Canvas 排版到 A4 │ │ +│ │ → 导出图片 │ │ +│ │ │ │ +│ │ 适用:涂色卡、折纸、手工、贴纸等 │ │ +│ │ 优点:品质高、风格可控 │ │ +│ │ 开发方式:素材管理 + 通用排版渲染器 │ │ +│ └──────────────────────────────────────┘ │ +│ │ +│ 类型 C:混合型 │ +│ ┌──────────────────────────────────────┐ │ +│ │ 算法生成结构 + 素材填充 │ │ +│ │ │ │ +│ │ 适用:迷宫(算法生路径+主题皮肤) │ │ +│ │ 找不同(模板+随机差异点) │ │ +│ │ 闪卡(模板+词库数据) │ │ +│ └──────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────┘ +``` + +--- + +## 七、PC Web 端技术预案 + +### 7.1 时机判断 + +**当前不急于开发 PC Web 的原因:** +- 小程序用户群与目标用户(家长)高度重合,微信即触达 +- PC Web 需要额外解决支付、登录、SEO 等问题 +- 先把小程序做好,积累内容和用户 + +**何时启动 PC Web:** +- 小程序 DAU 稳定 > 1000 +- 用户反馈中"想在电脑上用"的需求频繁出现 +- 内容积累到 100+ 种题型 + +### 7.2 技术选型预案 + +``` +PC Web 技术栈(未来): +┌────────────────────────────────────┐ +│ 框架:Next.js (App Router) │ +│ UI:Tailwind CSS + Radix UI │ +│ Canvas:HTML5 Canvas 2D │ +│ PDF:jsPDF + html2canvas │ +│ 状态:Zustand │ +│ 部署:Vercel │ +│ │ +│ 核心复用: │ +│ @doodle/core (共享核心层) │ +│ └── 绘制服务、生成器、数据模型 │ +│ → 直接 import 使用 │ +│ │ +│ 需新建: │ +│ • Web UI 组件 │ +│ • 平台适配层 (Web 实现) │ +│ • 用户登录(微信扫码/手机号) │ +│ • SEO 优化(SSR/SSG 题型页) │ +└────────────────────────────────────┘ +``` + +### 7.3 代码共享策略 + +``` +仓库结构(Monorepo,未来演进): +doodle/ +├── packages/ +│ └── core/ ← 共享核心(npm 包) +│ ├── src/ +│ │ ├── draw/ +│ │ ├── generators/ +│ │ ├── models/ +│ │ └── utils/ +│ ├── package.json +│ └── tsconfig.json +├── apps/ +│ ├── mini/ ← 微信小程序 +│ │ ├── miniprogram/ +│ │ ├── cloudfunctions/ +│ │ └── project.config.json +│ └── web/ ← PC Web(未来) +│ ├── src/ +│ ├── package.json +│ └── next.config.js +├── pnpm-workspace.yaml +└── package.json + +当前阶段不需要 Monorepo,只需在小程序项目中: +1. 将 core/ 作为目录组织代码 +2. 确保 core/ 内不 import 任何 wx.* API +3. 未来迁移时,将 core/ 提取为独立 npm 包即可 +``` + +--- + +## 八、前端重构路线图 + +### Phase 1:基础重构(第 1-2 周) + +``` +优先级:🔴 关键 + +目标:不改变现有功能,优化代码结构 + +1. 修复技术债务 + ├── 统一云函数名称(callCloud 中 robotaxi → doodle) + ├── 清理 cloudfunctions/doodle/index.js 中无效的模块引用 + ├── 移除 debug 页中指向不存在页面的死链 + └── 清理未使用的代码和资源 + +2. 建立 core/ 目录 + ├── 将 constants/ 迁移到 core/data/ + ├── 将纯工具函数迁移到 core/utils/ + ├── 将 DrawService 基类提取到 core/draw/ + └── 定义统一的 WorksheetType 数据模型 + +3. 建立 platform/ 目录 + ├── 抽取 canvas-adapter(封装 wx Canvas API) + ├── 抽取 storage-adapter(封装 wx.Storage) + └── 抽取 image-adapter(封装图片加载) + +4. 统一 WXML 模板 + └── 合并 mathPages 和 focusPages 的重复 canvas-page-template +``` + +### Phase 2:首页重构 + 内容配置化(第 3-4 周) + +``` +优先级:🟡 重要 + +1. 数据模型升级 + ├── WorksheetType 增加 category/ageRange/difficulty/tags 等字段 + ├── 定义 Category 模型 + └── 重构 MATH_FUNCTION_TYPES / FOCUS_FUNCTION_TYPES 为统一格式 + +2. 首页重构 + ├── 新建 pages/home/ 替代原四个 Tab 入口页 + ├── 实现分类标签栏 + 搜索 + 推荐区 + ├── 实现年龄筛选、难度筛选 + └── 使用新的 worksheet-card 组件(带预览图) + +3. TabBar 重构 + └── 发现 | 分龄 | 收藏 | 我的 + +4. 云数据库初始化 + ├── 建表:worksheets、categories + ├── 编写数据初始化脚本 + └── 实现前端数据加载(缓存优先 + 云端更新) +``` + +### Phase 3:新内容接入(第 5-6 周) + +``` +优先级:🟡 重要 + +1. 开发通用素材渲染器 + └── 通用的「加载图片 + A4 排版 + 导出」流程 + +2. 新增题型开发 + ├── 数学:时钟练习、形状分类 + ├── 语文:拼音练习、笔画练习 + ├── 英语:字母描红(复用 numberFind 逻辑) + ├── 益智:控笔练习 + └── 创意:涂色卡(素材型) + +3. 完善新分包 + ├── english/ 分包 + ├── puzzle/ 分包 + └── craft/ 分包 +``` + +### Phase 4:体验与功能升级(第 7-8 周) + +``` +优先级:🟢 增强 + +1. 用户体系 + ├── 微信登录 + ├── 收藏功能(本地 + 云端同步) + └── 下载历史 + +2. 打印体验 + ├── 打印指南页面 + ├── 批量生成(多题一页/多页) + └── PDF 导出(云函数) + +3. 运营能力 + ├── 数据埋点完善 + ├── 下载统计展示(热门排行) + └── 用户反馈入口 +``` + +--- + +## 九、成本预估 + +### 9.1 微信云开发费用 + +``` +免费额度(基础版 1): +┌────────────────────────────────────────┐ +│ 云数据库:2 GB 存储 / 50 万次读写/天 │ +│ 云存储:5 GB / 2 GB 下载/天 │ +│ 云函数:10 万次调用/月 / 1000 GBs/月 │ +│ CDN:5 GB/月 │ +└────────────────────────────────────────┘ + +预估用量(DAU 1000): +┌────────────────────────────────────────┐ +│ 云数据库:~100 MB(足够) │ +│ 云存储:~2 GB(素材渐增) │ +│ 云函数:~3 万次/月 │ +│ CDN:~3 GB/月 │ +│ │ +│ 结论:免费额度可覆盖到 DAU 3000 左右 │ +│ 超出后升级到 19.9 元/月即可 │ +└────────────────────────────────────────┘ +``` + +### 9.2 开发资源 + +``` +开发投入估算: +┌──────────────────────────────┐ +│ Phase 1: ~20 人时 │ +│ Phase 2: ~40 人时 │ +│ Phase 3: ~40 人时 │ +│ Phase 4: ~30 人时 │ +│ ────────────────────── │ +│ 总计: ~130 人时 │ +│ (1 人兼职 ~8 周可完成) │ +└──────────────────────────────┘ +``` + +--- + +## 十、技术风险与应对 + +| 风险 | 影响 | 应对方案 | +|------|------|---------| +| 云开发免费额度不够 | 功能受限 | ① 优化查询减少调用 ② 本地缓存减少读取 ③ 升级付费版(19.9元/月起) | +| Canvas 兼容性 | 低端机渲染异常 | ① 使用 Canvas 2D(已采用)② 控制单次绘制复杂度 ③ 降级方案 | +| 小程序包体积 | 超 2MB 限制 | ① 素材用 CDN / 云存储 ② 合理分包 ③ 图片压缩 | +| 素材制作瓶颈 | 涂色卡等需设计资源 | ① 使用开源 SVG 素材 ② AI 生成线稿 ③ 社区投稿 | +| 跨平台迁移成本 | Web 端重复开发 | ① core/ 层保持平台无关 ② 适配器模式隔离差异 | +| 云开发 HTTP API 限制 | PC Web 调用不便 | ① 使用云开发 HTTP API 触发器 ② 必要时引入轻量后端 | + +--- + +## 附录 A:现有代码与目标架构映射 + +| 现有文件 | 目标位置 | 迁移动作 | +|---------|---------|---------| +| `constants/mathFunctions.ts` | `core/data/worksheets.ts` | 合并,增加字段 | +| `constants/focusFunctions.ts` | `core/data/worksheets.ts` | 合并,增加字段 | +| `constants/words.ts` | `core/data/words.ts` | 移动 | +| `constants/colors.ts` | `core/data/colors.ts` | 移动 | +| `constants/shapes.ts` | `core/data/shapes.ts` | 移动 | +| `service/baseDraw.ts` | `core/draw/base-draw.ts` | 重构,去除 wx.* 依赖 | +| `service/wordDrawService.ts` | `core/draw/chinese-draw/word-draw.ts` | 移动,去除 wx.* | +| `service/drawServiceFactory.ts` | `core/draw/draw-factory.ts` | 扩展 | +| `mathPages/shared/service/*.ts` | `core/draw/math-draw/*.ts` | 移动,去除 wx.* | +| `focusPages/shared/service/*.ts` | `core/draw/focus-draw/*.ts` | 移动,去除 wx.* | +| `base/pageMixin.ts` | `services/print-service.ts` + 页面代码 | 拆分职责 | +| `base/callCloud.ts` | `platform/cloud-adapter.ts` | 重构 | +| `utils/saveImage.ts` | `platform/canvas-adapter.ts` | 合并到适配器 | +| `utils/downloadPrint.ts` | `services/print-service.ts` | 整合 | +| `utils/tracker.ts` | `services/stats-service.ts` | 整合 | +| `config/config.ts` | `core/models/print-config.ts` | 类型化 | + +## 附录 B:技术选型决策记录 + +| 决策点 | 选项 | 决策 | 理由 | +|--------|------|------|------| +| 跨端框架 | Taro / uni-app / 原生 | **原生** | 项目已用原生开发,迁移成本高;Taro 等框架对 Canvas 2D 支持有限;core/ 层抽取足以实现代码复用 | +| 状态管理 | MobX / 自定义 / 原生 setData | **轻量自定义** | 小程序场景简单,不需要 Redux 级方案;页面级 setData + 全局 Store 够用 | +| UI 组件库 | Vant / 自研 | **Vant + 自定义组件** | 已用 Vant,保持;业务组件自研 | +| 云开发 vs 自建 | 云开发 / 云服务器 | **云开发** | 零运维、免费额度充足、原生集成鉴权 | +| PDF 方案 | pdfkit(云) / jsPDF(端) | **两者结合** | 小程序用云端 pdfkit,Web 用 jsPDF | +| Monorepo | pnpm workspace / Turborepo | **暂不采用** | 当前只有小程序,过早引入增加复杂度;core/ 作为目录组织,未来再拆包 | diff --git a/docs/现有功能清单.md b/docs/现有功能清单.md new file mode 100644 index 0000000..c1a7ad5 --- /dev/null +++ b/docs/现有功能清单.md @@ -0,0 +1,220 @@ +# Doodle Mini 小程序 - 现有产品功能清单 + +> 定位:3-8 岁早教 A4 纸打印资料小程序 +> 最后更新:2026-03-24 + +--- + +## 一、产品概览 + +Doodle Mini 是一款面向 3-8 岁儿童的微信小程序,核心能力是通过 Canvas 动态生成可打印的 A4 教育资料(PNG 图片),涵盖数感启蒙、专注力培养、识字和练字四大模块。用户在小程序内选择题型、配置参数后,即可预览并保存到相册,打印后供孩子使用。 + +### 产品架构图 + +``` +┌──────────────────────────────────────────────┐ +│ 底部 TabBar │ +├───────────┬───────────┬──────────┬────────────┤ +│ 数感启蒙 │ 专注力培养 │ 识字 │ 练字 │ +│ mathIndex │focusIndex │ index │ copyBook │ +└─────┬─────┴─────┬─────┴────┬─────┴─────┬──────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ + 26种数学 13种专注力 涂色识字卡 笔顺练字贴 + 题型页面 题型页面 自定义生成 自定义生成 + (分包) (分包) (主包) (主包) +``` + +--- + +## 二、Tab 1:数感启蒙(26 种题型) + +入口页 `pages/mathIndex/mathIndex`,以卡片网格展示所有数学题型,点击进入对应 Canvas 生成页。 + +### 2.1 认识数字(基础阶段) + +| # | 功能 ID | 标题 | 描述 | 对应页面 | +|---|---------|------|------|----------| +| 1 | `number-find` | 找数字,涂一涂 | 在数字方阵中找出目标数字并涂色 | numberFind | +| 2 | `number-write` | 看数字,写一写 | 按笔画顺序练习书写数字 | numberFind | +| 3 | `number-coloring` | 按数字,涂颜色 | 按指定数字给对应圆圈涂色 | countMatch | + +### 2.2 数数与计数 + +| # | 功能 ID | 标题 | 描述 | 对应页面 | +|---|---------|------|------|----------| +| 4 | `counting-matching` | 数一数,连一连 | 连线配对数字和对应数量图形 | countMatch | +| 5 | `number-object-match` | 数物连线 | 连线相同数量的物品和数字 | numberObjectMatch | +| 6 | `number-object-fill` | 数物填写 | 数物品数量,填写对应数字 | numberObjectMatch | +| 7 | `counting-select` | 数一数,选一选 | 数出物品数量,圈出正确答案 | countingSelect | +| 8 | `counting-fill` | 数一数,填一填 | 数出物品数量,填写数字 | countingSelect | +| 9 | `compare` | 数一数,比大小 | 比较数量,填入 ><= | compare | + +### 2.3 数字序列 + +| # | 功能 ID | 标题 | 描述 | 对应页面 | +|---|---------|------|------|----------| +| 10 | `number-sort` | 数字排序 | 写出正确的数字顺序 | numberSort | +| 11 | `missing-number` | 填上缺少的数字 | 在数列中找出并填写缺失数字 | missingNumber | + +### 2.4 数的分与合 + +| # | 功能 ID | 标题 | 描述 | 对应页面 | +|---|---------|------|------|----------| +| 12 | `number-decompose` | 10以内数的分与合 | 把数字分一分,合一合 | numberDecompose | +| 13 | `number-decompose-20` | 20以内数的分与合 | 把数字分一分,合一合 | numberDecompose | + +### 2.5 简单运算(图形化) + +| # | 功能 ID | 标题 | 描述 | 对应页面 | +|---|---------|------|------|----------| +| 14 | `one-digit-addition` | 一位数加法 | 通过圆点学习一位数加法运算 | oneDigitAddition | +| 15 | `addition-5` | 5以内加法 | 图形化展示 5 以内加法 | addition | +| 16 | `addition-10` | 10以内加法 | 图形化展示 10 以内加法 | addition | +| 17 | `subtraction-10` | 10以内减法 | 图形化展示 10 以内减法 | addition | +| 18 | `addition-subtraction-10` | 10以内加减法 | 加减法混合运算 | addition | + +### 2.6 进阶运算方法 + +| # | 功能 ID | 标题 | 描述 | 对应页面 | +|---|---------|------|------|----------| +| 19 | `make-ten` | 凑十法练习 | 20 以内进位加法 | makeTen | +| 20 | `break-ten` | 破十法练习 | 20 以内退位减法 | breakTen | +| 21 | `flat-ten` | 平十法练习 | 20 以内退位减法 | flatTen | +| 22 | `borrow-ten` | 借十法练习 | 20 以上退位减法 | borrowTen | + +### 2.7 综合计算练习 + +| # | 功能 ID | 标题 | 描述 | 对应页面 | +|---|---------|------|------|----------| +| 23 | `practice-addition` | 加法运算 | 10/20/50/100 以内加法 | calculationPractice | +| 24 | `practice-subtraction` | 减法运算 | 10/20/50/100 以内减法 | calculationPractice | +| 25 | `practice-mixed` | 混合运算 | 10/20/50/100 以内加减法混合 | calculationPractice | +| 26 | `multiplication-table` | 九九乘法表 | 学习九九乘法口诀 | multiplicationTable | + +### 数学模块共用能力 + +- Canvas 预览 → 保存图片到相册 → 打印 +- 随机生成题目(可重复随机) +- 题型/模式选择器 +- 分享小程序给微信好友或朋友圈 +- 原生广告展示 + +--- + +## 三、Tab 2:专注力培养(13 种题型) + +入口页 `pages/focusIndex/focusIndex`,以卡片网格展示。 + +| # | 功能 ID | 标题 | 描述 | 对应页面 | +|---|---------|------|------|----------| +| 1 | `color-shape-match` | 根据颜色画图形 | 根据颜色画出对应图形 | colorShapeMatch | +| 2 | `shape-symbol` | 图形符号配对 | 根据图形画对应符号 | shapeSymbol | +| 3 | `shape-recognition` | 识别形状 | 识别形状,涂一涂 | shape | +| 4 | `position-coloring` | 方位涂涂乐 | 观察位置,在方格中涂色 | positionColoring | +| 5 | `color-pattern` | 颜色找规律 | 观察颜色规律,在空白图形中涂色 | colorPattern | +| 6 | `match-connect` | 连连看 | 根据物品连一连 | matchConnect | +| 7 | `line-recognition` | 线条识别 | 认识不同线条,画出颜色对应的线条 | lineRecognition | +| 8 | `grid-reasoning` | 方格推理 | 推理出合并方格并连线 | gridReasoning | +| 9 | `code-connect` | 译码连线 | 按数字顺序将数字对应颜色连线 | codeConnect | +| 10 | `dot-connect` | 数字点连线 | 按数字顺序连点成图 | dotConnect | +| 11 | `grid-drawing-3x3` | 格子仿画 3×3 | 简单有趣,培养专注力 | gridDrawing | +| 12 | `grid-drawing-5x5` | 格子仿画 5×5 | 创意挑战,提升观察力 | gridDrawing | +| 13 | `grid-drawing-7x7` | 格子仿画 7×7 | 大师挑战,锻炼耐心 | gridDrawing | + +--- + +## 四、Tab 3:识字 + +入口页 `pages/index/index` + +### 核心流程 + +1. **输入/选择汉字**:最多选 6 个字 + - 手动输入汉字 + - 从分类词库中选择(基础独体字、生活高频字、自然与动作、常用量词/颜色/动物/食物等 8+ 分类) +2. **个性化配色**:从 24 色水彩调色盘中为每个字卡选择颜色 +3. **选择模板**: + - `grid` 模板:识字网格布局 + - `find` 模板:找一找布局 +4. **Canvas 预览**:实时预览 A4 打印效果 +5. **操作**: + - 随机生成字卡 + - 清空重选 + - 保存图片到相册 + - 分享给好友 + +### 词库分类 + +| 类别 | 示例 | +|------|------| +| 基础独体字 | 人、口、手、上、下、日、月、水、火、山... | +| 生活高频字 | 爸、妈、书、包、吃、喝、走、跑... | +| 自然与动作 | 风、雪、星、光、春、夏、秋、冬... | +| 常用量词/颜色/动物/食物等 | 多个子分类 | + +--- + +## 五、Tab 4:练字 + +入口页 `pages/copyBook/copyBook` + +### 核心流程 + +1. **输入/选择汉字**:最多选 11 个字 +2. **获取笔画数据**:从网络加载汉字 SVG 笔画数据 +3. **Canvas 绘制**: + - 田字格底纹 + - 笔顺展示(第一个格完整描红,后续格逐步减淡) + - A4 纸面排版 +4. **导出**:保存到相册 → 打印 + +--- + +## 六、通用能力与技术架构 + +### 6.1 通用功能 + +| 能力 | 说明 | +|------|------| +| 打印配置 | 页眉样式可选(微信码/无Logo/Logo图片/极简),可配置应用名称 | +| Canvas 导出 | 统一的 Canvas → 临时文件 → 保存相册流程 | +| 分享 | 支持分享给好友、分享到朋友圈(含 CDN 分享图) | +| 新手引导 | 识字页有多步骤新手引导弹窗 | +| 添加提示 | 首次使用提示添加到「我的小程序」 | +| 广告 | 原生广告展示(数学/专注力子页面) | +| Debug 模式 | 非 release 环境可调试打印配置、真机调试开关 | +| 埋点追踪 | `tracker` 工具跟踪用户行为 | + +### 6.2 技术栈 + +| 技术 | 说明 | +|------|------| +| 框架 | 微信小程序原生(TypeScript + Less) | +| 渲染 | Skyline + Glass-Easel 组件框架 | +| UI 库 | Vant Weapp | +| 分包 | 主包 + mathPages 分包 + focusPages 分包 | +| 云开发 | 云函数 `doodle`(获取 OpenID、实验性 PDF 生成) | +| 绘制服务 | DrawService 工厂模式,各题型独立 Draw 服务 | +| 预加载 | 所有 Tab 页预加载两个分包 | + +### 6.3 页面架构 + +| 模式 | 说明 | +|------|------| +| pageMixin | 基础页面混入:Canvas 初始化、导出图片、分享配置、页面信息初始化 | +| mathPageMixin | 数学页面混入:继承 pageMixin,增加数学题型选择、随机生成 | +| focusPageMixin | 专注力页面混入:与数学对称,专注力题型的共用逻辑 | +| drawServiceFactory | 根据 functionId 创建对应的绘制服务实例 | + +--- + +## 七、功能统计 + +| 模块 | 题型/功能数量 | +|------|-------------| +| 数感启蒙 | 26 种题型 | +| 专注力培养 | 13 种题型 | +| 识字 | 1 个功能(含 2 种模板) | +| 练字 | 1 个功能 | +| **合计** | **41 种可打印资料** | diff --git a/miniprogram/constants/colors.ts b/miniprogram/constants/colors.ts index e63e88a..71ee8d3 100644 --- a/miniprogram/constants/colors.ts +++ b/miniprogram/constants/colors.ts @@ -149,6 +149,9 @@ export function getRandomUniqueNumberColors(count: number): string[] { return Array.from(selectedColors); } +/** A4 打印导出尺寸:150 DPI,兼顾清晰度与文件体积/打印速度 */ +export const A4_EXPORT_SIZE_150DPI = { width: 1240, height: 1754 }; + export const PAPER_SIZE = { A4: { // width: 2480, diff --git a/miniprogram/utils/saveImage.ts b/miniprogram/utils/saveImage.ts index f773c47..dd6e684 100644 --- a/miniprogram/utils/saveImage.ts +++ b/miniprogram/utils/saveImage.ts @@ -1,8 +1,16 @@ +import { A4_EXPORT_SIZE_150DPI } from '../constants/colors'; + +/** + * 导出为固定打印分辨率(A4 150 DPI),避免高 DPR 设备导出过大图导致打印慢、文件大 + */ const doSaveImage = (canvas: Canvas) => { + const { width: destWidth, height: destHeight } = A4_EXPORT_SIZE_150DPI; wx.canvasToTempFilePath({ - canvas: canvas, - fileType: 'png', - quality: 1, + canvas, + fileType: 'jpg', + quality: 0.9, + destWidth, + destHeight, success: (res) => { wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath,