import { _decorator, Component, Node, instantiate, Label, Sprite, UITransform, } from "cc"; import li_BaseView from "db://assets/Scripts/Main/Common/li_BaseView"; import Utils from "db://assets/Scripts/Main/Common/Utils"; import { GButton } from "db://assets/Scripts/Main/Common/GButton"; import ResManager from "db://assets/Scripts/Main/Manager/ResManager"; import { ThemeItem } from "../../uiitems/ThemeItem"; import { NavigationManager, PageTransitionType, PanelType, } from "../../manager/NavigationManager"; import { GirlListItem } from "../../uiitems/GirlListItem"; import LanguageUtils from "../../../Main/Common/LanguageUtils"; import { ViewManager } from "../../../Main/Manager/ViewManager"; import { InnerMsgCode } from "../../../Main/Config/InnerMsgCode"; import { ThemeService } from "db://assets/Scripts/chat18x/network/services/ThemeService"; import { GirlService } from "db://assets/Scripts/chat18x/network/services/GirlService"; import { ShopService } from "db://assets/Scripts/chat18x/network/services/ShopService"; import { DataManager, DataId } from "../../data/DataManager"; import { ThemeData } from "../../data/ThemeData"; import { GirlData } from "../../data/GirlData"; import { WalletData } from "../../data/WalletData"; import { AccountData } from "../../data/AccountData"; import { ShopData } from "../../data/ShopData"; import { EnvData } from "../../data/EnvData"; import proto from "db://assets/Scripts/proto/proto.pb.js"; import GameRootUI from "../../../Main/Common/GameRootUI"; import { MainController } from "../../core/MainController"; import { GirlListPanel } from "./GirlListPanel"; const { ccclass, property } = _decorator; @ccclass("ThemePanel") export class ThemePanel extends li_BaseView { private _nodeTab: any = {}; coinNum: Label; itemInst: ThemeItem; content: Node; private vipLeftTime: Label; recId: number; recName: Label; recSprite: Sprite; cache: ThemeItem[] = []; // 子页面管理 // 加载状态保护 private isLoading: boolean = false; private loadingPromise: Promise | null = null; private abortController: AbortController | null = null; onLoadCT() { Utils.parseNode(this.node, this._nodeTab); this.coinNum = this._nodeTab.coinNum.getComponent(Label); this.recName = this._nodeTab.characterNameText.getComponent(Label); this.recSprite = this._nodeTab.recPic.getComponent(Sprite); this.vipLeftTime = this._nodeTab.vipText.getComponent(Label); this.registerListener(); this.itemInst = this._nodeTab.ThemeItem.getComponent(ThemeItem); this.itemInst.node.active = false; this.content = this._nodeTab.allThemecontent; this.Show(); } rectNameKey: string; async Show(forceRefresh: boolean = false) { // 防止重复加载 if (this.isLoading) { console.log("[ThemePanel] 已在加载中,等待当前加载完成"); if (this.loadingPromise) { await this.loadingPromise; } return; } this.isLoading = true; this.loadingPromise = this._showInternal(forceRefresh); try { await this.loadingPromise; } finally { this.isLoading = false; this.loadingPromise = null; } } private async _showInternal(forceRefresh: boolean = false) { // 创建新的AbortController用于取消操作 this.abortController = new AbortController(); const signal = this.abortController.signal; try { this._nodeTab.loadingRec.active = true; //some temp data this.refreshCoinNum(); this.refreshVipExpire(); const accountData = DataManager.I.getDataById( DataId.Account ); //this.uid.string = "uid: " + accountData.accId; this.recId = 1; // 检查是否已被取消 if (signal.aborted) { throw new Error("Operation was aborted"); } // 清理旧的cache节点(每次都清理,解决内存泄漏问题) this.clearCache(); // 如果需要强制刷新,先刷新数据 if (forceRefresh) { console.log("[ThemePanel] 开始强制刷新数据"); await Promise.all([ MainController.I.refreshThemeData(), MainController.I.refreshDailyRecommend(), ]); console.log("[ThemePanel] 数据刷新完成"); // 再次检查是否已被取消 if (signal.aborted) { throw new Error("Operation was aborted"); } } // 优先使用MainController中预加载的数据 const preloadStatus = MainController.I.getPreloadStatus(); console.log("[ThemePanel] 预加载状态:", preloadStatus); // 处理主题数据 await this.handleThemeData(preloadStatus.themeData); // 检查是否已被取消 if (signal.aborted) { throw new Error("Operation was aborted"); } // 处理每日推荐数据 await this.handleDailyRecommendData(preloadStatus.dailyRecommend); // 检查是否已被取消 if (signal.aborted) { throw new Error("Operation was aborted"); } this._nodeTab.loadingRec.active = false; // 处理商品列表数据 await this.handleShopListData(preloadStatus.shopList); } catch (error) { console.error("[ThemePanel] Show操作出错:", error); this._nodeTab.loadingRec.active = false; // 如果不是取消操作导致的错误,可以考虑显示错误提示 if (error.message !== "Operation was aborted") { // 这里可以添加错误提示逻辑 console.error("[ThemePanel] 数据加载失败,请稍后重试"); } } finally { this.abortController = null; } } /** * 处理主题数据 */ private async handleThemeData(isPreloaded: boolean): Promise { if (isPreloaded) { console.log("[ThemePanel] 使用预加载的主题数据"); // 直接使用预加载的数据渲染界面 const themeData = DataManager.I.getDataById(DataId.Theme); if (themeData && themeData.themes) { this.renderThemeData(themeData); return; } } // 如果没有预加载数据,则请求数据 console.log("[ThemePanel] 请求主题数据"); const reqData = {}; let res = await ThemeService.I.reqHallTheme(reqData); if (res && res.code === proto.cs.EnmRetCode.SUCCESS) { // 保存数据 const themeData = DataManager.I.getDataById(DataId.Theme); themeData.themes = res.data; this.renderThemeData(themeData); } } /** * 渲染主题数据 */ private renderThemeData(themeData: ThemeData): void { const themeIds = themeData.themeIds; for (let id of themeIds) { let newNode = instantiate(this.itemInst.node); let item = newNode.getComponent(ThemeItem); item.refresh(id, this.node); newNode.active = true; this.cache.push(item); this.content.addChild(newNode); } } /** * 处理每日推荐数据 */ private async handleDailyRecommendData(isPreloaded: boolean): Promise { if (isPreloaded) { console.log("[ThemePanel] 使用预加载的每日推荐数据"); // 直接使用预加载的数据渲染界面 const girlData = DataManager.I.getDataById(DataId.Girl); if (girlData) { this.renderDailyRecommendData(girlData); return; } } // 如果没有预加载数据,则请求数据 console.log("[ThemePanel] 请求每日推荐数据"); const reqData = {}; let res = await GirlService.I.reqDailyRecommend(reqData); if (res && res.code === proto.cs.EnmRetCode.SUCCESS) { const girlData = DataManager.I.getDataById(DataId.Girl); girlData.setDailyRecommend(res.data); this.renderDailyRecommendData(girlData); } } /** * 渲染每日推荐数据 */ private renderDailyRecommendData(girlData: GirlData): void { this.recId = girlData.getRecommendGirlId(); this.rectNameKey = girlData.getRecommendGrilName(); let avatarPath = girlData.getRecommendGrilAvatar(); this.recName.string = LanguageUtils.getText(this.rectNameKey); // 加载远程资源 const envData = DataManager.I.getDataById(DataId.Env); let newPath = envData.cdn + "/" + "Girls/" + avatarPath + ".png"; ResManager.I.changeRemoteSpriteFrame(this.recSprite, newPath, () => { let sizeTran = this.recSprite.node.parent.getComponent(UITransform); Utils.adjustBgPixelRatioToSize( sizeTran.contentSize, this.recSprite.node, 1 ); }); } /** * 处理商品列表数据 */ private async handleShopListData(isPreloaded: boolean): Promise { if (isPreloaded) { console.log("[ThemePanel] 商品列表数据已预加载"); // 数据已经在DataManager中,不需要额外处理 return; } // 如果没有预加载数据,则请求数据 console.log("[ThemePanel] 请求商品列表数据"); await this.reqShopList(); } private registerListener() { GButton.BandClick(this._nodeTab.settingBtn, this.openSetting, this); GButton.BandClick(this._nodeTab.msgBoxBtn, this.openMsgBox, this); GButton.BandClick(this._nodeTab.ChatWithRecBtn, this.chatWithRec, this); GButton.BandClick(this._nodeTab.ShopPanelEntry, this.enterShop, this); Utils.addInnerEL(InnerMsgCode.LanguageChange, this, this.onLanguageChange); Utils.addInnerEL(InnerMsgCode.BalanceChange, this, this.onBalanceChange); Utils.addInnerEL( InnerMsgCode.VipExpireChange, this, this.onVipExpireChange ); } enterShop() { NavigationManager.Instance.openSubPanel("PurchasePanel", this.node); } chatWithRec() { const girlData = DataManager.I.getDataById(DataId.Girl); // 是否已经解锁 const isRelease = girlData.getIsRelease( girlData.getGrilCategoryById(this.recId).toString(), this.recId ); const isFree = girlData.getGrilPrice( girlData.getGrilCategoryById(this.recId).toString(), this.recId ) == 0; if (isRelease || isFree) { NavigationManager.Instance.setSelectedGirlId(this.recId); NavigationManager.Instance.setSelectedCategoryId( girlData.getGrilCategoryById(this.recId) ); NavigationManager.Instance.switchToPanel(PanelType.GIRL_DETAIL); } else { //未解锁 NavigationManager.Instance.openPopupPanel("GirlListPopupPanel", { base: this, category: girlData.getGrilCategoryById(this.recId), id: this.recId, }); } } openSetting() { // 通过NavigationManager切换到个人信息面板,保持动画和状态同步 NavigationManager.Instance.openSubPanel("SettingPanel", this.node); } openMsgBox() { console.log("打开信箱"); } // 刷新余额 private refreshCoinNum() { const walletData = DataManager.I.getDataById(DataId.Wallet); const balance = walletData.getOriginalBalance(); this.coinNum.string = balance.toString(); } // 刷新 vip失效时间戳 private refreshVipExpire() { const walletData = DataManager.I.getDataById(DataId.Wallet); if (!walletData.isVip) { this.vipLeftTime.string = LanguageUtils.getText("purchasepanel.notvip"); } else { const vipExpire = walletData.vipExpire; const leftTime = Utils.formatVipLeftTime(vipExpire); this.vipLeftTime.string = LanguageUtils.getText( "purchasepanel.vip_left" ).replace("${leftTime}", leftTime); } } // 获取商品列表 async reqShopList() { // 请求购买商品 const reqData = {}; let res = await ShopService.I.reqShopList(reqData); if (res && res.code === proto.cs.EnmRetCode.SUCCESS) { const resData = res.data; // 保存数据 const shopData = DataManager.I.getDataById(DataId.Shop); shopData.goods = res.data; } } /** * 清理缓存节点 */ private clearCache(): void { if (this.cache && this.cache.length > 0) { console.log(`[ThemePanel] 清理 ${this.cache.length} 个缓存节点`); for (let i = this.cache.length - 1; i >= 0; i--) { if (this.cache[i] && this.cache[i].node && this.cache[i].node.isValid) { this.cache[i].node.destroy(); } } this.cache = []; } } /** * 页面被隐藏时调用 */ public onHide(): void { console.log("[ThemePanel] onHide called"); this.cancelCurrentOperation(); } /** * 取消当前操作 */ private cancelCurrentOperation(): void { if (this.abortController) { console.log("[ThemePanel] 取消当前操作"); this.abortController.abort(); this.abortController = null; } } onDestroy(): void { console.log("[ThemePanel] onDestroy called"); // 取消当前操作 this.cancelCurrentOperation(); // 清理缓存 this.clearCache(); // 重置加载状态 this.isLoading = false; this.loadingPromise = null; // 移除事件监听器(修复回调函数引用问题) Utils.removeInnerEL( InnerMsgCode.LanguageChange, this, this.onLanguageChange ); Utils.removeInnerEL(InnerMsgCode.BalanceChange, this, this.onBalanceChange); Utils.removeInnerEL( InnerMsgCode.VipExpireChange, this, this.onVipExpireChange ); } // 事件回调函数(避免匿名函数导致的内存泄漏) private onLanguageChange = () => { this.recName.string = LanguageUtils.getText(this.rectNameKey); this.refreshVipExpire(); }; private onBalanceChange = () => { this.refreshCoinNum(); }; private onVipExpireChange = () => { this.refreshVipExpire(); }; }