feat: 英文字母描红开发
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
import LetterTracingDraw from '../shared/service/letterTracingDraw';
|
||||
import { createPage, type CanvasDataState } from '../../base/pageMixin';
|
||||
import { defaultShareConfig } from '../../config/config';
|
||||
import { getWorksheetById } from '../../core/data/worksheets';
|
||||
import {
|
||||
generateLetterTracing,
|
||||
mergeLetterTracingConfig,
|
||||
type LetterTracingGeneratorConfig,
|
||||
type LetterTracingMode,
|
||||
} from '../../core/generators/letter-tracing-generator';
|
||||
import { LETTERS_UPPER } from '../../core/data/alphabet';
|
||||
|
||||
const PAGE_META: Record<string, { title: string; desc: string }> = {
|
||||
'letter-tracing-single': {
|
||||
title: '字母学习页',
|
||||
desc: '单字母配图与描红',
|
||||
},
|
||||
'letter-tracing-full': {
|
||||
title: '26 字母描红',
|
||||
desc: '整页字母书写练习',
|
||||
},
|
||||
'letter-tracing-upper-lower': {
|
||||
title: '大小写字母对照',
|
||||
desc: '一页认识 A-Z 与 a-z',
|
||||
},
|
||||
'letter-tracing-two-column': {
|
||||
title: '字母描红(两列)',
|
||||
desc: 'A–M / N–Z 两列练习',
|
||||
},
|
||||
};
|
||||
|
||||
function pageInfoLookup(id: string) {
|
||||
return PAGE_META[id];
|
||||
}
|
||||
|
||||
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;
|
||||
selectedLetter: string;
|
||||
letterCaseLower: boolean;
|
||||
showLetterPicker: boolean;
|
||||
showCaseToggle: boolean;
|
||||
showNextLetter: boolean;
|
||||
letterGrid: string[];
|
||||
modeOptions: ReadonlyArray<{ id: string; label: string }>;
|
||||
};
|
||||
|
||||
createPage(
|
||||
{
|
||||
canvas: null as Canvas | null,
|
||||
ctx: null as RenderingContext | null,
|
||||
boxHeight: 0,
|
||||
boxWidth: 0,
|
||||
drawService: null as LetterTracingDraw | null,
|
||||
|
||||
data: {
|
||||
pageTitle: '字母描红',
|
||||
functionId: '',
|
||||
hasContent: false,
|
||||
showShareDialog: false,
|
||||
worksheetId: 'letter-tracing-single',
|
||||
traceMode: 'single-letter',
|
||||
selectedLetter: 'A',
|
||||
letterCaseLower: false,
|
||||
showLetterPicker: true,
|
||||
showCaseToggle: false,
|
||||
showNextLetter: true,
|
||||
letterGrid: LETTERS_UPPER,
|
||||
modeOptions: [...MODE_OPTIONS],
|
||||
} as unknown as PageData,
|
||||
|
||||
onLoad(options: { id?: string }) {
|
||||
const worksheetId =
|
||||
options.id && PAGE_META[options.id]
|
||||
? options.id
|
||||
: 'letter-tracing-single';
|
||||
const def = getWorksheetById(worksheetId);
|
||||
const base = (def?.generatorConfig ??
|
||||
{}) as Partial<LetterTracingGeneratorConfig>;
|
||||
const merged = mergeLetterTracingConfig(base, {});
|
||||
|
||||
const traceMode = merged.mode;
|
||||
const showLetterPicker = traceMode === 'single-letter';
|
||||
const showCaseToggle =
|
||||
traceMode === 'full-alphabet' || traceMode === 'two-column';
|
||||
const showNextLetter = traceMode === 'single-letter';
|
||||
|
||||
this.setData({
|
||||
worksheetId,
|
||||
functionId: worksheetId,
|
||||
traceMode,
|
||||
selectedLetter: normalizePick(merged.selectedLetter),
|
||||
letterCaseLower: merged.letterCase === 'lower',
|
||||
showLetterPicker,
|
||||
showCaseToggle,
|
||||
showNextLetter,
|
||||
});
|
||||
|
||||
this.initPageInfo(worksheetId, PAGE_META[worksheetId]?.title ?? '字母描红');
|
||||
},
|
||||
|
||||
onSelectMode(e: WechatMiniprogram.TouchEvent) {
|
||||
const id = e.currentTarget.dataset.id as string | undefined;
|
||||
if (!id || id === this.data.worksheetId) return;
|
||||
wx.redirectTo({
|
||||
url: `/englishPages/letterTracing/letterTracing?id=${id}`,
|
||||
});
|
||||
},
|
||||
|
||||
onReady() {
|
||||
this.initCanvas({
|
||||
createDrawService: (
|
||||
canvas: Canvas,
|
||||
ctx: RenderingContext,
|
||||
options?: Record<string, unknown>,
|
||||
) => new LetterTracingDraw(canvas, ctx, options),
|
||||
drawServiceOptions: {
|
||||
title: this.data.pageTitle,
|
||||
subTitle: this.data.subTitle || '',
|
||||
},
|
||||
onCanvasReady: () => {
|
||||
this.drawCanvas();
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
buildRuntimeConfig(): LetterTracingGeneratorConfig {
|
||||
const def = getWorksheetById(this.data.worksheetId);
|
||||
const base = (def?.generatorConfig ??
|
||||
{}) as Partial<LetterTracingGeneratorConfig>;
|
||||
const letterCase =
|
||||
this.data.traceMode === 'single-letter'
|
||||
? (base.letterCase ?? 'upper')
|
||||
: this.data.letterCaseLower
|
||||
? 'lower'
|
||||
: 'upper';
|
||||
return mergeLetterTracingConfig(base, {
|
||||
selectedLetter: this.data.selectedLetter,
|
||||
letterCase,
|
||||
});
|
||||
},
|
||||
|
||||
async drawCanvas() {
|
||||
if (!this.ctx || !this.drawService) return;
|
||||
try {
|
||||
const config = this.buildRuntimeConfig();
|
||||
const data = generateLetterTracing(config);
|
||||
await (this.drawService as LetterTracingDraw).draw(data);
|
||||
this.setData({ hasContent: true });
|
||||
} catch (e) {
|
||||
console.error('letterTracing draw failed', e);
|
||||
this.setData({ hasContent: false });
|
||||
}
|
||||
},
|
||||
|
||||
onSelectLetter(e: WechatMiniprogram.TouchEvent) {
|
||||
const letter = e.currentTarget.dataset.letter as string;
|
||||
if (!letter) return;
|
||||
this.setData({ selectedLetter: letter });
|
||||
this.drawCanvas();
|
||||
},
|
||||
|
||||
onSelectCaseUpper() {
|
||||
this.setData({ letterCaseLower: false });
|
||||
this.drawCanvas();
|
||||
},
|
||||
|
||||
onSelectCaseLower() {
|
||||
this.setData({ letterCaseLower: true });
|
||||
this.drawCanvas();
|
||||
},
|
||||
|
||||
onNextLetter() {
|
||||
const list = LETTERS_UPPER;
|
||||
const i = list.indexOf(this.data.selectedLetter);
|
||||
const next = list[(i + 1) % list.length];
|
||||
this.setData({ selectedLetter: next });
|
||||
this.drawCanvas();
|
||||
},
|
||||
},
|
||||
{
|
||||
shareConfig: defaultShareConfig,
|
||||
pageInfoLookup,
|
||||
},
|
||||
);
|
||||
|
||||
function normalizePick(c?: string): string {
|
||||
if (!c || c.length === 0) return 'A';
|
||||
return c.trim().toUpperCase().charAt(0);
|
||||
}
|
||||
Reference in New Issue
Block a user