Files
doodle-mini/miniprogram/chinesePages/wordTestSheet/wordTestSheet.ts
T
2026-06-11 14:39:06 +08:00

266 lines
8.7 KiB
TypeScript

import WordTestDrawService from './draw/wordTestDrawService';
import {
buildWordTestCategories,
buildWordTestGroups,
DEFAULT_WORD_TEST_CATEGORY_ID,
findWordTestCategory,
type WordTestCategory,
type WordTestGroup,
} from './data/wordTestCategories';
import {
getModeInfo,
getPublishMetaByMode,
isValidMode,
WORD_TEST_WORKSHEET_ID,
} from './wordTestSheet.config';
import { createPage, type CanvasDataState } from '../../base/pageMixin';
import { defaultShareConfig } from '../../config/config';
import type { DebugPublishMeta } from '../../utils/debugPublish';
import {
addFavorite,
removeFavorite,
batchCheckFavorited,
} from '../../utils/favorites';
const pageInfoLookup = getModeInfo;
function buildSelectedMap(id: string | null): Record<string, boolean> {
if (!id) return {};
return { [id]: true };
}
type PageData = CanvasDataState & {
worksheetId: string;
categoryList: WordTestCategory[];
groupList: WordTestGroup[];
selectedCategoryId: string;
selectedGroupIndex: number;
selectedCategoryMap: Record<string, boolean>;
selectedGroupMap: Record<string, boolean>;
isPreviewFavorite: boolean;
isDevEnv: boolean;
debugPublishVisible: boolean;
debugPublishLoading: boolean;
debugPublishMeta: DebugPublishMeta | null;
};
createPage(
{
canvas: null as Canvas | null,
ctx: null as RenderingContext | null,
boxHeight: 0,
boxWidth: 0,
drawService: null as WordTestDrawService | null,
_favoritedMap: {} as Record<string, boolean>,
data: {
pageTitle: '测字表',
functionId: WORD_TEST_WORKSHEET_ID,
hasContent: false,
showShareDialog: false,
worksheetId: WORD_TEST_WORKSHEET_ID,
categoryList: [] as WordTestCategory[],
groupList: [] as WordTestGroup[],
selectedCategoryId: DEFAULT_WORD_TEST_CATEGORY_ID,
selectedGroupIndex: 1,
selectedCategoryMap: buildSelectedMap(
DEFAULT_WORD_TEST_CATEGORY_ID,
),
selectedGroupMap: buildSelectedMap('1'),
isPreviewFavorite: false,
isDevEnv: false,
debugPublishVisible: false,
debugPublishLoading: false,
debugPublishMeta: null,
} as unknown as PageData,
onLoad(options: { id?: string }) {
this.syncDebugPublishEnv();
const worksheetId =
options.id && isValidMode(options.id)
? options.id
: WORD_TEST_WORKSHEET_ID;
const categoryList = buildWordTestCategories();
const defaultCategory =
findWordTestCategory(
categoryList,
DEFAULT_WORD_TEST_CATEGORY_ID,
) || categoryList[0];
const selectedCategoryId = defaultCategory?.id || '';
const groupList = buildWordTestGroups(defaultCategory?.words || []);
this.setData({
worksheetId,
functionId: worksheetId,
categoryList,
groupList,
selectedCategoryId,
selectedGroupIndex: 1,
selectedCategoryMap: buildSelectedMap(selectedCategoryId),
selectedGroupMap: buildSelectedMap('1'),
});
this.initPageInfo(worksheetId, '测字表');
this.loadFavoritedMap();
},
onCanvasReady(e: WechatMiniprogram.CustomEvent) {
const category = this.getSelectedCategory();
this.initCanvasFromComponent(e.detail, {
createDrawService: (
canvas: Canvas,
ctx: RenderingContext,
opts?: Record<string, unknown>,
) => new WordTestDrawService(canvas, ctx, opts),
drawServiceOptions: {
title: this.getSheetTitle(category),
},
onCanvasReady: () => {
this.drawCanvas();
},
});
},
getSelectedCategory(): WordTestCategory | undefined {
return findWordTestCategory(
this.data.categoryList,
this.data.selectedCategoryId,
);
},
getSelectedGroup(): WordTestGroup | undefined {
return (this.data.groupList as WordTestGroup[]).find(
(group: WordTestGroup) =>
group.index === this.data.selectedGroupIndex,
);
},
getSheetTitle(category?: WordTestCategory): string {
if (!category) return '测字表';
return `${category.name}(测字表)`;
},
async drawCanvas() {
if (!this.drawService) return;
const group = this.getSelectedGroup();
if (!group || group.words.length === 0) {
this.setData({ hasContent: false });
return;
}
const category = this.getSelectedCategory();
const title = this.getSheetTitle(category);
try {
(this.drawService as WordTestDrawService).options.title = title;
await (this.drawService as WordTestDrawService).draw({
words: group.words,
pageNumber: group.index,
});
this.setData({ hasContent: true });
} catch (e) {
console.error('wordTestSheet draw failed', e);
this.setData({ hasContent: false });
}
},
onSelectCategory(e: WechatMiniprogram.TouchEvent) {
const id = e.currentTarget.dataset.id as string;
if (!id || id === this.data.selectedCategoryId) return;
const category = findWordTestCategory(this.data.categoryList, id);
if (!category) return;
const groupList = buildWordTestGroups(category.words);
this.setData(
{
selectedCategoryId: id,
selectedCategoryMap: buildSelectedMap(id),
groupList,
selectedGroupIndex: 1,
selectedGroupMap: buildSelectedMap('1'),
},
() => this.drawCanvas(),
);
},
onSelectGroup(e: WechatMiniprogram.TouchEvent) {
const index = Number(e.currentTarget.dataset.index);
if (!index || index === this.data.selectedGroupIndex) return;
this.setData(
{
selectedGroupIndex: index,
selectedGroupMap: buildSelectedMap(String(index)),
},
() => this.drawCanvas(),
);
},
onPreviewRefresh() {
const groupList = this.data.groupList as WordTestGroup[];
if (!groupList.length) {
this.drawCanvas();
return;
}
const currentIdx = groupList.findIndex(
(group) => group.index === this.data.selectedGroupIndex,
);
const nextIdx =
currentIdx < 0 ? 0 : (currentIdx + 1) % groupList.length;
const nextGroup = groupList[nextIdx];
this.setData(
{
selectedGroupIndex: nextGroup.index,
selectedGroupMap: buildSelectedMap(String(nextGroup.index)),
},
() => this.drawCanvas(),
);
},
async onPreviewFavorite() {
const next = !this.data.isPreviewFavorite;
this.setData({ isPreviewFavorite: next });
const id = this.data.worksheetId;
if (id) {
this._favoritedMap[id] = next;
if (next) {
addFavorite(id);
} else {
removeFavorite(id);
}
}
wx.showToast({
title: next ? '收藏成功' : '已取消收藏',
icon: 'none',
});
},
async loadFavoritedMap() {
const ids = [WORD_TEST_WORKSHEET_ID];
this._favoritedMap = await batchCheckFavorited(ids);
if (this._favoritedMap[this.data.worksheetId]) {
this.setData({ isPreviewFavorite: true });
}
},
getPublishMeta(): DebugPublishMeta {
const meta = getPublishMetaByMode(this.data.worksheetId);
if (!meta) {
throw new Error('当前题型配置不存在');
}
return meta;
},
},
{
shareConfig: defaultShareConfig,
pageInfoLookup,
},
);