import { _decorator, Button, Color, Component, EventHandler, instantiate, JsonAsset, Label, Layout, Node, ScrollView, sp, Sprite, SpriteAtlas, SpriteFrame, tween, UITransform, v3, Vec3 } from 'cc'; import { ScrollControl } from './ScrollControl'; import { fixNum, getTimezoneOffsetString, getTranslate, hideAllChildren, ICON_RATE, updateLang, waitNextFrame } from './Tools'; let { ccclass, property } = _decorator; @ccclass('HistoryDetail') export class HistoryDetail extends Component { @property(JsonAsset) langJson: JsonAsset | null = null; /**loading 动画节点*/ @property(Node) loading: Node = null @property(Node) pnl_title: Node = null; @property(Node) item_round_winning: Node = null; @property(ScrollView) list_round_winning: ScrollView = null; @property(Node) item_detail: Node = null; @property(ScrollView) list_detail: ScrollView = null; @property(Node) item_symbol: Node = null; @property(Node) item_win_kind: Node = null; @property(Node) flip: Node = null; @property(ScrollControl) scrollControl: ScrollControl = null @property(SpriteAtlas) symbolsAtlas: SpriteAtlas = null!; @property(SpriteAtlas) MultisAtlas: SpriteAtlas = null!; @property(SpriteAtlas) bgAtlas: SpriteAtlas = null!; dict = null lang = "th" data: any = null currTotalMulti = 0 protected onLoad(): void { this.node.on("show_history_formula_detail", this.showFormulaDetail, this) this.node.on("hide_history_formula_detail", this.hideFormulaDetail, this) this.node.on("remark_round_winning_list", this.remarkRoundWinningList, this) this.list_round_winning.node.active = false this.item_round_winning.active = false this.item_symbol.active = false this.item_win_kind.active = false this.item_detail.active = false } protected start(): void { } protected onDisable(): void { this.node.off("show_history_formula_detail", this.showFormulaDetail, this) this.node.off("hide_history_formula_detail", this.hideFormulaDetail, this) this.node.off("remark_round_winning_list", this.remarkRoundWinningList, this) } setDetailData(data, lang) { this.data = null this.data = JSON.parse(JSON.stringify(data)); this.dict = this.langJson.json[lang] ?? this.langJson.json["en"]; updateLang(this.node, this.dict, lang) } loadRoundWinningList(scoreInfos) { this.data.scoreInfos = scoreInfos let content = this.list_round_winning.content content.destroyAllChildren() let currencySymbol = this.data.currencySymbol let yellowColor = new Color(0xFF, 0xAE, 0x00) scoreInfos.forEach((v, i) => { let item = instantiate(this.item_round_winning) let txt_round = item.getChildByName("txt_round").getComponent(Label) let txt_score = item.getChildByName("txt_score").getComponent(Label) if (i == 0) { txt_round.string = getTranslate(this.dict, "Normal Spin") txt_round.color = yellowColor txt_score.color = yellowColor } else { txt_round.string = getTranslate(this.dict, "Free Spin:") + ` ${i}/${scoreInfos.length - 1}` txt_round.color = Color.WHITE txt_score.color = Color.WHITE } txt_score.string = `${currencySymbol}${fixNum(v.Score)}` item.name = v.StartIndex.toString() item.position = new Vec3() content.addChild(item) }); } jumpToPage(event) { let item = event.target as any as Node let page = item.name this.scrollControl.jumpToPage(Number(page)) this.hideRoundWinningList() } remarkRoundWinningList(page) { let txt_spin = this.pnl_title.getChildByName("txt_spin").getComponent(Label) if (!this.data) { return } if (!this.data.scoreInfos) { txt_spin.string = getTranslate(this.dict, "Normal Spin") return } let maxIdx = this.data.scoreInfos.length - 1 let findIndex = maxIdx for (let i = maxIdx; i >= 0; i--) { let scoreInfo = this.data.scoreInfos[i] if (page >= scoreInfo.StartIndex) { findIndex = i break } } // console.log(`findIndex, ${findIndex}`) if (findIndex == 0) { txt_spin.string = getTranslate(this.dict, "Normal Spin") } else { txt_spin.string = getTranslate(this.dict, "Free Spin:") + `${findIndex}/${maxIdx}` } let yellowColor = new Color(0xFF, 0xAE, 0x00) this.list_round_winning.content.children.forEach((item, i) => { let txt_round = item.getChildByName("txt_round").getComponent(Label) let txt_score = item.getChildByName("txt_score").getComponent(Label) if (i == findIndex) { txt_round.color = yellowColor txt_score.color = yellowColor } else { txt_round.color = Color.WHITE txt_score.color = Color.WHITE } }) } showRoundWinningList() { let isActive = this.list_round_winning.node.active if (isActive) { this.hideRoundWinningList() return } let node = this.list_round_winning.node let content = this.list_round_winning.content content.children.forEach(v => { v.active = true }) node.active = true let close_Lab = this.list_round_winning.node.getChildByName('btn_close').getChildByName('Label'); close_Lab.getComponent(Label).string = getTranslate(this.dict, "Close"); let startVec = new Vec3(0, 3000) let endVec = new Vec3(0, this.list_detail.node.getPosition().y) node.position = startVec tween(node).to(0.2, { position: endVec }).call(() => { let sp = this.pnl_title.getChildByName("txt_spin").getChildByName("sp") sp.scale = new Vec3(1, -1) }).start() } hideRoundWinningList() { let node = this.list_round_winning.node let content = this.list_round_winning.content let startVec = new Vec3(0, 3000) tween(this.list_round_winning.node).to(0.2, { position: startVec }) .call(() => { content.children.forEach(v => { v.active = false }) node.active = false let sp = this.pnl_title.getChildByName("txt_spin").getChildByName("sp") sp.scale = new Vec3(1, 1) }).start() } /** 图标固定宽高 */ ICON_WIDTH = 174; ICON_HEIGHT = 160; getIconPosition(pos: number): Vec3 { if (pos < 0 || pos >= 30) { console.error(`索引 ${pos} 超出范围 (0~29)`); return v3(0, 0, 0); } let col = Math.floor(pos / 5); // 6列 let row = pos % 5; // 5行 let x = (col - 2.5) * this.ICON_WIDTH; let y = (2 - row) * this.ICON_HEIGHT; return v3(x, y, 0); } formatData(data) { let result = []; let isFirstRound = true; let currentRoundBefore = 0; data.panDetails.forEach((pan, index) => { let isRoundEnd = pan.RoundInfo && pan.RoundInfo.Current === pan.RoundInfo.Total let isRoundMore = pan.RoundInfo && pan.RoundInfo.Total > 1; let roundWin = pan.RoundInfo && pan.RoundInfo.AllScoreMul || 0; let obj = { bet: index === 0 ? data.bet : 0, profit: 0, beforeScore: 0, afterScore: 0, }; let profit, before, after; // 第一盘数据 包含是否进入了免费游戏 if (isFirstRound) { if (isRoundMore) { if (isRoundEnd) { profit = roundWin; before = pan.Balance - roundWin; after = pan.Balance; isFirstRound = false; } else if (pan.RoundInfo && pan.RoundInfo.Current == 1) { profit = -data.bet; before = pan.Balance + data.bet - roundWin; after = pan.Balance - roundWin; } else { profit = 0; before = pan.Balance - roundWin; after = pan.Balance - roundWin; } } else { profit = pan.AllScore - data.bet; before = pan.Balance - profit; after = pan.Balance; isFirstRound = false; } } else { if (isRoundMore) { if (isRoundEnd) { profit = roundWin; before = pan.Balance - roundWin; after = pan.Balance; isFirstRound = false; } else if (pan.Index == 0) { profit = 0; before = pan.Balance - roundWin; after = pan.Balance - roundWin; } else { profit = 0; before = pan.Balance - roundWin; after = pan.Balance - roundWin; } } else { profit = 0; before = pan.Balance; after = pan.Balance; } } obj.profit = profit; obj.beforeScore = before; obj.afterScore = after; result.push(obj); }); console.log(result); return result; } ICON_SERVER_MAP = { 1: 0, 3: 1, 4: 2, 5: 3, 6: 4, 7: 5, 8: 6, 9: 7, 10: 8, 11: 9, 12: 10, } getScatterNum(Bottom: any[]) { let scatterNum = 0 for (let i = 0; i < Bottom.length; i++) { if (Bottom[i] == 1) { scatterNum++ } } return scatterNum } getMultiSymbolFrames(multi: number): SpriteFrame { switch (true) { case multi <= 8: return this.MultisAtlas.getSpriteFrame('0') case multi <= 25: return this.MultisAtlas.getSpriteFrame('1') case multi <= 50: return this.MultisAtlas.getSpriteFrame('2') case multi <= 100: return this.MultisAtlas.getSpriteFrame('3') case multi <= 1000: return this.MultisAtlas.getSpriteFrame('4') } } // 加载一盘数据 loadOne(item: Node, pan, idx, formattedData) { let winInfo = pan.SymbolWinInfos; item.position = new Vec3() this.list_detail.content.addChild(item) let currencySymbol = this.data.currencySymbol let currency = this.data.currency let info = item.getChildByName("info"); info.getChildByName("txt_transaction").getComponent(Label).string = this.data.roundId; let roundInfo = pan.RoundInfo; let bet = formattedData.bet; let curBalance = formattedData.afterScore; let beforeBalance = formattedData.beforeScore; let profit = formattedData.profit; // 是否是第一次进入免费游戏 let Free = pan.FreeSpin; let isFirstEnterFreeGame = false; if (Free != null) { isFirstEnterFreeGame = Free.LeftCount == Free.MaxCount; } // 下注额 info.getChildByName("txt_bet").getComponent(Label).string = fixNum(bet); info.getChildByName("Label_Bet").getComponent(Label).string = getTranslate(this.dict, "Bet") + `(${currencySymbol})`; // 利润 info.getChildByName("txt_profit").getComponent(Label).string = fixNum(profit); info.getChildByName("Label_Profit").getComponent(Label).string = getTranslate(this.dict, "Profit") + `(${currencySymbol})`; // 之前 之后 info.getChildByName("txt_balance_before").getComponent(Label).string = fixNum(beforeBalance) + "➡️"; info.getChildByName("txt_balance_after").getComponent(Label).string = profit !== 0 ? fixNum(curBalance) : fixNum(beforeBalance); info.getChildByName("Label_Balance").getComponent(Label).string = getTranslate(this.dict, "Balance") + `(${currencySymbol})`; // 小盘信息 let content = item.getComponent(ScrollView).content; let bet_info = content.getChildByName("bet_info") if (pan.RoundInfo) { let txt_round = bet_info.getChildByName("txt_round").getComponent(Label) txt_round.string = getTranslate(this.dict, "Round:") + ` ${pan.RoundInfo.Current}/${pan.RoundInfo.Total}` } else { bet_info.getChildByName("txt_round").active = false } let roller_normal = content.getChildByName('Roller').getChildByName('icon_normal'); let roller_gray = content.getChildByName('Roller').getChildByName('gray'); let roller_wins = content.getChildByName('Roller').getChildByName('icon_wins'); let roller_scatter = content.getChildByName('Roller').getChildByName('icon_scatter'); let totalMulti = content.getChildByName('Roller').getChildByName('totalMulti'); roller_normal.removeAllChildren(); roller_gray.active = false; roller_wins.removeAllChildren(); roller_scatter.removeAllChildren(); // let showMulti = pan.WinMultiPlier - pan.WinMultiPlierReal totalMulti.getComponent(Label).string = this.currTotalMulti <= 0 ? " " : ('x' + this.currTotalMulti) let upIconIndexs = []; if (winInfo[0] != null) { // 对{}进行遍历 roller_gray.active = true; for (let key in winInfo) { let middle = winInfo[key]; upIconIndexs.push(...middle.BottomPos); } // 去重 upIconIndexs = upIconIndexs.filter((value, index, self) => self.indexOf(value) === index); } for (let index = 0; index < pan.PanColor.Bottom.length; index++) { let iconServerIndex = pan.PanColor.Bottom[index]; let iconIndex = this.ICON_SERVER_MAP[iconServerIndex]; // 等于10就跳过,10是multi icon if (iconIndex == 10) { continue; } let iconPre = instantiate(this.item_symbol); let pathBg = `${iconIndex}`; let symbolSpriteFrame = this.symbolsAtlas.getSpriteFrame(pathBg); let bgspriteFrame = this.bgAtlas.getSpriteFrame(pathBg); let bgSprite = iconPre.getChildByName("bg").getComponent(Sprite); if (bgspriteFrame) { bgSprite.spriteFrame = bgspriteFrame; } else { bgSprite.spriteFrame = null; } let iconSprite = iconPre.getChildByName("symbol").getComponent(Sprite); iconSprite.spriteFrame = symbolSpriteFrame; let multiNode = iconPre.getChildByName('multi'); multiNode.active = false; if (iconIndex == 0) { roller_scatter.addChild(iconPre) } else if (upIconIndexs.indexOf(index) != -1) { roller_wins.addChild(iconPre); } else { roller_normal.addChild(iconPre); } iconPre.active = true; let iconPosition = this.getIconPosition(index); iconPre.setPosition(iconPosition); } if (pan.MulInfo != null) { for (let index = 0; index < pan.MulInfo.length; index++) { let element = pan.MulInfo[index]; let iconPos = element.Pos; let iconPre = instantiate(this.item_symbol); let bgSpriteFrame = this.bgAtlas.getSpriteFrame(`${10}`) let symbolSpriteFrame = this.getMultiSymbolFrames(element.Mul); let iconSprite = iconPre.getChildByName("symbol").getComponent(Sprite); iconSprite.spriteFrame = symbolSpriteFrame; let bgSprite = iconPre.getChildByName("bg").getComponent(Sprite); bgSprite.spriteFrame = bgSpriteFrame; let iconPosition = this.getIconPosition(iconPos); iconPre.setPosition(iconPosition); let multiLabel = iconPre.getChildByName('multi').getComponent(Label); multiLabel.string = 'x' + element.Mul.toString(); multiLabel.node.active = true; iconPre.active = true; roller_wins.addChild(iconPre); } } // No Winning Combination let node_no_winning = content.getChildByName("node_no_winning") node_no_winning.active = winInfo[0] == null; // let node_feature_buy = content.getChildByName("node_feature_buy") let isActive = this.data.isBuy && isFirstEnterFreeGame; node_feature_buy.active = isActive // Win Multiplier x ? let node_win_multiplier = content.getChildByName("node_win_multiplier") node_win_multiplier.active = false; let node_win_multiplier_1 = content.getChildByName("node_win_multiplier_1") node_win_multiplier_1.active = false; if (pan.RoundInfo != null) { if (pan.RoundInfo && pan.RoundInfo.Mul > 1) { // let mulDesc = winInfo.MulDesc; let txt_win_multiplier = node_win_multiplier.getChildByName("txt_win_multiplier") txt_win_multiplier.getComponent(Label).string = getTranslate(this.dict, "Win Multiplier") + " x " + pan.RoundInfo.Mul; node_win_multiplier.active = true; let txt_win_multiplier_1 = node_win_multiplier_1.getChildByName("txt_win_multiplier_1"); txt_win_multiplier_1.getComponent(Label).string = getTranslate(this.dict, "Win Multiplier"); let mulited = node_win_multiplier_1.getChildByName("mulited"); mulited.getComponent(Label).string = `${currencySymbol} ${fixNum(pan.RoundInfo.AllScoreMul)}` + ''; let unmulited = node_win_multiplier_1.getChildByName("unmulited"); unmulited.getComponent(Label).string = `${currencySymbol} ${fixNum(pan.RoundInfo.AllScore)} x ${pan.RoundInfo.Mul}`; node_win_multiplier_1.active = true; this.currTotalMulti = pan.RoundInfo.Mul } } // 第一次进入scatter 数量统计 node_scatter if (this.getScatterNum(pan.PanColor.Bottom) >= 4 && isFirstEnterFreeGame && Free != null) { let node_scatter = content.getChildByName("node_scatter") let txt_scatter_num = node_scatter.getChildByName("txt_scatter_num").getComponent(Label) txt_scatter_num.string = "x " + this.getScatterNum(pan.PanColor.Bottom) let txt_free_spin = node_scatter.getChildByName("txt_free_spin").getComponent(Label) txt_free_spin.string = pan.FreeSpin.MaxCount + " " + getTranslate(this.dict, "Free Spins") node_scatter.active = true } else if (this.getScatterNum(pan.PanColor.Bottom) >= 3 && !isFirstEnterFreeGame && Free != null) { let node_scatter = content.getChildByName("node_scatter") let txt_scatter_num = node_scatter.getChildByName("txt_scatter_num").getComponent(Label) txt_scatter_num.string = "x " + this.getScatterNum(pan.PanColor.Bottom) let txt_free_spin = node_scatter.getChildByName("txt_free_spin").getComponent(Label) txt_free_spin.string = "+5 " + getTranslate(this.dict, "Free Spins") node_scatter.active = true } else { let node_scatter = content.getChildByName("node_scatter") node_scatter.removeFromParent() node_scatter.destroy() } // let node_formula = content.getChildByName('node_formula'); // let item_kind = instantiate(this.item_win_kind); if (winInfo[0] != null) { let node_formula = content.getChildByName('node_formula'); for (let key in winInfo) { let symbolWinInfo = winInfo[key]; let hitColor = this.ICON_SERVER_MAP[pan.PanColor.Bottom[symbolWinInfo.BottomPos[0]]] let item_win_kind = instantiate(this.item_win_kind) item_win_kind.name = `item_win_kind_${hitColor}`; let bg = item_win_kind.getChildByName("bg").getComponent(Sprite); let sp = item_win_kind.getChildByPath("bg/sp").getComponent(Sprite); let path_symbol = `${hitColor}`; bg.spriteFrame = this.bgAtlas.getSpriteFrame(path_symbol); sp.spriteFrame = this.symbolsAtlas.getSpriteFrame(path_symbol); let txt_kind = item_win_kind.getChildByName("txt_kind").getComponent(Label); txt_kind.string = 'x' + symbolWinInfo.BottomPos.length; let txt_win = item_win_kind.getChildByName("txt_win").getComponent(Label) txt_win.string = `${currencySymbol}${fixNum(symbolWinInfo.Score)}` let formula_detail = item_win_kind.getChildByName("formula_detail"); let Label_Formual = formula_detail.getChildByName("Label_Formual").getComponent(Label) Label_Formual.string = getTranslate(this.dict, "BxS") let txt_formual_detail = formula_detail.getChildByName("txt_formual_detail").getComponent(Label) txt_formual_detail.string = fixNum(pan.Bet) + ' x ' + this.getWinSymbolMulti(pan.PanColor.Bottom, symbolWinInfo.BottomPos).toFixed(2); formula_detail.active = false; item_win_kind.position = new Vec3() item_win_kind.active = true; node_formula.addChild(item_win_kind); } // 每一条 item_win_kind 可以点开 自己的 formula_detail // 要求列表前面的item_win_kind弹出来formula_detail ,盖住后面的 item_win_kind // 但 addChild的顺序决定后 后面会盖住前面,所以这里要反转一下 // 而且一定要关掉 Layout ,因为它会把 SiblingIndex最小的放到最上面 let lyt = node_formula.getComponent(Layout) lyt.updateLayout() lyt.enabled = false let children = node_formula.children.slice().reverse(); children.forEach((child, i) => { child.active = true child.setSiblingIndex(i); }); let contentlyt = content.getComponent(Layout) contentlyt.updateLayout() contentlyt.enabled = false // 多给一截滑动空间 content.getComponent(UITransform).height = content.getComponent(UITransform).height + 200 } hideAllChildren(item) } getWinSymbolMulti(panColor, BottomPos: any[]) { let hitColor: number = this.ICON_SERVER_MAP[panColor[BottomPos[0]]] let winLevel: number = 0 if (BottomPos.length <= 9) { winLevel = 0 } else if (BottomPos.length <= 11) { winLevel = 1 } else { winLevel = 2 } return ICON_RATE[hitColor][winLevel] } async loadDetailList() { // 时间 let pnl_title = this.node.getChildByName("pnl_title") let txt_time = pnl_title.getChildByName("txt_time").getComponent(Label) let timestamp = this.data.startTime; let date = new Date(timestamp * 1000); // JS 使用毫秒,所以要 *1000 let pad = (n: number) => (n < 10 ? '0' + n : String(n)); let formatted = `${date.getFullYear()}/${pad(date.getMonth() + 1)}/${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`; let str = formatted + getTimezoneOffsetString() txt_time.string = str let currencySymbol = this.data.currencySymbol let currency = this.data.currency let scoreInfos = this.data.panDetails[0].ScoreInfos let btn_winning_list = this.pnl_title.getChildByName("txt_spin").getChildByName("btn_winning_list").getComponent(Button) let sp = this.pnl_title.getChildByName("txt_spin").getChildByName("sp") if (scoreInfos) { this.loadRoundWinningList(scoreInfos) btn_winning_list.interactable = true sp.active = true } else { btn_winning_list.interactable = false sp.active = false } let formattedData = this.formatData(this.data); this.data.panDetails.forEach(async (pan, idx) => { let item = instantiate(this.item_detail); item.active = true this.loadOne(item, pan, idx, formattedData[idx]) if (idx == this.data.panDetails.length - 1) { // console.log("已全部生成完") this.hideLoading() this.scrollControl.jumpToPage(0) } // 等待下一帧再生成下一个 await waitNextFrame(); }) this.item_detail.removeFromParent() this.scrollControl.vert_scrollView = this.list_detail.content.children[0].getComponent(ScrollView) this.list_detail.node.active = true } // wild 是0, scatter 是1 isScatterOrWild(v) { return v == 0 || v == 1 } clickPageUp() { this.scrollControl.pageUp() } clickPageDown() { this.scrollControl.pageDown() } async entryFinish() { // this.node.children.forEach((node, i) => { // node.active = true // }) this.showLoading() await this.loadDetailList() } removeReturnBtn() { let btn_return = this.node.getChildByName("btn_return") btn_return.destroy() } clickReturn() { let self = this tween(this.node).to(0.2, { position: new Vec3(2000, 0) }) .call(() => { self.node.destroy() }) .start() } // 传过来的是 item_win_kind showFormulaDetail(item_win_kind) { // 隐藏其他的formula_detail item_win_kind.parent.children.forEach(child => { if (child != item_win_kind) child.getChildByName("formula_detail").active = false }) // 显示就隐藏,隐藏就显示 let isActive = item_win_kind.getChildByName("formula_detail").active item_win_kind.getChildByName("formula_detail").active = !isActive } // 传过来的是 item_win_kind showFormulaDetail2(event) { let btn = event.target as Node as any let item_win_kind = btn.parent // 隐藏其他的formula_detail item_win_kind.parent.children.forEach(child => { if (child != item_win_kind) child.getChildByName("formula_detail").active = false }) // 显示就隐藏,隐藏就显示 let isActive = item_win_kind.getChildByName("formula_detail").active item_win_kind.getChildByName("formula_detail").active = !isActive } hideFormulaDetail(scrollVeiw: ScrollView) { let node_formula = scrollVeiw.content.getChildByName("node_formula") node_formula.children.forEach(node => { node.getChildByName("formula_detail").active = false }) } showLoading() { this.loading.active = true let sk = this.loading.getComponent(sp.Skeleton) // sk.paused = false // sk.loop = true sk.setAnimation(0, 'loadingLoop') } hideLoading() { let sk = this.loading.getComponent(sp.Skeleton) // sk.paused = true // sk.loop = false sk.clearAnimations() this.loading.active = false } }