feat: 每日打卡

This commit is contained in:
R524809
2026-04-22 16:49:29 +08:00
parent de74666c9f
commit 2a1dbad164
8 changed files with 541 additions and 34 deletions
@@ -56,6 +56,12 @@ const MODES = [
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<
@@ -72,6 +78,21 @@ for (let i = 0; i < LETTERS_UPPER.length; i += 3) {
TRIPLE_GROUPS.push({ label, letters: [...group] });
}
/** 每日打卡分组:4 个字母一组 */
const DAILY_GROUPS: { label: string; letters: string[] }[] = [];
for (let i = 0; i < LETTERS_UPPER.length; i += 4) {
const group = LETTERS_UPPER.slice(i, i + 4);
const label =
group.length > 1 ? `${group[0]}${group[group.length - 1]}` : group[0];
DAILY_GROUPS.push({ label, letters: [...group] });
}
function getDailyGroupIndex(letters?: string[]): number {
const first = normalizeLetter(letters?.[0] ?? 'A');
const idx = DAILY_GROUPS.findIndex((group) => group.letters[0] === first);
return idx >= 0 ? idx : 0;
}
/** 根据 worksheetId 查找页面元信息 */
function pageInfoLookup(id: string) {
const m = MODE_MAP[id];
@@ -88,8 +109,11 @@ type PageData = CanvasDataState & {
showCaseToggle: boolean;
showNextLetter: boolean;
showTripleGroupPicker: boolean;
showDailyGroupPicker: boolean;
tripleGroups: { label: string; letters: string[] }[];
selectedTripleGroupIdx: number;
dailyGroups: { label: string; letters: string[] }[];
selectedDailyGroupIdx: number;
letterGrid: string[];
modeOptions: ReadonlyArray<{ id: string; label: string; desc: string }>;
isPreviewFavorite: boolean;
@@ -118,8 +142,11 @@ createPage(
showCaseToggle: false,
showNextLetter: true,
showTripleGroupPicker: false,
showDailyGroupPicker: false,
tripleGroups: TRIPLE_GROUPS,
selectedTripleGroupIdx: 0,
dailyGroups: DAILY_GROUPS,
selectedDailyGroupIdx: 0,
letterGrid: LETTERS_PAIRS,
modeOptions: [...MODES],
isPreviewFavorite: false,
@@ -204,6 +231,8 @@ createPage(
this.data.traceMode === 'letter-tracing-case-pairing' ||
this.data.traceMode === 'letter-tracing-half';
const isTriple = this.data.traceMode === 'letter-tracing-three';
const isDaily =
this.data.traceMode === 'letter-tracing-daily-checkin';
return mergeLetterTracingConfig(base, {
selectedLetter: this.data.selectedLetter,
letterCase,
@@ -221,6 +250,13 @@ createPage(
?.letters,
}
: {}),
...(isDaily
? {
dailyLetters:
DAILY_GROUPS[this.data.selectedDailyGroupIdx]
?.letters,
}
: {}),
});
},
@@ -293,6 +329,14 @@ createPage(
this.drawCanvas();
},
/** 用户在每日打卡分组选择器中选择了一组 */
onSelectDailyGroup(e: WechatMiniprogram.TouchEvent) {
const idx = Number(e.currentTarget.dataset.idx);
if (isNaN(idx) || idx === this.data.selectedDailyGroupIdx) return;
this.setData({ selectedDailyGroupIdx: idx });
this.drawCanvas();
},
/**
* 应用指定的 worksheet 配置到页面状态
* 根据 worksheet 的 generatorConfig 决定 UI 控件的显隐(字母选择器、大小写切换等)
@@ -320,9 +364,15 @@ createPage(
traceMode === 'letter-tracing-half';
const showNextLetter = traceMode === 'letter-tracing-single';
const showTripleGroupPicker = traceMode === 'letter-tracing-three';
const showDailyGroupPicker =
traceMode === 'letter-tracing-daily-checkin';
const selectedLetter = options?.preserveLetter
? (this.data.selectedLetter ?? 'A')
: normalizeLetter(merged.selectedLetter ?? '');
const selectedDailyGroupIdx =
options?.preserveLetter && showDailyGroupPicker
? (this.data.selectedDailyGroupIdx ?? 0)
: getDailyGroupIndex(merged.dailyLetters);
const letterCaseLower =
traceMode === 'letter-tracing-case-pairing' ||
traceMode === 'letter-tracing-half'
@@ -343,6 +393,8 @@ createPage(
showCaseToggle,
showNextLetter,
showTripleGroupPicker,
showDailyGroupPicker,
selectedDailyGroupIdx,
},
() => {
this.initPageInfo(