feat: 时钟连线和认识时钟合并
This commit is contained in:
@@ -27,7 +27,7 @@
|
|||||||
{
|
{
|
||||||
"root": "mathPages",
|
"root": "mathPages",
|
||||||
"name": "mathPages",
|
"name": "mathPages",
|
||||||
"pages": ["mathDraw/mathDraw", "clockReading/clockReading", "clockConnect/clockConnect"],
|
"pages": ["mathDraw/mathDraw", "clockReading/clockReading"],
|
||||||
"independent": false
|
"independent": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
// };
|
// };
|
||||||
|
|
||||||
/** 当前应用版本号;profile 页和首页公告共用 */
|
/** 当前应用版本号;profile 页和首页公告共用 */
|
||||||
export const APP_VERSION = '3.3.0';
|
export const APP_VERSION = '3.4.0';
|
||||||
|
|
||||||
export const defaultPrintConfig: PrintConfig = {
|
export const defaultPrintConfig: PrintConfig = {
|
||||||
// header: 'LogoImage',
|
// header: 'LogoImage',
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
import type { DebugPublishMeta } from '../../utils/debugPublish';
|
|
||||||
import { inferGradeFromAge } from '../../utils/debugPublish';
|
|
||||||
import { CLOCK_CONNECT_WORKSHEET_DEFINITIONS } from '../../config/worksheets/clock';
|
|
||||||
import {
|
|
||||||
CLOCK_CONNECT_TIME_MODE_OPTIONS,
|
|
||||||
type ClockConnectTimeMode,
|
|
||||||
} from './generators/clock-connect-generator';
|
|
||||||
|
|
||||||
export { CLOCK_CONNECT_WORKSHEET_DEFINITIONS };
|
|
||||||
|
|
||||||
export type { ClockConnectTimeMode };
|
|
||||||
|
|
||||||
type ClockConnectWorksheetRow =
|
|
||||||
(typeof CLOCK_CONNECT_WORKSHEET_DEFINITIONS)[number];
|
|
||||||
|
|
||||||
const CLOCK_CONNECT_WORKSHEET_BY_ID = Object.fromEntries(
|
|
||||||
CLOCK_CONNECT_WORKSHEET_DEFINITIONS.map((m) => [m.id, m]),
|
|
||||||
) as Record<string, ClockConnectWorksheetRow>;
|
|
||||||
|
|
||||||
export const CLOCK_CONNECT_MODE_OPTIONS = CLOCK_CONNECT_WORKSHEET_DEFINITIONS;
|
|
||||||
|
|
||||||
export { CLOCK_CONNECT_TIME_MODE_OPTIONS };
|
|
||||||
|
|
||||||
export function getModeInfo(id: string) {
|
|
||||||
const m = CLOCK_CONNECT_WORKSHEET_BY_ID[id];
|
|
||||||
return m ? { title: m.title, desc: m.subtitle } : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isValidMode(id: string): boolean {
|
|
||||||
return id in CLOCK_CONNECT_WORKSHEET_BY_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPublishMetaByMode(id: string): DebugPublishMeta | null {
|
|
||||||
const m = CLOCK_CONNECT_WORKSHEET_BY_ID[id];
|
|
||||||
if (!m) return null;
|
|
||||||
return {
|
|
||||||
id: m.id,
|
|
||||||
title: m.title,
|
|
||||||
subtitle: m.subtitle,
|
|
||||||
category: 'math',
|
|
||||||
subcategory: 'clock-connect',
|
|
||||||
path: `/mathPages/clockConnect/clockConnect?id=${m.id}`,
|
|
||||||
ageMin: m.ageMin,
|
|
||||||
ageMax: m.ageMax,
|
|
||||||
grade: inferGradeFromAge(m.ageMin, m.ageMax),
|
|
||||||
difficulty: m.difficulty,
|
|
||||||
previewImg: '',
|
|
||||||
tags: [...m.tags],
|
|
||||||
isNew: false,
|
|
||||||
isHot: false,
|
|
||||||
sortOrder: m.sortOrder,
|
|
||||||
status: 'draft',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"navigationStyle": "custom",
|
|
||||||
"navigationBarTitleText": "时钟连线",
|
|
||||||
"navigationBarBackgroundColor": "#F8F0E0",
|
|
||||||
"navigationBarTextStyle": "black",
|
|
||||||
"backgroundColor": "#FEF6E7",
|
|
||||||
"enablePullDownRefresh": false,
|
|
||||||
"usingComponents": {
|
|
||||||
"nav-bar": "../../components3.0/nav-bar/nav-bar",
|
|
||||||
"share-guide-popup": "../../components/share-guide-popup/share-guide-popup",
|
|
||||||
"preview-footer-actions": "../../components3.0/preview-footer-actions/preview-footer-actions",
|
|
||||||
"debug-publish-tools": "../../components3.0/debug-publish-tools/debug-publish-tools",
|
|
||||||
"preview-card": "../../components3.0/preview-card/preview-card"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
@import '../../style/theme.less';
|
|
||||||
|
|
||||||
page {
|
|
||||||
background-color: @bg-page;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-page {
|
|
||||||
min-height: 100vh;
|
|
||||||
padding: 0 @page-padding-x;
|
|
||||||
padding-bottom: calc(200rpx + env(safe-area-inset-bottom));
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-main {
|
|
||||||
padding-top: 24rpx;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 64rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 32rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-section-title {
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #6d3b00;
|
|
||||||
padding-left: 8rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-chip-row {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
gap: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-chip {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 24rpx 16rpx;
|
|
||||||
color: @text-secondary;
|
|
||||||
background: @bg-card;
|
|
||||||
border-radius: 32rpx;
|
|
||||||
transition:
|
|
||||||
background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
|
|
||||||
transform 0.2s cubic-bezier(0.4, 0, 0.2, 1),
|
|
||||||
color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
|
|
||||||
box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-chip--pressed {
|
|
||||||
transform: scale(0.96);
|
|
||||||
background: @brand;
|
|
||||||
color: @text-selected-btn;
|
|
||||||
font-weight: 700;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(50, 46, 37, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-chip--active {
|
|
||||||
background: @brand;
|
|
||||||
color: @text-selected-btn;
|
|
||||||
font-weight: 700;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(50, 46, 37, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-chip__text {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4rpx;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-chip__label {
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 36rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-chip__subtitle {
|
|
||||||
font-size: 20rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 28rpx;
|
|
||||||
opacity: 0.75;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cc-chip--active .cc-chip__subtitle,
|
|
||||||
.cc-chip--pressed .cc-chip__subtitle {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
import ClockConnectDraw from './draw/clockConnectDraw';
|
|
||||||
import {
|
|
||||||
buildClockConnectData,
|
|
||||||
type ClockConnectTimeMode,
|
|
||||||
} from './generators/clock-connect-generator';
|
|
||||||
import { createPage, type CanvasDataState } from '../../base/pageMixin';
|
|
||||||
import { defaultShareConfig } from '../../config/config';
|
|
||||||
import {
|
|
||||||
getModeInfo,
|
|
||||||
getPublishMetaByMode,
|
|
||||||
isValidMode,
|
|
||||||
CLOCK_CONNECT_TIME_MODE_OPTIONS,
|
|
||||||
} from './clockConnect.config';
|
|
||||||
import type { DebugPublishMeta } from '../../utils/debugPublish';
|
|
||||||
import {
|
|
||||||
addFavorite,
|
|
||||||
removeFavorite,
|
|
||||||
batchCheckFavorited,
|
|
||||||
} from '../../utils/favorites';
|
|
||||||
|
|
||||||
const pageInfoLookup = getModeInfo;
|
|
||||||
const WORKSHEET_ID = 'clock-connect';
|
|
||||||
|
|
||||||
type PageData = CanvasDataState & {
|
|
||||||
worksheetId: string;
|
|
||||||
timeMode: ClockConnectTimeMode;
|
|
||||||
timeModeOptions: typeof CLOCK_CONNECT_TIME_MODE_OPTIONS;
|
|
||||||
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 ClockConnectDraw | null,
|
|
||||||
_favoritedMap: {} as Record<string, boolean>,
|
|
||||||
|
|
||||||
data: {
|
|
||||||
pageTitle: '时钟连线',
|
|
||||||
functionId: WORKSHEET_ID,
|
|
||||||
hasContent: false,
|
|
||||||
showShareDialog: false,
|
|
||||||
worksheetId: WORKSHEET_ID,
|
|
||||||
timeMode: 'whole-hour' as ClockConnectTimeMode,
|
|
||||||
timeModeOptions: CLOCK_CONNECT_TIME_MODE_OPTIONS,
|
|
||||||
isPreviewFavorite: false,
|
|
||||||
isDevEnv: false,
|
|
||||||
debugPublishVisible: false,
|
|
||||||
debugPublishLoading: false,
|
|
||||||
debugPublishMeta: null,
|
|
||||||
} as unknown as PageData,
|
|
||||||
|
|
||||||
onLoad(options: { id?: string }) {
|
|
||||||
const worksheetId =
|
|
||||||
options.id && isValidMode(options.id)
|
|
||||||
? options.id
|
|
||||||
: WORKSHEET_ID;
|
|
||||||
this.syncDebugPublishEnv();
|
|
||||||
this.applyWorksheet(worksheetId);
|
|
||||||
this.loadFavoritedMap();
|
|
||||||
},
|
|
||||||
|
|
||||||
onSelectTimeMode(e: WechatMiniprogram.TouchEvent) {
|
|
||||||
const mode = e.currentTarget.dataset.mode as
|
|
||||||
| ClockConnectTimeMode
|
|
||||||
| undefined;
|
|
||||||
if (!mode || mode === this.data.timeMode) return;
|
|
||||||
this.setData({ timeMode: mode }, () => this.drawCanvas());
|
|
||||||
},
|
|
||||||
|
|
||||||
onCanvasReady(e: WechatMiniprogram.CustomEvent) {
|
|
||||||
this.initCanvasFromComponent(e.detail, {
|
|
||||||
createDrawService: (
|
|
||||||
canvas: Canvas,
|
|
||||||
ctx: RenderingContext,
|
|
||||||
options?: Record<string, unknown>,
|
|
||||||
) => new ClockConnectDraw(canvas, ctx, options),
|
|
||||||
drawServiceOptions: {
|
|
||||||
title: this.data.pageTitle,
|
|
||||||
},
|
|
||||||
onCanvasReady: () => {
|
|
||||||
this.drawCanvas();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
async drawCanvas() {
|
|
||||||
if (!this.ctx || !this.drawService) return;
|
|
||||||
try {
|
|
||||||
const data = buildClockConnectData(this.data.timeMode);
|
|
||||||
await (this.drawService as ClockConnectDraw).draw(data);
|
|
||||||
this.setData({ hasContent: true });
|
|
||||||
} catch (e) {
|
|
||||||
console.error('clockConnect draw failed', e);
|
|
||||||
this.setData({ hasContent: false });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onPreviewRefresh() {
|
|
||||||
this.drawCanvas();
|
|
||||||
},
|
|
||||||
|
|
||||||
async onPreviewFavorite() {
|
|
||||||
const next = !this.data.isPreviewFavorite;
|
|
||||||
this.setData({ isPreviewFavorite: next });
|
|
||||||
const id = this.data.worksheetId;
|
|
||||||
if (id && this._favoritedMap) {
|
|
||||||
this._favoritedMap[id] = next;
|
|
||||||
if (next) {
|
|
||||||
addFavorite(id);
|
|
||||||
} else {
|
|
||||||
removeFavorite(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wx.showToast({
|
|
||||||
title: next ? '收藏成功' : '已取消收藏',
|
|
||||||
icon: 'none',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
async loadFavoritedMap() {
|
|
||||||
const ids = [WORKSHEET_ID];
|
|
||||||
this._favoritedMap = await batchCheckFavorited(ids);
|
|
||||||
if (this._favoritedMap?.[WORKSHEET_ID]) {
|
|
||||||
this.setData({ isPreviewFavorite: true });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getPublishMeta(): DebugPublishMeta {
|
|
||||||
const meta = getPublishMetaByMode(this.data.worksheetId);
|
|
||||||
if (!meta) {
|
|
||||||
throw new Error('当前题型配置不存在');
|
|
||||||
}
|
|
||||||
return meta;
|
|
||||||
},
|
|
||||||
|
|
||||||
getWorksheetStatsId() {
|
|
||||||
return this.data.worksheetId;
|
|
||||||
},
|
|
||||||
|
|
||||||
applyWorksheet(worksheetId: string) {
|
|
||||||
if (!isValidMode(worksheetId)) return;
|
|
||||||
|
|
||||||
this.setData(
|
|
||||||
{
|
|
||||||
worksheetId,
|
|
||||||
functionId: worksheetId,
|
|
||||||
isPreviewFavorite: !!this._favoritedMap?.[worksheetId],
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.initPageInfo(worksheetId, '时钟连线');
|
|
||||||
if (this.drawService) {
|
|
||||||
this.drawService.options.title = this.data.pageTitle;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
shareConfig: defaultShareConfig,
|
|
||||||
pageInfoLookup,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<nav-bar title="时钟连线" />
|
|
||||||
|
|
||||||
<view class="cc-page">
|
|
||||||
<view class="cc-main">
|
|
||||||
<preview-card
|
|
||||||
id="previewCard"
|
|
||||||
showRefresh="{{true}}"
|
|
||||||
showFavorite="{{true}}"
|
|
||||||
favorited="{{isPreviewFavorite}}"
|
|
||||||
bind:canvas-ready="onCanvasReady"
|
|
||||||
bind:refresh="onPreviewRefresh"
|
|
||||||
bind:favorite="onPreviewFavorite" />
|
|
||||||
|
|
||||||
<view class="cc-section">
|
|
||||||
<text class="cc-section-title">时刻类型</text>
|
|
||||||
<view class="cc-chip-row">
|
|
||||||
<view
|
|
||||||
wx:for="{{timeModeOptions}}"
|
|
||||||
wx:key="id"
|
|
||||||
class="cc-chip {{timeMode === item.id ? 'cc-chip--active' : ''}}"
|
|
||||||
hover-class="cc-chip--pressed"
|
|
||||||
hover-start-time="0"
|
|
||||||
hover-stay-time="70"
|
|
||||||
data-mode="{{item.id}}"
|
|
||||||
bind:tap="onSelectTimeMode">
|
|
||||||
<view class="cc-chip__text">
|
|
||||||
<text class="cc-chip__label">{{item.label}}</text>
|
|
||||||
<text class="cc-chip__subtitle">{{item.subtitle}}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<preview-footer-actions
|
|
||||||
disabled="{{!hasContent}}"
|
|
||||||
bind:primary="exportToPrint"
|
|
||||||
bind:secondary="onShare" />
|
|
||||||
|
|
||||||
<debug-publish-tools
|
|
||||||
wx:if="{{isDevEnv && hasContent}}"
|
|
||||||
id="debugPublishTools"
|
|
||||||
visible="{{debugPublishVisible}}"
|
|
||||||
loading="{{debugPublishLoading}}"
|
|
||||||
meta="{{debugPublishMeta}}"
|
|
||||||
bind:open="onOpenDebugPublish"
|
|
||||||
bind:close="onCloseDebugPublish"
|
|
||||||
bind:confirm="onConfirmDebugPublish" />
|
|
||||||
|
|
||||||
<share-guide-popup
|
|
||||||
show="{{showShareDialog}}"
|
|
||||||
bind:onClose="onCloseShareDialog"
|
|
||||||
bind:onShareSuccess="onShareSuccess" />
|
|
||||||
@@ -1,44 +1,60 @@
|
|||||||
import type { DebugPublishMeta } from '../../utils/debugPublish';
|
import type { DebugPublishMeta } from '../../utils/debugPublish';
|
||||||
import { inferGradeFromAge } from '../../utils/debugPublish';
|
import { inferGradeFromAge } from '../../utils/debugPublish';
|
||||||
import { CLOCK_READING_WORKSHEET_DEFINITIONS } from '../../config/worksheets/clock';
|
|
||||||
import {
|
import {
|
||||||
CLOCK_TIME_MODE_OPTIONS,
|
CLOCK_READING_WORKSHEET_DEFINITIONS,
|
||||||
type ClockReadingTimeMode,
|
CLOCK_CONNECT_WORKSHEET_DEFINITIONS,
|
||||||
} from './generators/clock-generator';
|
} from '../../config/worksheets/clock';
|
||||||
|
|
||||||
export { CLOCK_READING_WORKSHEET_DEFINITIONS };
|
export { CLOCK_READING_WORKSHEET_DEFINITIONS, CLOCK_CONNECT_WORKSHEET_DEFINITIONS };
|
||||||
|
|
||||||
export type { ClockReadingTimeMode };
|
/** 合并所有钟表类 worksheet 定义 */
|
||||||
|
const ALL_CLOCK_DEFINITIONS = [
|
||||||
|
...CLOCK_READING_WORKSHEET_DEFINITIONS,
|
||||||
|
...CLOCK_CONNECT_WORKSHEET_DEFINITIONS,
|
||||||
|
];
|
||||||
|
|
||||||
type ClockReadingWorksheetRow =
|
type ClockWorksheetRow = (typeof ALL_CLOCK_DEFINITIONS)[number];
|
||||||
(typeof CLOCK_READING_WORKSHEET_DEFINITIONS)[number];
|
|
||||||
|
|
||||||
const CLOCK_READING_WORKSHEET_BY_ID = Object.fromEntries(
|
const CLOCK_WORKSHEET_BY_ID = Object.fromEntries(
|
||||||
CLOCK_READING_WORKSHEET_DEFINITIONS.map((m) => [m.id, m]),
|
ALL_CLOCK_DEFINITIONS.map((m) => [m.id, m]),
|
||||||
) as Record<string, ClockReadingWorksheetRow>;
|
) as Record<string, ClockWorksheetRow>;
|
||||||
|
|
||||||
export const CLOCK_READING_MODE_OPTIONS = CLOCK_READING_WORKSHEET_DEFINITIONS;
|
/** 时刻类型选项(顺序:随机、整点、半点、刻钟) */
|
||||||
|
export const CLOCK_TIME_MODE_OPTIONS = [
|
||||||
|
{ id: 'random' as const, label: '随机', subtitle: '0–59 分均可' },
|
||||||
|
{ id: 'whole-hour' as const, label: '整点', subtitle: '如 3:00' },
|
||||||
|
{ id: 'half-hour' as const, label: '半点', subtitle: '如 6:30' },
|
||||||
|
{ id: 'quarter-hour' as const, label: '刻钟', subtitle: '如 2:15、7:45' },
|
||||||
|
];
|
||||||
|
|
||||||
export { CLOCK_TIME_MODE_OPTIONS };
|
export type ClockTimeMode = (typeof CLOCK_TIME_MODE_OPTIONS)[number]['id'];
|
||||||
|
|
||||||
|
/** 练习类型选项(顺序:认识时钟、时钟连线) */
|
||||||
|
export const CLOCK_EXERCISE_TYPE_OPTIONS = [
|
||||||
|
{ id: 'clock-reading' as const, label: '认识时钟', subtitle: '看钟写时间' },
|
||||||
|
{ id: 'clock-connect' as const, label: '时钟连线', subtitle: '钟表连对应时间' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export type ClockExerciseType = (typeof CLOCK_EXERCISE_TYPE_OPTIONS)[number]['id'];
|
||||||
|
|
||||||
export function getModeInfo(id: string) {
|
export function getModeInfo(id: string) {
|
||||||
const m = CLOCK_READING_WORKSHEET_BY_ID[id];
|
const m = CLOCK_WORKSHEET_BY_ID[id];
|
||||||
return m ? { title: m.title, desc: m.subtitle } : undefined;
|
return m ? { title: m.title, desc: m.subtitle } : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValidMode(id: string): boolean {
|
export function isValidMode(id: string): boolean {
|
||||||
return id in CLOCK_READING_WORKSHEET_BY_ID;
|
return id in CLOCK_WORKSHEET_BY_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPublishMetaByMode(id: string): DebugPublishMeta | null {
|
export function getPublishMetaByMode(id: string): DebugPublishMeta | null {
|
||||||
const m = CLOCK_READING_WORKSHEET_BY_ID[id];
|
const m = CLOCK_WORKSHEET_BY_ID[id];
|
||||||
if (!m) return null;
|
if (!m) return null;
|
||||||
return {
|
return {
|
||||||
id: m.id,
|
id: m.id,
|
||||||
title: m.title,
|
title: m.title,
|
||||||
subtitle: m.subtitle,
|
subtitle: m.subtitle,
|
||||||
category: 'math',
|
category: 'math',
|
||||||
subcategory: 'clock-reading',
|
subcategory: 'clock',
|
||||||
path: `/mathPages/clockReading/clockReading?id=${m.id}`,
|
path: `/mathPages/clockReading/clockReading?id=${m.id}`,
|
||||||
ageMin: m.ageMin,
|
ageMin: m.ageMin,
|
||||||
ageMax: m.ageMax,
|
ageMax: m.ageMax,
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import ClockReadingDraw from './draw/clockReadingDraw';
|
import ClockReadingDraw from './draw/clockReadingDraw';
|
||||||
|
import ClockConnectDraw from './draw/clockConnectDraw';
|
||||||
import {
|
import {
|
||||||
buildClockReadingData,
|
buildClockReadingData,
|
||||||
type ClockReadingTimeMode,
|
type ClockReadingTimeMode,
|
||||||
} from './generators/clock-generator';
|
} from './generators/clock-generator';
|
||||||
|
import { buildClockConnectData } from './generators/clock-connect-generator';
|
||||||
import { createPage, type CanvasDataState } from '../../base/pageMixin';
|
import { createPage, type CanvasDataState } from '../../base/pageMixin';
|
||||||
import { defaultShareConfig } from '../../config/config';
|
import { defaultShareConfig } from '../../config/config';
|
||||||
import {
|
import {
|
||||||
@@ -10,6 +12,9 @@ import {
|
|||||||
getPublishMetaByMode,
|
getPublishMetaByMode,
|
||||||
isValidMode,
|
isValidMode,
|
||||||
CLOCK_TIME_MODE_OPTIONS,
|
CLOCK_TIME_MODE_OPTIONS,
|
||||||
|
CLOCK_EXERCISE_TYPE_OPTIONS,
|
||||||
|
type ClockTimeMode,
|
||||||
|
type ClockExerciseType,
|
||||||
} from './clockReading.config';
|
} from './clockReading.config';
|
||||||
import type { DebugPublishMeta } from '../../utils/debugPublish';
|
import type { DebugPublishMeta } from '../../utils/debugPublish';
|
||||||
import {
|
import {
|
||||||
@@ -17,14 +22,17 @@ import {
|
|||||||
removeFavorite,
|
removeFavorite,
|
||||||
batchCheckFavorited,
|
batchCheckFavorited,
|
||||||
} from '../../utils/favorites';
|
} from '../../utils/favorites';
|
||||||
|
import type { BaseDrawService } from '../../core/draw/baseDraw';
|
||||||
|
|
||||||
const pageInfoLookup = getModeInfo;
|
const pageInfoLookup = getModeInfo;
|
||||||
const WORKSHEET_ID = 'clock-reading';
|
const DEFAULT_WORKSHEET_ID = 'clock-reading';
|
||||||
|
|
||||||
type PageData = CanvasDataState & {
|
type PageData = CanvasDataState & {
|
||||||
worksheetId: string;
|
worksheetId: string;
|
||||||
timeMode: ClockReadingTimeMode;
|
timeMode: ClockTimeMode;
|
||||||
timeModeOptions: typeof CLOCK_TIME_MODE_OPTIONS;
|
timeModeOptions: typeof CLOCK_TIME_MODE_OPTIONS;
|
||||||
|
exerciseType: ClockExerciseType;
|
||||||
|
exerciseTypeOptions: typeof CLOCK_EXERCISE_TYPE_OPTIONS;
|
||||||
isPreviewFavorite: boolean;
|
isPreviewFavorite: boolean;
|
||||||
isDevEnv: boolean;
|
isDevEnv: boolean;
|
||||||
debugPublishVisible: boolean;
|
debugPublishVisible: boolean;
|
||||||
@@ -38,17 +46,19 @@ createPage(
|
|||||||
ctx: null as RenderingContext | null,
|
ctx: null as RenderingContext | null,
|
||||||
boxHeight: 0,
|
boxHeight: 0,
|
||||||
boxWidth: 0,
|
boxWidth: 0,
|
||||||
drawService: null as ClockReadingDraw | null,
|
drawService: null as BaseDrawService | null,
|
||||||
_favoritedMap: {} as Record<string, boolean>,
|
_favoritedMap: {} as Record<string, boolean>,
|
||||||
|
|
||||||
data: {
|
data: {
|
||||||
pageTitle: '认识钟表',
|
pageTitle: '认识钟表',
|
||||||
functionId: WORKSHEET_ID,
|
functionId: DEFAULT_WORKSHEET_ID,
|
||||||
hasContent: false,
|
hasContent: false,
|
||||||
showShareDialog: false,
|
showShareDialog: false,
|
||||||
worksheetId: WORKSHEET_ID,
|
worksheetId: DEFAULT_WORKSHEET_ID,
|
||||||
timeMode: 'random' as ClockReadingTimeMode,
|
timeMode: 'random' as ClockTimeMode,
|
||||||
timeModeOptions: CLOCK_TIME_MODE_OPTIONS,
|
timeModeOptions: CLOCK_TIME_MODE_OPTIONS,
|
||||||
|
exerciseType: 'clock-reading' as ClockExerciseType,
|
||||||
|
exerciseTypeOptions: CLOCK_EXERCISE_TYPE_OPTIONS,
|
||||||
isPreviewFavorite: false,
|
isPreviewFavorite: false,
|
||||||
isDevEnv: false,
|
isDevEnv: false,
|
||||||
debugPublishVisible: false,
|
debugPublishVisible: false,
|
||||||
@@ -60,27 +70,48 @@ createPage(
|
|||||||
const worksheetId =
|
const worksheetId =
|
||||||
options.id && isValidMode(options.id)
|
options.id && isValidMode(options.id)
|
||||||
? options.id
|
? options.id
|
||||||
: WORKSHEET_ID;
|
: DEFAULT_WORKSHEET_ID;
|
||||||
|
|
||||||
this.syncDebugPublishEnv();
|
this.syncDebugPublishEnv();
|
||||||
|
|
||||||
|
// 根据传入 id 判断练习类型
|
||||||
|
const exerciseType: ClockExerciseType =
|
||||||
|
worksheetId === 'clock-connect' ? 'clock-connect' : 'clock-reading';
|
||||||
|
this.setData({ exerciseType });
|
||||||
|
|
||||||
this.applyWorksheet(worksheetId);
|
this.applyWorksheet(worksheetId);
|
||||||
this.loadFavoritedMap();
|
this.loadFavoritedMap();
|
||||||
},
|
},
|
||||||
|
|
||||||
onSelectTimeMode(e: WechatMiniprogram.TouchEvent) {
|
onSelectTimeMode(e: WechatMiniprogram.TouchEvent) {
|
||||||
const mode = e.currentTarget.dataset.mode as
|
const mode = e.currentTarget.dataset.mode as
|
||||||
| ClockReadingTimeMode
|
| ClockTimeMode
|
||||||
| undefined;
|
| undefined;
|
||||||
if (!mode || mode === this.data.timeMode) return;
|
if (!mode || mode === this.data.timeMode) return;
|
||||||
this.setData({ timeMode: mode }, () => this.drawCanvas());
|
this.setData({ timeMode: mode }, () => this.drawCanvas());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onSelectExerciseType(e: WechatMiniprogram.TouchEvent) {
|
||||||
|
const type = e.currentTarget.dataset.type as
|
||||||
|
| ClockExerciseType
|
||||||
|
| undefined;
|
||||||
|
if (!type || type === this.data.exerciseType) return;
|
||||||
|
|
||||||
|
const worksheetId = type;
|
||||||
|
this.setData({ exerciseType: type });
|
||||||
|
this.applyWorksheet(worksheetId);
|
||||||
|
|
||||||
|
// 切换练习类型需要重新创建 drawService
|
||||||
|
this.recreateDrawService();
|
||||||
|
},
|
||||||
|
|
||||||
onCanvasReady(e: WechatMiniprogram.CustomEvent) {
|
onCanvasReady(e: WechatMiniprogram.CustomEvent) {
|
||||||
this.initCanvasFromComponent(e.detail, {
|
this.initCanvasFromComponent(e.detail, {
|
||||||
createDrawService: (
|
createDrawService: (
|
||||||
canvas: Canvas,
|
canvas: Canvas,
|
||||||
ctx: RenderingContext,
|
ctx: RenderingContext,
|
||||||
options?: Record<string, unknown>,
|
options?: Record<string, unknown>,
|
||||||
) => new ClockReadingDraw(canvas, ctx, options),
|
) => this.createDrawForType(canvas, ctx, options),
|
||||||
drawServiceOptions: {
|
drawServiceOptions: {
|
||||||
title: this.data.pageTitle,
|
title: this.data.pageTitle,
|
||||||
},
|
},
|
||||||
@@ -90,14 +121,45 @@ createPage(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
createDrawForType(
|
||||||
|
canvas: Canvas,
|
||||||
|
ctx: RenderingContext,
|
||||||
|
options?: Record<string, unknown>,
|
||||||
|
): BaseDrawService {
|
||||||
|
if (this.data.exerciseType === 'clock-connect') {
|
||||||
|
return new ClockConnectDraw(canvas, ctx, options);
|
||||||
|
}
|
||||||
|
return new ClockReadingDraw(canvas, ctx, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
recreateDrawService() {
|
||||||
|
if (!this.canvas || !this.ctx) return;
|
||||||
|
const options = { title: this.data.pageTitle };
|
||||||
|
this.drawService = this.createDrawForType(
|
||||||
|
this.canvas,
|
||||||
|
this.ctx,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
this.drawCanvas();
|
||||||
|
},
|
||||||
|
|
||||||
async drawCanvas() {
|
async drawCanvas() {
|
||||||
if (!this.ctx || !this.drawService) return;
|
if (!this.ctx || !this.drawService) return;
|
||||||
try {
|
try {
|
||||||
const data = buildClockReadingData(this.data.timeMode);
|
if (this.data.exerciseType === 'clock-connect') {
|
||||||
await (this.drawService as ClockReadingDraw).draw(data);
|
const data = buildClockConnectData(
|
||||||
|
this.data.timeMode as ClockTimeMode,
|
||||||
|
);
|
||||||
|
await (this.drawService as ClockConnectDraw).draw(data);
|
||||||
|
} else {
|
||||||
|
const data = buildClockReadingData(
|
||||||
|
this.data.timeMode as ClockReadingTimeMode,
|
||||||
|
);
|
||||||
|
await (this.drawService as ClockReadingDraw).draw(data);
|
||||||
|
}
|
||||||
this.setData({ hasContent: true });
|
this.setData({ hasContent: true });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('clockReading draw failed', e);
|
console.error('clock draw failed', e);
|
||||||
this.setData({ hasContent: false });
|
this.setData({ hasContent: false });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -125,9 +187,9 @@ createPage(
|
|||||||
},
|
},
|
||||||
|
|
||||||
async loadFavoritedMap() {
|
async loadFavoritedMap() {
|
||||||
const ids = [WORKSHEET_ID];
|
const ids = ['clock-reading', 'clock-connect'];
|
||||||
this._favoritedMap = await batchCheckFavorited(ids);
|
this._favoritedMap = await batchCheckFavorited(ids);
|
||||||
if (this._favoritedMap?.[WORKSHEET_ID]) {
|
if (this._favoritedMap?.[this.data.worksheetId]) {
|
||||||
this.setData({ isPreviewFavorite: true });
|
this.setData({ isPreviewFavorite: true });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -30,6 +30,26 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view class="cr-section">
|
||||||
|
<text class="cr-section-title">练习类型</text>
|
||||||
|
<view class="cr-chip-row">
|
||||||
|
<view
|
||||||
|
wx:for="{{exerciseTypeOptions}}"
|
||||||
|
wx:key="id"
|
||||||
|
class="cr-chip {{exerciseType === item.id ? 'cr-chip--active' : ''}}"
|
||||||
|
hover-class="cr-chip--pressed"
|
||||||
|
hover-start-time="0"
|
||||||
|
hover-stay-time="70"
|
||||||
|
data-type="{{item.id}}"
|
||||||
|
bind:tap="onSelectExerciseType">
|
||||||
|
<view class="cr-chip__text">
|
||||||
|
<text class="cr-chip__label">{{item.label}}</text>
|
||||||
|
<text class="cr-chip__subtitle">{{item.subtitle}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ import type {
|
|||||||
ClockConnectData,
|
ClockConnectData,
|
||||||
ClockConnectProblem,
|
ClockConnectProblem,
|
||||||
} from '../generators/clock-connect-generator';
|
} from '../generators/clock-connect-generator';
|
||||||
import { drawAnalogClock } from '../../clockReading/draw/drawAnalogClock';
|
import { drawAnalogClock } from './drawAnalogClock';
|
||||||
import { NUMBER_COLORS } from '../../../constants/colors';
|
import { NUMBER_COLORS } from '../../../constants/colors';
|
||||||
|
|
||||||
const ROWS = 6;
|
const ROWS = 6;
|
||||||
+1
-2
@@ -32,8 +32,7 @@ const MINUTES_BY_MODE: Record<
|
|||||||
|
|
||||||
function pickMinute(timeMode: ClockConnectTimeMode): number {
|
function pickMinute(timeMode: ClockConnectTimeMode): number {
|
||||||
if (timeMode === 'random') {
|
if (timeMode === 'random') {
|
||||||
const options = [0, 15, 30, 45];
|
return Math.floor(Math.random() * 60);
|
||||||
return options[Math.floor(Math.random() * options.length)];
|
|
||||||
}
|
}
|
||||||
const pool = MINUTES_BY_MODE[timeMode];
|
const pool = MINUTES_BY_MODE[timeMode];
|
||||||
return pool[Math.floor(Math.random() * pool.length)] ?? 0;
|
return pool[Math.floor(Math.random() * pool.length)] ?? 0;
|
||||||
@@ -72,12 +72,12 @@ export const HOME_NOTICES: HomeNotice[] = [
|
|||||||
{
|
{
|
||||||
id: 'welcome',
|
id: 'welcome',
|
||||||
text: '欢迎来到 涂鸦丫,趣味练习纸任你选',
|
text: '欢迎来到 涂鸦丫,趣味练习纸任你选',
|
||||||
path: '/mathPages/clockReading/clockReading',
|
path: '/mathPages/clockReading/clockReading?id=clock-connect',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: `update-${APP_VERSION}`,
|
id: `update-${APP_VERSION}`,
|
||||||
text: `${APP_VERSION} 上线:新增幼儿认识时钟练习`,
|
text: `${APP_VERSION} 上线:新增幼儿认识时钟,连线练习题`,
|
||||||
path: '/mathPages/clockReading/clockReading',
|
path: '/mathPages/clockReading/clockReading?id=clock-connect',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { MOCK_SEED_COUNTS } from './mockLikes';
|
import { MOCK_SEED_COUNTS } from './mockLikes';
|
||||||
import {
|
import {
|
||||||
MATH_WORKSHEET_DEFINITIONS,
|
MATH_WORKSHEET_DEFINITIONS,
|
||||||
|
CLOCK_READING_WORKSHEET_DEFINITIONS,
|
||||||
CLOCK_CONNECT_WORKSHEET_DEFINITIONS,
|
CLOCK_CONNECT_WORKSHEET_DEFINITIONS,
|
||||||
FOCUS_WORKSHEET_DEFINITIONS,
|
FOCUS_WORKSHEET_DEFINITIONS,
|
||||||
LETTER_TRACING_WORKSHEET_DEFINITIONS,
|
LETTER_TRACING_WORKSHEET_DEFINITIONS,
|
||||||
@@ -80,6 +81,10 @@ const CONFIG_SOURCES: ConfigSource[] = [
|
|||||||
label: 'wordColoring',
|
label: 'wordColoring',
|
||||||
data: WORD_COLORING_WORKSHEET_DEFINITIONS,
|
data: WORD_COLORING_WORKSHEET_DEFINITIONS,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'clockReading',
|
||||||
|
data: CLOCK_READING_WORKSHEET_DEFINITIONS,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'clockConnect',
|
label: 'clockConnect',
|
||||||
data: CLOCK_CONNECT_WORKSHEET_DEFINITIONS,
|
data: CLOCK_CONNECT_WORKSHEET_DEFINITIONS,
|
||||||
|
|||||||
Reference in New Issue
Block a user