/** * 下载打印通用工具 * 支持下载次数限制和激励广告 */ import { checkAndSaveImage } from './saveImage'; import tracker from './tracker'; import { incrementWorksheetDownloads } from './worksheetStats'; // 存储键名 const STORAGE_KEY_DOWNLOAD_COUNT = 'downloadCount'; const STORAGE_KEY_DOWNLOAD_DATE = 'downloadDate'; const STORAGE_KEY_WATCHED_AD_TODAY = 'watchedAdToday'; // 免费下载次数限制 const FREE_DOWNLOAD_LIMIT = 5; /** * 开发调试环境:本地 develop 包或开发者工具(含桌面模拟器) * 此环境下不弹广告、不限制下载次数 */ function isDevBypassLimits(): boolean { try { const env = wx.getAccountInfoSync().miniProgram.envVersion || 'release'; if (env === 'develop') { return true; } if (wx.getSystemInfoSync().platform === 'devtools') { return true; } } catch { // ignore } return false; } // 激励视频广告单元ID const AD_UNIT_ID = 'adunit-eff5626f8b68c2e0'; /** * 获取今天的日期字符串(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}`; } /** * 获取今日下载次数(供个人中心等展示;与内部计数逻辑一致) */ export function getTodayDownloadCount(): number { const today = getTodayDateString(); const downloadDate = wx.getStorageSync(STORAGE_KEY_DOWNLOAD_DATE); // 如果不是今天,重置计数 if (downloadDate !== today) { wx.setStorageSync(STORAGE_KEY_DOWNLOAD_COUNT, 0); wx.setStorageSync(STORAGE_KEY_DOWNLOAD_DATE, today); wx.setStorageSync(STORAGE_KEY_WATCHED_AD_TODAY, false); return 0; } return wx.getStorageSync(STORAGE_KEY_DOWNLOAD_COUNT) || 0; } /** * 增加今日下载次数 */ function incrementDownloadCount(): void { const today = getTodayDateString(); const count = getTodayDownloadCount(); wx.setStorageSync(STORAGE_KEY_DOWNLOAD_COUNT, count + 1); wx.setStorageSync(STORAGE_KEY_DOWNLOAD_DATE, today); } /** * 检查今日是否已观看广告 */ function hasWatchedAdToday(): boolean { const today = getTodayDateString(); const watchedDate = wx.getStorageSync(STORAGE_KEY_WATCHED_AD_TODAY); return watchedDate === today; } /** * 标记今日已观看广告 */ function markWatchedAdToday(): void { const today = getTodayDateString(); wx.setStorageSync(STORAGE_KEY_WATCHED_AD_TODAY, today); } /** * 创建激励视频广告实例 */ function createVideoAd() { if (!wx.createRewardedVideoAd) { return null; } const videoAd = wx.createRewardedVideoAd({ adUnitId: AD_UNIT_ID, }); videoAd.onLoad(() => { console.log('激励视频广告加载成功'); }); videoAd.onError((err) => { console.error('激励视频广告加载失败', err); }); return videoAd; } /** * 显示激励视频广告 */ function showVideoAd(): Promise { return new Promise((resolve) => { const videoAd = createVideoAd(); if (!videoAd) { wx.showToast({ title: '当前环境不支持激励广告', icon: 'none', }); resolve(false); return; } // 显示 loading wx.showLoading({ title: '加载中...', mask: true, }); // 监听广告关闭事件 videoAd.onClose((res) => { // 隐藏 loading(如果还在显示) wx.hideLoading(); if (res && res.isEnded) { // 用户完整观看了广告 markWatchedAdToday(); resolve(true); } else { // 用户提前关闭了广告 resolve(false); } }); // 显示广告 videoAd .show() .then(() => { // 广告显示成功,隐藏 loading wx.hideLoading(); }) .catch(() => { // 失败重试,保持 loading 显示 videoAd .load() .then(() => { // 加载成功,继续显示广告 return videoAd.show(); }) .then(() => { // 广告显示成功,隐藏 loading wx.hideLoading(); }) .catch((err) => { // 最终失败,隐藏 loading 并提示 wx.hideLoading(); console.error('激励视频广告显示失败', err); wx.showToast({ title: '广告加载失败,请稍后重试', icon: 'none', }); resolve(false); }); }); }); } /** * 执行下载 */ function doDownload( canvas: Canvas, options: { successToast?: string; errorToast?: string; trackerName?: string; trackerMode?: string; worksheetId?: string; }, ): Promise { // 上报下载埋点 if (options.trackerName) { if (options.trackerMode) { tracker.reportDownload(options.trackerName, options.trackerMode); } else { tracker.reportDownload(options.trackerName); } } return checkAndSaveImage(canvas).then((saved) => { if (saved) { incrementDownloadCount(); if (options.worksheetId) { incrementWorksheetDownloads(options.worksheetId); } } return saved; }); } /** * 下载打印(通用方法) * @param canvas Canvas 实例 * @param options 配置选项 * @param options.successToast 成功提示(可选,默认:'保存成功,请在相册中查看') * @param options.errorToast 错误提示(可选,默认:'请先生成内容') * @param options.trackerName 埋点名称(可选) * @param options.trackerMode 埋点模式(可选) * @param options.worksheetId worksheet ID(可选,保存成功后更新 downloads) */ export async function downloadPrint( canvas: Canvas | null, options: { successToast?: string; errorToast?: string; trackerName?: string; trackerMode?: string; worksheetId?: string; } = {}, ): Promise { // 检查 canvas 是否存在 if (!canvas) { wx.showToast({ title: options.errorToast || '请先生成内容', icon: 'none', }); return false; } if (isDevBypassLimits()) { return doDownload(canvas, options); } // 获取今日下载次数 const downloadCount = getTodayDownloadCount(); const hasWatchedAd = hasWatchedAdToday(); // 如果已观看广告,直接下载 if (hasWatchedAd) { return doDownload(canvas, options); } // 如果未超过免费次数,直接下载 if (downloadCount < FREE_DOWNLOAD_LIMIT) { return doDownload(canvas, options); } // 超过免费次数,需要观看广告 const watched = await showVideoAd(); if (watched) { // 观看完成,可以下载 return doDownload(canvas, options); } /* else { // 未观看完成,提示用户 wx.showToast({ title: '需要完整观看广告才能下载', icon: 'none', duration: 2000, }); } */ return false; }