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 LanguageUtils from "../../../Main/Common/LanguageUtils"; 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 { MainController } from "../../core/MainController"; import { logger } from "db://assets/Scripts/Main/Common/Logger"; import { RecomandItem } from "../../uiitems/RecomandItem"; const { ccclass, property } = _decorator; @ccclass("ThemePanel") export class ThemePanel extends li_BaseView { private _nodeTab: any = {}; coinNum: Label; itemInst: ThemeItem; recItemInst: RecomandItem; themeContent: Node; recGirlContent: Node; private vipLeftTime: Label; //recName: Label; //recSprite: Sprite; cache: ThemeItem[] = []; recItemCache: RecomandItem[] = []; // 子页面管理 // 加载状态保护 private isLoading: boolean = false; private loadingPromise: Promise | null = null; private abortController: AbortController | null = null; private recomandListBtn: Node; private moreThemeBtn: Node; private themeScroll: Node; private recomandScroll: Node; 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.recomandListBtn = this._nodeTab.recomandList; this.moreThemeBtn = this._nodeTab.moreTheme; this.themeScroll = this._nodeTab.themeScroll; this.recomandScroll = this._nodeTab.recomandScroll; this.registerListener(); this.itemInst = this._nodeTab.ThemeItem.getComponent(ThemeItem); this.itemInst.node.active = false; this.recItemInst = this._nodeTab.recItem.getComponent(RecomandItem); this.recItemInst.node.active = false; this.themeContent = this._nodeTab.allThemecontent; this.recGirlContent = this._nodeTab.allRecGirlContent; this.Show(); } async Show(forceRefresh: boolean = false) { // 防止重复加载 if (this.isLoading) { logger.log("[ThemePanel] 已在加载中,等待当前加载完成"); if (this.loadingPromise) { await this.loadingPromise; } return; } this.isLoading = true; this.loadingPromise = this._refreshDataInternal(forceRefresh); try { await this.loadingPromise; } finally { this.isLoading = false; this.loadingPromise = null; } this.openRecomandList(); } private async _refreshDataInternal(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; // 检查是否已被取消 if (signal.aborted) { throw new Error("Operation was aborted"); } // 清理旧的cache节点(每次都清理,解决内存泄漏问题) this.clearCache(); // 如果需要强制刷新,先刷新数据 if (forceRefresh) { logger.log("[ThemePanel] 开始强制刷新数据"); await Promise.all([ MainController.I.refreshThemeData(), MainController.I.refreshDailyRecommend(), ]); logger.log("[ThemePanel] 数据刷新完成"); // 再次检查是否已被取消 if (signal.aborted) { throw new Error("Operation was aborted"); } } // 优先使用MainController中预加载的数据 const preloadStatus = MainController.I.getPreloadStatus(); logger.log("[ThemePanel] 预加载状态:", preloadStatus); // 处理主题数据 await this.handleThemeData(preloadStatus.themeData); // 检查是否已被取消 if (signal.aborted) { throw new Error("Operation was aborted"); } // 处理每日推荐数据 await this.handleRecommendData(preloadStatus.dailyRecommend); // 检查是否已被取消 if (signal.aborted) { throw new Error("Operation was aborted"); } this._nodeTab.loadingRec.active = false; // 处理商品列表数据 await this.handleShopListData(preloadStatus.shopList); } catch (error) { logger.error("[ThemePanel] Show操作出错:", error); this._nodeTab.loadingRec.active = false; // 如果不是取消操作导致的错误,可以考虑显示错误提示 if (error.message !== "Operation was aborted") { // 这里可以添加错误提示逻辑 logger.error("[ThemePanel] 数据加载失败,请稍后重试"); } } finally { this.abortController = null; } } /** * 处理主题数据 */ private async handleThemeData(isPreloaded: boolean): Promise { if (isPreloaded) { logger.log("[ThemePanel] 使用预加载的主题数据"); // 直接使用预加载的数据渲染界面 const themeData = DataManager.I.getDataById(DataId.Theme); if (themeData && themeData.themes) { return; } } // 如果没有预加载数据,则请求数据 logger.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; } } /** * 渲染主题数据 */ private renderThemeData(): void { if (this.cache.length > 0) return; const themeData = DataManager.I.getDataById(DataId.Theme); 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.themeContent.addChild(newNode); } } /** * 处理推荐数据 */ private async handleRecommendData(isPreloaded: boolean): Promise { if (isPreloaded) { logger.log("[ThemePanel] 使用预加载的每日推荐数据"); // 直接使用预加载的数据渲染界面 const girlData = DataManager.I.getDataById(DataId.Girl); if (girlData) { return; } } // 如果没有预加载数据,则请求数据 logger.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); } } /** * 渲染每日推荐数据 */ private renderRecommendData(): void { if (this.recItemCache.length > 0) return; const girlData = DataManager.I.getDataById(DataId.Girl); let girlIDs = []; girlIDs.push(girlData.getRecommendGirlId()); for (let id of girlIDs) { let newNode = instantiate(this.recItemInst.node); let item = newNode.getComponent(RecomandItem); item.init(); item.refresh(id); newNode.active = true; this.recItemCache.push(item); this.recGirlContent.addChild(newNode); } console.error("未实现每日推荐数据渲染"); } /** * 处理商品列表数据 */ private async handleShopListData(isPreloaded: boolean): Promise { if (isPreloaded) { logger.log("[ThemePanel] 商品列表数据已预加载"); // 数据已经在DataManager中,不需要额外处理 return; } // 如果没有预加载数据,则请求数据 logger.log("[ThemePanel] 请求商品列表数据"); await this.reqShopList(); } private registerListener() { GButton.BandClick(this._nodeTab.ShopPanelEntry, this.enterShop, this); GButton.BandClick(this.recomandListBtn, this.openRecomandList, this); GButton.BandClick(this.moreThemeBtn, this.openMoreTheme, 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, { base: this.node }, { openAnimation: PageTransitionType.SLIDE_LEFT, closeAnimation: PageTransitionType.SLIDE_RIGHT, } ); } openRecomandList() { this.themeScroll.active = false; this.recomandScroll.active = true; //todo:是否需要刷新数据 this.renderRecommendData(); this.updateTagState(true); } openMoreTheme() { this.themeScroll.active = true; this.recomandScroll.active = false; //todo:是否需要刷新数据 this.renderThemeData(); this.updateTagState(false); } updateTagState(isRecomnend: boolean) { this.recomandListBtn.children[0].active = !isRecomnend; this.recomandListBtn.children[1].active = isRecomnend; this.moreThemeBtn.children[0].active = isRecomnend; this.moreThemeBtn.children[1].active = !isRecomnend; } // 刷新余额 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); if (leftTime == null) { LanguageUtils.getText("purchasepanel.notvip"); } else { 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) { logger.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 { logger.log("[ThemePanel] onHide called"); this.cancelCurrentOperation(); } /** * 取消当前操作 */ private cancelCurrentOperation(): void { if (this.abortController) { logger.log("[ThemePanel] 取消当前操作"); this.abortController.abort(); this.abortController = null; } } onDestroy(): void { logger.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(); }; }