feat: 完成三类字母描红开发

This commit is contained in:
R524809
2026-04-17 15:59:55 +08:00
parent 6c98e96506
commit 15ad5cce75
13 changed files with 565 additions and 233 deletions
@@ -10,41 +10,58 @@ import {
type LetterTracingMode,
} from '../shared/generators/letter-tracing-generator';
import { LETTERS_UPPER } from '../shared/data/alphabet';
import {
DEFAULT_LETTER_PROFILE,
getFontProfile,
type FontProfile,
} from '../shared/data/fontProfiles';
import { loadLetterFont } from '../shared/draw/drawTools';
/** 各 worksheetId 对应的页面标题和描述 */
const PAGE_META: Record<string, { title: string; desc: string }> = {
'letter-tracing-single': {
title: '看图描红',
desc: '配图、例句与六行描红',
/** 练习模式定义(顺序与产品文档一致),同时用于模式选择器和页面元信息 */
const MODES = [
{
id: 'letter-tracing-single',
label: '看图识字',
desc: '配图、例句与描红',
},
'letter-tracing-full': {
title: '分栏对照',
desc: '半组字母左大写右小写',
},
'letter-tracing-upper-lower': {
title: '字母总览',
{
id: 'letter-tracing-upper-lower',
label: '字母总览',
desc: 'Uppercase / Lowercase 总览',
},
'letter-tracing-two-column': {
title: '大小写配对',
{
id: 'letter-tracing-two-column',
label: '大小写配对',
desc: '左 AM、右 NZ 配对描红',
},
};
{
id: 'letter-tracing-full',
label: '分栏对照',
desc: '半组字母左大写右小写',
},
{
id: 'letter-tracing-triple',
label: '三字母精练',
desc: '每页聚焦 3 个字母深度书写',
},
{
id: 'letter-tracing-single-line',
label: '单字母逐行',
desc: '每行一个字母,13 字母半表',
},
] as const;
const MODE_MAP = Object.fromEntries(MODES.map((m) => [m.id, m])) as Record<
string,
(typeof MODES)[number]
>;
/** 根据 worksheetId 查找页面元信息 */
function pageInfoLookup(id: string) {
return PAGE_META[id];
const m = MODE_MAP[id];
return m ? { title: m.label, desc: m.desc } : undefined;
}
/** 模式选择器的选项列表 */
const MODE_OPTIONS = [
{ id: 'letter-tracing-single', label: '看图描红' },
{ id: 'letter-tracing-full', label: '分栏对照' },
{ id: 'letter-tracing-upper-lower', label: '字母总览' },
{ id: 'letter-tracing-two-column', label: '大小写配对' },
] as const;
type PageData = CanvasDataState & {
worksheetId: string;
traceMode: LetterTracingMode;
@@ -54,7 +71,7 @@ type PageData = CanvasDataState & {
showCaseToggle: boolean;
showNextLetter: boolean;
letterGrid: string[];
modeOptions: ReadonlyArray<{ id: string; label: string }>;
modeOptions: ReadonlyArray<{ id: string; label: string; desc: string }>;
};
createPage(
@@ -64,6 +81,7 @@ createPage(
boxHeight: 0,
boxWidth: 0,
drawService: null as LetterTracingDraw | null,
fontProfile: DEFAULT_LETTER_PROFILE as FontProfile,
data: {
pageTitle: '字母描红',
@@ -78,18 +96,22 @@ createPage(
showCaseToggle: false,
showNextLetter: true,
letterGrid: LETTERS_UPPER,
modeOptions: [...MODE_OPTIONS],
modeOptions: [...MODES],
} as unknown as PageData,
/** 页面加载:从路由参数获取 worksheetId、letter、case 并应用,同时预加载字体 */
/** 页面加载:从路由参数获取 worksheetId、letter、case、font 并应用,同时预加载字体 */
onLoad(options: {
id?: string;
letter?: string;
case?: 'upper' | 'lower';
font?: string;
}) {
loadLetterFont().catch(() => {});
if (options.font) {
this.fontProfile = getFontProfile(options.font);
}
loadLetterFont(this.fontProfile).catch(() => {});
const worksheetId =
options.id && PAGE_META[options.id]
options.id && MODE_MAP[options.id]
? options.id
: 'letter-tracing-single';
this.applyWorksheet(worksheetId);
@@ -149,10 +171,13 @@ createPage(
: this.data.letterCaseLower
? 'lower'
: 'upper';
const needsHalf =
this.data.traceMode === 'column-compare' ||
this.data.traceMode === 'single-line';
return mergeLetterTracingConfig(base, {
selectedLetter: this.data.selectedLetter,
letterCase,
...(this.data.traceMode === 'column-compare'
...(needsHalf
? {
alphabetHalf: this.data.letterCaseLower
? 'N-Z'
@@ -166,7 +191,7 @@ createPage(
async drawCanvas() {
if (!this.ctx || !this.drawService) return;
try {
await loadLetterFont();
await loadLetterFont(this.fontProfile);
const config = this.buildRuntimeConfig();
const data = generateLetterTracing(config);
console.log('drawCanvas data', data);
@@ -228,14 +253,16 @@ createPage(
const merged = mergeLetterTracingConfig(base, {});
const traceMode = merged.mode;
const showLetterPicker = traceMode === 'picture-tracing';
const showCaseToggle = traceMode === 'column-compare';
const showLetterPicker =
traceMode === 'picture-tracing' || traceMode === 'triple-focus';
const showCaseToggle =
traceMode === 'column-compare' || traceMode === 'single-line';
const showNextLetter = traceMode === 'picture-tracing';
const selectedLetter = options?.preserveLetter
? (this.data.selectedLetter ?? 'A')
: normalizeLetter(merged.selectedLetter ?? '');
const letterCaseLower =
traceMode === 'column-compare'
traceMode === 'column-compare' || traceMode === 'single-line'
? merged.alphabetHalf === 'N-Z'
: traceMode === 'picture-tracing'
? merged.letterCase === 'lower'
@@ -255,7 +282,7 @@ createPage(
() => {
this.initPageInfo(
worksheetId,
PAGE_META[worksheetId]?.title ?? '字母描红',
MODE_MAP[worksheetId]?.label ?? '字母描红',
);
if (this.drawService) {