import { SpriteFrame, Texture2D, ImageAsset, assetManager } from 'cc'; import { HttpUtil } from './HttpUtil'; import { WxSDK } from './WxSDK'; import { API_ENDPOINTS, getShareDetailUrl, getShareJoinUrl, getShareSubmitUrl, API_TIMEOUT } from '../config/ApiConfig'; import { ApiEnvelope, CreateShareData, JoinShareData, ShareLevelData, CreatedShareItem, CreatedShareListData, ParticipatedShareItem, ParticipatedShareListData, ShareDetailData, SubmitShareData, SubmitShareLevel, } from '../types/ApiTypes'; import { RuntimeLevelConfig } from '../types/LevelTypes'; /** * 分享管理器 * 负责创建分享、加入分享、缓存分享关卡数据 */ export class ShareManager { private static _instance: ShareManager | null = null; /** 分享模式的关卡数据(null 表示正常模式) */ private _shareLevels: RuntimeLevelConfig[] | null = null; /** API 返回的原始关卡数据(保留 image1Url/image2Url 用于懒加载) */ private _shareApiLevels: ShareLevelData[] = []; private _shareTitle: string = ''; private _shareCode: string | null = null; private _createdShares: CreatedShareItem[] = []; private _participatedShares: ParticipatedShareItem[] = []; /** 图片缓存:URL -> SpriteFrame */ private _imageCache: Map = new Map(); static get instance(): ShareManager { if (!this._instance) { this._instance = new ShareManager(); } return this._instance; } private constructor() {} get isShareMode(): boolean { return this._shareLevels !== null && this._shareLevels.length > 0; } get createdShares(): CreatedShareItem[] { return [...this._createdShares]; } get participatedShares(): ParticipatedShareItem[] { return [...this._participatedShares]; } get shareCode(): string | null { return this._shareCode; } get shareTitle(): string { return this._shareTitle; } async createShare(title: string, levelIds: string[]): Promise { try { const response = await HttpUtil.post>( API_ENDPOINTS.SHARE_CREATE, { title, levelIds }, API_TIMEOUT.DEFAULT, ); if (!response.success || !response.data) { console.error('[ShareManager] 创建分享失败:', response.message); return null; } return response.data.shareCode; } catch (err) { console.error('[ShareManager] 创建分享异常:', err); return null; } } async joinShare(code: string): Promise { try { const response = await HttpUtil.post>( getShareJoinUrl(code), {}, API_TIMEOUT.DEFAULT, ); if (!response.success || !response.data) { console.error('[ShareManager] 加入分享失败:', response.message); return false; } const { shareCode, title, levels } = response.data; this._shareCode = shareCode; this._shareTitle = title; this._shareApiLevels = levels; const runtimeLevels: RuntimeLevelConfig[] = levels.map((level) => ({ id: level.id, name: `第${level.level}关`, spriteFrame1: null, spriteFrame2: null, image1Description: level.image1Description, image2Description: level.image2Description, punchline: level.punchline, clue1: level.hint1, clue2: level.hint2, clue3: level.hint3, answer: level.answer, completed: false, timeLimit: null, })); // 预加载首关图片(两张并行加载) if (levels.length > 0) { const [sf1, sf2] = await Promise.all([ this._loadImage(levels[0].image1Url), this._loadImage(levels[0].image2Url), ]); if (sf1) { runtimeLevels[0].spriteFrame1 = sf1; } if (sf2) { runtimeLevels[0].spriteFrame2 = sf2; } } this._shareLevels = runtimeLevels; console.log(`[ShareManager] 加入分享成功: ${title}, ${levels.length} 关`); return true; } catch (err) { console.error('[ShareManager] 加入分享异常:', err); return false; } } async fetchCreatedShares(): Promise { try { const response = await HttpUtil.get>( API_ENDPOINTS.SHARE_CREATED, API_TIMEOUT.DEFAULT, ); if (!response.success || !response.data) { console.error('[ShareManager] 获取我创建的挑战列表失败:', response.message); return null; } this._createdShares = response.data.items ?? []; console.log(`[ShareManager] 获取我创建的挑战列表成功: ${this._createdShares.length} 条`); return this.createdShares; } catch (err) { console.error('[ShareManager] 获取我创建的挑战列表异常:', err); return null; } } async fetchParticipatedShares(): Promise { try { const response = await HttpUtil.get>( API_ENDPOINTS.SHARE_PARTICIPATED, API_TIMEOUT.DEFAULT, ); if (!response.success || !response.data) { console.error('[ShareManager] 获取我参与的挑战列表失败:', response.message); return null; } this._participatedShares = response.data.items ?? []; console.log(`[ShareManager] 获取我参与的挑战列表成功: ${this._participatedShares.length} 条`); return this.participatedShares; } catch (err) { console.error('[ShareManager] 获取我参与的挑战列表异常:', err); return null; } } async fetchShareDetail(code: string): Promise { try { const response = await HttpUtil.get>( getShareDetailUrl(code), API_TIMEOUT.DEFAULT, ); if (!response.success || !response.data) { console.error('[ShareManager] 获取分享挑战详情失败:', response.message); return null; } console.log(`[ShareManager] 获取分享挑战详情成功: ${response.data.title}, ${response.data.rankings?.length ?? 0} 条排行`); return response.data; } catch (err) { console.error('[ShareManager] 获取分享挑战详情异常:', err); return null; } } async ensureShareLevelReady(index: number): Promise { if (!this._shareLevels || index < 0 || index >= this._shareLevels.length) { return null; } const config = this._shareLevels[index]; if (config.spriteFrame1) { return config; } const apiLevel = this._shareApiLevels[index]; if (apiLevel?.image1Url) { const [sf1, sf2] = await Promise.all([ this._loadImage(apiLevel.image1Url), this._loadImage(apiLevel.image2Url), ]); if (sf1) { config.spriteFrame1 = sf1; } if (sf2) { config.spriteFrame2 = sf2; } } return config; } getShareLevelCount(): number { return this._shareLevels?.length ?? 0; } getShareLevelIds(): string[] { return this._shareApiLevels.map(level => level.id); } async submitShareChallenge(levels: SubmitShareLevel[]): Promise { if (!this._shareCode) { console.warn('[ShareManager] submitShareChallenge: 无分享码,跳过提交'); return null; } try { const response = await HttpUtil.post>( getShareSubmitUrl(this._shareCode), { levels }, API_TIMEOUT.DEFAULT, ); if (!response.success || !response.data) { console.error('[ShareManager] 提交挑战结果失败:', response.message); return null; } console.log( `[ShareManager] 提交挑战结果成功: rank=${response.data.rank}, correct=${response.data.correctCount}/${response.data.levelCount}`, ); return response.data; } catch (err) { console.error('[ShareManager] 提交挑战结果异常:', err); return null; } } triggerWxShare(title: string, shareCode: string): void { WxSDK.shareAppMessage({ title: title || '来挑战我出的谐音梗吧!', query: `shareCode=${shareCode}`, }); } clearShareMode(): void { this._shareLevels = null; this._shareApiLevels = []; this._shareTitle = ''; this._shareCode = null; this._imageCache.clear(); } private _loadImage(url: string): Promise { const cached = this._imageCache.get(url); if (cached) { return Promise.resolve(cached); } return new Promise((resolve) => { assetManager.loadRemote(url, (err, imageAsset) => { if (err) { console.error('[ShareManager] 加载图片失败:', url, err); resolve(null); return; } const texture = new Texture2D(); texture.image = imageAsset; const spriteFrame = new SpriteFrame(); spriteFrame.texture = texture; this._imageCache.set(url, spriteFrame); resolve(spriteFrame); }); }); } }