feat: 涂色识字完善、找字涂色完成

This commit is contained in:
R524809
2026-05-09 09:56:16 +08:00
parent b85afde7c0
commit c21ac9e935
27 changed files with 328 additions and 1135 deletions
@@ -1,6 +1,6 @@
import type { DebugPublishMeta } from '../../utils/debugPublish';
import { inferGradeFromAge } from '../../utils/debugPublish';
import type { TemplateType } from '../../service/drawServiceFactory';
import type { TemplateType } from '../shared/draw/drawServiceFactory';
/** 本地 worksheet 元数据(与云库 `worksheets` 文档 `_id` 对齐) */
interface WordColoringWorksheetDefinition {
@@ -35,9 +35,9 @@ export const WORD_COLORING_WORKSHEET_DEFINITIONS = [
icon: 'search',
title: '找字涂色',
subtitle: '在字海中找到目标字并涂色',
ageMin: 4,
ageMax: 7,
difficulty: 2,
ageMin: 3,
ageMax: 6,
difficulty: 1,
tags: ['识字', '涂色', '找字'],
sortOrder: 31,
},
@@ -12,7 +12,7 @@
"debug-publish-tools": "../../components3.0/debug-publish-tools/debug-publish-tools",
"share-guide-popup": "../../components/share-guide-popup/share-guide-popup",
"toy-icon": "../../toy/icon/icon",
"color-picker": "../../components/color-picker/color-picker",
"word-picker": "../../components/word-picker/word-picker"
"color-picker": "../../components3.0/color-picker/color-picker",
"word-picker": "../../components3.0/word-picker/word-picker"
}
}
@@ -1,6 +1,9 @@
import { WATER_COLORS } from '../../constants/colors';
import { WORDS } from '../../constants/words';
import { DrawServiceFactory, type IDrawService } from '../../service/drawServiceFactory';
import { WORDS } from '../../core/data/words';
import {
DrawServiceFactory,
type IDrawService,
} from '../shared/draw/drawServiceFactory';
import { createPage, type CanvasDataState } from '../../base/pageMixin';
import { defaultShareConfig } from '../../config/config';
import {
@@ -12,14 +15,26 @@ import {
WORD_COLORING_WORKSHEET_DEFINITIONS,
} from './wordColoring.config';
import type { DebugPublishMeta } from '../../utils/debugPublish';
import { addFavorite, removeFavorite, batchCheckFavorited } from '../../utils/favorites';
import {
addFavorite,
removeFavorite,
batchCheckFavorited,
} from '../../utils/favorites';
type CardItem = { color: string; word: string };
const COLOR_MAP: Record<string, string> = {
: '#FF0000', : '#0000FF', 绿: '#00FF00', : '#FFFF00',
: '#000000', : '#FFFFFF', : '#800080', : '#FF7F00',
: '#FF69B4', : '#A52A2A', : '#808080',
: '#FF0000',
: '#0000FF',
绿: '#00FF00',
: '#FFFF00',
: '#000000',
: '#FFFFFF',
: '#800080',
: '#FF7F00',
: '#FF69B4',
: '#A52A2A',
: '#808080',
};
const MAX_WORDS = 3;
@@ -109,7 +124,13 @@ createPage(
canvas: Canvas,
ctx: RenderingContext,
options?: Record<string, any>,
) => DrawServiceFactory.create(templateType, canvas, ctx, options),
) =>
DrawServiceFactory.create(
templateType,
canvas,
ctx,
options,
),
drawServiceOptions: {
title: this.data.pageTitle,
},
@@ -121,7 +142,7 @@ createPage(
});
},
// PLACEHOLDER_TS_PART3
// PLACEHOLDER_TS_PART3
/** 执行 Canvas 绘制 */
async drawCanvas() {
@@ -183,23 +204,33 @@ createPage(
const w = allWords[idx];
if (!selected.includes(w)) selected.push(w);
}
const colors = [...WATER_COLORS.basic12].sort(() => Math.random() - 0.5);
const colors = [...WATER_COLORS.basic12].sort(
() => Math.random() - 0.5,
);
const cardList = selected.map((word, i) => ({
word,
color: COLOR_MAP[word] || colors[i % colors.length].hex,
}));
const inputValue = selected.join('');
this.setData({ cardList, selectedWords: selected, inputValue }, () => {
this.drawCanvas();
});
this.setData(
{ cardList, selectedWords: selected, inputValue },
() => {
this.drawCanvas();
},
);
},
/** 清空文字卡片 */
clearCardList() {
this.setData({ cardList: [], selectedWords: [], inputValue: '', hasContent: false });
this.setData({
cardList: [],
selectedWords: [],
inputValue: '',
hasContent: false,
});
},
// PLACEHOLDER_TS_PART4
// PLACEHOLDER_TS_PART4
/** 输入框内容变化:同步 cardList */
onInputChange(e: WechatMiniprogram.Input) {
@@ -215,7 +246,12 @@ createPage(
/** 清空输入框及卡片 */
onClearInput() {
this.setData({ inputValue: '', cardList: [], selectedWords: [], hasContent: false });
this.setData({
inputValue: '',
cardList: [],
selectedWords: [],
hasContent: false,
});
if (this.drawService) {
this.drawCanvas();
}
@@ -223,9 +259,15 @@ createPage(
/** 将输入文本同步为 cardList */
syncCardsFromInput(value: string) {
const chars = [...new Set(value.split('').filter((c: string) => c.trim()))].slice(0, 6);
const oldCardMap = new Map<string, string>(this.data.cardList.map((c: CardItem) => [c.word, c.color]));
const allColors = WATER_COLORS.basic12.map((c: { hex: string }) => c.hex);
const chars = [
...new Set(value.split('').filter((c: string) => c.trim())),
].slice(0, 6);
const oldCardMap = new Map<string, string>(
this.data.cardList.map((c: CardItem) => [c.word, c.color]),
);
const allColors = WATER_COLORS.basic12.map(
(c: { hex: string }) => c.hex,
);
const usedColors = new Set<string>();
const cardList = chars.map((char) => {
@@ -241,7 +283,9 @@ createPage(
}
const available = allColors.filter((c) => !usedColors.has(c));
const shuffled = [...available].sort(() => Math.random() - 0.5);
const color = shuffled[0] || allColors[Math.floor(Math.random() * allColors.length)];
const color =
shuffled[0] ||
allColors[Math.floor(Math.random() * allColors.length)];
usedColors.add(color);
return { word: char, color };
});
@@ -256,17 +300,28 @@ createPage(
onColorDotTap(e: WechatMiniprogram.TouchEvent) {
const key = Number(e.currentTarget.dataset.key);
const color = e.currentTarget.dataset.color as string;
this.setData({ showColorPopup: true, currentKey: key, currentColor: color });
this.setData({
showColorPopup: true,
currentKey: key,
currentColor: color,
});
},
/** 分类标签点击:打开弹窗定位到对应分类 */
onCategoryTap(e: WechatMiniprogram.TouchEvent) {
const categoryId = Number(e.currentTarget.dataset.categoryId);
this.setData({ showSelectWordPopup: true, pickerCurrentTab: categoryId });
this.setData({
showSelectWordPopup: true,
pickerCurrentTab: categoryId,
});
},
onCloseColorPopup() {
this.setData({ showColorPopup: false, currentKey: 0, currentColor: '' });
this.setData({
showColorPopup: false,
currentKey: 0,
currentColor: '',
});
},
onChangeColor(e: WechatMiniprogram.CustomEvent) {
@@ -290,8 +345,12 @@ createPage(
onChangeWord(e: WechatMiniprogram.CustomEvent) {
const selectedWords = e.detail.selectedWords as string[];
const oldCardMap = new Map<string, string>(this.data.cardList.map((c: CardItem) => [c.word, c.color]));
const allColors = WATER_COLORS.basic12.map((c: { hex: string }) => c.hex);
const oldCardMap = new Map<string, string>(
this.data.cardList.map((c: CardItem) => [c.word, c.color]),
);
const allColors = WATER_COLORS.basic12.map(
(c: { hex: string }) => c.hex,
);
const usedColors = new Set<string>();
const cardList = selectedWords.map((word) => {
@@ -307,15 +366,25 @@ createPage(
}
const available = allColors.filter((c) => !usedColors.has(c));
const shuffled = [...available].sort(() => Math.random() - 0.5);
const color = shuffled[0] || allColors[Math.floor(Math.random() * allColors.length)];
const color =
shuffled[0] ||
allColors[Math.floor(Math.random() * allColors.length)];
usedColors.add(color);
return { word, color };
});
const inputValue = selectedWords.join('');
this.setData({ showSelectWordPopup: false, cardList, selectedWords, inputValue }, () => {
this.drawCanvas();
});
this.setData(
{
showSelectWordPopup: false,
cardList,
selectedWords,
inputValue,
},
() => {
this.drawCanvas();
},
);
},
/** 收藏 */
@@ -328,7 +397,10 @@ createPage(
if (next) addFavorite(id);
else removeFavorite(id);
}
wx.showToast({ title: next ? '收藏成功' : '已取消收藏', icon: 'none' });
wx.showToast({
title: next ? '收藏成功' : '已取消收藏',
icon: 'none',
});
},
async loadFavoritedMap() {