From 0c51905ad4d5733db8c6550e6f2a6bb2a64139d3 Mon Sep 17 00:00:00 2001 From: R524809 Date: Mon, 22 Dec 2025 09:59:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=95=B0=E5=AD=97=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/app.json | 3 +- miniprogram/constants/mathFunctions.ts | 7 + .../mathPages/numberSort/numberSort.json | 13 ++ .../mathPages/numberSort/numberSort.less | 1 + .../mathPages/numberSort/numberSort.ts | 132 ++++++++++++ .../mathPages/numberSort/numberSort.wxml | 38 ++++ .../shared/service/numberSortDraw.ts | 188 ++++++++++++++++++ project.private.config.json | 11 +- 8 files changed, 390 insertions(+), 3 deletions(-) create mode 100644 miniprogram/mathPages/numberSort/numberSort.json create mode 100644 miniprogram/mathPages/numberSort/numberSort.less create mode 100644 miniprogram/mathPages/numberSort/numberSort.ts create mode 100644 miniprogram/mathPages/numberSort/numberSort.wxml create mode 100644 miniprogram/mathPages/shared/service/numberSortDraw.ts diff --git a/miniprogram/app.json b/miniprogram/app.json index 4d41246..d261859 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -17,7 +17,8 @@ "missingNumber/missingNumber", "compare/compare", "countingSelect/countingSelect", - "numberDecompose/numberDecompose" + "numberDecompose/numberDecompose", + "numberSort/numberSort" ], "independent": false }, diff --git a/miniprogram/constants/mathFunctions.ts b/miniprogram/constants/mathFunctions.ts index d586c6f..e0c3cb1 100644 --- a/miniprogram/constants/mathFunctions.ts +++ b/miniprogram/constants/mathFunctions.ts @@ -66,6 +66,13 @@ export const MATH_FUNCTION_TYPES: MathFunctionType[] = [ desc: '在数字序列中找出并填写缺失的数字', icon: '❓', }, + { + id: 'number-sort', + page: 'numberSort', + title: '数字排序', + desc: '数字牌被打乱了,把正确的数字按顺序写下来吧~', + icon: '🔢', + }, { id: 'number-decompose', page: 'numberDecompose', diff --git a/miniprogram/mathPages/numberSort/numberSort.json b/miniprogram/mathPages/numberSort/numberSort.json new file mode 100644 index 0000000..2e3e057 --- /dev/null +++ b/miniprogram/mathPages/numberSort/numberSort.json @@ -0,0 +1,13 @@ +{ + "navigationBarTitleText": "数字排序", + "navigationBarBackgroundColor": "#FFD719", + "homeButton": true, + "backgroundColor": "#F6F6F6", + "enablePullDownRefresh": false, + "usingComponents": { + "toy-button": "../../ui/button/button", + "share-guide-popup": "../../components/share-guide-popup/share-guide-popup", + "math-bottom-buttons": "../../components/math-bottom-buttons/math-bottom-buttons", + "draw-ad": "../../components/draw-ad/draw-ad" + } +} diff --git a/miniprogram/mathPages/numberSort/numberSort.less b/miniprogram/mathPages/numberSort/numberSort.less new file mode 100644 index 0000000..e2b2a7b --- /dev/null +++ b/miniprogram/mathPages/numberSort/numberSort.less @@ -0,0 +1 @@ +@import '../../base/baseDrawPage.wxss'; \ No newline at end of file diff --git a/miniprogram/mathPages/numberSort/numberSort.ts b/miniprogram/mathPages/numberSort/numberSort.ts new file mode 100644 index 0000000..9ceeb2e --- /dev/null +++ b/miniprogram/mathPages/numberSort/numberSort.ts @@ -0,0 +1,132 @@ +import NumberSortDraw from '../shared/service/numberSortDraw'; +import { + createMathPage, + CanvasDataState, +} from '../shared/common/mathPageMixin'; +import { NumberSortData } from '../shared/service/numberSortDraw'; +import { NUMBER_COLORS, getNumberColors } from '../../constants/colors'; + +createMathPage({ + canvas: null as Canvas | null, + ctx: null as RenderingContext | null, + boxHeight: 0, + boxWidth: 0, + drawService: null as NumberSortDraw | null, + sortData: null as NumberSortData | null, + + data: { + pageTitle: '数字排序', + functionId: '', + hasContent: false, + showShareDialog: false, + } as CanvasDataState, + + onLoad(options: { id?: string }) { + const functionId = options.id || 'number-sort'; + this.setData({ + functionId, + }); + this.initPageInfo(functionId, '数字排序'); + }, + + onReady() { + this.initCanvas({ + createDrawService: ( + canvas: Canvas, + ctx: RenderingContext, + options?: Record, + ) => { + return new NumberSortDraw(canvas, ctx, options); + }, + drawServiceOptions: { + title: this.data.pageTitle, + subTitle: '数字牌被打乱了,把正确的数字按顺序写下来吧~', + functionId: this.data.functionId, + }, + onCanvasReady: () => { + // 初始随机生成 + this.onRandom(); + }, + }); + }, + + /** + * 绘制Canvas内容 + */ + async drawCanvas() { + if (!this.ctx || !this.drawService || !this.sortData) { + return; + } + + try { + await this.drawService.draw(this.sortData); + this.setData({ hasContent: true }); + } catch (error) { + console.error('绘制失败:', error); + this.setData({ hasContent: false }); + } + }, + + /** + * 随机生成 + */ + onRandom() { + const groups: NumberSortData['groups'] = []; + const availableColors = getNumberColors(); + + // 生成6组题目 + for (let i = 0; i < 6; i++) { + // 随机选择4个不同的数字(范围1-9) + const availableNumbers = Array.from({ length: 9 }, (_, i) => i + 1); + const selectedNumbers: number[] = []; + + // 随机选择4个数字 + for (let j = 0; j < 4; j++) { + const randomIndex = Math.floor( + Math.random() * availableNumbers.length, + ); + selectedNumbers.push( + availableNumbers.splice(randomIndex, 1)[0], + ); + } + + // 打乱顺序 + const shuffledNumbers = [...selectedNumbers]; + for (let j = shuffledNumbers.length - 1; j > 0; j--) { + const k = Math.floor(Math.random() * (j + 1)); + [shuffledNumbers[j], shuffledNumbers[k]] = [ + shuffledNumbers[k], + shuffledNumbers[j], + ]; + } + + // 为每个数字分配颜色和倾斜角度 + const numbersWithColors = shuffledNumbers.map((number) => { + // 使用数字对应的颜色,如果数字超出范围则随机选择 + const color = + NUMBER_COLORS[number as keyof typeof NUMBER_COLORS] || + availableColors[ + Math.floor(Math.random() * availableColors.length) + ]; + // 生成随机倾斜角度(-30度到+30度,转换为弧度) + const angleDegrees = (Math.random() - 0.5) * 60; // -30到+30度 + const angle = (angleDegrees * Math.PI) / 180; // 转换为弧度 + return { + number, + color, + angle, + }; + }); + + groups.push({ + numbers: numbersWithColors, + }); + } + + this.sortData = { + groups, + }; + + this.drawCanvas(); + }, +}); diff --git a/miniprogram/mathPages/numberSort/numberSort.wxml b/miniprogram/mathPages/numberSort/numberSort.wxml new file mode 100644 index 0000000..9ee45f2 --- /dev/null +++ b/miniprogram/mathPages/numberSort/numberSort.wxml @@ -0,0 +1,38 @@ + + + 预览打印效果 + + + + + + + + + + 随机生成 + + + + + + + + diff --git a/miniprogram/mathPages/shared/service/numberSortDraw.ts b/miniprogram/mathPages/shared/service/numberSortDraw.ts new file mode 100644 index 0000000..46d3536 --- /dev/null +++ b/miniprogram/mathPages/shared/service/numberSortDraw.ts @@ -0,0 +1,188 @@ +/** + * 数字排序绘制服务 + */ + +import { BaseDrawService } from '../../../service/baseDraw'; + +/** + * 数字排序数据 + */ +export interface NumberSortData { + /** 6组题目数据 */ + groups: Array<{ + /** 4个乱序的数字及其颜色 */ + numbers: Array<{ + number: number; + color: string; + angle?: number; // 倾斜角度(弧度),-30度到+30度 + }>; + }>; +} + +/** + * 数字排序绘制服务 + */ +class NumberSortDraw extends BaseDrawService { + sortData: NumberSortData | null = null; + + constructor( + canvas: Canvas, + ctx: RenderingContext, + options?: Record, + ) { + super(canvas, ctx, options); + } + + /** + * 绘制数字排序内容 + */ + async draw(sortData: NumberSortData) { + if (!sortData || !sortData.groups) { + return; + } + + this.setPrintConfig(); + this.sortData = sortData; + this.clear(); + this.setPaper(); + + // 绘制Header + if (this.headerType !== 'minimal') { + await this.drawHeader(); + } else { + this.drawMiniHeader(); + } + + // 绘制内容区域 + this.drawDivider(); + this.drawContent({ + ctx: this.ctx, + sortData: this.sortData, + canvasWidth: this.canvasWidth, + startY: this.currentY, + }); + } + + /** + * 绘制内容区域 + */ + private drawContent(params: { + ctx: RenderingContext; + sortData: NumberSortData; + canvasWidth: number; + startY: number; + }): void { + const { ctx, sortData, canvasWidth } = params; + let { startY } = params; + + startY = startY + 25; + + const margin = 40; // 左右边距 + const rowSpacing = 60; // 行间距 + const colSpacing = 40; // 列间距 + const boxSpacing = 10; // 格子之间的间距 + + // 数字区域参数 + const numberSize = 120; // 数字大小(字体大小) + const numberAreaHeight = 120; // 数字区域高度(增大以容纳更大的数字) + const numberOverlapSpacing = 35; // 数字之间的间距(用于重叠效果) + + // 格子参数 + const boxWidth = 40; // 格子宽度 + const boxHeight = 50; // 格子高度(高比宽长) + const boxBorderWidth = 1; // 边框宽度 + const boxBorderColor = '#999'; // 边框颜色 + + // 4个格子的总宽度 + const boxesTotalWidth = 4 * boxWidth + 3 * boxSpacing; + + // 每组的总宽度(以格子的总宽度为准) + const groupWidth = boxesTotalWidth; + + // 计算总宽度(两列 + 一列间距) + const totalWidth = 2 * groupWidth + colSpacing; + const groupsStartX = + margin + (canvasWidth - margin * 2 - totalWidth) / 2; + + // 每组的总高度(数字区域 + 格子区域) + const groupHeight = numberAreaHeight + boxHeight; + + // 绘制6个组(三行两列) + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 2; col++) { + const groupIndex = row * 2 + col; + const group = sortData.groups[groupIndex]; + if (!group) continue; + + const groupX = groupsStartX + col * (groupWidth + colSpacing); + const groupY = startY + row * (groupHeight + rowSpacing); + + // 格子的起始X坐标(居中) + const boxesStartX = groupX; + const boxesY = groupY + numberAreaHeight; + + // 计算数字组的中心位置(与格子中心对齐) + const boxesCenterX = boxesStartX + boxesTotalWidth / 2; + + // 计算数字组的总宽度(从第一个数字中心到最后一个数字中心的距离) + const numbersGroupWidth = 3 * numberOverlapSpacing; + + // 第一个数字的中心位置(数字组居中对齐) + const firstNumberCenterX = boxesCenterX - numbersGroupWidth / 2; + + // 绘制4个数字(上边),有重叠效果 + for (let i = 0; i < group.numbers.length; i++) { + const numberItem = group.numbers[i]; + // 数字中心位置(有重叠) + const numberX = + firstNumberCenterX + i * numberOverlapSpacing; + const numberY = groupY + numberAreaHeight / 2; + + // 获取倾斜角度(如果存在,否则使用0) + const angle = numberItem.angle || 0; + + // 保存上下文状态 + ctx.save(); + + // 移动到数字位置 + ctx.translate(numberX, numberY); + // 旋转(角度转换为弧度) + ctx.rotate(angle); + + // 绘制数字(带边线) + const text = numberItem.number.toString(); + ctx.font = `bold ${numberSize}px Arial`; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + // 先绘制边线 + ctx.strokeStyle = '#141414'; + ctx.lineWidth = 3; + ctx.strokeText(text, 0, 0); + + // 再绘制填充 + ctx.fillStyle = numberItem.color; + ctx.fillText(text, 0, 0); + + // 恢复上下文状态 + ctx.restore(); + } + + // 绘制4个长方形格子(下边) + + for (let i = 0; i < 4; i++) { + const boxX = boxesStartX + i * (boxWidth + boxSpacing); + + // 绘制格子边框 + ctx.strokeStyle = boxBorderColor; + ctx.lineWidth = boxBorderWidth; + ctx.beginPath(); + ctx.rect(boxX, boxesY, boxWidth, boxHeight); + ctx.stroke(); + } + } + } + } +} + +export default NumberSortDraw; diff --git a/project.private.config.json b/project.private.config.json index c74b149..96d53fe 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -23,12 +23,19 @@ "condition": { "miniprogram": { "list": [ + { + "name": "mathPages/numberSort/numberSort", + "pathName": "mathPages/numberSort/numberSort", + "query": "id=number-sort", + "scene": null, + "launchMode": "default" + }, { "name": "focusPages/codeConnect/codeConnect", "pathName": "focusPages/codeConnect/codeConnect", "query": "id=code-connect", - "scene": null, - "launchMode": "default" + "launchMode": "default", + "scene": null }, { "name": "focusPages/gridReasoning/gridReasoning",