feat: worksheet发布功能开发

This commit is contained in:
R524809
2026-04-24 17:49:11 +08:00
parent 5106dbbd7c
commit bb69d5c49d
24 changed files with 2540 additions and 1014 deletions
@@ -1,7 +1,6 @@
import LetterTracingDraw from './draw/letterTracingDraw';
import { createPage, type CanvasDataState } from '../../base/pageMixin';
import { defaultShareConfig } from '../../config/config';
import { getWorksheetById } from '../../core/data/worksheets';
import {
generateLetterTracing,
mergeLetterTracingConfig,
@@ -9,6 +8,12 @@ import {
type LetterTracingGeneratorConfig,
type LetterTracingMode,
} from './generators/letter-tracing-generator';
import {
getModeInfo,
getPublishMetaByMode,
isValidMode,
LETTER_TRACING_MODE_OPTIONS,
} from './letterTracing.config';
import { LETTERS_UPPER, LETTERS_PAIRS } from '../shared/data/alphabet';
import {
DEFAULT_LETTER_PROFILE,
@@ -16,75 +21,24 @@ import {
type FontProfile,
} from '../shared/data/fontProfiles';
import { loadLetterFont } from '../shared/draw/drawTools';
/** 练习模式定义(顺序与产品文档一致),同时用于模式选择器和页面元信息 */
const MODES = [
{
id: 'letter-tracing-single',
icon: 'start-a',
label: '默认字帖',
desc: '配图、例句与描红',
},
{
id: 'letter-tracing-upper-lower',
icon: 'draw-o',
// label: '字母总览',
label: '基础描红',
desc: 'Uppercase / Lowercase 总览',
},
{
id: 'letter-tracing-case-pairing',
icon: 'font-size',
label: '大小写对照',
desc: '半组字母左大写右小写',
},
{
id: 'letter-tracing-two-column',
icon: 'two-columns',
label: '两列描红',
desc: '左 AM、右 NZ 配对描红',
},
{
id: 'letter-tracing-half',
icon: 'square-half',
label: '13字母半表',
desc: '每行一个字母,13 字母半表',
},
{
id: 'letter-tracing-three',
icon: 'ABC-list',
label: '三字母精练',
desc: '每页聚焦 3 个字母深度书写',
},
{
id: 'letter-tracing-daily-checkin',
icon: 'draw-o',
label: '每日打卡',
desc: '四宫格每日字母打卡练习',
},
] as const;
const MODE_MAP = Object.fromEntries(MODES.map((m) => [m.id, m])) as Record<
string,
(typeof MODES)[number]
>;
import type { DebugPublishMeta } from '../../utils/debugPublish';
/** 三字母精练分组:26 字母每 3 个一组 */
const TRIPLE_GROUPS: { label: string; letters: string[] }[] = [];
const TRIPLE_GROUPS: { title: string; letters: string[] }[] = [];
for (let i = 0; i < LETTERS_UPPER.length; i += 3) {
const group = LETTERS_UPPER.slice(i, i + 3);
const label =
const title =
group.length > 1 ? `${group[0]}${group[group.length - 1]}` : group[0];
TRIPLE_GROUPS.push({ label, letters: [...group] });
TRIPLE_GROUPS.push({ title, letters: [...group] });
}
/** 每日打卡分组:4 个字母一组 */
const DAILY_GROUPS: { label: string; letters: string[] }[] = [];
const DAILY_GROUPS: { title: string; letters: string[] }[] = [];
for (let i = 0; i < LETTERS_UPPER.length; i += 4) {
const group = LETTERS_UPPER.slice(i, i + 4);
const label =
const title =
group.length > 1 ? `${group[0]}${group[group.length - 1]}` : group[0];
DAILY_GROUPS.push({ label, letters: [...group] });
DAILY_GROUPS.push({ title, letters: [...group] });
}
function getDailyGroupIndex(letters?: string[]): number {
@@ -93,11 +47,7 @@ function getDailyGroupIndex(letters?: string[]): number {
return idx >= 0 ? idx : 0;
}
/** 根据 worksheetId 查找页面元信息 */
function pageInfoLookup(id: string) {
const m = MODE_MAP[id];
return m ? { title: m.label, desc: m.desc } : undefined;
}
const pageInfoLookup = getModeInfo;
type PageData = CanvasDataState & {
worksheetId: string;
@@ -110,13 +60,17 @@ type PageData = CanvasDataState & {
showNextLetter: boolean;
showTripleGroupPicker: boolean;
showDailyGroupPicker: boolean;
tripleGroups: { label: string; letters: string[] }[];
tripleGroups: { title: string; letters: string[] }[];
selectedTripleGroupIdx: number;
dailyGroups: { label: string; letters: string[] }[];
dailyGroups: { title: string; letters: string[] }[];
selectedDailyGroupIdx: number;
letterGrid: string[];
modeOptions: ReadonlyArray<{ id: string; label: string; desc: string }>;
modeOptions: typeof LETTER_TRACING_MODE_OPTIONS;
isPreviewFavorite: boolean;
isDevEnv: boolean;
debugPublishVisible: boolean;
debugPublishLoading: boolean;
debugPublishMeta: DebugPublishMeta | null;
};
createPage(
@@ -148,8 +102,12 @@ createPage(
dailyGroups: DAILY_GROUPS,
selectedDailyGroupIdx: 0,
letterGrid: LETTERS_PAIRS,
modeOptions: [...MODES],
modeOptions: LETTER_TRACING_MODE_OPTIONS,
isPreviewFavorite: false,
isDevEnv: false,
debugPublishVisible: false,
debugPublishLoading: false,
debugPublishMeta: null,
} as unknown as PageData,
/** 页面加载:从路由参数获取 worksheetId、letter、case、font 并应用,同时预加载字体 */
@@ -164,9 +122,10 @@ createPage(
}
loadLetterFont(this.fontProfile).catch(() => {});
const worksheetId =
options.id && MODE_MAP[options.id]
options.id && isValidMode(options.id)
? options.id
: 'letter-tracing-single';
this.syncDebugPublishEnv();
this.applyWorksheet(worksheetId);
const updates: Partial<PageData> = {};
@@ -216,11 +175,11 @@ createPage(
});
},
/** 构建运行时生成器配置:合并 worksheet 预设 + 当前页面状态 */
/** 构建运行时生成器配置:合并页面模式预设 + 当前页面状态 */
buildRuntimeConfig(): LetterTracingGeneratorConfig {
const def = getWorksheetById(this.data.worksheetId);
const base = (def?.generatorConfig ??
{}) as Partial<LetterTracingGeneratorConfig>;
const base: Partial<LetterTracingGeneratorConfig> = {
mode: this.data.traceMode,
};
const letterCase =
this.data.traceMode === 'letter-tracing-single'
? (base.letterCase ?? 'upper')
@@ -321,6 +280,14 @@ createPage(
});
},
getPublishMeta(): DebugPublishMeta {
const meta = getPublishMetaByMode(this.data.worksheetId);
if (!meta) {
throw new Error('当前题型配置不存在');
}
return meta;
},
/** 用户在三字母分组选择器中选择了一组 */
onSelectTripleGroup(e: WechatMiniprogram.TouchEvent) {
const idx = Number(e.currentTarget.dataset.idx);
@@ -338,9 +305,9 @@ createPage(
},
/**
* 应用指定的 worksheet 配置到页面状态
* 根据 worksheet 的 generatorConfig 决定 UI 控件的显隐(字母选择器、大小写切换等)
* @param worksheetId - 要应用的 worksheet ID
* 应用指定的页面模式配置到页面状态
* 根据当前模式的运行时默认参数决定 UI 控件的显隐(字母选择器、大小写切换等)
* @param worksheetId - 要应用的模式 ID
* @param options.preserveLetter - 是否保留当前选中的字母(模式切换时使用)
* @param options.redraw - 是否立即重绘 Canvas
*/
@@ -351,11 +318,12 @@ createPage(
redraw?: boolean;
},
) {
const def = getWorksheetById(worksheetId);
console.log('def', def);
const base = (def?.generatorConfig ??
{}) as Partial<LetterTracingGeneratorConfig>;
const merged = mergeLetterTracingConfig(base, {});
if (!isValidMode(worksheetId)) return;
const merged = mergeLetterTracingConfig(
{ mode: worksheetId as LetterTracingMode },
{},
);
const traceMode = merged.mode;
const showLetterPicker = traceMode === 'letter-tracing-single';
@@ -397,10 +365,7 @@ createPage(
selectedDailyGroupIdx,
},
() => {
this.initPageInfo(
worksheetId,
MODE_MAP[worksheetId]?.label ?? '字母描红',
);
this.initPageInfo(worksheetId, '字母描红');
if (this.drawService) {
this.drawService.options.title = this.data.pageTitle;