feat: 增加下载分享检查功能

This commit is contained in:
R524809
2025-11-20 17:54:16 +08:00
parent 654ea69915
commit ddab64bb20
11 changed files with 350 additions and 52 deletions
+1
View File
@@ -7,6 +7,7 @@
"usingComponents": { "usingComponents": {
"toy-button": "/ui/button/button", "toy-button": "/ui/button/button",
"van-icon": "@vant/weapp/icon/index", "van-icon": "@vant/weapp/icon/index",
"van-dialog": "@vant/weapp/dialog/index",
"word-input": "/components/word-input/word-input", "word-input": "/components/word-input/word-input",
"word-card": "/components/word-card/word-card", "word-card": "/components/word-card/word-card",
"word-picker": "/components/word-picker/word-picker", "word-picker": "/components/word-picker/word-picker",
+103 -22
View File
@@ -1,5 +1,9 @@
import WordDrawService from '../../service/wordDrawService'; import WordDrawService from '../../service/wordDrawService';
import { checkAndSaveImage } from '../../utils/saveImage'; import { checkAndSaveImage } from '../../utils/saveImage';
import {
shouldShowShareGuide,
recordShareSuccess,
} from '../../utils/shareGuide';
import { PAPER_SIZE } from '../../constants/colors'; import { PAPER_SIZE } from '../../constants/colors';
import { getWordsSvgData } from '../../utils/getWordsSvgJson'; import { getWordsSvgData } from '../../utils/getWordsSvgJson';
import { WORDS } from '../../constants/words'; import { WORDS } from '../../constants/words';
@@ -22,6 +26,7 @@ Page({
currentColor: '', currentColor: '',
boxWidth: 0, boxWidth: 0,
boxHeight: 0, boxHeight: 0,
showShareDialog: false, // 显示分享引导弹窗
}, },
async onLoad() { async onLoad() {
@@ -29,14 +34,17 @@ Page({
const hasShowPracticeDemo = const hasShowPracticeDemo =
wx.getStorageSync('hasShowPracticeDemo') || false; wx.getStorageSync('hasShowPracticeDemo') || false;
if (!hasShowPracticeDemo) { if (!hasShowPracticeDemo) {
this.setData({ this.setData(
words: ['好', '好', '学', '习', '天', '天', '向', '上'] {
}, () => { words: ['好', '好', '学', '习', '天', '天', '向', '上'],
wx.setStorageSync('hasShowPracticeDemo', true); },
}) () => {
wx.setStorageSync('hasShowPracticeDemo', true);
},
);
} }
await this.setCanvasBoxSize(); await this.setCanvasBoxSize();
await this.initCanvas() await this.initCanvas();
}, },
async loadSvgWords() { async loadSvgWords() {
@@ -48,7 +56,11 @@ Page({
this.svgWords = svgWordsData; this.svgWords = svgWordsData;
wx.hideToast(); wx.hideToast();
console.log('SVG汉字数据加载成功,共', Object.keys(this.svgWords).length, '个汉字'); console.log(
'SVG汉字数据加载成功,共',
Object.keys(this.svgWords).length,
'个汉字',
);
const { words } = this.data as any; const { words } = this.data as any;
if (words && words.length > 0) { if (words && words.length > 0) {
@@ -70,7 +82,7 @@ Page({
// 用户点击重试,重新加载 // 用户点击重试,重新加载
this.loadSvgWords(); this.loadSvgWords();
} }
} },
}); });
} }
}, },
@@ -143,18 +155,25 @@ Page({
const { key } = e.detail; const { key } = e.detail;
const { words } = this.data as any; const { words } = this.data as any;
const next = words.filter((_: string, index: number) => index !== key); const next = words.filter((_: string, index: number) => index !== key);
this.setData({ words: next }, () => this.renderPracticeContent().catch(console.error)); this.setData({ words: next }, () =>
this.renderPracticeContent().catch(console.error),
);
}, },
// 清空 // 清空
clearWords() { clearWords() {
this.setData({ words: [] }, () => this.renderPracticeContent().catch(console.error)); this.setData({ words: [] }, () =>
this.renderPracticeContent().catch(console.error),
);
}, },
// 随机生成(取基础分类,过滤为可用SVG字,最多11个) // 随机生成(取基础分类,过滤为可用SVG字,最多11个)
refreshWords() { refreshWords() {
// 选取较简单的几个分类(如 0:基础独体字,1:生活高频字,2:自然与动作) // 选取较简单的几个分类(如 0:基础独体字,1:生活高频字,2:自然与动作)
const candidate = WORDS.slice(0, 3).reduce((acc: string[], c: any) => acc.concat(c.words), [] as string[]); const candidate = WORDS.slice(0, 3).reduce(
(acc: string[], c: any) => acc.concat(c.words),
[] as string[],
);
// 去重 // 去重
const unique = Array.from(new Set(candidate)); const unique = Array.from(new Set(candidate));
// 打乱 // 打乱
@@ -164,10 +183,15 @@ Page({
// 过滤为支持的SVG字 // 过滤为支持的SVG字
const supported = this.getSupportedWords(picked); const supported = this.getSupportedWords(picked);
if (supported.length === 0) { if (supported.length === 0) {
wx.showToast({ title: '随机到的字暂不支持,重试一下', icon: 'none' }); wx.showToast({
title: '随机到的字暂不支持,重试一下',
icon: 'none',
});
return; return;
} }
this.setData({ words: supported }, () => this.renderPracticeContent().catch(console.error)); this.setData({ words: supported }, () =>
this.renderPracticeContent().catch(console.error),
);
}, },
// 校验 & 分割 // 校验 & 分割
@@ -181,7 +205,6 @@ Page({
return matches || []; return matches || [];
}, },
setCanvasBoxSize() { setCanvasBoxSize() {
const query = wx.createSelectorQuery(); const query = wx.createSelectorQuery();
query query
@@ -212,13 +235,17 @@ Page({
if (ctx) { if (ctx) {
this.canvas = canvas; this.canvas = canvas;
this.ctx = ctx; this.ctx = ctx;
this.wordDrawService = new WordDrawService(canvas, ctx); this.wordDrawService = new WordDrawService(
canvas,
ctx,
);
// 初始化时只绘制页眉和布局 // 初始化时只绘制页眉和布局
await this.wordDrawService.drawLayout(); await this.wordDrawService.drawLayout();
// 绘制完成后计算并缓存最大行列数(与实际绘制一致) // 绘制完成后计算并缓存最大行列数(与实际绘制一致)
const { maxRow, maxCol } = this.wordDrawService.getMaxGridLayout(); const { maxRow, maxCol } =
this.wordDrawService.getMaxGridLayout();
this.maxRow = maxRow; this.maxRow = maxRow;
this.maxCol = maxCol; this.maxCol = maxCol;
@@ -269,18 +296,25 @@ Page({
} }
// 处理布局和生成练字数据(基于实际最大行列数) // 处理布局和生成练字数据(基于实际最大行列数)
const characterData = this.processCharacterLayout(supportedWords, maxRow, maxCol); const characterData = this.processCharacterLayout(
supportedWords,
maxRow,
maxCol,
);
this.wordDrawService.drawPracticeContent(characterData); this.wordDrawService.drawPracticeContent(characterData);
}, },
/** 检查汉字是否支持,返回支持的汉字列表 */ /** 检查汉字是否支持,返回支持的汉字列表 */
getSupportedWords(words: string[]): string[] { getSupportedWords(words: string[]): string[] {
return words.filter(word => this.svgWords[word]); return words.filter((word) => this.svgWords[word]);
}, },
/** 处理汉字布局,生成练字数据 */ /** 处理汉字布局,生成练字数据 */
processCharacterLayout(words: string[], maxRow: number, maxCol: number): CharacterItem[] { processCharacterLayout(
words: string[],
maxRow: number,
maxCol: number,
): CharacterItem[] {
let rowIndex = 0; let rowIndex = 0;
const characterData: CharacterItem[] = []; const characterData: CharacterItem[] = [];
const boundaryWords: string[] = []; const boundaryWords: string[] = [];
@@ -319,11 +353,58 @@ Page({
wx.showToast({ title: '请先生成练字贴', icon: 'none' }); wx.showToast({ title: '请先生成练字贴', icon: 'none' });
return; return;
} }
// 检查是否需要显示分享引导
if (shouldShowShareGuide()) {
this.setData({ showShareDialog: true });
return;
}
// 直接下载
checkAndSaveImage(this.canvas); checkAndSaveImage(this.canvas);
}, },
/** 关闭分享引导弹窗 */
onCloseShareDialog() {
this.setData({ showShareDialog: false });
},
/** 点击转发按钮 */
onShareToFriend() {
// 记录分享成功(用户点击了分享按钮,视为已分享)
recordShareSuccess();
this.setData({ showShareDialog: false });
// 允许继续下载
if (this.canvas) {
checkAndSaveImage(this.canvas);
}
wx.showToast({
title: '分享后即可继续下载',
icon: 'success',
duration: 2000,
});
},
/** 点击分享到朋友圈按钮 */
onShareToTimeline() {
// 记录分享成功(用户点击了分享按钮,视为已分享)
recordShareSuccess();
this.setData({ showShareDialog: false });
// 允许继续下载
if (this.canvas) {
checkAndSaveImage(this.canvas);
}
wx.showToast({
title: '分享后即可继续下载',
icon: 'success',
duration: 2000,
});
},
// 分享功能 // 分享功能
onShareAppMessage() { onShareAppMessage() {
// 记录分享成功(用户真正分享了)
recordShareSuccess();
return { return {
title: '涂鸦丫-练字|识字|打印', title: '涂鸦丫-练字|识字|打印',
path: '/pages/copyBook/index', path: '/pages/copyBook/index',
@@ -331,11 +412,11 @@ Page({
}, },
onShareTimeline() { onShareTimeline() {
// 记录分享成功(用户真正分享了)
recordShareSuccess();
return { return {
title: '涂鸦丫-练字|识字|打印', title: '涂鸦丫-练字|识字|打印',
query: '/pages/copyBook/index', query: '/pages/copyBook/index',
}; };
}, },
}); });
+10
View File
@@ -91,6 +91,16 @@
max="11" max="11"
bind:onClose="closeSelectWordPopup" bind:onClose="closeSelectWordPopup"
bind:onChange="onChangeWord" /> bind:onChange="onChangeWord" />
<van-dialog
show="{{showShareDialog}}"
title="分享解锁下载"
message="今日免费下载次数已用完,分享给好友或朋友圈后即可继续免费下载"
show-cancel-button
confirm-button-text="转发给好友"
cancel-button-text="分享到朋友圈"
bind:confirm="onShareToFriend"
bind:cancel="onShareToTimeline"
bind:close="onCloseShareDialog" />
<view class="empty"></view> <view class="empty"></view>
</view> </view>
+1
View File
@@ -8,6 +8,7 @@
"van-cell": "@vant/weapp/cell/index", "van-cell": "@vant/weapp/cell/index",
"van-icon": "@vant/weapp/icon/index", "van-icon": "@vant/weapp/icon/index",
"van-popup": "@vant/weapp/popup/index", "van-popup": "@vant/weapp/popup/index",
"van-dialog": "@vant/weapp/dialog/index",
"word-input": "../../components/word-input/word-input", "word-input": "../../components/word-input/word-input",
"word-card": "../../components/word-card/word-card", "word-card": "../../components/word-card/word-card",
"color-picker": "../../components/color-picker/color-picker", "color-picker": "../../components/color-picker/color-picker",
+56 -2
View File
@@ -6,6 +6,10 @@ import {
TemplateType, TemplateType,
} from '../../service/drawServiceFactory'; } from '../../service/drawServiceFactory';
import { checkAndSaveImage } from '../../utils/saveImage'; import { checkAndSaveImage } from '../../utils/saveImage';
import {
shouldShowShareGuide,
recordShareSuccess,
} from '../../utils/shareGuide';
Page({ Page({
canvas: null as Canvas | null, canvas: null as Canvas | null,
@@ -25,6 +29,7 @@ Page({
selectedTemplate: 'find', // 选中的模板类型 selectedTemplate: 'find', // 选中的模板类型
env: 'release', env: 'release',
isPCDevtool: false, isPCDevtool: false,
showShareDialog: false, // 显示分享引导弹窗
}, },
onLoad() { onLoad() {
@@ -280,10 +285,55 @@ Page({
/** 下载打印 */ /** 下载打印 */
exportToPrint() { exportToPrint() {
if (this.canvas && this.data.cardList.length > 0) { if (!this.canvas || this.data.cardList.length <= 0) {
checkAndSaveImage(this.canvas);
return; return;
} }
// 检查是否需要显示分享引导
if (shouldShowShareGuide()) {
this.setData({ showShareDialog: true });
return;
}
// 直接下载
checkAndSaveImage(this.canvas);
},
/** 关闭分享引导弹窗 */
onCloseShareDialog() {
this.setData({ showShareDialog: false });
},
/** 点击转发按钮 */
onShareToFriend() {
// 记录分享成功(用户点击了分享按钮,视为已分享)
recordShareSuccess();
this.setData({ showShareDialog: false });
// 允许继续下载
if (this.canvas && this.data.cardList.length > 0) {
checkAndSaveImage(this.canvas);
}
wx.showToast({
title: '分享后即可继续下载',
icon: 'success',
duration: 2000,
});
},
/** 点击分享到朋友圈按钮 */
onShareToTimeline() {
// 记录分享成功(用户点击了分享按钮,视为已分享)
recordShareSuccess();
this.setData({ showShareDialog: false });
// 允许继续下载
if (this.canvas && this.data.cardList.length > 0) {
checkAndSaveImage(this.canvas);
}
wx.showToast({
title: '分享后即可继续下载',
icon: 'success',
duration: 2000,
});
}, },
onColorTap(e: WechatMiniprogram.CustomEvent) { onColorTap(e: WechatMiniprogram.CustomEvent) {
@@ -324,12 +374,16 @@ Page({
}, },
onShareAppMessage() { onShareAppMessage() {
// 记录分享成功(用户真正分享了)
recordShareSuccess();
return { return {
title: '涂鸦丫-涂色|识字|画画|打印', title: '涂鸦丫-涂色|识字|画画|打印',
path: '/pages/index/index', path: '/pages/index/index',
}; };
}, },
onShareTimeline() { onShareTimeline() {
// 记录分享成功(用户真正分享了)
recordShareSuccess();
return { return {
title: '涂鸦丫-涂色|识字|画画|打印', title: '涂鸦丫-涂色|识字|画画|打印',
query: '/pages/index/index', query: '/pages/index/index',
+13 -3
View File
@@ -135,6 +135,16 @@
下载打印 下载打印
</toy-button> </toy-button>
</view> </view>
<introduction-popup <introduction-popup
wx:if="{{showIntroductionPopup}}" wx:if="{{showIntroductionPopup}}"
bind:onClose="onCloseIntroductionPopup" /> bind:onClose="onCloseIntroductionPopup" />
<van-dialog
show="{{showShareDialog}}"
title="分享解锁下载"
message="今日免费下载次数已用完,分享给好友或朋友圈后即可继续免费下载"
show-cancel-button
confirm-button-text="转发给好友"
cancel-button-text="分享到朋友圈"
bind:confirm="onShareToFriend"
bind:cancel="onShareToTimeline"
bind:close="onCloseShareDialog" />
+1
View File
@@ -8,6 +8,7 @@
"van-divider": "@vant/weapp/divider/index", "van-divider": "@vant/weapp/divider/index",
"van-icon": "@vant/weapp/icon/index", "van-icon": "@vant/weapp/icon/index",
"van-popup": "@vant/weapp/popup/index", "van-popup": "@vant/weapp/popup/index",
"van-dialog": "@vant/weapp/dialog/index",
"toy-button": "../../ui/button/button", "toy-button": "../../ui/button/button",
"shape-card": "../../components/shape-card/shape-card", "shape-card": "../../components/shape-card/shape-card",
"shape-picker": "../../components/shape-picker/shape-picker", "shape-picker": "../../components/shape-picker/shape-picker",
+56 -2
View File
@@ -2,6 +2,10 @@ import { SHAPES, ShapeCard } from '../../constants/shapes';
import { WATER_COLORS, PAPER_SIZE } from '../../constants/colors'; import { WATER_COLORS, PAPER_SIZE } from '../../constants/colors';
import ShapeDrawService from '../../service/shapeDrawService'; import ShapeDrawService from '../../service/shapeDrawService';
import { checkAndSaveImage } from '../../utils/saveImage'; import { checkAndSaveImage } from '../../utils/saveImage';
import {
shouldShowShareGuide,
recordShareSuccess,
} from '../../utils/shareGuide';
Page({ Page({
@@ -20,6 +24,7 @@ Page({
currentIndex: 0, currentIndex: 0,
currentColor: '', currentColor: '',
isPCDevtool: false, isPCDevtool: false,
showShareDialog: false, // 显示分享引导弹窗
}, },
onLoad() { onLoad() {
@@ -263,12 +268,16 @@ Page({
}, },
onShareAppMessage() { onShareAppMessage() {
// 记录分享成功(用户真正分享了)
recordShareSuccess();
return { return {
title: '涂鸦丫-涂色|识字|画画|打印', title: '涂鸦丫-涂色|识字|画画|打印',
path: '/pages/index/index', path: '/pages/index/index',
}; };
}, },
onShareTimeline() { onShareTimeline() {
// 记录分享成功(用户真正分享了)
recordShareSuccess();
return { return {
title: '涂鸦丫-涂色|识字|画画|打印', title: '涂鸦丫-涂色|识字|画画|打印',
query: '/pages/index/index', query: '/pages/index/index',
@@ -277,10 +286,55 @@ Page({
/** 下载打印 */ /** 下载打印 */
exportToPrint() { exportToPrint() {
if (this.canvas && this.data.shapeList.length > 0) { if (!this.canvas || this.data.shapeList.length <= 0) {
checkAndSaveImage(this.canvas);
return; return;
} }
// 检查是否需要显示分享引导
if (shouldShowShareGuide()) {
this.setData({ showShareDialog: true });
return;
}
// 直接下载
checkAndSaveImage(this.canvas);
},
/** 关闭分享引导弹窗 */
onCloseShareDialog() {
this.setData({ showShareDialog: false });
},
/** 点击转发按钮 */
onShareToFriend() {
// 记录分享成功(用户点击了分享按钮,视为已分享)
recordShareSuccess();
this.setData({ showShareDialog: false });
// 允许继续下载
if (this.canvas && this.data.shapeList.length > 0) {
checkAndSaveImage(this.canvas);
}
wx.showToast({
title: '分享后即可继续下载',
icon: 'success',
duration: 2000,
});
},
/** 点击分享到朋友圈按钮 */
onShareToTimeline() {
// 记录分享成功(用户点击了分享按钮,视为已分享)
recordShareSuccess();
this.setData({ showShareDialog: false });
// 允许继续下载
if (this.canvas && this.data.shapeList.length > 0) {
checkAndSaveImage(this.canvas);
}
wx.showToast({
title: '分享后即可继续下载',
icon: 'success',
duration: 2000,
});
}, },
onUnload() { onUnload() {
+10
View File
@@ -67,6 +67,16 @@
</view> </view>
<view class="empty"></view> <view class="empty"></view>
</view> </view>
<van-dialog
show="{{showShareDialog}}"
title="分享解锁下载"
message="今日免费下载次数已用完,分享给好友或朋友圈后即可继续免费下载"
show-cancel-button
confirm-button-text="转发给好友"
cancel-button-text="分享到朋友圈"
bind:confirm="onShareToFriend"
bind:cancel="onShareToTimeline"
bind:close="onCloseShareDialog" />
<view class="bottom-btn-box"> <view class="bottom-btn-box">
<toy-button <toy-button
openType="share" openType="share"
+28 -23
View File
@@ -1,3 +1,5 @@
import { recordDownloadSuccess } from './shareGuide';
const doSaveImage = (canvas: Canvas) => { const doSaveImage = (canvas: Canvas) => {
wx.canvasToTempFilePath({ wx.canvasToTempFilePath({
canvas: canvas, canvas: canvas,
@@ -6,11 +8,15 @@ const doSaveImage = (canvas: Canvas) => {
success: (res) => { success: (res) => {
wx.saveImageToPhotosAlbum({ wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath, filePath: res.tempFilePath,
success: () => wx.showToast({ success: () => {
title: '保存成功,请在相册中查看', // 记录下载成功
icon: 'success', recordDownloadSuccess();
duration: 2000, wx.showToast({
}), title: '保存成功,请在相册中查看',
icon: 'success',
duration: 2000,
});
},
// fail: () => wx.showToast({ // fail: () => wx.showToast({
// title: '保存涂色卡失败,请重试!', // title: '保存涂色卡失败,请重试!',
// icon: 'none', // icon: 'none',
@@ -18,38 +24,37 @@ const doSaveImage = (canvas: Canvas) => {
// }) // })
}); });
}, },
fail: (err: any) => { fail: () => {
wx.showToast({ wx.showToast({
title: '生成涂色卡失败,请重试!', title: '生成涂色卡失败,请重试!',
icon: 'none', icon: 'none',
duration: 2000, duration: 2000,
}) });
} },
}); });
} };
const requestPhotoPermission = (canvas: Canvas) => { const requestPhotoPermission = (canvas: Canvas) => {
wx.authorize({ wx.authorize({
scope: 'scope.writePhotosAlbum', scope: 'scope.writePhotosAlbum',
success: () => doSaveImage(canvas), success: () => doSaveImage(canvas),
fail: () => wx.showToast({ fail: () =>
title: '请在“设置-添加到相册”中开启相册权限以保存涂色卡', wx.showToast({
icon: 'none', title: '请在“设置-添加到相册”中开启相册权限以保存涂色卡',
duration: 3000, icon: 'none',
}) duration: 3000,
}) }),
} });
};
export const checkAndSaveImage = (canvas: Canvas) => { export const checkAndSaveImage = (canvas: Canvas) => {
wx.getSetting({ wx.getSetting({
success: res => { success: (res) => {
if (!res.authSetting['scope.writePhotosAlbum']) { if (!res.authSetting['scope.writePhotosAlbum']) {
requestPhotoPermission(canvas) requestPhotoPermission(canvas);
} else { } else {
doSaveImage(canvas) doSaveImage(canvas);
} }
} },
}) });
}; };
+71
View File
@@ -0,0 +1,71 @@
/**
* 分享引导工具
* 用于控制每日免费下载次数和分享引导
*/
const STORAGE_KEY_DOWNLOAD_DATE = 'downloadDate';
const STORAGE_KEY_DOWNLOAD_COUNT = 'downloadCount';
const STORAGE_KEY_SHARED_DATE = 'sharedDate';
/**
* 获取今天的日期字符串(YYYY-MM-DD格式)
*/
function getTodayDateString(): string {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
/**
* 检查今天是否已经下载过
* @returns true表示今天已下载过,false表示今天未下载
*/
export function hasDownloadedToday(): boolean {
const today = getTodayDateString();
const downloadDate = wx.getStorageSync(STORAGE_KEY_DOWNLOAD_DATE);
return downloadDate === today;
}
/**
* 记录今天的下载成功
*/
export function recordDownloadSuccess(): void {
const today = getTodayDateString();
wx.setStorageSync(STORAGE_KEY_DOWNLOAD_DATE, today);
const count = wx.getStorageSync(STORAGE_KEY_DOWNLOAD_COUNT) || 0;
wx.setStorageSync(STORAGE_KEY_DOWNLOAD_COUNT, count + 1);
}
/**
* 检查今天是否已经分享过
* @returns true表示今天已分享过,false表示今天未分享
*/
export function hasSharedToday(): boolean {
const today = getTodayDateString();
const sharedDate = wx.getStorageSync(STORAGE_KEY_SHARED_DATE);
return sharedDate === today;
}
/**
* 记录今天的分享成功
*/
export function recordShareSuccess(): void {
const today = getTodayDateString();
wx.setStorageSync(STORAGE_KEY_SHARED_DATE, today);
}
/**
* 检查是否需要显示分享引导
* @returns true表示需要显示分享引导,false表示不需要
*/
export function shouldShowShareGuide(): boolean {
// 如果今天已经分享过,不需要显示引导
if (hasSharedToday()) {
return false;
}
// 如果今天已经下载过,需要显示引导
return hasDownloadedToday();
}