123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- /** @format */
- /**
- * UIManager界面管理类
- *
- * 1.打开界面,根据配置自动加载界面、调用初始化、播放打开动画、隐藏其他界面、屏蔽下方界面点击
- * 2.关闭界面,根据配置自动关闭界面、播放关闭动画、恢复其他界面
- * 3.切换界面,与打开界面类似,但是是将当前栈顶的界面切换成新的界面(先关闭再打开)
- * 4.提供界面缓存功能
- *
- */
- import {BaseUI, UIShowTypes} from '../ui/BaseUI'
- import {IUIConfig, UICfg} from '../config/UICfg'
- import {ccUtils} from '../utils/ccUtils'
- import {UI} from '../enums/UI'
- import {Data, Mgr} from '../GameControl'
- import {Log} from '../utils/LogUtils'
- import {IOperateNeed} from '../interface/GlobalInterface'
- import {IMessage, IReward, IRewardNty, ItemUICfg} from '../interface/UIInterface'
- import {SOUND} from '../enums/Sound'
- /** UI栈结构体 */
- export interface UIInfo {
- uiID: number
- baseUI: BaseUI
- uiArgs: any
- uiCfg: IUIConfig
- preventNode?: cc.Node
- aniNode?: cc.Node
- zOrder?: number
- isClose?: boolean
- hideTime?: number
- prefab?: cc.Prefab
- }
- export interface GroupUIInfo {
- uiID: number
- uiArgs?: any
- }
- export class UIManager {
- /** 是否正在关闭UI */
- private isClosing = false
- /** 是否正在打开UI */
- private isOpening = false
- /** UI界面缓存(key为UIId,value为BaseUI节点)*/
- private UICache: {[UIId: number]: UIInfo} = {}
- /** UI界面栈({UIID + BaseUI + UIArgs}数组)*/
- private UIStack: UIInfo[] = []
- /** UI待打开列表 */
- private UIOpenQueue: UIInfo[] = []
- /** UI待关闭列表 */
- private UICloseQueue: number[] = []
- /** UI配置 */
- private releaseTimeID: any
- /** 打开一组UI */
- private groupUIs: GroupUIInfo[] = []
- private curGroupUI: GroupUIInfo = null
- public prefabBundle: cc.AssetManager.Bundle = null
- /** UI打开前回调 */
- public uiOpenBeforeDelegate: (uiID: number, preUIId: number) => void = null
- /** UI打开回调 */
- public uiOpenDelegate: (uiID: number, preUIId: number) => void = null
- /** UI关闭回调 */
- public uiCloseDelegate: (uiID: number) => void = null
- public async init() {
- if (this.releaseTimeID) clearInterval(this.releaseTimeID)
- this.releaseTimeID = setInterval(this.cleanUI.bind(this), 15000)
- Data.main.texBundle = await ccUtils.getBundleAsync('texture')
- this.prefabBundle = await ccUtils.getBundleAsync('prefab')
- //加载全局通用预制体
- this.prefabBundle.loadDir('items', cc.Prefab, (error, assets: cc.Prefab[]) => {
- if (error) {
- Log.error(error)
- } else {
- for (let j = 0; j < assets.length; j++) {
- Data.main.itemsPrefabMap.set(assets[j].name, assets[j])
- let pool = Data.main.itemsPoolMap.get(assets[j].name)
- if (!pool) {
- pool = new cc.NodePool()
- Data.main.itemsPoolMap.set(assets[j].name, pool)
- }
- }
- }
- })
- return this.prefabBundle != null
- }
- /****************** 私有方法,UIManager内部的功能和基础规则 *******************/
- /**
- * 添加防触摸层
- * @param zOrder 屏蔽层的层级
- */
- private preventTouch(zOrder: number) {
- let node = new cc.Node()
- node.name = 'preventTouch'
- node.setContentSize(cc.winSize)
- node.on(
- cc.Node.EventType.TOUCH_START,
- (event: cc.Event.EventCustom) => {
- event.stopPropagation()
- },
- node,
- )
- let child = cc.director.getScene().getChildByName('Canvas')
- child.addChild(node, zOrder)
- return node
- }
- /** 自动执行下一个待关闭或待打开的界面 */
- private autoExecNextUI() {
- // 逻辑上是先关后开
- if (this.UICloseQueue.length > 0) {
- let closeUI = this.UICloseQueue[0]
- this.UICloseQueue.splice(0, 1)
- this.hide(closeUI)
- } else if (this.UIOpenQueue.length > 0) {
- let uiQueueInfo = this.UIOpenQueue[0]
- this.UIOpenQueue.splice(0, 1)
- this.show(uiQueueInfo.uiID, uiQueueInfo.uiArgs)
- }
- }
- /**
- * 自动检测动画组件以及特定动画,如存在则播放动画,无论动画是否播放,都执行回调
- * @param aniName 动画名
- * @param aniOverCallback 动画播放完成回调
- */
- private autoExecAnimation(baseUI: BaseUI, aniName: string, aniOverCallback: () => void) {
- // 暂时先省略动画播放的逻辑
- let node = baseUI.node
- switch (aniName) {
- case 'uiOpen':
- if (
- baseUI.showType >= UIShowTypes.UIAddition &&
- ![UI.CurrencyUI, UI.LoadingUI, UI.TipUI, UI.PowerUpUI, UI.GameLoadingUI].includes(baseUI.uiID)
- ) {
- Mgr.audio.playSFX(SOUND.uiPop)
- node.setScale(0)
- node.opacity = 0
- cc.tween(node)
- .to(0.3, {scale: 1.1}, {easing: 'backOut'}) // 缩放动作,0.3秒内从 0 缩放到 1,使用 backOut 缓动效果
- .to(0.3, {opacity: 255}) // 渐显动作,0.1秒内从透明度 0 到 255
- .union()
- .to(0.1, {scale: 1}) // 缩小一点,形成回弹效果
- .call(aniOverCallback)
- .start()
- } else {
- aniOverCallback()
- }
- break
- case 'uiClose':
- aniOverCallback()
- break
- }
- }
- /**
- * 异步加载一个UI的prefab,成功加载了一个prefab之后
- * @param uiID 界面id
- * @param processCallback 加载进度回调
- * @param completeCallback 加载完成回调
- * @param uiArgs 初始化参数
- */
- private getOrCreateUI(
- uiID: number,
- processCallback: any,
- completeCallback: (baseUI: BaseUI, prefab?: cc.Prefab) => void,
- uiArgs: any,
- ): void {
- // 如果找到缓存对象,则直接返回
- let baseUI: BaseUI
- let cacheUIInfo = this.UICache[uiID]
- if (cacheUIInfo) {
- completeCallback(cacheUIInfo.baseUI)
- return
- }
- // 找到UI配置
- let uiPath = UICfg.get(uiID).url
- if (null == uiPath) {
- cc.log(`getOrCreateUI ${uiID} faile, prefab conf not found!`)
- completeCallback(null)
- return
- }
- this.prefabBundle.load(uiPath, cc.Prefab, processCallback, (err: Error, prefab: cc.Prefab) => {
- // 检查加载资源错误
- if (err) {
- cc.error(`getOrCreateUI loadRes ${uiID} faile, path: ${uiPath} error: ${err}`)
- completeCallback(null)
- return
- }
- // 检查实例化错误
- let uiNode: cc.Node = cc.instantiate(prefab)
- if (null == uiNode) {
- cc.error(`getOrCreateUI instantiate ${uiID} faile, path: ${uiPath}`)
- completeCallback(null)
- cc.assetManager.releaseAsset(prefab)
- return
- }
- // 检查组件获取错误
- baseUI = uiNode.getComponent(BaseUI)
- if (null == baseUI) {
- cc.error(`getOrCreateUI getComponent ${uiID} faile, path: ${uiPath}`)
- uiNode.destroy()
- completeCallback(null)
- cc.assetManager.releaseAsset(prefab)
- return
- }
- baseUI.uiID = uiID
- baseUI.init(uiArgs)
- completeCallback(baseUI, prefab)
- })
- }
- /**
- * UI被打开时回调,对UI进行初始化设置,刷新其他界面的显示,并根据
- * @param uiID 哪个界面被打开了
- * @param baseUI 界面对象
- * @param uiInfo 界面栈对应的信息结构
- * @param uiArgs 界面初始化参数
- */
- private onUIOpen(uiID: number, baseUI: BaseUI, uiInfo: UIInfo, uiArgs: any) {
- if (null == baseUI) {
- return
- }
- // 激活界面
- uiInfo.baseUI = baseUI
- baseUI.node.active = true
- let realZIndex = uiInfo.zOrder + baseUI.showType
- baseUI.node.zIndex = realZIndex
- if (baseUI.prevent) {
- let blockInputEvents = baseUI.node.getChildByName('blockInputEvents')
- if (!blockInputEvents) {
- blockInputEvents = new cc.Node()
- blockInputEvents.name = 'blockInputEvents'
- blockInputEvents.setContentSize(cc.winSize)
- blockInputEvents.addComponent(cc.BlockInputEvents)
- baseUI.node.addChild(blockInputEvents, -9999)
- }
- // 这里直接给node添加BlockInputEvents导致子节点setSwallowTouches无法吞噬,改成上面的实现方式
- // baseUI.node.setContentSize(cc.winSize)
- // if (!baseUI.node.getComponent(cc.BlockInputEvents)) baseUI.node.addComponent(cc.BlockInputEvents)
- }
- // 快速关闭界面的设置,绑定界面中的background,实现快速关闭
- if (baseUI.quickClose) {
- let backGround = baseUI.node.getChildByName('background')
- if (!backGround) {
- backGround = new cc.Node()
- backGround.name = 'background'
- backGround.setContentSize(cc.winSize)
- baseUI.node.addChild(backGround, -1)
- }
- backGround.targetOff(cc.Node.EventType.TOUCH_START)
- backGround.on(
- cc.Node.EventType.TOUCH_START,
- (event: cc.Event.EventCustom) => {
- event.stopPropagation()
- this.hideBaseUI(baseUI)
- },
- backGround,
- )
- }
- // 添加到场景中
- let child = cc.director.getScene().getChildByName('Canvas')
- child.addChild(baseUI.node)
- // 从那个界面打开的
- let fromUIID = 0
- if (this.UIStack.length > 1) {
- fromUIID = this.UIStack[this.UIStack.length - 2].uiID
- }
- // 打开界面之前回调
- if (this.uiOpenBeforeDelegate) {
- this.uiOpenBeforeDelegate(uiID, fromUIID)
- }
- // 执行onOpen回调 下一帧执行保证onLoad onEnable先执行
- baseUI.scheduleOnce(() => {
- if (!uiInfo.isClose && baseUI.node.activeInHierarchy) baseUI.onShow(uiArgs, fromUIID)
- })
- this.autoExecAnimation(baseUI, 'uiOpen', () => {
- baseUI.onOpenAniOver()
- if (this.uiOpenDelegate) {
- this.uiOpenDelegate(uiID, fromUIID)
- }
- })
- }
- /** 打开界面并添加到界面栈中 */
- public show(uiID: number, uiArgs: any = null, progressCallback: Function = null): void {
- let uiInfo: UIInfo = {
- uiCfg: UICfg.get(uiID),
- uiID: uiID,
- uiArgs: uiArgs,
- baseUI: null,
- }
- if (this.isOpening || this.isClosing) {
- // 插入待打开队列
- let openIndex = this.UIOpenQueue.findIndex(item => item.uiID == uiID)
- if (openIndex >= 0) this.UIOpenQueue.splice(openIndex, 1)
- this.UIOpenQueue.push(uiInfo)
- return
- }
- let uiInfoTmp = this.getUIInfo(uiID)
- if (uiInfoTmp) {
- // 重复打开了同一个界面
- this.hide(uiID)
- this.show(uiID, uiArgs)
- return
- }
- // 设置UI的zOrder
- uiInfo.zOrder = this.UIStack.length
- this.UIStack.push(uiInfo)
- // 先屏蔽点击
- uiInfo.preventNode = this.preventTouch(10000)
- this.isOpening = true
- // 预加载资源,并在资源加载完成后自动打开界面
- this.getOrCreateUI(
- uiID,
- progressCallback,
- (baseUI: BaseUI, prefab: cc.Prefab): void => {
- if (uiInfo.preventNode) {
- uiInfo.preventNode.destroy()
- uiInfo.preventNode = null
- }
- // 如果界面已经被关闭或创建失败
- if (uiInfo.isClose || null == baseUI) {
- cc.log(`getOrCreateUI ${uiID} faile!
- close state : ${uiInfo.isClose} , baseUI : ${baseUI}`)
- this.isOpening = false
- return
- }
- if (prefab) uiInfo.prefab = prefab
- this.onUIOpen(uiID, baseUI, uiInfo, uiArgs)
- this.isOpening = false
- this.autoExecNextUI()
- },
- uiArgs,
- )
- }
- /** 显示一组UI */
- showUIs(UIs: GroupUIInfo[]) {
- if (!UIs) return
- UIs = UIs.filter(value => value)
- if (UIs.length <= 0) return
- this.groupUIs = UIs
- this.curGroupUI = this.groupUIs.splice(0, 1)[0]
- this.show(this.curGroupUI.uiID, this.curGroupUI.uiArgs)
- }
- /** 替换栈顶界面 */
- public replace(uiID: number, uiArgs: any = null) {
- this.hideBaseUI(this.UIStack[this.UIStack.length - 1].baseUI)
- this.show(uiID, uiArgs)
- }
- /**
- * 关闭当前界面
- * @param closeUI 要关闭的界面
- */
- public hideBaseUI(closeUI?: BaseUI) {
- let uiCount = this.UIStack.length
- if (uiCount < 1 || this.isClosing || this.isOpening) {
- if (closeUI) {
- // 插入待关闭队列
- let closeIndex = this.UICloseQueue.findIndex(v => v == closeUI.uiID)
- if (closeIndex >= 0) this.UICloseQueue.splice(closeIndex, 1)
- this.UICloseQueue.push(closeUI.uiID)
- }
- return
- }
- let uiInfo: UIInfo
- if (closeUI) {
- let isSplice = false
- for (let index = this.UIStack.length - 1; index >= 0; index--) {
- let ui = this.UIStack[index]
- if (ui.baseUI === closeUI) {
- uiInfo = ui
- isSplice = true
- this.UIStack.splice(index, 1)
- break
- }
- }
- if (isSplice) this.resetUIStackZIndex()
- // 找不到这个UI
- if (uiInfo === undefined) {
- let index = this.UIOpenQueue.findIndex(value => value.uiID == closeUI.uiID)
- if (index >= 0) {
- this.UIOpenQueue.splice(index, 1)
- }
- this.autoExecNextUI()
- return
- }
- } else {
- uiInfo = this.UIStack.pop()
- }
- // 关闭当前界面
- let uiID = uiInfo.uiID
- let baseUI = uiInfo.baseUI
- uiInfo.isClose = true
- // 回收遮罩层
- if (uiInfo.preventNode) {
- uiInfo.preventNode.destroy()
- uiInfo.preventNode = null
- }
- if (null == baseUI) {
- return
- }
- this.isClosing = true
- let preUIInfo = null
- for (let i = uiCount - 2; i >= 0; i--) {
- if (this.UIStack[i] && this.UIStack[i].baseUI.showType == baseUI.showType) {
- preUIInfo = this.UIStack[i]
- break
- }
- }
- let close = () => {
- this.isClosing = false
- // 显示之前的界面
- if (preUIInfo && preUIInfo.baseUI && preUIInfo.baseUI.node.activeInHierarchy) {
- // 回调onTop onTop只是当前层级生效
- preUIInfo.baseUI.onTop(uiID)
- }
- if (this.uiCloseDelegate) {
- this.uiCloseDelegate(uiID)
- }
- this.releaseUI(uiInfo)
- baseUI.onHide()
- this.autoExecNextUI()
- if (this.groupUIs.length > 0) {
- this.curGroupUI = this.groupUIs.splice(0, 1)[0]
- this.show(this.curGroupUI.uiID, this.curGroupUI.uiArgs)
- }
- }
- // 执行关闭动画
- this.autoExecAnimation(baseUI, 'uiClose', close)
- }
- /**
- * 关闭当前界面
- * @param uiID 要关闭的界面
- */
- public hide(uiID: UI) {
- let uiCount = this.UIStack.length
- if (uiCount < 1 || this.isClosing || this.isOpening) {
- if (uiID) {
- // 插入待关闭队列
- const openIndex = this.UIOpenQueue.findIndex(v => v.uiID == uiID)
- if (openIndex != -1) {
- this.UIOpenQueue.splice(openIndex, 1)
- } else {
- this.UICloseQueue.push(uiID)
- }
- }
- return
- }
- if (this.getUI(uiID)) this.hideBaseUI(this.getUI(uiID))
- }
- /** 关闭所有界面 */
- public closeAll(remainUIs: UI[] = []) {
- // 不播放动画,也不清理缓存
- let remainUIInfo = []
- for (const uiInfo of this.UIStack) {
- if (remainUIs.includes(uiInfo.uiID)) {
- remainUIInfo.push(uiInfo)
- continue
- }
- uiInfo.isClose = true
- if (uiInfo.preventNode) {
- uiInfo.preventNode.destroy()
- uiInfo.preventNode = null
- }
- if (uiInfo.baseUI) {
- //uiInfo.baseUI.decAllRef()
- this.releaseUI(uiInfo)
- uiInfo.baseUI.onHide()
- }
- }
- this.UIOpenQueue = []
- this.UICloseQueue = []
- this.UIStack = remainUIInfo
- this.resetUIStackZIndex()
- this.isOpening = false
- this.isClosing = false
- this.curGroupUI = null
- this.groupUIs = []
- }
- releaseUI(uiInfo: UIInfo) {
- let baseUI = uiInfo.baseUI
- baseUI.node.parent = null
- this.UICache[uiInfo.uiID] = uiInfo
- if (!baseUI.cache) {
- uiInfo.hideTime = Date.now()
- }
- }
- cleanUI() {
- let now = Date.now()
- for (let key in this.UICache) {
- let uiInfo = this.UICache[key]
- if (uiInfo) {
- let node = uiInfo.baseUI.node
- let hideTime = uiInfo.hideTime
- let prefab = uiInfo.prefab
- if (!node.parent && hideTime > 0 && now - hideTime > 15000 && !this.isClosing && !this.isOpening) {
- console.log('UIMgr releaseUI:', node.name)
- uiInfo.baseUI.decAllRef()
- node.destroy()
- cc.assetManager.releaseAsset(prefab)
- delete this.UICache[key]
- }
- }
- }
- }
- resetUIStackZIndex() {
- for (let i = 0; i < this.UIStack.length; i++) {
- let uiInfo = this.UIStack[i]
- uiInfo.zOrder = i
- uiInfo.baseUI.node.zIndex = i + uiInfo.baseUI.showType
- }
- }
- /******************** UI的便捷接口 *******************/
- //可能存在当时UI正在加载node,没有baseUI,顶层不是那么精确
- public isTopUI(uiID, isCurLayer: boolean = true): boolean {
- let curUIs = this.UIStack
- let uiInfo = curUIs.find(v => v.uiID == uiID)
- if (!uiInfo) return false
- if (uiInfo && isCurLayer) {
- curUIs = this.UIStack.filter(v => v.baseUI && uiInfo.baseUI && v.baseUI.showType == uiInfo.baseUI.showType)
- }
- return curUIs[curUIs.length - 1]?.uiID == uiID
- }
- public getUI(uiID: number): BaseUI {
- for (let index = 0; index < this.UIStack.length; index++) {
- const element = this.UIStack[index]
- if (uiID == element.uiID) {
- return element.baseUI
- }
- }
- return null
- }
- //返回uiID,可能存在当时UI正在加载node,没有baseUI
- public getTopUI(): number {
- if (this.UIStack.length > 0) {
- return this.UIStack[this.UIStack.length - 1].uiID
- }
- return null
- }
- public getUIInfo(uiID: number): UIInfo {
- for (let index = 0; index < this.UIStack.length; index++) {
- let element = this.UIStack[index]
- if (uiID == element.uiID) {
- return element
- }
- }
- return null
- }
- public getGroupUIInfo(uiID: number, args?: any): GroupUIInfo {
- return {uiID, uiArgs: args}
- }
- public getRewardGroupUIInfo(rewardNty: IRewardNty): GroupUIInfo | null {
- let hasReward = false
- for (let key in rewardNty) {
- hasReward ||= Array.isArray(rewardNty[key]) && rewardNty[key].length > 0
- }
- if (hasReward) {
- let rewardArgs: IReward = {idNumArr: Mgr.goods.getGoodsListByRewardNty(rewardNty)}
- return {uiID: UI.RewardUI, uiArgs: rewardArgs}
- } else {
- return null
- }
- }
- public callOnShow(uiID: UI, args: any) {
- let uiInfo = this.getUIInfo(uiID)
- if (uiInfo && uiInfo.baseUI) {
- uiInfo.baseUI.onShow(args, null)
- }
- }
- /******************** 通用UI的操作接口 *******************/
- public tip(text: string = '') {
- if (text == '') {
- return
- }
- this.hide(UI.TipUI)
- this.show(UI.TipUI, text)
- }
- /**
- * 显示网络请求等待响应屏蔽触摸的界面
- * @param str 显示的文本
- * @param isDelay 是否延时显示可见的屏蔽层,延时中为透明的屏蔽层
- * @param cutNet 超时后是否重启游戏
- */
- public showLoading(str: string = '', isDelay: boolean = true, cutNet: boolean = false, timeOut: boolean = false) {
- this.show(UI.LoadingUI, {str, isDelay, cutNet, timeOut})
- }
- /**
- * 隐藏网络请求等待响应屏蔽触摸的界面
- */
- public hideLoading() {
- this.hide(UI.LoadingUI)
- }
- public message(text: string = '', sureFunc: Function, isHideCancel: boolean = false, sureLb: string = '') {
- if (text == '') {
- return
- }
- let args: IMessage = {
- sureFuc: sureFunc,
- tip: text,
- isHideCancel,
- sureLb,
- }
- this.show(UI.MessageUI, args)
- }
- public fadeShow(uiID: number, uiArgs: any = null, inOrOut = true) {
- this.show(UI.FadeInOutUI, {
- inOrOut,
- aniFinishFuc: () => {},
- })
- if (uiID > 0) this.show(uiID, uiArgs)
- }
- public showReward(rewardNty: IRewardNty, itemUICfgArr?: ItemUICfg[]) {
- if (!rewardNty) return
- let hasReward = false
- for (let key in rewardNty) {
- hasReward ||= Array.isArray(rewardNty[key]) && rewardNty[key].length > 0
- }
- if (hasReward) {
- let rewardArgs: IReward = {idNumArr: Mgr.goods.getGoodsListByRewardNty(rewardNty), itemUICfgArr}
- this.show(UI.RewardUI, rewardArgs)
- }
- }
- //传入needNum表示根据needGoods道具ID判断是否显示UI。不传值默认显示UI
- public showObtain(needGoods: number | IOperateNeed, needNum: number = 0): boolean {
- let operateNeed: IOperateNeed
- let showObtain = true
- if (typeof needGoods == 'number') {
- operateNeed = {
- canUp: false,
- isMax: false,
- need: [
- {
- id: needGoods,
- num: Data.user.goods.get(needGoods) ? Data.user.goods.get(needGoods) : 0,
- need: needNum,
- },
- ],
- }
- } else {
- operateNeed = needGoods
- }
- if (needNum > 0) {
- let hasNum = Data.user.goods.get(operateNeed.need[0]?.id)
- showObtain = hasNum < needNum
- }
- if (showObtain) this.show(UI.ObtainChannelUI, operateNeed)
- return showObtain
- }
- }
|