import NumberDecomposeDraw from '../service/numberDecomposeDraw'; import { getMathPageCommonMethods, CanvasDataState, } from '../common/mathPageMixin'; // 获取公共方法 const commonMethods = getMathPageCommonMethods({ pagePath: 'numberDecompose/numberDecompose', }); type DecomposeMode = 'with-image' | 'decompose' | 'compose'; Page({ canvas: null as Canvas | null, ctx: null as RenderingContext | null, boxHeight: 0, boxWidth: 0, drawService: null as NumberDecomposeDraw | null, decomposeData: null as { problems: Array<{ whole: number | null; // 总数(null表示组合模式需要填写) part1: number | null; // 第一个部分(null表示需要填写) part2: number | null; // 第二个部分(null表示需要填写) imageIndex?: number; // 图片索引(有图片模式需要) imageType?: 'fruits' | 'twelve-animals'; // 图片类型 }>; mode: DecomposeMode; } | null, data: { pageTitle: '10以内数的分与合', subTitle: '学习数的分解与组合', functionId: '', hasContent: false, showShareDialog: false, showTypeSelector: true, currentType: 'with-image', currentTypeName: '有图片模式', typeActions: [ { name: '有图片模式', value: 'with-image' }, { name: '分模式', value: 'decompose' }, { name: '组合模式', value: 'compose' }, ], } as CanvasDataState & { showTypeSelector: boolean; currentType: DecomposeMode; currentTypeName: string; typeActions: Array<{ name: string; value: DecomposeMode }>; }, onLoad(options: { id?: string; mode?: DecomposeMode }) { const functionId = options.id || 'number-decompose'; const mode = options.mode || 'with-image'; const currentTypeName = mode === 'with-image' ? '有图片模式' : mode === 'decompose' ? '分模式' : '组合模式'; this.setData({ currentType: mode, currentTypeName, }); this.initPageInfo(functionId, '10以内数的分与合'); }, onReady() { this.initCanvas({ createDrawService: (canvas, ctx, options) => { return new NumberDecomposeDraw(canvas, ctx, options); }, drawServiceOptions: { subTitle: this.data.subTitle, }, onCanvasReady: () => { // Canvas 初始化完成后,生成初始数据 this.onRandom(); }, }); }, /** * 绘制Canvas内容 */ async drawCanvas() { if (!this.ctx || !this.drawService || !this.decomposeData) { return; } try { await this.drawService.draw(this.decomposeData); this.setData({ hasContent: true }); } catch (error) { console.error('绘制失败:', error); this.setData({ hasContent: false }); } }, /** * 随机生成 */ onRandom() { this.generateDecomposeData(); this.drawCanvas(); }, /** * 生成分解数据(确保不重复) */ generateDecomposeData() { const mode = this.data.currentType; const problems: Array<{ whole: number | null; part1: number | null; part2: number | null; imageIndex?: number; imageType?: 'fruits' | 'twelve-animals'; }> = []; // 用于去重的 Set,存储题目唯一标识 // 格式:对于分解模式 "whole:part1:part2:showPart1",对于组合模式 "part1:part2" const usedKeys = new Set(); if (mode === 'with-image') { // 有图片模式:9个题目,一行三列,总共三行 const problemCount = 9; let attempts = 0; const maxAttempts = problemCount * 50; // 最大尝试次数 while (problems.length < problemCount && attempts < maxAttempts) { attempts++; // 生成总数(2-10) const whole = Math.floor(Math.random() * 9) + 2; // 随机选择一个部分(1 到 whole-1) const part1 = Math.floor(Math.random() * (whole - 1)) + 1; const part2 = whole - part1; // 随机决定显示 part1 还是 part2(另一个为 null) const showPart1 = Math.random() < 0.5; // 生成唯一标识(统一格式:part1 <= part2) const minPart = Math.min(part1, part2); const maxPart = Math.max(part1, part2); const key = `${whole}:${minPart}:${maxPart}:${showPart1}`; // 检查是否已存在 if (usedKeys.has(key)) { continue; } usedKeys.add(key); // 随机选择图片类型和索引 const imageType: 'fruits' | 'twelve-animals' = Math.random() < 0.5 ? 'fruits' : 'twelve-animals'; const maxImageIndex = imageType === 'fruits' ? 22 : 12; const imageIndex = Math.floor(Math.random() * maxImageIndex) + 1; problems.push({ whole, part1: showPart1 ? part1 : null, part2: showPart1 ? null : part2, imageIndex, imageType, }); } } else if (mode === 'decompose') { // 分模式:15个题目,一行3个,总共5行 const problemCount = 15; let attempts = 0; const maxAttempts = problemCount * 50; // 最大尝试次数 while (problems.length < problemCount && attempts < maxAttempts) { attempts++; // 生成总数(2-10) const whole = Math.floor(Math.random() * 9) + 2; // 随机选择一个部分(1 到 whole-1) const part1 = Math.floor(Math.random() * (whole - 1)) + 1; const part2 = whole - part1; // 随机决定显示 part1 还是 part2(另一个为 null) const showPart1 = Math.random() < 0.5; // 生成唯一标识(统一格式:part1 <= part2) const minPart = Math.min(part1, part2); const maxPart = Math.max(part1, part2); const key = `${whole}:${minPart}:${maxPart}:${showPart1}`; // 检查是否已存在 if (usedKeys.has(key)) { continue; } usedKeys.add(key); problems.push({ whole, part1: showPart1 ? part1 : null, part2: showPart1 ? null : part2, }); } } else if (mode === 'compose') { // 组合模式:15个题目,一行3个,总共5行 const problemCount = 15; let attempts = 0; const maxAttempts = problemCount * 50; // 最大尝试次数 while (problems.length < problemCount && attempts < maxAttempts) { attempts++; // 生成总数(2-10) const whole = Math.floor(Math.random() * 9) + 2; // 随机选择一个部分(1 到 whole-1) const part1 = Math.floor(Math.random() * (whole - 1)) + 1; const part2 = whole - part1; // 生成唯一标识(统一格式:part1 <= part2) const minPart = Math.min(part1, part2); const maxPart = Math.max(part1, part2); const key = `${minPart}:${maxPart}`; // 检查是否已存在 if (usedKeys.has(key)) { continue; } usedKeys.add(key); // 组合模式:两个部分都显示,根节点为 null problems.push({ whole: null, // 根节点需要填写 part1, part2, }); } } this.decomposeData = { problems, mode }; }, // ========== 使用公共方法 ========== initCanvas: commonMethods.initCanvas, exportToPrint: commonMethods.exportToPrint, onShareAppMessage: commonMethods.onShareAppMessage, onShareTimeline: commonMethods.onShareTimeline, onCloseShareDialog: commonMethods.onCloseShareDialog, onShareSuccess: commonMethods.onShareSuccess, initPageInfo: commonMethods.initPageInfo, /** 选择类型 */ onSelectType(event: any) { const { name, value } = event.detail; this.setData({ currentType: value, currentTypeName: name, }); // 重新生成数据 this.onRandom(); }, });