Files
doodle-mini/skills/create-draw-page/SKILL.md
T
2026-05-19 18:24:43 +08:00

8.3 KiB
Raw Blame History

name, description
name description
create-draw-page 基于现有 draw 页面模板创建新的绘制页(worksheet page)。 当用户说「基于现有的draw页面来开发新页面」「基于draw页面开发新页面」 「新建绘制页」「创建一个新的draw页面」「新增一个worksheet页」时触发。

创建新的绘制页(Draw Page

基于 englishPages/letterTracing 模板,快速搭建一个新的 Canvas 绘制页。

模板参考

miniprogram/englishPages/letterTracing 为标准模板,新页面的文件结构与代码风格应与之对齐。创建前先阅读模板页的以下文件:

  • letterTracing.ts — 页面逻辑
  • letterTracing.wxml — 页面模板
  • letterTracing.less — 页面样式
  • letterTracing.json — 组件注册
  • letterTracing.config.ts — worksheet 元数据配置

新页面必备文件

假设新页面名为 newPage,需要创建以下文件:

newPage/
├── newPage.ts            # 页面逻辑(使用 createPage
├── newPage.wxml          # 页面模板
├── newPage.less          # 页面样式
├── newPage.json          # 组件注册
├── newPage.config.ts     # worksheet 元数据
└── draw/                 # 绘制服务
    └── newPageDraw.ts    # 继承 BaseDrawService

必备要求

1. xxx.config.ts — worksheet 元数据配置

每个绘制页必须有对应的 xxx.config.ts 文件。参考 letterTracing.config.ts 的结构,至少包含:

worksheet 定义数组(核心):

interface XxxWorksheetDefinition {
    id: string; // 唯一标识,格式:{pageName}-{variant}
    icon: string; // 图标名(使用 toy-icon 支持的图标)
    title: string; // 标题(简短,4-6 字)
    subtitle: string; // 副标题(描述该模式的特点)
    ageMin: number; // 最小适用年龄
    ageMax: number; // 最大适用年龄
    difficulty: 1 | 2 | 3 | 4; // 难度等级
    tags: string[]; // 标签数组
    sortOrder: number; // 排序权重
}

export const XXX_WORKSHEET_DEFINITIONS = [
    {
        id: 'xxx-default',
        icon: 'icon-name',
        title: '默认模式',
        subtitle: '模式描述',
        ageMin: 4,
        ageMax: 7,
        difficulty: 1,
        tags: ['标签1', '标签2'],
        sortOrder: 50,
    },
    // ... 更多模式
] as const satisfies ReadonlyArray<XxxWorksheetDefinition>;

必须导出的辅助函数(参照 letterTracing.config.ts):

  • getModeInfo(id) — 返回 { title, desc } 用于 pageInfoLookup
  • isValidMode(id) — 校验 id 是否合法
  • getPublishMetaByMode(id) — 生成 DebugPublishMeta,使用 inferGradeFromAge 推断年级
  • 模式选项常量(如 XXX_MODE_OPTIONS

getPublishMetaByMode 中的 categorysubcategory 需根据页面所属学科正确设置:

  • categorymath | puzzle | pinyin | chinese | english | craft
  • subcategory:页面功能简称,如 letter-tracingword-coloring

2. 必须使用的组件

每个绘制页必须.json.wxml 中注册并使用以下组件:

{
    "usingComponents": {
        "nav-bar": "../../components3.0/nav-bar/nav-bar",
        "preview-card": "../../components3.0/preview-card/preview-card",
        "preview-footer-actions": "../../components3.0/preview-footer-actions/preview-footer-actions",
        "debug-publish-tools": "../../components3.0/debug-publish-tools/debug-publish-tools",
        "share-guide-popup": "../../components/share-guide-popup/share-guide-popup",
        "toy-icon": "../../toy/icon/icon"
    }
}

路径中的 ../../ 需根据新页面实际所在目录调整层级。

wxml 中的基本布局结构

<nav-bar title="页面标题" />

<view class="page-wrapper">
    <view class="page-main">
        <preview-card
            id="previewCard"
            showRefresh="{{false}}"
            showFavorite="{{true}}"
            favorited="{{isPreviewFavorite}}"
            bind:canvas-ready="onCanvasReady"
            bind:favorite="onPreviewFavorite" />

        <!-- 页面特有的交互区域放这里 -->
    </view>
</view>

<preview-footer-actions
    disabled="{{!hasContent}}"
    bind:primary="exportToPrint"
    bind:secondary="onShare" />

<debug-publish-tools
    wx:if="{{isDevEnv && hasContent}}"
    id="debugPublishTools"
    visible="{{debugPublishVisible}}"
    loading="{{debugPublishLoading}}"
    meta="{{debugPublishMeta}}"
    bind:open="onOpenDebugPublish"
    bind:close="onCloseDebugPublish"
    bind:confirm="onConfirmDebugPublish" />

<share-guide-popup
    show="{{showShareDialog}}"
    bind:onClose="onCloseShareDialog"
    bind:onShareSuccess="onShareSuccess" />

3. 图标使用

图标优先使用 toy-icon 组件(路径 ../../toy/icon/icon):

<toy-icon name="refresh" size="40rpx" color="#605b50" />

如果 toy-icon 没有所需图标,可直接引入 iconfont:

@import '../../assets/fonts/iconfont.less';

4. 使用 createPage 创建页面

页面必须使用 base/pageMixin.ts 中的 createPage 函数创建,不能直接调用 Page()

import { createPage, type CanvasDataState } from '../../base/pageMixin';

createPage(
    {
        canvas: null as Canvas | null,
        ctx: null as RenderingContext | null,
        boxHeight: 0,
        boxWidth: 0,
        drawService: null as XxxDraw | null,

        data: {
            pageTitle: '页面标题',
            functionId: '',
            hasContent: false,
            showShareDialog: false,
            // ... 页面特有数据
            isPreviewFavorite: false,
            isDevEnv: false,
            debugPublishVisible: false,
            debugPublishLoading: false,
            debugPublishMeta: null,
        } as unknown as PageData,

        onLoad(options: { id?: string }) {
            // 1. syncDebugPublishEnv()
            // 2. 解析路由参数、应用默认模式
            // 3. 加载收藏状态
        },

        onCanvasReady(e: WechatMiniprogram.CustomEvent) {
            this.initCanvasFromComponent(e.detail, {
                createDrawService: (canvas, ctx, opts) =>
                    new XxxDraw(canvas, ctx, opts),
                onCanvasReady: () => this.drawCanvas(),
            });
        },

        async drawCanvas() {
            // 生成数据 → 调用 drawService 渲染
        },

        getPublishMeta() {
            // 调用 config 中的 getPublishMetaByMode
        },
    },
    {
        shareConfig: defaultShareConfig,
        pageInfoLookup,
    },
);

createPage 自动混入的公共方法包括:

  • initCanvas / initCanvasFromComponent — Canvas 初始化
  • exportToPrint — 导出打印
  • onShareAppMessage / onShareTimeline — 分享
  • onCloseShareDialog / onShareSuccess — 分享弹窗
  • syncDebugPublishEnv / onOpenDebugPublish / onCloseDebugPublish / onConfirmDebugPublish — 调试发布
  • initPageInfo — 页面标题初始化
  • getShareOptions — 分享路径

不要重复实现这些方法,直接使用即可。

5. 主题色与设计风格

保持与模板页一致的暖色调主题,除非用户另行指定 UI 稿:

@import '../../style/theme.less';

page {
    background-color: @bg-page;
}

关键设计 token(来自 theme.less):

  • 页面背景:@bg-page
  • 卡片背景:@bg-card
  • 品牌色/选中态:@brand
  • 主标题色:#6d3b00
  • 正文色:@text-secondary
  • 选中文字色:@text-selected-btn
  • 页面左右内边距:@page-padding-x
  • 底部安全区留白:calc(200rpx + env(safe-area-inset-bottom))
  • 圆角:24rpx(卡片)/ 32rpx(按钮/chip

开发检查清单

创建完成后逐项确认:

  • xxx.config.ts,包含 worksheet 定义数组和辅助函数
  • .json 中注册了全部 5 个必备组件 + toy-icon
  • .wxml 中包含 nav-barpreview-cardpreview-footer-actionsdebug-publish-toolsshare-guide-popup
  • .ts 中使用 createPage() 创建页面
  • .less 中引入 theme.less 并使用主题变量
  • draw/ 目录放置绘制服务
  • onLoad 中调用了 syncDebugPublishEnv()
  • 实现了 getPublishMeta() 方法
  • app.json 中注册了新页面路径