feat: 汉字每日打卡页面优化

This commit is contained in:
R524809
2026-05-22 11:00:04 +08:00
parent 41082f59ef
commit bcece55238
7 changed files with 95 additions and 27 deletions
@@ -38,7 +38,7 @@ export const HANDWRITING_SHEET_WORKSHEET_DEFINITIONS: HandwritingSheetWorksheetD
ageMin: 5, ageMin: 5,
ageMax: 8, ageMax: 8,
difficulty: 2, difficulty: 2,
tags: ['汉字', '每日练习', '打卡', '拼音', '笔顺'], tags: ['汉字', '每日练习', '每日打卡', '打卡', '拼音', '笔顺'],
sortOrder: 36, sortOrder: 36,
}, },
]; ];
@@ -8,7 +8,7 @@ import {
pickPrimaryPinyin, pickPrimaryPinyin,
HanziReadingsMap, HanziReadingsMap,
} from '../shared/getWordsSvgJson'; } from '../shared/getWordsSvgJson';
import { WORDS } from '../../core/data/words'; import { WORDS, getCategoryTabIndex } from '../../core/data/words';
import { CharacterItem } from '../../types/characterType'; import { CharacterItem } from '../../types/characterType';
import tracker from '../../utils/tracker'; import tracker from '../../utils/tracker';
import { createPage } from '../../base/pageMixin'; import { createPage } from '../../base/pageMixin';
@@ -179,7 +179,7 @@ createPage(
currentMode: mode, currentMode: mode,
functionId: mode, functionId: mode,
pickerMax: max, pickerMax: max,
showCustomPanel: !isCheckin, showCustomPanel: true,
}, },
() => { () => {
this.initPageInfo(mode); this.initPageInfo(mode);
@@ -300,7 +300,7 @@ createPage(
const categoryId = Number(e.currentTarget.dataset.categoryId); const categoryId = Number(e.currentTarget.dataset.categoryId);
this.setData({ this.setData({
showSelectWordPopup: true, showSelectWordPopup: true,
pickerCurrentTab: categoryId, pickerCurrentTab: getCategoryTabIndex(categoryId),
}); });
}, },
@@ -428,9 +428,9 @@ createPage(
this.setData( this.setData(
{ {
words: supported, words: supported,
inputWords: isCheckin ? [] : supported, inputWords: supported,
selectedWords: isCheckin ? supported : [], selectedWords: [],
inputValue: isCheckin ? '' : supported.join(''), inputValue: supported.join(''),
}, },
() => this.renderPracticeContent().catch(console.error), () => this.renderPracticeContent().catch(console.error),
); );
@@ -1,5 +1,9 @@
import { WATER_COLORS } from '../../constants/colors'; import { WATER_COLORS } from '../../constants/colors';
import { WORDS } from '../../core/data/words'; import {
WORDS,
collectCategoryWords,
getCategoryTabIndex,
} from '../../core/data/words';
import { import {
DrawServiceFactory, DrawServiceFactory,
type IDrawService, type IDrawService,
@@ -195,7 +199,7 @@ createPage(
/** 随机生成文字卡片 */ /** 随机生成文字卡片 */
refreshCardList() { refreshCardList() {
const allWords = WORDS.slice(0, 2).reduce( const allWords = WORDS.slice(0, 2).reduce(
(acc, cat) => acc.concat(cat.words), (acc, cat) => acc.concat(collectCategoryWords(cat)),
[] as string[], [] as string[],
); );
const selected: string[] = []; const selected: string[] = [];
@@ -312,7 +316,7 @@ createPage(
const categoryId = Number(e.currentTarget.dataset.categoryId); const categoryId = Number(e.currentTarget.dataset.categoryId);
this.setData({ this.setData({
showSelectWordPopup: true, showSelectWordPopup: true,
pickerCurrentTab: categoryId, pickerCurrentTab: getCategoryTabIndex(categoryId),
}); });
}, },
@@ -33,34 +33,56 @@
} }
.word-list-wrapper { .word-list-wrapper {
padding: 28rpx 0; padding: 20rpx 0;
overflow-y: auto; overflow-y: auto;
height: 500rpx; height: 500rpx;
// 一二年级等有上下册分区的 tab
.word-section { .word-section {
margin-bottom: 36rpx; margin-bottom: 12rpx;
padding-top: 12rpx;
&:first-child {
padding-top: 4rpx;
}
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 6rpx;
} }
.word-section-title { .word-section-title {
font-size: 26rpx;
color: #888888;
padding-left: 28rpx;
margin-bottom: 20rpx;
font-weight: bold;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center;
text-align: center;
font-size: 34rpx;
font-weight: bold;
color: #453900;
letter-spacing: 4rpx;
margin: 26rpx 0 24rpx;
// padding: 0 28rpx;
&::before,
&::after {
content: "";
flex: 1;
max-width: 80rpx;
height: 2rpx;
background: linear-gradient(90deg,
transparent,
rgba(147, 211, 51, 0.65));
border-radius: 2rpx;
}
&::before { &::before {
content: ""; margin-right: 20rpx;
display: inline-block; }
width: 6rpx;
height: 24rpx; &::after {
background-color: #93d333; margin-left: 20rpx;
margin-right: 12rpx; background: linear-gradient(90deg,
border-radius: 3rpx; rgba(147, 211, 51, 0.65),
transparent);
} }
} }
} }
+19
View File
@@ -255,3 +255,22 @@ export const WORDS = [
words: ['个', '只', '匹', '条', '朵', '棵', '片', '张', '本', '杯', '块', '双'], words: ['个', '只', '匹', '条', '朵', '棵', '片', '张', '本', '杯', '块', '双'],
}, },
]; ];
/** 将 categoryId 转为 word-picker / van-tabs 使用的数组下标 */
export function getCategoryTabIndex(categoryId: number): number {
const index = WORDS.findIndex((cat) => cat.categoryId === categoryId);
return index >= 0 ? index : 0;
}
/** 汇总分类下全部汉字(含一二年级 sections) */
export function collectCategoryWords(
cat: (typeof WORDS)[number],
): string[] {
if (cat.words?.length) {
return cat.words;
}
if (cat.sections?.length) {
return cat.sections.flatMap((section) => section.words);
}
return [];
}
+24 -1
View File
@@ -113,10 +113,11 @@ export class BaseDrawService {
} }
/** /**
* 暂未使用
* 页脚:顶部分割线 + 居中 `doodle-footer.png`(小鸭与「涂鸦丫」品牌图)。 * 页脚:顶部分割线 + 居中 `doodle-footer.png`(小鸭与「涂鸦丫」品牌图)。
* 图片底边与纸张底边留白对齐,便于「探头」视觉。请在整页正文绘制完成后调用,避免被内容覆盖。 * 图片底边与纸张底边留白对齐,便于「探头」视觉。请在整页正文绘制完成后调用,避免被内容覆盖。
*/ */
async drawPrintFooter(): Promise<void> { async drawPrintImageFooter(): Promise<void> {
const { ctx, canvasWidth, canvasHeight } = this; const { ctx, canvasWidth, canvasHeight } = this;
const margin = 24; const margin = 24;
const bottomMargin = 2; const bottomMargin = 2;
@@ -172,6 +173,28 @@ export class BaseDrawService {
} }
} }
/**
* 页脚:页面底部居中绘制品牌文案「涂鸦丫小程序」(粗体)。
* 请在整页正文绘制完成后调用,避免被内容覆盖。
*/
async drawPrintFooter(): Promise<void> {
const { ctx, canvasWidth, canvasHeight } = this;
const text = '涂鸦丫小程序';
const bottomMargin = 12;
const fontSize = 13;
const font = `bold ${fontSize}px "Microsoft Yahei", sans-serif`;
const textColor = '#7C766A';
ctx.save();
ctx.font = font;
ctx.fillStyle = textColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const y = canvasHeight - bottomMargin - fontSize / 2;
ctx.fillText(text, canvasWidth / 2, y);
ctx.restore();
}
/** /**
* 绘制分割线(逻辑像素,尺寸除以3) * 绘制分割线(逻辑像素,尺寸除以3)
*/ */
@@ -51,7 +51,7 @@ export default class TripleDraw extends BaseDrawService {
loadLetterFont(PRINT_CLEARLY_DASHED), loadLetterFont(PRINT_CLEARLY_DASHED),
]); ]);
this.drawContent(data.sections); this.drawContent(data.sections);
this.drawPrintFooter(); // this.drawPrintFooter();
} }
private drawContent(sections: TripleSection[]) { private drawContent(sections: TripleSection[]) {