feat:添加埋点,createPage 重构
This commit is contained in:
@@ -60,7 +60,7 @@
|
||||
"pagePath": "pages/mathIndex/mathIndex",
|
||||
"iconPath": "assets/tabBar/icon-math.png",
|
||||
"selectedIconPath": "assets/tabBar/icon-math-active.png",
|
||||
"text": "数学"
|
||||
"text": "数感启蒙"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/index/index",
|
||||
|
||||
+4
-4
@@ -2,19 +2,19 @@ import config from './config/config';
|
||||
|
||||
const defaultPrintConfig: PrintConfig = config.printHeader as PrintConfig;
|
||||
|
||||
|
||||
// app.ts
|
||||
App<IAppOption>({
|
||||
globalData: {
|
||||
env: 'release',
|
||||
printConfig: defaultPrintConfig
|
||||
printConfig: defaultPrintConfig,
|
||||
},
|
||||
onLaunch() {
|
||||
const accountInfo = wx.getAccountInfoSync();
|
||||
const env = accountInfo.miniProgram.envVersion || 'release';
|
||||
this.globalData.env = env;
|
||||
if (env !== 'release') {
|
||||
const printConfig = wx.getStorageSync('printConfig') || defaultPrintConfig;
|
||||
const printConfig =
|
||||
wx.getStorageSync('printConfig') || defaultPrintConfig;
|
||||
this.globalData.printConfig = printConfig;
|
||||
}
|
||||
},
|
||||
@@ -34,5 +34,5 @@ App<IAppOption>({
|
||||
setPrintConfig(config: PrintConfig) {
|
||||
this.globalData.printConfig = config;
|
||||
wx.setStorageSync('printConfig', config);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { PAPER_SIZE } from '../../constants/colors';
|
||||
import { checkAndSaveImage } from '../../utils/saveImage';
|
||||
import { shouldShowShareGuide } from '../../utils/shareGuide';
|
||||
import AdditionDraw from '../service/additionDraw';
|
||||
import {
|
||||
MATH_FUNCTION_TYPES,
|
||||
MathFunctionType,
|
||||
} from '../../constants/mathFunctions';
|
||||
import { applyMathPageMixin, CanvasDataState } from '../common/mathPageMixin';
|
||||
|
||||
Page({
|
||||
Page(
|
||||
applyMathPageMixin(
|
||||
{
|
||||
canvas: null as Canvas | null,
|
||||
ctx: null as RenderingContext | null,
|
||||
boxHeight: 0,
|
||||
@@ -24,6 +20,7 @@ Page({
|
||||
|
||||
data: {
|
||||
pageTitle: '加减法计算',
|
||||
subTitle: '通过图形化方式学习加减法运算',
|
||||
functionId: '',
|
||||
hasContent: false,
|
||||
showShareDialog: false,
|
||||
@@ -36,19 +33,16 @@ Page({
|
||||
{ name: '10以内加减法', value: 'addition-subtraction-10' },
|
||||
],
|
||||
imageType: 'twelve-animals', // 图片类型:twelve-animals 或 fruits
|
||||
} as CanvasDataState & {
|
||||
currentType: string;
|
||||
currentTypeName: string;
|
||||
typeActions: Array<{ name: string; value: string }>;
|
||||
imageType: string;
|
||||
},
|
||||
|
||||
onLoad(options: { id?: string }) {
|
||||
const functionId = options.id || 'addition-5';
|
||||
this.setData({ functionId });
|
||||
|
||||
const functionItem = MATH_FUNCTION_TYPES.find(
|
||||
(item: MathFunctionType) => item.id === functionId,
|
||||
);
|
||||
|
||||
const pageTitle = functionItem?.title || '加减法计算';
|
||||
this.setData({ pageTitle });
|
||||
wx.setNavigationBarTitle({ title: pageTitle });
|
||||
this.initPageInfo(functionId, '加减法计算');
|
||||
|
||||
// 根据 functionId 设置默认类型
|
||||
if (functionId === 'addition-5') {
|
||||
@@ -75,59 +69,22 @@ Page({
|
||||
},
|
||||
|
||||
onReady() {
|
||||
this.initCanvas();
|
||||
this.initCanvas({
|
||||
createDrawService: (
|
||||
canvas: Canvas,
|
||||
ctx: RenderingContext,
|
||||
options?: Record<string, any>,
|
||||
) => {
|
||||
return new AdditionDraw(canvas, ctx, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化Canvas
|
||||
*/
|
||||
initCanvas() {
|
||||
const query = wx.createSelectorQuery();
|
||||
query
|
||||
.select('#canvasWrapper')
|
||||
.boundingClientRect((rect) => {
|
||||
if (rect) {
|
||||
const { width, height } = PAPER_SIZE['A4'];
|
||||
const boxWidth = rect.width;
|
||||
const boxHeight = boxWidth / (width / height);
|
||||
|
||||
this.boxHeight = boxHeight;
|
||||
this.boxWidth = boxWidth;
|
||||
|
||||
this.setData({ boxWidth, boxHeight });
|
||||
|
||||
const canvas = wx
|
||||
.createSelectorQuery()
|
||||
.select('#canvasContent');
|
||||
canvas.fields({ node: true, size: true }).exec((res) => {
|
||||
if (res[0]) {
|
||||
const canvasNode = res[0].node;
|
||||
const ctx = canvasNode.getContext('2d');
|
||||
const dpr = wx.getSystemInfoSync().pixelRatio;
|
||||
|
||||
canvasNode.width = boxWidth * dpr;
|
||||
canvasNode.height = boxHeight * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
|
||||
this.canvas = canvasNode;
|
||||
this.ctx = ctx;
|
||||
|
||||
this.drawService = new AdditionDraw(
|
||||
canvasNode,
|
||||
ctx,
|
||||
{
|
||||
title: this.data.currentTypeName,
|
||||
subTitle: '通过图形化方式学习加减法运算',
|
||||
drawServiceOptions: {
|
||||
subTitle: this.data.subTitle,
|
||||
},
|
||||
);
|
||||
|
||||
onCanvasReady: () => {
|
||||
// 初始随机生成
|
||||
this.onRandom();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -141,7 +98,8 @@ Page({
|
||||
try {
|
||||
// 更新 Header 的 Title
|
||||
if (this.drawService) {
|
||||
this.drawService.options.title = this.data.currentTypeName;
|
||||
this.drawService.options.title =
|
||||
this.data.currentTypeName;
|
||||
}
|
||||
|
||||
await this.drawService.draw(
|
||||
@@ -168,26 +126,38 @@ Page({
|
||||
|
||||
const type = this.data.currentType;
|
||||
|
||||
// 生成6道题目
|
||||
// 生成5道题目
|
||||
for (let i = 0; i < 5; i++) {
|
||||
if (type === 'addition-5') {
|
||||
// 5以内加法:和 ≤ 5
|
||||
// left >= 1, right >= 1, left + right <= 5
|
||||
const maxSum = 5;
|
||||
const left = Math.floor(Math.random() * (maxSum - 1)) + 1; // 1 到 4
|
||||
const left =
|
||||
Math.floor(Math.random() * (maxSum - 1)) + 1; // 1 到 4
|
||||
const maxRight = maxSum - left; // 确保 left + right <= 5
|
||||
const right = Math.floor(Math.random() * maxRight) + 1; // 1 到 maxRight
|
||||
const result = left + right;
|
||||
problems.push({ type: 'addition', left, right, result });
|
||||
problems.push({
|
||||
type: 'addition',
|
||||
left,
|
||||
right,
|
||||
result,
|
||||
});
|
||||
} else if (type === 'addition-10') {
|
||||
// 10以内加法:和 ≤ 10
|
||||
// left >= 1, right >= 1, left + right <= 10
|
||||
const maxSum = 10;
|
||||
const left = Math.floor(Math.random() * (maxSum - 1)) + 1; // 1 到 9
|
||||
const left =
|
||||
Math.floor(Math.random() * (maxSum - 1)) + 1; // 1 到 9
|
||||
const maxRight = maxSum - left; // 确保 left + right <= 10
|
||||
const right = Math.floor(Math.random() * maxRight) + 1; // 1 到 maxRight
|
||||
const result = left + right;
|
||||
problems.push({ type: 'addition', left, right, result });
|
||||
problems.push({
|
||||
type: 'addition',
|
||||
left,
|
||||
right,
|
||||
result,
|
||||
});
|
||||
} else if (type === 'subtraction-10') {
|
||||
// 10以内减法:被减数 ≤ 10
|
||||
// left <= 10, left - right = result, result >= 1
|
||||
@@ -196,25 +166,44 @@ Page({
|
||||
const maxRight = left - 1; // 确保 result >= 1
|
||||
const right = Math.floor(Math.random() * maxRight) + 1; // 1 到 maxRight
|
||||
const result = left - right;
|
||||
problems.push({ type: 'subtraction', left, right, result });
|
||||
problems.push({
|
||||
type: 'subtraction',
|
||||
left,
|
||||
right,
|
||||
result,
|
||||
});
|
||||
} else if (type === 'addition-subtraction-10') {
|
||||
// 加减法混合
|
||||
if (Math.random() < 0.5) {
|
||||
// 加法:和 ≤ 10
|
||||
const maxSum = 10;
|
||||
const left = Math.floor(Math.random() * (maxSum - 1)) + 1; // 1 到 9
|
||||
const left =
|
||||
Math.floor(Math.random() * (maxSum - 1)) + 1; // 1 到 9
|
||||
const maxRight = maxSum - left; // 确保 left + right <= 10
|
||||
const right = Math.floor(Math.random() * maxRight) + 1; // 1 到 maxRight
|
||||
const right =
|
||||
Math.floor(Math.random() * maxRight) + 1; // 1 到 maxRight
|
||||
const result = left + right;
|
||||
problems.push({ type: 'addition', left, right, result });
|
||||
problems.push({
|
||||
type: 'addition',
|
||||
left,
|
||||
right,
|
||||
result,
|
||||
});
|
||||
} else {
|
||||
// 减法:被减数 ≤ 10
|
||||
const maxLeft = 10;
|
||||
const left = Math.floor(Math.random() * maxLeft) + 1; // 1 到 10
|
||||
const left =
|
||||
Math.floor(Math.random() * maxLeft) + 1; // 1 到 10
|
||||
const maxRight = left - 1; // 确保 result >= 1
|
||||
const right = Math.floor(Math.random() * maxRight) + 1; // 1 到 maxRight
|
||||
const right =
|
||||
Math.floor(Math.random() * maxRight) + 1; // 1 到 maxRight
|
||||
const result = left - right;
|
||||
problems.push({ type: 'subtraction', left, right, result });
|
||||
problems.push({
|
||||
type: 'subtraction',
|
||||
left,
|
||||
right,
|
||||
result,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,56 +212,6 @@ Page({
|
||||
this.drawCanvas();
|
||||
},
|
||||
|
||||
/**
|
||||
* 导出打印
|
||||
*/
|
||||
exportToPrint() {
|
||||
if (!this.canvas || !this.data.hasContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldShowShareGuide()) {
|
||||
this.setData({ showShareDialog: true });
|
||||
return;
|
||||
}
|
||||
|
||||
checkAndSaveImage(this.canvas);
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享小程序
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '涂鸦丫-数学学习涂鸦卡',
|
||||
path: `/mathPages/addition/addition?id=${this.data.functionId}`,
|
||||
imageUrl:
|
||||
'https://cdn.joeyone.cn/doodle/share-img/index-share-v2.png',
|
||||
};
|
||||
},
|
||||
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: '涂鸦丫-数学学习涂鸦卡',
|
||||
query: `id=${this.data.functionId}`,
|
||||
imageUrl:
|
||||
'https://cdn.joeyone.cn/doodle/share-img/index-share-v2.png',
|
||||
};
|
||||
},
|
||||
|
||||
/** 关闭分享引导弹窗 */
|
||||
onCloseShareDialog() {
|
||||
this.setData({ showShareDialog: false });
|
||||
},
|
||||
|
||||
/** 分享成功回调 */
|
||||
onShareSuccess() {
|
||||
this.setData({ showShareDialog: false });
|
||||
if (this.canvas) {
|
||||
checkAndSaveImage(this.canvas);
|
||||
}
|
||||
},
|
||||
|
||||
/** 选择类型 */
|
||||
onSelectType(event: any) {
|
||||
const { name, value } = event.detail;
|
||||
@@ -283,4 +222,9 @@ Page({
|
||||
// 重新生成数据
|
||||
this.onRandom();
|
||||
},
|
||||
});
|
||||
},
|
||||
{
|
||||
pagePath: 'addition/addition',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
MATH_FUNCTION_TYPES,
|
||||
MathFunctionType,
|
||||
} from '../../constants/mathFunctions';
|
||||
import tracker from '../../utils/tracker';
|
||||
|
||||
/**
|
||||
* Canvas 相关的页面实例属性
|
||||
@@ -16,6 +17,7 @@ export interface MathPageCanvasInstance {
|
||||
boxHeight: number;
|
||||
boxWidth: number;
|
||||
drawService: BaseMathDrawService | null;
|
||||
setData(data: any, callback?: () => void): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,11 +65,16 @@ export interface ShareOptions {
|
||||
pagePath: string;
|
||||
}
|
||||
|
||||
const shareConfig = {
|
||||
title: '涂鸦丫-数学学习涂鸦卡',
|
||||
imageUrl: 'https://cdn.joeyone.cn/doodle/share-img/index-share-v2.png',
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取数学页面的公共方法
|
||||
* 这些方法可以在所有数学页面中复用
|
||||
*/
|
||||
export function getMathPageCommonMethods(shareOptions: ShareOptions) {
|
||||
export function getMathPageCommonMethods() {
|
||||
return {
|
||||
/**
|
||||
* 初始化 Canvas
|
||||
@@ -76,6 +83,7 @@ export function getMathPageCommonMethods(shareOptions: ShareOptions) {
|
||||
this: MathPageCanvasInstance & { data: CanvasDataState },
|
||||
options: InitCanvasOptions,
|
||||
) {
|
||||
console.log('initCanvas this', this);
|
||||
const query = wx.createSelectorQuery();
|
||||
query
|
||||
.select('#canvasWrapper')
|
||||
@@ -145,6 +153,9 @@ export function getMathPageCommonMethods(shareOptions: ShareOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 上报下载埋点
|
||||
tracker.reportDownload(this.data.pageTitle);
|
||||
|
||||
checkAndSaveImage(this.canvas);
|
||||
},
|
||||
|
||||
@@ -154,11 +165,13 @@ export function getMathPageCommonMethods(shareOptions: ShareOptions) {
|
||||
onShareAppMessage(
|
||||
this: MathPageCanvasInstance & { data: CanvasDataState },
|
||||
) {
|
||||
console.log('onShareAppMessage');
|
||||
// 上报分享埋点
|
||||
tracker.reportShare(this.data.pageTitle);
|
||||
|
||||
return {
|
||||
title: '涂鸦丫-数学学习涂鸦卡',
|
||||
path: `/mathPages/${shareOptions.pagePath}?id=${this.data.functionId}`,
|
||||
imageUrl:
|
||||
'https://cdn.joeyone.cn/doodle/share-img/index-share-v2.png',
|
||||
...shareConfig,
|
||||
query: `id=${this.data.functionId}`,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -168,11 +181,13 @@ export function getMathPageCommonMethods(shareOptions: ShareOptions) {
|
||||
onShareTimeline(
|
||||
this: MathPageCanvasInstance & { data: CanvasDataState },
|
||||
) {
|
||||
console.log('onShareTimeline');
|
||||
// 上报分享埋点
|
||||
tracker.reportShare(this.data.pageTitle);
|
||||
|
||||
return {
|
||||
title: '涂鸦丫-数学学习涂鸦卡',
|
||||
...shareConfig,
|
||||
query: `id=${this.data.functionId}`,
|
||||
imageUrl:
|
||||
'https://cdn.joeyone.cn/doodle/share-img/index-share-v2.png',
|
||||
};
|
||||
},
|
||||
|
||||
@@ -193,6 +208,8 @@ export function getMathPageCommonMethods(shareOptions: ShareOptions) {
|
||||
) {
|
||||
this.setData({ showShareDialog: false });
|
||||
if (this.canvas) {
|
||||
// 上报下载埋点(分享成功后下载)
|
||||
tracker.reportDownload(this.data.pageTitle);
|
||||
checkAndSaveImage(this.canvas);
|
||||
}
|
||||
},
|
||||
@@ -222,3 +239,40 @@ export function getMathPageCommonMethods(shareOptions: ShareOptions) {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用数学页面公共方法的辅助函数
|
||||
* 自动混入公共方法,简化页面代码
|
||||
* @param pageOptions 页面选项
|
||||
* @param shareOptions 分享配置选项
|
||||
* @returns 合并后的页面选项
|
||||
*/
|
||||
export function applyMathPageMixin(pageOptions: any) {
|
||||
const commonMethods = getMathPageCommonMethods();
|
||||
|
||||
// 提取 pageOptions 中的 data(如果有)
|
||||
const pageData = pageOptions.data || {};
|
||||
|
||||
// 合并页面选项和公共方法
|
||||
// 注意:pageOptions 放在后面,这样页面可以覆盖公共方法
|
||||
const mergedOptions: any = {
|
||||
...commonMethods,
|
||||
...pageOptions,
|
||||
// 处理 data 的合并(需要特殊处理,避免覆盖)
|
||||
data: {
|
||||
...pageData,
|
||||
},
|
||||
};
|
||||
|
||||
return mergedOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建数学页面的便捷函数
|
||||
* 自动应用公共方法并注册为页面
|
||||
* 页面路径从函数调用栈自动推断(从调用文件路径提取)
|
||||
* @param pageOptions 页面选项
|
||||
*/
|
||||
export function createMathPage(pageOptions: any) {
|
||||
Page(applyMathPageMixin(pageOptions));
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { PAPER_SIZE } from '../../constants/colors';
|
||||
import { checkAndSaveImage } from '../../utils/saveImage';
|
||||
import { shouldShowShareGuide } from '../../utils/shareGuide';
|
||||
import CountMatchDraw from '../service/countMatchDraw';
|
||||
import NumberColorDraw from '../service/numberColorDraw';
|
||||
import {
|
||||
MATH_FUNCTION_TYPES,
|
||||
MathFunctionType,
|
||||
} from '../../constants/mathFunctions';
|
||||
import { applyMathPageMixin, CanvasDataState } from '../common/mathPageMixin';
|
||||
|
||||
Page({
|
||||
Page(
|
||||
applyMathPageMixin(
|
||||
{
|
||||
canvas: null as Canvas | null,
|
||||
ctx: null as RenderingContext | null,
|
||||
boxHeight: 0,
|
||||
@@ -34,19 +30,25 @@ Page({
|
||||
{ name: '十二生肖', value: 'twelve-animals' },
|
||||
{ name: '水果', value: 'fruits' },
|
||||
],
|
||||
} as CanvasDataState & {
|
||||
showTypeSelector: boolean;
|
||||
currentType: string;
|
||||
currentTypeName: string;
|
||||
typeActions: Array<{ name: string; value: string }>;
|
||||
},
|
||||
|
||||
onLoad(options: { id?: string }) {
|
||||
const functionId = options.id || 'counting-matching';
|
||||
this.setData({ functionId });
|
||||
|
||||
const functionItem = MATH_FUNCTION_TYPES.find(
|
||||
(item: MathFunctionType) => item.id === functionId,
|
||||
const functionItem =
|
||||
require('../../constants/mathFunctions').MATH_FUNCTION_TYPES.find(
|
||||
(item: any) => item.id === functionId,
|
||||
);
|
||||
|
||||
const pageTitle = functionItem?.title || '数一数,连一连';
|
||||
this.setData({ pageTitle });
|
||||
wx.setNavigationBarTitle({ title: pageTitle });
|
||||
this.initPageInfo(functionId, pageTitle);
|
||||
|
||||
// 根据 functionId 设置不同的类型选择器
|
||||
if (functionId === 'number-coloring') {
|
||||
@@ -62,72 +64,30 @@ Page({
|
||||
},
|
||||
|
||||
onReady() {
|
||||
this.initCanvas();
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化Canvas
|
||||
*/
|
||||
initCanvas() {
|
||||
const query = wx.createSelectorQuery();
|
||||
query
|
||||
.select('#canvasWrapper')
|
||||
.boundingClientRect((rect) => {
|
||||
if (rect) {
|
||||
const { width, height } = PAPER_SIZE['A4'];
|
||||
const boxWidth = rect.width;
|
||||
const boxHeight = boxWidth / (width / height);
|
||||
|
||||
this.boxHeight = boxHeight;
|
||||
this.boxWidth = boxWidth;
|
||||
|
||||
this.setData({ boxWidth, boxHeight });
|
||||
|
||||
const canvas = wx
|
||||
.createSelectorQuery()
|
||||
.select('#canvasContent');
|
||||
canvas.fields({ node: true, size: true }).exec((res) => {
|
||||
if (res[0]) {
|
||||
const canvasNode = res[0].node;
|
||||
const ctx = canvasNode.getContext('2d');
|
||||
const dpr = wx.getSystemInfoSync().pixelRatio;
|
||||
|
||||
canvasNode.width = boxWidth * dpr;
|
||||
canvasNode.height = boxHeight * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
|
||||
this.canvas = canvasNode;
|
||||
this.ctx = ctx;
|
||||
|
||||
this.initCanvas({
|
||||
createDrawService: (
|
||||
canvas: Canvas,
|
||||
ctx: RenderingContext,
|
||||
options?: Record<string, any>,
|
||||
) => {
|
||||
// 根据 functionId 创建不同的绘制服务
|
||||
if (this.data.functionId === 'number-coloring') {
|
||||
this.drawService = new NumberColorDraw(
|
||||
canvasNode,
|
||||
ctx,
|
||||
{
|
||||
title: this.data.pageTitle,
|
||||
subTitle: '按数字给相应的圆圈涂上颜色',
|
||||
},
|
||||
);
|
||||
return new NumberColorDraw(canvas, ctx, options);
|
||||
} else {
|
||||
this.drawService = new CountMatchDraw(
|
||||
canvasNode,
|
||||
ctx,
|
||||
{
|
||||
title: this.data.pageTitle,
|
||||
subTitle:
|
||||
'通过连线配对数字和对应的数量图形',
|
||||
},
|
||||
);
|
||||
return new CountMatchDraw(canvas, ctx, options);
|
||||
}
|
||||
|
||||
},
|
||||
drawServiceOptions: {
|
||||
subTitle:
|
||||
this.data.functionId === 'number-coloring'
|
||||
? '按数字给相应的圆圈涂上颜色'
|
||||
: '通过连线配对数字和对应的数量图形',
|
||||
},
|
||||
onCanvasReady: () => {
|
||||
// 初始随机生成
|
||||
this.onRandom();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -179,7 +139,10 @@ Page({
|
||||
const randomIndex = Math.floor(
|
||||
Math.random() * availableNumbers.length,
|
||||
);
|
||||
const number = availableNumbers.splice(randomIndex, 1)[0];
|
||||
const number = availableNumbers.splice(
|
||||
randomIndex,
|
||||
1,
|
||||
)[0];
|
||||
numbers.push(number);
|
||||
}
|
||||
|
||||
@@ -196,7 +159,10 @@ Page({
|
||||
const randomIndex = Math.floor(
|
||||
Math.random() * availableNumbers.length,
|
||||
);
|
||||
const number = availableNumbers.splice(randomIndex, 1)[0];
|
||||
const number = availableNumbers.splice(
|
||||
randomIndex,
|
||||
1,
|
||||
)[0];
|
||||
leftNumbers.push(number);
|
||||
}
|
||||
|
||||
@@ -216,56 +182,6 @@ Page({
|
||||
this.drawCanvas();
|
||||
},
|
||||
|
||||
/**
|
||||
* 导出打印
|
||||
*/
|
||||
exportToPrint() {
|
||||
if (!this.canvas || !this.data.hasContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldShowShareGuide()) {
|
||||
this.setData({ showShareDialog: true });
|
||||
return;
|
||||
}
|
||||
|
||||
checkAndSaveImage(this.canvas);
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享小程序
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '涂鸦丫-数学学习涂鸦卡',
|
||||
path: `/mathPages/countMatch/countMatch?id=${this.data.functionId}`,
|
||||
imageUrl:
|
||||
'https://cdn.joeyone.cn/doodle/share-img/index-share-v2.png',
|
||||
};
|
||||
},
|
||||
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: '涂鸦丫-数学学习涂鸦卡',
|
||||
query: `id=${this.data.functionId}`,
|
||||
imageUrl:
|
||||
'https://cdn.joeyone.cn/doodle/share-img/index-share-v2.png',
|
||||
};
|
||||
},
|
||||
|
||||
/** 关闭分享引导弹窗 */
|
||||
onCloseShareDialog() {
|
||||
this.setData({ showShareDialog: false });
|
||||
},
|
||||
|
||||
/** 分享成功回调 */
|
||||
onShareSuccess() {
|
||||
this.setData({ showShareDialog: false });
|
||||
if (this.canvas) {
|
||||
checkAndSaveImage(this.canvas);
|
||||
}
|
||||
},
|
||||
|
||||
/** 选择类型 */
|
||||
onSelectType(event: any) {
|
||||
const { name, value } = event.detail;
|
||||
@@ -276,4 +192,9 @@ Page({
|
||||
// 重新生成数据
|
||||
this.onRandom();
|
||||
},
|
||||
});
|
||||
},
|
||||
{
|
||||
pagePath: 'countMatch/countMatch',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import CountingSelectDraw from '../service/countingSelectDraw';
|
||||
import {
|
||||
getMathPageCommonMethods,
|
||||
CanvasDataState,
|
||||
} from '../common/mathPageMixin';
|
||||
import { applyMathPageMixin, CanvasDataState } from '../common/mathPageMixin';
|
||||
|
||||
// 获取公共方法
|
||||
const commonMethods = getMathPageCommonMethods({
|
||||
pagePath: 'countingSelect/countingSelect',
|
||||
});
|
||||
|
||||
Page({
|
||||
Page(
|
||||
applyMathPageMixin(
|
||||
{
|
||||
canvas: null as Canvas | null,
|
||||
ctx: null as RenderingContext | null,
|
||||
boxHeight: 0,
|
||||
@@ -31,7 +25,12 @@ Page({
|
||||
functionId: '',
|
||||
hasContent: false,
|
||||
showShareDialog: false,
|
||||
} as CanvasDataState,
|
||||
} as CanvasDataState & {
|
||||
showTypeSelector?: boolean;
|
||||
currentType?: string;
|
||||
currentTypeName?: string;
|
||||
typeActions?: Array<{ name: string; value: any }>;
|
||||
},
|
||||
|
||||
onLoad(options: { id?: string }) {
|
||||
const functionId = options.id || 'counting-select';
|
||||
@@ -41,7 +40,11 @@ Page({
|
||||
|
||||
onReady() {
|
||||
this.initCanvas({
|
||||
createDrawService: (canvas, ctx, options) => {
|
||||
createDrawService: (
|
||||
canvas: Canvas,
|
||||
ctx: RenderingContext,
|
||||
options?: Record<string, any>,
|
||||
) => {
|
||||
return new CountingSelectDraw(canvas, ctx, options);
|
||||
},
|
||||
drawServiceOptions: {
|
||||
@@ -58,14 +61,20 @@ Page({
|
||||
* 绘制Canvas内容
|
||||
*/
|
||||
async drawCanvas() {
|
||||
if (!this.ctx || !this.drawService || !this.countingSelectData) {
|
||||
if (
|
||||
!this.ctx ||
|
||||
!this.drawService ||
|
||||
!this.countingSelectData
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 判断是选一选还是填一填模式
|
||||
const mode =
|
||||
this.data.functionId === 'counting-fill' ? 'fill' : 'select';
|
||||
this.data.functionId === 'counting-fill'
|
||||
? 'fill'
|
||||
: 'select';
|
||||
await this.drawService.draw(this.countingSelectData, mode);
|
||||
this.setData({ hasContent: true });
|
||||
} catch (error) {
|
||||
@@ -108,7 +117,8 @@ Page({
|
||||
const count = Math.floor(Math.random() * 10) + 1;
|
||||
|
||||
// 随机选择图片索引
|
||||
const imageIndex = Math.floor(Math.random() * maxImageIndex) + 1;
|
||||
const imageIndex =
|
||||
Math.floor(Math.random() * maxImageIndex) + 1;
|
||||
|
||||
const problem: {
|
||||
count: number;
|
||||
@@ -134,7 +144,8 @@ Page({
|
||||
// 生成错误答案(与正确答案不同)
|
||||
let wrongAnswer: number;
|
||||
do {
|
||||
wrongAnswer = Math.floor(Math.random() * 10) + 1;
|
||||
wrongAnswer =
|
||||
Math.floor(Math.random() * 10) + 1;
|
||||
} while (wrongAnswer === count);
|
||||
options.push(wrongAnswer);
|
||||
}
|
||||
@@ -149,13 +160,9 @@ Page({
|
||||
|
||||
this.countingSelectData = { problems };
|
||||
},
|
||||
|
||||
// ========== 使用公共方法 ==========
|
||||
initCanvas: commonMethods.initCanvas,
|
||||
exportToPrint: commonMethods.exportToPrint,
|
||||
onShareAppMessage: commonMethods.onShareAppMessage,
|
||||
onShareTimeline: commonMethods.onShareTimeline,
|
||||
onCloseShareDialog: commonMethods.onCloseShareDialog,
|
||||
onShareSuccess: commonMethods.onShareSuccess,
|
||||
initPageInfo: commonMethods.initPageInfo,
|
||||
});
|
||||
},
|
||||
{
|
||||
pagePath: 'countingSelect/countingSelect',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
import { getRandomNumberColor } from '../../constants/colors';
|
||||
import MissingNumberDraw from '../service/missingNumberDraw';
|
||||
import {
|
||||
getMathPageCommonMethods,
|
||||
CanvasDataState,
|
||||
} from '../common/mathPageMixin';
|
||||
import { applyMathPageMixin, CanvasDataState } from '../common/mathPageMixin';
|
||||
|
||||
// 获取公共方法
|
||||
const commonMethods = getMathPageCommonMethods({
|
||||
pagePath: 'missingNumber/missingNumber',
|
||||
});
|
||||
|
||||
Page({
|
||||
Page(
|
||||
applyMathPageMixin(
|
||||
{
|
||||
canvas: null as Canvas | null,
|
||||
ctx: null as RenderingContext | null,
|
||||
boxHeight: 0,
|
||||
@@ -56,7 +50,11 @@ Page({
|
||||
|
||||
onReady() {
|
||||
this.initCanvas({
|
||||
createDrawService: (canvas, ctx, options) => {
|
||||
createDrawService: (
|
||||
canvas: Canvas,
|
||||
ctx: RenderingContext,
|
||||
options?: Record<string, any>,
|
||||
) => {
|
||||
return new MissingNumberDraw(canvas, ctx, options);
|
||||
},
|
||||
drawServiceOptions: {
|
||||
@@ -129,7 +127,8 @@ Page({
|
||||
gridCount: 1,
|
||||
},
|
||||
};
|
||||
const { gridCount } = gridMap[maxNumber as keyof typeof gridMap];
|
||||
const { gridCount } =
|
||||
gridMap[maxNumber as keyof typeof gridMap];
|
||||
|
||||
// 生成多个网格
|
||||
for (let gridIndex = 0; gridIndex < gridCount; gridIndex++) {
|
||||
@@ -156,13 +155,13 @@ Page({
|
||||
hiddenIndices.add(randomIndex);
|
||||
}
|
||||
|
||||
const gridNumbers: (number | null)[] = numbers.map((num, index) =>
|
||||
hiddenIndices.has(index) ? null : num,
|
||||
const gridNumbers: (number | null)[] = numbers.map(
|
||||
(num, index) => (hiddenIndices.has(index) ? null : num),
|
||||
);
|
||||
|
||||
// 为每个数字分配颜色(包括null位置)
|
||||
const gridColors: (string | null)[] = gridNumbers.map((num) =>
|
||||
num ? this.getRandomNumberColor() : null,
|
||||
const gridColors: (string | null)[] = gridNumbers.map(
|
||||
(num) => (num ? this.getRandomNumberColor() : null),
|
||||
);
|
||||
|
||||
grids.push({ numbers: gridNumbers, colors: gridColors });
|
||||
@@ -181,15 +180,6 @@ Page({
|
||||
return getRandomNumberColor();
|
||||
},
|
||||
|
||||
// ========== 使用公共方法 ==========
|
||||
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;
|
||||
@@ -200,4 +190,9 @@ Page({
|
||||
// 重新生成数据
|
||||
this.onRandom();
|
||||
},
|
||||
});
|
||||
},
|
||||
{
|
||||
pagePath: 'missingNumber/missingNumber',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
import NumberDecomposeDraw from '../service/numberDecomposeDraw';
|
||||
import {
|
||||
getMathPageCommonMethods,
|
||||
CanvasDataState,
|
||||
} from '../common/mathPageMixin';
|
||||
|
||||
// 获取公共方法
|
||||
const commonMethods = getMathPageCommonMethods({
|
||||
pagePath: 'numberDecompose/numberDecompose',
|
||||
});
|
||||
import { applyMathPageMixin, CanvasDataState } from '../common/mathPageMixin';
|
||||
|
||||
type DecomposeMode = 'with-image' | 'decompose' | 'compose';
|
||||
|
||||
Page({
|
||||
Page(
|
||||
applyMathPageMixin(
|
||||
{
|
||||
canvas: null as Canvas | null,
|
||||
ctx: null as RenderingContext | null,
|
||||
boxHeight: 0,
|
||||
@@ -67,7 +61,11 @@ Page({
|
||||
|
||||
onReady() {
|
||||
this.initCanvas({
|
||||
createDrawService: (canvas, ctx, options) => {
|
||||
createDrawService: (
|
||||
canvas: Canvas,
|
||||
ctx: RenderingContext,
|
||||
options?: Record<string, any>,
|
||||
) => {
|
||||
return new NumberDecomposeDraw(canvas, ctx, options);
|
||||
},
|
||||
drawServiceOptions: {
|
||||
@@ -128,13 +126,17 @@ Page({
|
||||
let attempts = 0;
|
||||
const maxAttempts = problemCount * 50; // 最大尝试次数
|
||||
|
||||
while (problems.length < problemCount && attempts < maxAttempts) {
|
||||
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 part1 =
|
||||
Math.floor(Math.random() * (whole - 1)) + 1;
|
||||
const part2 = whole - part1;
|
||||
|
||||
// 随机决定显示 part1 还是 part2(另一个为 null)
|
||||
@@ -173,13 +175,17 @@ Page({
|
||||
let attempts = 0;
|
||||
const maxAttempts = problemCount * 50; // 最大尝试次数
|
||||
|
||||
while (problems.length < problemCount && attempts < maxAttempts) {
|
||||
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 part1 =
|
||||
Math.floor(Math.random() * (whole - 1)) + 1;
|
||||
const part2 = whole - part1;
|
||||
|
||||
// 随机决定显示 part1 还是 part2(另一个为 null)
|
||||
@@ -209,13 +215,17 @@ Page({
|
||||
let attempts = 0;
|
||||
const maxAttempts = problemCount * 50; // 最大尝试次数
|
||||
|
||||
while (problems.length < problemCount && attempts < maxAttempts) {
|
||||
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 part1 =
|
||||
Math.floor(Math.random() * (whole - 1)) + 1;
|
||||
const part2 = whole - part1;
|
||||
|
||||
// 生成唯一标识(统一格式:part1 <= part2)
|
||||
@@ -242,15 +252,6 @@ Page({
|
||||
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;
|
||||
@@ -261,4 +262,9 @@ Page({
|
||||
// 重新生成数据
|
||||
this.onRandom();
|
||||
},
|
||||
});
|
||||
},
|
||||
{
|
||||
pagePath: 'numberDecompose/numberDecompose',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import { PAPER_SIZE } from '../../constants/colors';
|
||||
import { checkAndSaveImage } from '../../utils/saveImage';
|
||||
import { shouldShowShareGuide } from '../../utils/shareGuide';
|
||||
import NumberFindDraw from '../service/numberFindDraw';
|
||||
import {
|
||||
MATH_FUNCTION_TYPES,
|
||||
MathFunctionType,
|
||||
} from '../../constants/mathFunctions';
|
||||
import { createMathPage, CanvasDataState } from '../common/mathPageMixin';
|
||||
|
||||
Page({
|
||||
createMathPage({
|
||||
canvas: null as Canvas | null,
|
||||
ctx: null as RenderingContext | null,
|
||||
boxHeight: 0,
|
||||
@@ -19,90 +13,38 @@ Page({
|
||||
selectedNumber: 0, // 选中的数字
|
||||
functionId: '', // 功能ID,用于判断标题
|
||||
numberList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], // 数字列表
|
||||
showShareDialog: false, // 显示分享引导弹窗
|
||||
hasContent: false,
|
||||
showShareDialog: false,
|
||||
} as CanvasDataState & {
|
||||
selectedNumber: number;
|
||||
numberList: number[];
|
||||
},
|
||||
|
||||
onLoad(options: { id?: string }) {
|
||||
// 根据id参数判断页面标题
|
||||
const functionId = options.id || 'number-find';
|
||||
this.setData({
|
||||
functionId,
|
||||
});
|
||||
|
||||
// 根据functionId设置页面标题
|
||||
const functionItem = MATH_FUNCTION_TYPES.find(
|
||||
(item: MathFunctionType) => item.id === functionId,
|
||||
);
|
||||
|
||||
const pageTitle = functionItem?.title || '看数字,涂一涂';
|
||||
this.setData({
|
||||
pageTitle,
|
||||
});
|
||||
|
||||
// 设置导航栏标题
|
||||
wx.setNavigationBarTitle({
|
||||
title: pageTitle,
|
||||
});
|
||||
this.initPageInfo(functionId, '看数字,涂一涂');
|
||||
},
|
||||
|
||||
onReady() {
|
||||
// 初始化canvas
|
||||
this.initCanvas();
|
||||
this.initCanvas({
|
||||
createDrawService: (
|
||||
canvas: Canvas,
|
||||
ctx: RenderingContext,
|
||||
options?: Record<string, any>,
|
||||
) => {
|
||||
return new NumberFindDraw(canvas, ctx, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* 初始化Canvas
|
||||
*/
|
||||
initCanvas() {
|
||||
const query = wx.createSelectorQuery();
|
||||
query
|
||||
.select('#canvasWrapper')
|
||||
.boundingClientRect((rect) => {
|
||||
if (rect) {
|
||||
const { width, height } = PAPER_SIZE['A4'];
|
||||
const boxWidth = rect.width;
|
||||
const boxHeight = boxWidth / (width / height);
|
||||
|
||||
this.boxHeight = boxHeight;
|
||||
this.boxWidth = boxWidth;
|
||||
|
||||
this.setData({
|
||||
boxWidth,
|
||||
boxHeight,
|
||||
});
|
||||
|
||||
// 初始化canvas上下文
|
||||
const canvas = wx
|
||||
.createSelectorQuery()
|
||||
.select('#canvasContent');
|
||||
canvas.fields({ node: true, size: true }).exec((res) => {
|
||||
if (res[0]) {
|
||||
const canvasNode = res[0].node;
|
||||
const ctx = canvasNode.getContext('2d');
|
||||
const dpr = wx.getSystemInfoSync().pixelRatio;
|
||||
|
||||
canvasNode.width = boxWidth * dpr;
|
||||
canvasNode.height = boxHeight * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
|
||||
this.canvas = canvasNode;
|
||||
this.ctx = ctx;
|
||||
|
||||
// 初始化绘制服务
|
||||
this.drawService = new NumberFindDraw(
|
||||
canvasNode,
|
||||
ctx,
|
||||
{
|
||||
title: this.data.pageTitle,
|
||||
drawServiceOptions: {
|
||||
subTitle: '找一找下面相同的数字,涂上颜色',
|
||||
functionId: this.data.functionId,
|
||||
},
|
||||
);
|
||||
|
||||
onCanvasReady: () => {
|
||||
// 如果还没有选中数字,随机选择一个
|
||||
if (this.data.selectedNumber === 0) {
|
||||
const randomNumber =
|
||||
Math.floor(Math.random() * 10) + 1;
|
||||
const randomNumber = Math.floor(Math.random() * 10) + 1;
|
||||
this.setData({
|
||||
selectedNumber: randomNumber,
|
||||
});
|
||||
@@ -110,11 +52,8 @@ Page({
|
||||
|
||||
// 绘制初始内容
|
||||
this.drawCanvas();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -128,8 +67,10 @@ Page({
|
||||
if (this.data.selectedNumber > 0) {
|
||||
try {
|
||||
await this.drawService.draw(this.data.selectedNumber);
|
||||
this.setData({ hasContent: true });
|
||||
} catch (error) {
|
||||
console.error('绘制失败:', error);
|
||||
this.setData({ hasContent: false });
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -155,57 +96,4 @@ Page({
|
||||
});
|
||||
this.drawCanvas();
|
||||
},
|
||||
|
||||
/**
|
||||
* 导出打印
|
||||
*/
|
||||
exportToPrint() {
|
||||
if (!this.canvas || this.data.selectedNumber <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否需要显示分享引导
|
||||
if (shouldShowShareGuide()) {
|
||||
this.setData({ showShareDialog: true });
|
||||
return;
|
||||
}
|
||||
|
||||
// 直接下载
|
||||
checkAndSaveImage(this.canvas);
|
||||
},
|
||||
|
||||
/**
|
||||
* 分享小程序
|
||||
*/
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '涂鸦丫-数学学习涂鸦卡',
|
||||
path: `/mathPages/numberFind/numberFind?id=${this.data.functionId}`,
|
||||
imageUrl:
|
||||
'https://cdn.joeyone.cn/doodle/share-img/index-share-v2.png',
|
||||
};
|
||||
},
|
||||
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: '涂鸦丫-数学学习涂鸦卡',
|
||||
query: `id=${this.data.functionId}`,
|
||||
imageUrl:
|
||||
'https://cdn.joeyone.cn/doodle/share-img/index-share-v2.png',
|
||||
};
|
||||
},
|
||||
|
||||
/** 关闭分享引导弹窗 */
|
||||
onCloseShareDialog() {
|
||||
this.setData({ showShareDialog: false });
|
||||
},
|
||||
|
||||
/** 分享成功回调 */
|
||||
onShareSuccess() {
|
||||
this.setData({ showShareDialog: false });
|
||||
// 分享成功后直接下载
|
||||
if (this.canvas) {
|
||||
checkAndSaveImage(this.canvas);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* 埋点服务
|
||||
* 提供分享和下载打印事件的上报功能
|
||||
*/
|
||||
|
||||
// 生成唯一 UUID
|
||||
function generateUUID(): string {
|
||||
const timestamp = Date.now();
|
||||
const random = Math.floor(Math.random() * 1000000);
|
||||
return `${timestamp}-${random}`;
|
||||
}
|
||||
|
||||
// 格式化时间为 yyyy-MM-dd HH:mm
|
||||
function formatTime(date: Date = new Date()): string {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取今天的日期字符串(yyyy-MM-dd)
|
||||
*/
|
||||
function getTodayString(): string {
|
||||
const date = new Date();
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取事件计数(当天该事件上报的次数)
|
||||
* 使用本地存储持久化,每天重置计数
|
||||
*/
|
||||
function getEventCount(eventName: string): number {
|
||||
try {
|
||||
const storageKey = `tracker_count_${eventName}`;
|
||||
const dateKey = `tracker_date_${eventName}`;
|
||||
const today = getTodayString();
|
||||
|
||||
// 获取上次记录的日期
|
||||
const lastDate = wx.getStorageSync(dateKey);
|
||||
|
||||
let currentCount = 0;
|
||||
// 如果是今天,获取上次的计数;否则重置为0
|
||||
if (lastDate === today) {
|
||||
currentCount = wx.getStorageSync(storageKey) || 0;
|
||||
}
|
||||
|
||||
// 递增计数
|
||||
const newCount = currentCount + 1;
|
||||
|
||||
// 保存计数和日期
|
||||
wx.setStorageSync(storageKey, newCount);
|
||||
wx.setStorageSync(dateKey, today);
|
||||
|
||||
return newCount;
|
||||
} catch (error) {
|
||||
console.error('获取事件计数失败:', error);
|
||||
return 1; // 如果存储失败,返回 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 埋点追踪器
|
||||
*/
|
||||
class Tracker {
|
||||
private uuid: string;
|
||||
private openLog: boolean;
|
||||
|
||||
constructor() {
|
||||
// 初始化时获取或生成 UUID(持久化存储)
|
||||
this.uuid = this.getOrCreateUUID();
|
||||
this.openLog = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或创建 UUID
|
||||
*/
|
||||
private getOrCreateUUID(): string {
|
||||
const uuidKey = 'tracker_uuid';
|
||||
let storedUUID = wx.getStorageSync(uuidKey);
|
||||
if (!storedUUID) {
|
||||
storedUUID = generateUUID();
|
||||
wx.setStorageSync(uuidKey, storedUUID);
|
||||
}
|
||||
return storedUUID;
|
||||
}
|
||||
|
||||
printLog(tip: string, message?: string | object): void {
|
||||
if (this.openLog) {
|
||||
if (message) {
|
||||
if (typeof message === 'object') {
|
||||
console.log(tip, ':', JSON.stringify(message, null, 2));
|
||||
} else {
|
||||
console.log(tip, ':', message as string);
|
||||
}
|
||||
} else {
|
||||
console.log(tip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报分享点击事件
|
||||
* @param pageName 页面名称
|
||||
*/
|
||||
reportShare(pageName: string): void {
|
||||
try {
|
||||
const time = formatTime();
|
||||
const count = getEventCount('share_click');
|
||||
const params = {
|
||||
count,
|
||||
time,
|
||||
uuid: this.uuid,
|
||||
page_name: pageName,
|
||||
};
|
||||
|
||||
this.printLog('分享事件', params);
|
||||
wx.reportEvent('share_click', params);
|
||||
} catch (error) {
|
||||
console.error('上报分享事件失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报下载打印事件
|
||||
* @param pageName 页面名称
|
||||
*/
|
||||
reportDownload(pageName: string): void {
|
||||
try {
|
||||
const time = formatTime();
|
||||
const count = getEventCount('download');
|
||||
const params = {
|
||||
count,
|
||||
time,
|
||||
uuid: this.uuid,
|
||||
page_name: pageName,
|
||||
};
|
||||
|
||||
this.printLog('下载事件', params);
|
||||
wx.reportEvent('download', params);
|
||||
} catch (error) {
|
||||
console.error('上报下载事件失败:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建并导出 tracker 实例
|
||||
const tracker = new Tracker();
|
||||
|
||||
export default tracker;
|
||||
Reference in New Issue
Block a user