Files
doodle-mini/miniprogram/mathPages/clockReading/clockReading.ts
T
2026-07-29 17:15:25 +08:00

232 lines
7.7 KiB
TypeScript

import ClockReadingDraw from './draw/clockReadingDraw';
import ClockConnectDraw from './draw/clockConnectDraw';
import {
buildClockReadingData,
type ClockReadingTimeMode,
} from './generators/clock-generator';
import { buildClockConnectData } from './generators/clock-connect-generator';
import { createPage, type CanvasDataState } from '../../base/pageMixin';
import { defaultShareConfig } from '../../config/config';
import {
getModeInfo,
getPublishMetaByMode,
isValidMode,
CLOCK_TIME_MODE_OPTIONS,
CLOCK_EXERCISE_TYPE_OPTIONS,
type ClockTimeMode,
type ClockExerciseType,
} from './clockReading.config';
import type { DebugPublishMeta } from '../../utils/debugPublish';
import {
addFavorite,
removeFavorite,
batchCheckFavorited,
} from '../../utils/favorites';
import type { BaseDrawService } from '../../core/draw/baseDraw';
const pageInfoLookup = getModeInfo;
const DEFAULT_WORKSHEET_ID = 'clock-reading';
type PageData = CanvasDataState & {
worksheetId: string;
timeMode: ClockTimeMode;
timeModeOptions: typeof CLOCK_TIME_MODE_OPTIONS;
exerciseType: ClockExerciseType;
exerciseTypeOptions: typeof CLOCK_EXERCISE_TYPE_OPTIONS;
isPreviewFavorite: boolean;
isDevEnv: boolean;
debugPublishVisible: boolean;
debugPublishLoading: boolean;
debugPublishMeta: DebugPublishMeta | null;
};
createPage(
{
canvas: null as Canvas | null,
ctx: null as RenderingContext | null,
boxHeight: 0,
boxWidth: 0,
drawService: null as BaseDrawService | null,
_favoritedMap: {} as Record<string, boolean>,
data: {
pageTitle: '认识钟表',
functionId: DEFAULT_WORKSHEET_ID,
hasContent: false,
showShareDialog: false,
worksheetId: DEFAULT_WORKSHEET_ID,
timeMode: 'random' as ClockTimeMode,
timeModeOptions: CLOCK_TIME_MODE_OPTIONS,
exerciseType: 'clock-reading' as ClockExerciseType,
exerciseTypeOptions: CLOCK_EXERCISE_TYPE_OPTIONS,
isPreviewFavorite: false,
isDevEnv: false,
debugPublishVisible: false,
debugPublishLoading: false,
debugPublishMeta: null,
} as unknown as PageData,
onLoad(options: { id?: string }) {
const worksheetId =
options.id && isValidMode(options.id)
? options.id
: DEFAULT_WORKSHEET_ID;
this.syncDebugPublishEnv();
// 根据传入 id 判断练习类型
const exerciseType: ClockExerciseType =
worksheetId === 'clock-connect' ? 'clock-connect' : 'clock-reading';
this.setData({ exerciseType });
this.applyWorksheet(worksheetId);
this.loadFavoritedMap();
},
onSelectTimeMode(e: WechatMiniprogram.TouchEvent) {
const mode = e.currentTarget.dataset.mode as
| ClockTimeMode
| undefined;
if (!mode || mode === this.data.timeMode) return;
this.setData({ timeMode: mode }, () => this.drawCanvas());
},
onSelectExerciseType(e: WechatMiniprogram.TouchEvent) {
const type = e.currentTarget.dataset.type as
| ClockExerciseType
| undefined;
if (!type || type === this.data.exerciseType) return;
const worksheetId = type;
this.setData({ exerciseType: type });
this.applyWorksheet(worksheetId);
// 切换练习类型需要重新创建 drawService
this.recreateDrawService();
},
onCanvasReady(e: WechatMiniprogram.CustomEvent) {
this.initCanvasFromComponent(e.detail, {
createDrawService: (
canvas: Canvas,
ctx: RenderingContext,
options?: Record<string, unknown>,
) => this.createDrawForType(canvas, ctx, options),
drawServiceOptions: {
title: this.data.pageTitle,
},
onCanvasReady: () => {
this.drawCanvas();
},
});
},
createDrawForType(
canvas: Canvas,
ctx: RenderingContext,
options?: Record<string, unknown>,
): BaseDrawService {
if (this.data.exerciseType === 'clock-connect') {
return new ClockConnectDraw(canvas, ctx, options);
}
return new ClockReadingDraw(canvas, ctx, options);
},
recreateDrawService() {
if (!this.canvas || !this.ctx) return;
const options = { title: this.data.pageTitle };
this.drawService = this.createDrawForType(
this.canvas,
this.ctx,
options,
);
this.drawCanvas();
},
async drawCanvas() {
if (!this.ctx || !this.drawService) return;
try {
if (this.data.exerciseType === 'clock-connect') {
const data = buildClockConnectData(
this.data.timeMode as ClockTimeMode,
);
await (this.drawService as ClockConnectDraw).draw(data);
} else {
const data = buildClockReadingData(
this.data.timeMode as ClockReadingTimeMode,
);
await (this.drawService as ClockReadingDraw).draw(data);
}
this.setData({ hasContent: true });
} catch (e) {
console.error('clock draw failed', e);
this.setData({ hasContent: false });
}
},
onPreviewRefresh() {
this.drawCanvas();
},
async onPreviewFavorite() {
const next = !this.data.isPreviewFavorite;
this.setData({ isPreviewFavorite: next });
const id = this.data.worksheetId;
if (id && this._favoritedMap) {
this._favoritedMap[id] = next;
if (next) {
addFavorite(id);
} else {
removeFavorite(id);
}
}
wx.showToast({
title: next ? '收藏成功' : '已取消收藏',
icon: 'none',
});
},
async loadFavoritedMap() {
const ids = ['clock-reading', 'clock-connect'];
this._favoritedMap = await batchCheckFavorited(ids);
if (this._favoritedMap?.[this.data.worksheetId]) {
this.setData({ isPreviewFavorite: true });
}
},
getPublishMeta(): DebugPublishMeta {
const meta = getPublishMetaByMode(this.data.worksheetId);
if (!meta) {
throw new Error('当前题型配置不存在');
}
return meta;
},
getWorksheetStatsId() {
return this.data.worksheetId;
},
applyWorksheet(worksheetId: string) {
if (!isValidMode(worksheetId)) return;
this.setData(
{
worksheetId,
functionId: worksheetId,
isPreviewFavorite: !!this._favoritedMap?.[worksheetId],
},
() => {
this.initPageInfo(worksheetId, '认识钟表');
if (this.drawService) {
this.drawService.options.title = this.data.pageTitle;
}
},
);
},
},
{
shareConfig: defaultShareConfig,
pageInfoLookup,
},
);