300 lines
9.6 KiB
TypeScript
300 lines
9.6 KiB
TypeScript
import { createMathPage } from '../shared/common/mathPageMixin';
|
|
import { BaseDrawService } from '../../core/draw/baseDraw';
|
|
import {
|
|
MATH_TYPE_CONFIGS,
|
|
findTypeByRouteId,
|
|
type MathTypeConfig,
|
|
type MathTypeAction,
|
|
} from './registry';
|
|
import { getPublishMetaByMathState } from './mathDraw.config';
|
|
import type { DebugPublishMeta } from '../../utils/debugPublish';
|
|
import { incrementWorksheetLikes } from '../../utils/worksheetStats';
|
|
|
|
const TYPE_LIST = MATH_TYPE_CONFIGS.map((t) => ({
|
|
id: t.id,
|
|
title: t.title,
|
|
icon: t.icon,
|
|
}));
|
|
|
|
createMathPage({
|
|
canvas: null as Canvas | null,
|
|
ctx: null as RenderingContext | null,
|
|
boxHeight: 0,
|
|
boxWidth: 0,
|
|
drawService: null as BaseDrawService | null,
|
|
currentTypeConfig: null as MathTypeConfig | null,
|
|
currentData: null as any,
|
|
routeExtra: null as Record<string, any> | null,
|
|
|
|
data: {
|
|
pageTitle: '数学练习',
|
|
functionId: '',
|
|
hasContent: false,
|
|
showShareDialog: false,
|
|
boxWidth: 0,
|
|
boxHeight: 0,
|
|
selectedTypeId: '',
|
|
typeList: TYPE_LIST,
|
|
showActions: false,
|
|
actionsTitle: '选择模式',
|
|
currentActions: [] as MathTypeAction[],
|
|
currentMode: '',
|
|
showNumberGrid: false,
|
|
numberList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
selectedNumber: 0,
|
|
isPreviewFavorite: false,
|
|
isDevEnv: false,
|
|
debugPublishVisible: false,
|
|
debugPublishLoading: false,
|
|
debugPublishMeta: null as DebugPublishMeta | null,
|
|
},
|
|
|
|
onLoad(options: { id?: string; mode?: string }) {
|
|
const routeId = options.id || MATH_TYPE_CONFIGS[0].id;
|
|
const result = findTypeByRouteId(routeId);
|
|
if (!result) return;
|
|
|
|
this.syncDebugPublishEnv();
|
|
|
|
const { typeConfig, mode, extra } = result;
|
|
const initialMode =
|
|
options.mode || mode || typeConfig.defaultMode || '';
|
|
|
|
this.currentTypeConfig = typeConfig;
|
|
this.routeExtra = extra || null;
|
|
|
|
const title = typeConfig.getTitle
|
|
? typeConfig.getTitle(initialMode)
|
|
: typeConfig.title;
|
|
|
|
this.setData({
|
|
selectedTypeId: typeConfig.id,
|
|
functionId: routeId,
|
|
pageTitle: title,
|
|
showActions: !!typeConfig.actions,
|
|
currentActions: typeConfig.actions || [],
|
|
actionsTitle: typeConfig.actionsTitle || '选择模式',
|
|
currentMode: initialMode,
|
|
showNumberGrid: !!typeConfig.hasNumberGrid,
|
|
selectedNumber: typeConfig.hasNumberGrid
|
|
? Math.floor(Math.random() * 10) + 1
|
|
: 0,
|
|
});
|
|
|
|
this.initPageInfo(routeId, title);
|
|
},
|
|
|
|
onCanvasReady(e: WechatMiniprogram.CustomEvent) {
|
|
if (!this.currentTypeConfig) return;
|
|
|
|
const typeConfig = this.currentTypeConfig;
|
|
const mode = this.data.currentMode;
|
|
|
|
this.initCanvasFromComponent(e.detail, {
|
|
createDrawService: (
|
|
canvas: Canvas,
|
|
ctx: RenderingContext,
|
|
options?: Record<string, any>,
|
|
) => typeConfig.createDrawService(canvas, ctx, options),
|
|
drawServiceOptions: {
|
|
title: this.data.pageTitle,
|
|
subTitle: typeConfig.getSubTitle
|
|
? typeConfig.getSubTitle(mode)
|
|
: typeConfig.subTitle,
|
|
functionId: this.data.functionId,
|
|
},
|
|
onCanvasReady: () => {
|
|
this.onRandom();
|
|
},
|
|
});
|
|
},
|
|
|
|
/** 切换练习类型 */
|
|
onSelectType(e: WechatMiniprogram.TouchEvent) {
|
|
const id = e.currentTarget.dataset.id as string;
|
|
if (!id || id === this.data.selectedTypeId) return;
|
|
|
|
const typeConfig = MATH_TYPE_CONFIGS.find((t) => t.id === id);
|
|
if (!typeConfig) return;
|
|
|
|
this.currentTypeConfig = typeConfig;
|
|
this.routeExtra = null;
|
|
const mode = typeConfig.defaultMode || '';
|
|
const title = typeConfig.getTitle
|
|
? typeConfig.getTitle(mode)
|
|
: typeConfig.title;
|
|
const subTitle = typeConfig.getSubTitle
|
|
? typeConfig.getSubTitle(mode)
|
|
: typeConfig.subTitle;
|
|
|
|
this.setData({
|
|
selectedTypeId: id,
|
|
functionId: id,
|
|
pageTitle: title,
|
|
isPreviewFavorite: false,
|
|
showActions: !!typeConfig.actions,
|
|
currentActions: typeConfig.actions || [],
|
|
actionsTitle: typeConfig.actionsTitle || '选择模式',
|
|
currentMode: mode,
|
|
showNumberGrid: !!typeConfig.hasNumberGrid,
|
|
selectedNumber: typeConfig.hasNumberGrid
|
|
? Math.floor(Math.random() * 10) + 1
|
|
: 0,
|
|
});
|
|
|
|
this.initPageInfo(id, title);
|
|
|
|
if (this.canvas && this.ctx) {
|
|
this.drawService = typeConfig.createDrawService(
|
|
this.canvas,
|
|
this.ctx,
|
|
{ title, subTitle, functionId: id },
|
|
);
|
|
this.onRandom();
|
|
}
|
|
},
|
|
|
|
/** 切换子选项(模式) */
|
|
onSelectMode(e: WechatMiniprogram.TouchEvent) {
|
|
const value = e.currentTarget.dataset.value as string;
|
|
if (!value || value === this.data.currentMode) return;
|
|
|
|
const typeConfig = this.currentTypeConfig;
|
|
if (!typeConfig) return;
|
|
|
|
const title = typeConfig.getTitle
|
|
? typeConfig.getTitle(value)
|
|
: typeConfig.title;
|
|
const subTitle = typeConfig.getSubTitle
|
|
? typeConfig.getSubTitle(value)
|
|
: typeConfig.subTitle;
|
|
|
|
this.setData({
|
|
currentMode: value,
|
|
pageTitle: title,
|
|
isPreviewFavorite: false,
|
|
});
|
|
|
|
this.initPageInfo(this.data.functionId, title);
|
|
|
|
if (this.drawService) {
|
|
(this.drawService as any).options.title = title;
|
|
(this.drawService as any).options.subTitle = subTitle;
|
|
}
|
|
|
|
this.onRandom();
|
|
},
|
|
|
|
/** 选择数字(numberFind 专用) */
|
|
onSelectNumber(e: WechatMiniprogram.TouchEvent) {
|
|
const number = parseInt(e.currentTarget.dataset.number);
|
|
if (isNaN(number) || number === this.data.selectedNumber) return;
|
|
this.setData({ selectedNumber: number });
|
|
this.drawCanvas();
|
|
},
|
|
|
|
/** 执行 Canvas 绘制 */
|
|
async drawCanvas() {
|
|
if (!this.ctx || !this.drawService || !this.currentData) return;
|
|
|
|
try {
|
|
const typeId = this.data.selectedTypeId;
|
|
const mode = this.data.currentMode;
|
|
|
|
if (typeId === 'number-find') {
|
|
await this.drawService.draw(this.data.selectedNumber);
|
|
} else if (
|
|
typeId === 'counting-matching' ||
|
|
typeId === 'number-coloring' ||
|
|
typeId === 'number-object-match'
|
|
) {
|
|
await this.drawService.draw(this.currentData, mode);
|
|
} else if (typeId === 'missing-number') {
|
|
await this.drawService.draw(this.currentData, mode);
|
|
} else if (typeId === 'addition') {
|
|
if (this.drawService) {
|
|
(this.drawService as any).options.title =
|
|
this.data.pageTitle;
|
|
}
|
|
await this.drawService.draw(this.currentData, mode);
|
|
} else if (typeId === 'counting-select') {
|
|
const drawMode =
|
|
this.routeExtra?.functionId === 'counting-fill'
|
|
? 'fill'
|
|
: 'select';
|
|
await this.drawService.draw(this.currentData, drawMode);
|
|
} else if (typeId === 'multiplication-table') {
|
|
await this.drawService.draw({});
|
|
} else {
|
|
await this.drawService.draw(this.currentData);
|
|
}
|
|
|
|
this.setData({ hasContent: true });
|
|
} catch (error) {
|
|
console.error('绘制失败:', error);
|
|
this.setData({ hasContent: false });
|
|
}
|
|
},
|
|
|
|
/** 随机生成数据并绘制 */
|
|
onRandom() {
|
|
if (!this.currentTypeConfig) return;
|
|
|
|
const extra = {
|
|
selectedNumber: this.data.selectedNumber,
|
|
functionId: this.data.functionId,
|
|
...this.routeExtra,
|
|
};
|
|
|
|
if (this.currentTypeConfig.hasNumberGrid) {
|
|
const num = Math.floor(Math.random() * 10) + 1;
|
|
this.setData({ selectedNumber: num });
|
|
extra.selectedNumber = num;
|
|
}
|
|
|
|
this.currentData = this.currentTypeConfig.generateData(
|
|
this.data.currentMode,
|
|
extra,
|
|
);
|
|
this.drawCanvas();
|
|
},
|
|
|
|
onPreviewRefresh() {
|
|
this.onRandom();
|
|
},
|
|
|
|
async onPreviewFavorite() {
|
|
const next = !this.data.isPreviewFavorite;
|
|
this.setData({ isPreviewFavorite: next });
|
|
if (next) {
|
|
const id = this.getWorksheetStatsId();
|
|
if (id) incrementWorksheetLikes(id);
|
|
}
|
|
wx.showToast({
|
|
title: next ? '收藏成功' : '已取消收藏',
|
|
icon: 'none',
|
|
});
|
|
},
|
|
|
|
getWorksheetStatsId(): string {
|
|
const meta = getPublishMetaByMathState(
|
|
this.data.functionId,
|
|
this.data.selectedTypeId,
|
|
this.data.currentMode,
|
|
);
|
|
return meta?.id || this.data.functionId;
|
|
},
|
|
|
|
getPublishMeta(): DebugPublishMeta {
|
|
const meta = getPublishMetaByMathState(
|
|
this.data.functionId,
|
|
this.data.selectedTypeId,
|
|
this.data.currentMode,
|
|
);
|
|
if (!meta) {
|
|
throw new Error('当前题型配置不存在');
|
|
}
|
|
return meta;
|
|
},
|
|
});
|