Files
mp-xieyingeng/assets/scripts/utils/ShareManager.ts
2026-04-06 17:32:32 +08:00

168 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { SpriteFrame, Texture2D, ImageAsset, assetManager } from 'cc';
import { HttpUtil } from './HttpUtil';
import { WxSDK } from './WxSDK';
import { API_ENDPOINTS, getShareJoinUrl, API_TIMEOUT } from '../config/ApiConfig';
import { ApiEnvelope, CreateShareData, JoinShareData, ShareLevelData } from '../types/ApiTypes';
import { RuntimeLevelConfig } from '../types/LevelTypes';
/**
* 分享管理器
* 负责创建分享、加入分享、缓存分享关卡数据
*/
export class ShareManager {
private static _instance: ShareManager | null = null;
/** 分享模式的关卡数据null 表示正常模式) */
private _shareLevels: RuntimeLevelConfig[] | null = null;
/** API 返回的原始关卡数据(保留 imageUrl 用于懒加载) */
private _shareApiLevels: ShareLevelData[] = [];
private _shareTitle: string = '';
private _shareCode: string | null = null;
/** 图片缓存URL -> SpriteFrame */
private _imageCache: Map<string, SpriteFrame> = 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;
}
async createShare(title: string, levelIds: string[]): Promise<string | null> {
try {
const response = await HttpUtil.post<ApiEnvelope<CreateShareData>>(
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<boolean> {
try {
const response = await HttpUtil.post<ApiEnvelope<JoinShareData>>(
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}`,
spriteFrame: null,
clue1: level.hint1,
clue2: level.hint2,
clue3: level.hint3,
answer: level.answer,
}));
// 预加载首关图片
if (levels.length > 0) {
const sf = await this._loadImage(levels[0].imageUrl);
if (sf) {
runtimeLevels[0].spriteFrame = sf;
}
}
this._shareLevels = runtimeLevels;
console.log(`[ShareManager] 加入分享成功: ${title}, ${levels.length}`);
return true;
} catch (err) {
console.error('[ShareManager] 加入分享异常:', err);
return false;
}
}
async ensureShareLevelReady(index: number): Promise<RuntimeLevelConfig | null> {
if (!this._shareLevels || index < 0 || index >= this._shareLevels.length) {
return null;
}
const config = this._shareLevels[index];
if (config.spriteFrame) {
return config;
}
const apiLevel = this._shareApiLevels[index];
if (apiLevel?.imageUrl) {
const sf = await this._loadImage(apiLevel.imageUrl);
if (sf) {
config.spriteFrame = sf;
}
}
return config;
}
getShareLevelCount(): number {
return this._shareLevels?.length ?? 0;
}
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<SpriteFrame | null> {
const cached = this._imageCache.get(url);
if (cached) {
return Promise.resolve(cached);
}
return new Promise((resolve) => {
assetManager.loadRemote<ImageAsset>(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);
});
});
}
}