feat: 样式修改、13 字母半表、三字母精练开发

This commit is contained in:
R524809
2026-04-20 16:23:47 +08:00
parent 9febf7da4f
commit 21b515746b
12 changed files with 916 additions and 163 deletions
@@ -9,7 +9,7 @@ import {
type LetterTracingGeneratorConfig,
type LetterTracingMode,
} from '../shared/generators/letter-tracing-generator';
import { LETTERS_UPPER } from '../shared/data/alphabet';
import { LETTERS_UPPER, LETTERS_PAIRS } from '../shared/data/alphabet';
import {
DEFAULT_LETTER_PROFILE,
getFontProfile,
@@ -21,34 +21,35 @@ import { loadLetterFont } from '../shared/draw/drawTools';
const MODES = [
{
id: 'letter-tracing-single',
label: '看图识字',
label: '默认字帖',
desc: '配图、例句与描红',
},
{
id: 'letter-tracing-upper-lower',
label: '字母总览',
// label: '字母总览',
label: '基础描红',
desc: 'Uppercase / Lowercase 总览',
},
{
id: 'letter-tracing-case-pairing',
label: '大小写练习',
label: '大小写对照',
desc: '半组字母左大写右小写',
},
{
id: 'letter-tracing-two-column',
label: '两列练习',
label: '两列描红',
desc: '左 AM、右 NZ 配对描红',
},
{
id: 'letter-tracing-single-line',
label: '13字母半表',
desc: '每行一个字母,13 字母半表',
},
{
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<
@@ -56,6 +57,15 @@ const MODE_MAP = Object.fromEntries(MODES.map((m) => [m.id, m])) as Record<
(typeof MODES)[number]
>;
/** 三字母精练分组:26 字母每 3 个一组 */
const TRIPLE_GROUPS: { label: string; letters: string[] }[] = [];
for (let i = 0; i < LETTERS_UPPER.length; i += 3) {
const group = LETTERS_UPPER.slice(i, i + 3);
const label =
group.length > 1 ? `${group[0]}${group[group.length - 1]}` : group[0];
TRIPLE_GROUPS.push({ label, letters: [...group] });
}
/** 根据 worksheetId 查找页面元信息 */
function pageInfoLookup(id: string) {
const m = MODE_MAP[id];
@@ -66,11 +76,17 @@ type PageData = CanvasDataState & {
worksheetId: string;
traceMode: LetterTracingMode;
selectedLetter: string;
selectedLetterPair: string;
letterCaseLower: boolean;
showLetterPicker: boolean;
showCaseToggle: boolean;
showNextLetter: boolean;
showTripleGroupPicker: boolean;
tripleGroups: { label: string; letters: string[] }[];
selectedTripleGroupIdx: number;
letterGrid: string[];
letterGridExpanded: boolean;
letterGridPreview: string[];
modeOptions: ReadonlyArray<{ id: string; label: string; desc: string }>;
};
@@ -91,11 +107,17 @@ createPage(
worksheetId: 'letter-tracing-single',
traceMode: 'letter-tracing-single',
selectedLetter: 'A',
selectedLetterPair: 'Aa',
letterCaseLower: false,
showLetterPicker: true,
showCaseToggle: false,
showNextLetter: true,
letterGrid: LETTERS_UPPER,
showTripleGroupPicker: false,
tripleGroups: TRIPLE_GROUPS,
selectedTripleGroupIdx: 0,
letterGrid: LETTERS_PAIRS,
letterGridExpanded: false,
letterGridPreview: LETTERS_PAIRS.slice(0, 6),
modeOptions: [...MODES],
} as unknown as PageData,
@@ -119,7 +141,10 @@ createPage(
const updates: Partial<PageData> = {};
if (options.letter) {
const normalized = normalizeLetter(options.letter);
if (normalized) updates.selectedLetter = normalized;
if (normalized) {
updates.selectedLetter = normalized;
updates.selectedLetterPair = `${normalized}${normalized.toLowerCase()}`;
}
}
if (options.case === 'lower') {
updates.letterCaseLower = true;
@@ -174,6 +199,7 @@ createPage(
const needsHalf =
this.data.traceMode === 'letter-tracing-case-pairing' ||
this.data.traceMode === 'letter-tracing-single-line';
const isTriple = this.data.traceMode === 'letter-tracing-triple';
return mergeLetterTracingConfig(base, {
selectedLetter: this.data.selectedLetter,
letterCase,
@@ -184,6 +210,13 @@ createPage(
: 'A-M',
}
: {}),
...(isTriple
? {
tripleLetters:
TRIPLE_GROUPS[this.data.selectedTripleGroupIdx]
?.letters,
}
: {}),
});
},
@@ -203,11 +236,22 @@ createPage(
}
},
/** 用户在字母网格中选择了一个字母 */
/** 展开/收起字母网格 */
toggleLetterGrid() {
this.setData({
letterGridExpanded: !this.data.letterGridExpanded,
});
},
/** 用户在字母网格中选择了一个字母(item 为 "Aa" 格式,取首字母作为 selectedLetter */
onSelectLetter(e: WechatMiniprogram.TouchEvent) {
const letter = e.currentTarget.dataset.letter as string;
if (!letter) return;
this.setData({ selectedLetter: letter });
const raw = e.currentTarget.dataset.letter as string;
if (!raw) return;
const letter = raw.charAt(0).toUpperCase();
this.setData({
selectedLetter: letter,
selectedLetterPair: `${letter}${letter.toLowerCase()}`,
});
this.drawCanvas();
},
@@ -228,7 +272,18 @@ createPage(
const list = LETTERS_UPPER;
const i = list.indexOf(this.data.selectedLetter);
const next = list[(i + 1) % list.length];
this.setData({ selectedLetter: next });
this.setData({
selectedLetter: next,
selectedLetterPair: `${next}${next.toLowerCase()}`,
});
this.drawCanvas();
},
/** 用户在三字母分组选择器中选择了一组 */
onSelectTripleGroup(e: WechatMiniprogram.TouchEvent) {
const idx = Number(e.currentTarget.dataset.idx);
if (isNaN(idx) || idx === this.data.selectedTripleGroupIdx) return;
this.setData({ selectedTripleGroupIdx: idx });
this.drawCanvas();
},
@@ -253,13 +308,12 @@ createPage(
const merged = mergeLetterTracingConfig(base, {});
const traceMode = merged.mode;
const showLetterPicker =
traceMode === 'letter-tracing-single' ||
traceMode === 'letter-tracing-triple';
const showLetterPicker = traceMode === 'letter-tracing-single';
const showCaseToggle =
traceMode === 'letter-tracing-case-pairing' ||
traceMode === 'letter-tracing-single-line';
const showNextLetter = traceMode === 'letter-tracing-single';
const showTripleGroupPicker = traceMode === 'letter-tracing-triple';
const selectedLetter = options?.preserveLetter
? (this.data.selectedLetter ?? 'A')
: normalizeLetter(merged.selectedLetter ?? '');
@@ -277,10 +331,12 @@ createPage(
functionId: worksheetId,
traceMode,
selectedLetter,
selectedLetterPair: `${selectedLetter}${selectedLetter.toLowerCase()}`,
letterCaseLower,
showLetterPicker,
showCaseToggle,
showNextLetter,
showTripleGroupPicker,
},
() => {
this.initPageInfo(