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, 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, ) => this.createDrawForType(canvas, ctx, options), drawServiceOptions: { title: this.data.pageTitle, }, onCanvasReady: () => { this.drawCanvas(); }, }); }, createDrawForType( canvas: Canvas, ctx: RenderingContext, options?: Record, ): 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, }, );