1739 lines
53 KiB
Vue
1739 lines
53 KiB
Vue
<template>
|
||
<div
|
||
class="play"
|
||
:class="[
|
||
{ offcamera: !switchVideo },
|
||
{ no_bg: tableData && (tableData.game_id == 7 || tableData.game_id == 8) }
|
||
]"
|
||
>
|
||
<!-- Top Navigation Bar -->
|
||
<!-- Main View Container: Vertical Flex Stack -->
|
||
<div class="view">
|
||
|
||
<!-- 1. Video & Game Area (Top Section, Flex Grow to fill space) -->
|
||
<div class="video-container" ref="videoDom" @click.stop="closeSwitchView(false)">
|
||
|
||
|
||
<!-- Video Iframe -->
|
||
<iframe
|
||
v-if="switchVideo && tableData"
|
||
class="iframe"
|
||
:class="[
|
||
{
|
||
scale:
|
||
videoConfig.zoom &&
|
||
tableData.sendMode &&
|
||
(tableData.sendMode == 'endBet' ||
|
||
tableData.sendMode == 'sendScanResult')
|
||
}
|
||
]"
|
||
:src="videoUrl"
|
||
></iframe>
|
||
|
||
|
||
|
||
<!-- Overlays inside Top Section -->
|
||
|
||
|
||
<SwitchTableButton v-if="!switchtabshow" @click="showSwitchtab(true)" />
|
||
|
||
<!-- Status/Countdown Overlay (Moved to absolute end for visibility) -->
|
||
<div class="status-overlay" v-if="tableData">
|
||
<!-- Dealing Status -->
|
||
<div class="status-circle dealing" v-if="['endBet', 'sendScanResult', 'openingBaccaratResult', 'openingDtResult', 'openingNnResult', 'openingTcResult', 'openingToningResult', 'openingDiceResult', 'openingRouletteResult'].includes(tableData.sendMode)">
|
||
<span>发牌中</span>
|
||
</div>
|
||
<!-- Countdown -->
|
||
<div class="status-circle countdown" v-else-if="tableData.sendMode === 'startBetCountDown' || tableData.sendMode === 'toBet'">
|
||
<span>{{ circle.num }}</span>
|
||
</div>
|
||
<!-- Wait/Shuffle/Other -->
|
||
<div class="status-circle wait" v-else-if="!tableData.sendMode || tableData.sendMode === 'changeBoot'">
|
||
<span style="font-size: 12px;">洗牌中</span>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<!-- Back Button (Top Left) -->
|
||
<div class="video-btn-back" @click="handleBack"></div>
|
||
|
||
</div>
|
||
|
||
<!-- Top Navigation Bar (Moved below video) -->
|
||
<div class="nav">
|
||
<!-- 1. User Info -->
|
||
<div class="nav-item user-info">
|
||
<div class="icon user-icon"></div>
|
||
<div class="text">{{ userInfo.username }}</div>
|
||
</div>
|
||
|
||
<!-- 2. Balance -->
|
||
<div class="nav-item balance-info">
|
||
<div class="icon money-icon"></div>
|
||
<div class="text">{{ userInfo.money }}</div>
|
||
</div>
|
||
|
||
<!-- 3. Table Limit -->
|
||
<div class="nav-item limit-info">
|
||
<div class="icon limit-icon"></div>
|
||
<div class="text">{{ tableData && tableData.limit_money }}</div>
|
||
</div>
|
||
|
||
<!-- 4. Right Controls (Camera, etc.) -->
|
||
<div class="nav-item right-controls">
|
||
<!-- Camera moved to video overlay -->
|
||
<!-- <div class="btn muise" @click="toggleAplayer"></div> -->
|
||
<div class="btn menu" @click="showMenu"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Game Betting Area (Moved below Nav) -->
|
||
<div class="game-area-block" :class="{ 'nn-mode': tableData && (tableData.game_id == 4 || tableData.game_id == 5) }">
|
||
<div class="game-area-content">
|
||
<template
|
||
v-if="tableData && (tableData.game_id == 7 || tableData.game_id == 8)"
|
||
>
|
||
<Transition
|
||
name="custom-classes"
|
||
enter-active-class="animate__animated animate__faster animate__fadeInRight"
|
||
leave-active-class="animate__animated animate__faster animate__fadeOutRight"
|
||
>
|
||
<PlayTable
|
||
v-if="hideVideo"
|
||
class="dice-table"
|
||
ref="chipTable"
|
||
:game_id="tableData?.game_id"
|
||
:sendMode="tableData?.sendMode"
|
||
:table_id="tableData?.id"
|
||
:number_tab_id="tableData?.number_tab_id"
|
||
:is_scavenging="tableData?.is_scavenging"
|
||
:winArray="winArray"
|
||
:bet_amount_msg="tableData?.bet_amount_msg"
|
||
:can_bet_big_small="tableData?.can_bet_big_small"
|
||
:can_bet_luck_six="tableData?.can_bet_luck_six"
|
||
:limit_money="tableData?.limit_money"
|
||
:limit_money_pair="tableData?.limit_money_pair"
|
||
:limit_money_tie="tableData?.limit_money_tie"
|
||
:tableData="tableData"
|
||
></PlayTable>
|
||
</Transition>
|
||
</template>
|
||
<template v-else>
|
||
<PlayTable
|
||
ref="chipTable"
|
||
:game_id="tableData?.game_id"
|
||
:sendMode="tableData?.sendMode"
|
||
:table_id="tableData?.id"
|
||
:number_tab_id="tableData?.number_tab_id"
|
||
:is_scavenging="tableData?.is_scavenging"
|
||
:winArray="winArray"
|
||
:bet_amount_msg="tableData?.bet_amount_msg"
|
||
:can_bet_big_small="tableData?.can_bet_big_small"
|
||
:can_bet_luck_six="tableData?.can_bet_luck_six"
|
||
:limit_money="tableData?.limit_money"
|
||
:limit_money_pair="tableData?.limit_money_pair"
|
||
:limit_money_tie="tableData?.limit_money_tie"
|
||
:tableData="tableData"
|
||
:class="[
|
||
{
|
||
hideTable:
|
||
tableData &&
|
||
(tableData.sendMode == 'sendScanResult' ||
|
||
tableData.sendMode == 'endBet') &&
|
||
(tableData.game_id == 4 || tableData.game_id == 5)
|
||
}
|
||
]"
|
||
></PlayTable>
|
||
</template>
|
||
<RushVillage
|
||
v-if="tableData && tableData.is_rob == 1"
|
||
:thisData="tableData"
|
||
></RushVillage>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 2. Chip Control Bar (Middle Section, Fixed Height) -->
|
||
<PlayChip class="bet-chip-bar"></PlayChip>
|
||
|
||
<!-- 3. Poker Cards for NN/TC (Separate section above roadmap) -->
|
||
<div
|
||
class="poker-section"
|
||
v-if="tableData && (tableData.game_id == 4 || tableData.game_id == 5) && tableData.is_scavenging == 1"
|
||
>
|
||
<Poker
|
||
class="pokerView nn-compact"
|
||
:thisData="tableData"
|
||
></Poker>
|
||
</div>
|
||
|
||
<!-- 4. Roadmap (Bottom Section, Fixed Height or Flex Basis) -->
|
||
<div class="roadmap-container" :class="{ 'nn-mode': tableData && (tableData.game_id == 4 || tableData.game_id == 5) }" @click.stop="closeSwitchView(false)">
|
||
<PlayWay :tableData="tableData"></PlayWay>
|
||
<!-- Poker for Baccarat/Dragon Tiger (overlay style) -->
|
||
<Poker
|
||
class="pokerView"
|
||
:thisData="tableData"
|
||
v-if="tableData && tableData.is_scavenging == 1 && tableData.game_id != 4 && tableData.game_id != 5"
|
||
></Poker>
|
||
<ToningResult
|
||
v-if="showToningResult"
|
||
:result="tableData.round && tableData.round.result"
|
||
:sendMode="tableData.sendMode"
|
||
></ToningResult>
|
||
<DiceResult
|
||
v-if="showDiceResult"
|
||
:result="tableData.round && tableData.round.result"
|
||
:sendMode="tableData.sendMode"
|
||
></DiceResult>
|
||
<RouletteResult
|
||
v-if="showRouletteResult"
|
||
:resultInfo="tableData.round"
|
||
:sendMode="tableData.sendMode"
|
||
></RouletteResult>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- Moved Switch Views to Root View Level for Full Height Overlay -->
|
||
<van-popup
|
||
v-model:show="switchtabshow"
|
||
position="bottom"
|
||
:style="{ height: '100%' }"
|
||
:overlay="true"
|
||
:close-on-click-overlay="false"
|
||
@click.stop
|
||
>
|
||
<SwitchTab
|
||
@showSwitchtab="showSwitchtab"
|
||
:tabInfo="{
|
||
game_id: tableData && tableData.game_id,
|
||
table_id: tableData && tableData.id
|
||
}"
|
||
></SwitchTab>
|
||
</van-popup>
|
||
<div
|
||
class="switchView camera animate__fadeIn animated0"
|
||
v-if="switchCameraShow"
|
||
>
|
||
<setCamera @showSwitchCamera="showSwitchCamera"></setCamera>
|
||
</div>
|
||
|
||
|
||
<!-- Popups -->
|
||
<PlayTypePop class="play-type-pop"></PlayTypePop>
|
||
<TableInfoPop class="table-info-pop" :tableData="tableData"></TableInfoPop>
|
||
<OnLinePop class="online-pop"></OnLinePop>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { ref, computed, watch, nextTick, onUnmounted } from "vue"
|
||
import { useRouter, useRoute } from "vue-router"
|
||
import { useStore } from "vuex"
|
||
import { showToast, showDialog, closeDialog, closeToast } from "vant"
|
||
import PlayTable from "@/components/PlayTable/Index.vue"
|
||
import PlayWay from "@/components/PlayWay.vue"
|
||
import PlayChip from "@/components/PlayChip.vue"
|
||
import Poker from "@/components/Poker"
|
||
import RushVillage from "@/components/RushVillage"
|
||
import ToningResult from "@/components/ToningResult"
|
||
import DiceResult from "@/components/DiceResult"
|
||
import RouletteResult from "@/components/RouletteResult"
|
||
import SwitchTab from "@/components/SwitchTab2"
|
||
import SwitchTableButton from "@/components/SwitchTableButton"
|
||
import setCamera from "@/components/setCamera"
|
||
import PlayTypePop from "@/components/PlayTypePop"
|
||
import TableInfoPop from "@/components/TableInfoPop"
|
||
import OnLinePop from "@/components/OnLinePop"
|
||
import { audioMp3 } from "@/assets/js/sound.js"
|
||
import {
|
||
getUserBetBaccarat,
|
||
getUserBetDt,
|
||
getUserBetNn,
|
||
getUserBetTc,
|
||
getUserBetToning,
|
||
getUserBetDice,
|
||
getUserBetRoulette
|
||
} from "@/utils/api"
|
||
|
||
export default {
|
||
name: "playView",
|
||
components: {
|
||
PlayTable,
|
||
PlayWay,
|
||
PlayChip,
|
||
Poker,
|
||
SwitchTab,
|
||
SwitchTableButton,
|
||
setCamera,
|
||
PlayTypePop,
|
||
TableInfoPop,
|
||
OnLinePop,
|
||
RushVillage,
|
||
ToningResult,
|
||
DiceResult,
|
||
RouletteResult
|
||
},
|
||
setup() {
|
||
const audio = ref(null)
|
||
const videoDom = ref(null)
|
||
const foxVideo = ref({ w: 0, h: 0, mt: 0, ml: 0 })
|
||
const hideVideo = ref(true)
|
||
const table_id = ref(null)
|
||
const chipTable = ref(null)
|
||
const currentRate = ref(0)
|
||
const switchtabshow = ref(false)
|
||
const isSwitchtab = ref(false)
|
||
const switchCameraShow = ref(false)
|
||
const isSwitchCamera = ref(false)
|
||
const showToningResult = ref(false)
|
||
const showDiceResult = ref(false)
|
||
const showRouletteResult = ref(false)
|
||
const winArray = ref([])
|
||
const router = useRouter()
|
||
const route = useRoute()
|
||
const store = useStore()
|
||
const baccaratType = computed(() => store.state.config.baccaratType)
|
||
const rouletteType = computed(() => store.state.config.roulette_type)
|
||
const rouletteLockTable = computed(
|
||
() => store.state.config.rouletteLockTable
|
||
)
|
||
const tableData = computed(() => store.getters.getTableById(table_id.value))
|
||
const circle = computed(() => {
|
||
const data = { num: 0, rate: 0 }
|
||
if (tableData.value) {
|
||
const { count_down, wait_time, sendMode } = tableData.value
|
||
if (!sendMode) {
|
||
data.num = wait_time
|
||
data.rate = (data.num / wait_time) * 100
|
||
} else {
|
||
data.num = count_down || 0
|
||
data.rate = (data.num / wait_time) * 100
|
||
}
|
||
}
|
||
return data
|
||
})
|
||
const Type = computed(() => store.state.config.$Type)
|
||
const Lang = computed(() => store.state.config.$lang)
|
||
const routerStack = computed(() => store.state.app.routerStack)
|
||
const phoneModel = computed(() => store.state.config.phoneModel)
|
||
const phoneScreen = computed(() => store.state.config.phoneScreen)
|
||
const switchVideo = computed(() => store.state.config.switchVideo)
|
||
const videoConfig = computed(() => store.state.config.video)
|
||
const videoUrl = computed(() => {
|
||
let src = "",
|
||
media_url = ""
|
||
if (tableData.value && videoConfig.value) {
|
||
// line决定使用近景(near)还是远景(far),definition决定使用flv还是ws
|
||
if (videoConfig.value.line == 1) {
|
||
// 使用近景
|
||
if (videoConfig.value.definition == 1) {
|
||
media_url = tableData.value.media_near_flv
|
||
} else {
|
||
media_url = tableData.value.media_near_ws
|
||
}
|
||
} else {
|
||
// 使用远景
|
||
if (videoConfig.value.definition == 1) {
|
||
media_url = tableData.value.media_far_flv
|
||
} else {
|
||
media_url = tableData.value.media_far_ws
|
||
}
|
||
}
|
||
src = `${videoConfig.value.player}?url=${media_url}`
|
||
} else {
|
||
src = `static/video.html?url=${media_url}`
|
||
}
|
||
// const src = `static/video.html?url=https://al2-flv.live.huajiao.com/live_huajiao_h265/_LC_AL2_non_h265_SD_26820950716932293510114149_OX.flv`
|
||
return src
|
||
})
|
||
const closeSwitchView = () => {
|
||
showSwitchtab(false)
|
||
showSwitchCamera(false)
|
||
}
|
||
|
||
// 处理返回按钮
|
||
const handleBack = () => {
|
||
// 检查是否从 Portal 跳转过来
|
||
const urlParams = new URLSearchParams(window.location.search)
|
||
const from = urlParams.get('from')
|
||
const returnUrl = urlParams.get('returnUrl')
|
||
const language = urlParams.get('language')
|
||
|
||
if (from === 'portal' && returnUrl) {
|
||
// 返回到 Portal,保留语言设置
|
||
let finalUrl = decodeURIComponent(returnUrl)
|
||
if (language) {
|
||
// 如果 URL 中已有参数,用 & 连接,否则用 ?
|
||
const separator = finalUrl.includes('?') ? '&' : '?'
|
||
finalUrl = `${finalUrl}${separator}language=${language}`
|
||
}
|
||
window.location.href = finalUrl
|
||
} else {
|
||
// 返回到游戏大厅
|
||
router.replace({ name: routerStack.value })
|
||
}
|
||
}
|
||
|
||
// 显示快捷换台列表
|
||
const showSwitchtab = (type) => {
|
||
store.commit("app/standbyTime")
|
||
if (type == false) {
|
||
switchtabshow.value = false
|
||
} else {
|
||
switchtabshow.value = true
|
||
}
|
||
}
|
||
// 切换视频线路
|
||
const showSwitchCamera = (type) => {
|
||
store.commit("app/standbyTime")
|
||
// isSwitchCamera.value = type
|
||
if (type == false) {
|
||
switchCameraShow.value = false
|
||
} else {
|
||
switchCameraShow.value = true
|
||
}
|
||
}
|
||
|
||
const userInfo = computed(() => store.state.app.userInfo)
|
||
// 视频开关
|
||
const offCamera = () => {
|
||
store.commit("config/switchVideo", !switchVideo.value)
|
||
}
|
||
// 显示音乐播放器
|
||
const toggleAplayer = () => {
|
||
store.commit("config/showAplayer")
|
||
}
|
||
|
||
// 显示隐藏视频
|
||
const toggleVide = () => {
|
||
hideVideo.value = !hideVideo.value
|
||
}
|
||
|
||
// 获取单台数据
|
||
let getSingletableTimer = null,
|
||
getSingletableNun = 0
|
||
const getSingletable = (id) => {
|
||
getSingletableNun++
|
||
clearTimeout(getSingletableTimer)
|
||
if (tableData.value && tableData.value.id) {
|
||
store.dispatch("socket/updateSingletable", {
|
||
type: "update",
|
||
table_id: id
|
||
})
|
||
let num = Math.floor(Math.random() * 6) + 1
|
||
if (num == 4) {
|
||
num = 1
|
||
}
|
||
let name = ""
|
||
switch (tableData.value.game_id) {
|
||
case 1:
|
||
name = "baccarat"
|
||
break
|
||
case 2:
|
||
name = "lh"
|
||
break
|
||
case 3:
|
||
break
|
||
case 4:
|
||
name = "nn"
|
||
break
|
||
case 5:
|
||
name = "tc"
|
||
break
|
||
case 6:
|
||
name = "toning"
|
||
break
|
||
case 7:
|
||
name = "dice"
|
||
break
|
||
case 8:
|
||
name = "lp"
|
||
break
|
||
}
|
||
audioMp3([`${name}_w_p${num}`]).Play()
|
||
} else {
|
||
if (getSingletableNun < 10) {
|
||
getSingletableTimer = setTimeout(() => {
|
||
getSingletable(id)
|
||
}, 1000)
|
||
}
|
||
}
|
||
}
|
||
const clearChip = (state) => {
|
||
nextTick(() => {
|
||
chipTable.value.resetChip(state)
|
||
})
|
||
}
|
||
const cancelChip = () => {
|
||
nextTick(() => {
|
||
chipTable.value.cancelChip()
|
||
})
|
||
}
|
||
// 显示菜单
|
||
const showMenu = () => {
|
||
store.commit("config/showMenu", true)
|
||
}
|
||
// 显示免佣设置
|
||
const showSetFree = () => {
|
||
store.commit("config/showSetFree")
|
||
}
|
||
// 显示玩法
|
||
const showBaccaratPlayType = () => {
|
||
store.commit("config/showBaccaratPlayType")
|
||
}
|
||
// 显示桌台信息
|
||
const showTableInfo = () => {
|
||
store.commit("config/showTableInfo", true)
|
||
}
|
||
// 显示在线人数
|
||
const showOnLine = () => {
|
||
store.commit("config/showOnLine")
|
||
}
|
||
// 切换轮盘 玩法
|
||
const switchRouletteType = () => {
|
||
if (rouletteLockTable.value) {
|
||
showToast("已下注")
|
||
} else {
|
||
store.commit("config/switchRouletteType")
|
||
}
|
||
}
|
||
|
||
// 百家乐结果
|
||
const baccaratResult = (data) => {
|
||
store.dispatch("socket/getGoodTabData")
|
||
getwinResult(1)
|
||
let mp3list = [],
|
||
win = [],
|
||
text = ""
|
||
mp3list.push(
|
||
"baccarat_banker",
|
||
`${data.round.banker}_point`,
|
||
"baccarat_player",
|
||
`${data.round.player}_point`
|
||
)
|
||
if (data.round.opening == 1) {
|
||
text = Lang.value[Type.value].msg_banker_win
|
||
win.push("banker")
|
||
mp3list.push("baccarat_b_win")
|
||
} else if (data.round.opening == 2) {
|
||
text = Lang.value[Type.value].msg_player_win
|
||
win.push("player")
|
||
mp3list.push("baccarat_p_win")
|
||
} else if (data.round.opening == 3) {
|
||
text = Lang.value[Type.value].msg_tie_win
|
||
win.push("tie")
|
||
mp3list.push("baccarat_tie")
|
||
}
|
||
// 大小
|
||
if (data.can_bet_big_small == 1) {
|
||
if (data.round.big_small == 1) {
|
||
text = text + "、" + Lang.value[Type.value].big
|
||
win.push("big")
|
||
} else if (data.round.big_small == 2) {
|
||
text = text + "、" + Lang.value[Type.value].small
|
||
win.push("small")
|
||
}
|
||
}
|
||
|
||
// 幸运6
|
||
if (data.can_bet_luck_six == 1) {
|
||
if (data.round.luck_six == 2) {
|
||
text = text + "、" + Lang.value[Type.value].luckSix + "X2"
|
||
win.push("luck_six")
|
||
} else if (data.round.luck_six == 3) {
|
||
text = text + "、" + Lang.value[Type.value].luckSix + "X3"
|
||
win.push("luck_six")
|
||
}
|
||
}
|
||
// 对子
|
||
if (data.round.pair == 1) {
|
||
text = text + "、" + Lang.value[Type.value].msg_banker_pair
|
||
win.push("banker_pair")
|
||
mp3list.push("baccarat_b_pair")
|
||
} else if (data.round.pair == 2) {
|
||
text = text + "、" + Lang.value[Type.value].msg_player_pair
|
||
win.push("player_pair")
|
||
mp3list.push("baccarat_p_pair")
|
||
} else if (data.round.pair == 3) {
|
||
text =
|
||
text +
|
||
"、" +
|
||
Lang.value[Type.value].msg_banker_pair +
|
||
"、" +
|
||
Lang.value[Type.value].msg_player_pair
|
||
win.push("banker_pair", "player_pair")
|
||
mp3list.push("baccarat_b_pair", "baccarat_p_pair")
|
||
}
|
||
showToast(text)
|
||
winArray.value = win
|
||
audioMp3(mp3list).Play()
|
||
setTimeout(() => {
|
||
winArray.value = []
|
||
clearChip()
|
||
}, 7000)
|
||
}
|
||
// 龙虎结果
|
||
const longhuResult = (data) => {
|
||
getwinResult(2)
|
||
let mp3list = [],
|
||
win = [],
|
||
text = ""
|
||
mp3list.push(
|
||
"lh_dragon",
|
||
`${data.round.banker}_point`,
|
||
"lh_tiger",
|
||
`${data.round.player}_point`
|
||
)
|
||
if (data.round.opening == 1) {
|
||
text = Lang.value[Type.value].msg_dragon_win
|
||
win.push("banker")
|
||
mp3list.push("lh_dragon_win")
|
||
} else if (data.round.opening == 2) {
|
||
text = Lang.value[Type.value].msg_tiger_win
|
||
win.push("player")
|
||
mp3list.push("lh_tiger_win")
|
||
} else if (data.round.opening == 3) {
|
||
text = Lang.value[Type.value].msg_tie_win
|
||
win.push("tie")
|
||
mp3list.push("lh_tie")
|
||
}
|
||
audioMp3(mp3list).Play()
|
||
showToast(text)
|
||
winArray.value = win
|
||
setTimeout(() => {
|
||
winArray.value = []
|
||
clearChip()
|
||
}, 7000)
|
||
}
|
||
|
||
// 牛牛
|
||
const nnResult = (data) => {
|
||
if (data.game_id == 4) {
|
||
getwinResult(4)
|
||
} else {
|
||
getwinResult(5)
|
||
}
|
||
let mp3list = [],
|
||
win = [],
|
||
text = ""
|
||
if (
|
||
data.round.win_player_1 == 0 &&
|
||
data.round.win_player_2 == 0 &&
|
||
data.round.win_player_3 == 0
|
||
) {
|
||
text = Lang.value[Type.value].msg_banker_win
|
||
mp3list.push("nn_banker")
|
||
win.push("player_1_banker", "player_2_banker", "player_3_banker")
|
||
win
|
||
} else {
|
||
if (data.round.win_player_1 == 1) {
|
||
text = text + Lang.value[Type.value].player1
|
||
mp3list.push("nn_player_1")
|
||
win.push("player_1")
|
||
} else {
|
||
win.push("player_1_banker")
|
||
}
|
||
if (data.round.win_player_2 == 1) {
|
||
text = text + Lang.value[Type.value].player2
|
||
mp3list.push("nn_player_2")
|
||
win.push("player_2")
|
||
} else {
|
||
win.push("player_2_banker")
|
||
}
|
||
if (data.round.win_player_3 == 1) {
|
||
text = text + Lang.value[Type.value].player3
|
||
mp3list.push("nn_player_3")
|
||
win.push("player_3")
|
||
} else {
|
||
win.push("player_3_banker")
|
||
}
|
||
}
|
||
audioMp3(mp3list).Play()
|
||
showToast(text)
|
||
winArray.value = win
|
||
setTimeout(() => {
|
||
winArray.value = []
|
||
clearChip()
|
||
}, 5000)
|
||
}
|
||
// 色碟
|
||
const toningResult = (data) => {
|
||
const language = Lang.value[Type.value]
|
||
getwinResult(6)
|
||
showToningResult.value = true
|
||
let mp3list = [],
|
||
win = [],
|
||
text = ""
|
||
switch (data.round.result) {
|
||
case 0:
|
||
win.push("toning_zero", "toning_plural", "toning_small")
|
||
mp3list.push("toning_4_white", "toning_even", "toning_small")
|
||
// text = "四白,双,小"
|
||
text = `${language.four} ${language.white},${language.even},${language.small}`
|
||
break
|
||
case 1:
|
||
win.push("toning_one", "toning_singular", "toning_small")
|
||
mp3list.push("toning_3_w_1_r", "toning_odd", "toning_small")
|
||
// text = "三白一红,单,小"
|
||
text = `${language.three} ${language.white} ${language.one} ${language.red},${language.odd},${language.small}`
|
||
break
|
||
case 2:
|
||
win.push("toning_plural")
|
||
mp3list.push("toning_2_w_2_r", "toning_even")
|
||
// text = "二红二白,双"
|
||
text = `${language.two} ${language.red} ${language.two} ${language.white},${language.even}`
|
||
break
|
||
case 3:
|
||
win.push("toning_three", "toning_singular", "toning_big")
|
||
mp3list.push("toning_1_w_3_r", "toning_odd", "toning_big")
|
||
// text = "三红一白,单,大"
|
||
text = `${language.three} ${language.red} ${language.one} ${language.white},${language.odd},${language.big}`
|
||
break
|
||
case 4:
|
||
win.push("toning_four", "toning_plural", "toning_big")
|
||
mp3list.push("toning_4_red", "toning_even", "toning_big")
|
||
// text = "四红,双,大"
|
||
text = `${language.four} ${language.red},${language.odd},${language.big}`
|
||
break
|
||
}
|
||
audioMp3(mp3list).Play()
|
||
showToast(text)
|
||
winArray.value = win
|
||
setTimeout(() => {
|
||
winArray.value = []
|
||
showToningResult.value = false
|
||
clearChip()
|
||
}, 5000)
|
||
}
|
||
// 骰宝
|
||
const diceResult = (data) => {
|
||
showDiceResult.value = true
|
||
getwinResult(7)
|
||
let mp3list = [],
|
||
text = ""
|
||
const result = data.round.result
|
||
const first = parseInt(result[0])
|
||
const second = parseInt(result[1])
|
||
const third = parseInt(result[2])
|
||
mp3list.push(
|
||
`dice_num_${first}`,
|
||
`dice_num_${second}`,
|
||
`dice_num_${third}`
|
||
)
|
||
if (first == second && second == third) {
|
||
text = "豹子,"
|
||
mp3list.push("dice_any_triple")
|
||
}
|
||
const totle = first + second + third
|
||
text = `${text}${totle}点`
|
||
mp3list.push(`${totle}_point`)
|
||
|
||
audioMp3(mp3list).Play()
|
||
showToast(text)
|
||
winArray.value = data.round.result_parse
|
||
setTimeout(() => {
|
||
winArray.value = []
|
||
showDiceResult.value = false
|
||
clearChip()
|
||
}, 5000)
|
||
}
|
||
// 轮盘
|
||
const rouletteResult = (data) => {
|
||
showRouletteResult.value = true
|
||
getwinResult(7)
|
||
let mp3list = [],
|
||
text = ""
|
||
const result = data.round.result
|
||
text = result
|
||
mp3list.push(`${result}_point`)
|
||
// console.log(result, mp3list)
|
||
showToast(text)
|
||
winArray.value = data.round.result_parse
|
||
setTimeout(() => {
|
||
winArray.value = []
|
||
showRouletteResult.value = false
|
||
clearChip()
|
||
}, 3000)
|
||
}
|
||
const getwinResult = (game) => {
|
||
let Api = ""
|
||
if (game == 1) {
|
||
Api = getUserBetBaccarat
|
||
} else if (game == 2) {
|
||
Api = getUserBetDt
|
||
} else if (game == 4) {
|
||
Api = getUserBetNn
|
||
} else if (game == 5) {
|
||
Api = getUserBetTc
|
||
} else if (game == 6) {
|
||
Api = getUserBetToning
|
||
} else if (game == 7) {
|
||
Api = getUserBetDice
|
||
} else if (game == 8) {
|
||
Api = getUserBetRoulette
|
||
}
|
||
const params = {
|
||
user_id: userInfo.value.id,
|
||
api_token: userInfo.value.api_token,
|
||
number_tab_id: tableData.value?.previous_number_tab_id,
|
||
table_id: tableData.value.id
|
||
}
|
||
Api(params)
|
||
.then((response) => {
|
||
setTimeout(() => {
|
||
if (response.Success == 1) {
|
||
const data = response.Data
|
||
// console.log("输赢金额", data)
|
||
if (
|
||
game == 4 ||
|
||
game == 5 ||
|
||
game == 6 ||
|
||
game == 7 ||
|
||
game == 8
|
||
) {
|
||
showDialog({
|
||
allowHtml: true,
|
||
title: Lang.value[Type.value].msg_win_lose,
|
||
message:
|
||
'<div class="item title"><span>' +
|
||
Lang.value[Type.value].msg_bet_total +
|
||
"</span><span>" +
|
||
Lang.value[Type.value].msg_win_lose +
|
||
"</span><span>" +
|
||
Lang.value[Type.value].msg_balance +
|
||
"</span></div>" +
|
||
'<div class="item"><span>' +
|
||
data.amount +
|
||
"</span><span>" +
|
||
returnFloat(data.win_total) +
|
||
"</span><span>" +
|
||
data.end_money +
|
||
"</span></div>",
|
||
className: "alert",
|
||
confirmButtonText: Lang.value[Type.value].Confirm
|
||
})
|
||
} else {
|
||
popResult(data)
|
||
}
|
||
} else {
|
||
// console.log(response)
|
||
}
|
||
tableData.value.sendMode = ""
|
||
}, 3500)
|
||
})
|
||
.catch((error) => {
|
||
console.log(error)
|
||
})
|
||
}
|
||
const popResult = (data) => {
|
||
let html = ""
|
||
let text = ""
|
||
data.returnData.forEach((v) => {
|
||
if (v.amount > 0) {
|
||
if (v.win_amount > 0) {
|
||
text = Lang.value[Type.value].win
|
||
} else if (v.win_amount < 0) {
|
||
text = Lang.value[Type.value].lose
|
||
} else {
|
||
text = Lang.value[Type.value].tie
|
||
}
|
||
html =
|
||
html +
|
||
'<div class="item"><span>' +
|
||
v.name +
|
||
"</span><span>" +
|
||
v.amount +
|
||
"</span><span>" +
|
||
text +
|
||
"</span><span>" +
|
||
v.win_amount +
|
||
"</span></div>"
|
||
}
|
||
})
|
||
|
||
html =
|
||
'<div class="item title"><span>' +
|
||
Lang.value[Type.value].bet_type +
|
||
"</span><span>" +
|
||
Lang.value[Type.value].bet_amount +
|
||
"</span><span>" +
|
||
Lang.value[Type.value].note_result +
|
||
"</span><span>" +
|
||
Lang.value[Type.value].note_win_lose +
|
||
"</span></div>" +
|
||
html
|
||
showDialog({
|
||
allowHtml: true,
|
||
title:
|
||
Lang.value[Type.value].msg_win_lose +
|
||
":" +
|
||
returnFloat(data.win_total),
|
||
message: html,
|
||
className: "alert",
|
||
confirmButtonText: Lang.value[Type.value].Confirm
|
||
})
|
||
}
|
||
const returnFloat = (num) => {
|
||
let value = Math.round(parseFloat(num) * 100) / 100
|
||
let xsd = value.toString().split(".")
|
||
if (xsd.length == 1) {
|
||
value = value.toString() + ".00"
|
||
return value
|
||
}
|
||
if (xsd.length > 1) {
|
||
if (xsd[1].length < 2) {
|
||
value = value.toString() + "0"
|
||
}
|
||
return value
|
||
}
|
||
}
|
||
const foxVideoFn = () => {
|
||
nextTick(() => {
|
||
if (!videoDom.value) return;
|
||
const containerH = videoDom.value.clientHeight;
|
||
const containerW = videoDom.value.clientWidth;
|
||
|
||
// Default to 16:9 if missing
|
||
const proportion = videoConfig.value.proportion || [16, 9];
|
||
const videoRatio = proportion[0] / proportion[1];
|
||
const screenRatio = containerW / containerH; // Inverse for calculation check
|
||
|
||
let w, h, ml = 0, mt = 0;
|
||
|
||
if (screenRatio > videoRatio) {
|
||
// Screen is wider than video (or video is taller than screen) -> Height constrained
|
||
// e.g. Landscape or wide container
|
||
h = containerH;
|
||
w = h * videoRatio;
|
||
ml = (containerW - w) / 2;
|
||
} else {
|
||
// Screen is narrower than video (Standard Mobile Portrait) -> Width constrained
|
||
w = containerW;
|
||
h = w / videoRatio;
|
||
mt = (containerH - h) / 2;
|
||
}
|
||
|
||
// Apply specific offsets if needed, though usually centering is best for 'contain'
|
||
if (phoneModel.value == "ios") {
|
||
if (phoneScreen.value == "landscape") {
|
||
mt += videoConfig.value.offset.iosLandscape || 0;
|
||
} else {
|
||
mt += videoConfig.value.offset.iosPortrait || 0;
|
||
}
|
||
} else if (phoneModel.value == "android") {
|
||
mt += videoConfig.value.offset.android || 0;
|
||
} else {
|
||
mt += videoConfig.value.offset.pc || 0;
|
||
}
|
||
|
||
// Ensure values are safe
|
||
if (isNaN(w)) w = containerW;
|
||
if (isNaN(h)) h = containerW * 0.56; // Fallback 16:9
|
||
|
||
foxVideo.value.w = `${w}px`
|
||
foxVideo.value.h = `${h}px`
|
||
foxVideo.value.mt = `${mt}px`
|
||
foxVideo.value.ml = `${ml}px`
|
||
foxVideo.value.model = phoneModel.value
|
||
foxVideo.value.screen = phoneScreen.value
|
||
})
|
||
}
|
||
// 牛牛点数声音
|
||
const playNNsound = (data) => {
|
||
const position = parseInt(data.round.order_num)
|
||
if (data.game_id == 4) {
|
||
if ([15, 25, 35, 45].includes(position)) {
|
||
soundType(data.round.result)
|
||
} else {
|
||
audioMp3(["show_card"]).Play()
|
||
}
|
||
} else if (data.game_id == 5) {
|
||
if ([13, 23, 33, 43].includes(position)) {
|
||
soundType(data.round.result)
|
||
} else {
|
||
audioMp3(["show_card"]).Play()
|
||
}
|
||
}
|
||
function soundType(result) {
|
||
let name = ""
|
||
switch (result) {
|
||
case "无牛":
|
||
case "N0":
|
||
name = "no_bull"
|
||
break
|
||
case "牛1":
|
||
case "N1":
|
||
name = "bull_1"
|
||
break
|
||
case "牛2":
|
||
case "N2":
|
||
name = "bull_2"
|
||
break
|
||
case "牛3":
|
||
case "N3":
|
||
name = "bull_3"
|
||
break
|
||
case "牛4":
|
||
case "N4":
|
||
name = "bull_4"
|
||
break
|
||
case "牛5":
|
||
case "N5":
|
||
name = "bull_5"
|
||
break
|
||
case "牛6":
|
||
case "N6":
|
||
name = "bull_6"
|
||
break
|
||
case "牛7":
|
||
case "N7":
|
||
name = "bull_7"
|
||
break
|
||
case "牛8":
|
||
case "N8":
|
||
name = "bull_8"
|
||
break
|
||
case "牛9":
|
||
case "N9":
|
||
name = "bull_9"
|
||
break
|
||
case "牛牛":
|
||
case "NN":
|
||
name = "bull_bull"
|
||
break
|
||
case "五公":
|
||
name = "five_pictur_bull"
|
||
break
|
||
case "豹子":
|
||
name = "any_triple"
|
||
break
|
||
case "同花顺":
|
||
name = "straight_flush"
|
||
break
|
||
case "皇家同花順":
|
||
name = "royal_flush"
|
||
break
|
||
}
|
||
audioMp3([`${data.game_id == 4 ? "nn" : "tc"}_${name}`]).Play()
|
||
}
|
||
}
|
||
// 离开销毁
|
||
onUnmounted(() => {
|
||
closeDialog()
|
||
closeToast()
|
||
audioMp3().Pause()
|
||
})
|
||
// 监听机型和横竖屏
|
||
watch(
|
||
() => [phoneModel, phoneScreen],
|
||
() => {
|
||
foxVideoFn()
|
||
},
|
||
{ immediate: true, deep: true }
|
||
)
|
||
// switchVideo
|
||
watch(
|
||
() => [switchVideo.value],
|
||
([state]) => {
|
||
if (state == false) {
|
||
hideVideo.value = true
|
||
}
|
||
},
|
||
{ immediate: true, deep: true }
|
||
)
|
||
// 监听路由切换
|
||
watch(
|
||
() => [route.query],
|
||
([query]) => {
|
||
winArray.value = []
|
||
table_id.value = query.id
|
||
getSingletable(query.id)
|
||
const { game_id = 1 } = tableData.value
|
||
store.commit("app/updateGameId", game_id)
|
||
},
|
||
{ immediate: true, deep: true }
|
||
)
|
||
watch(
|
||
() => [tableData.value],
|
||
([data]) => {
|
||
const sendMode = (data && data.sendMode) || null
|
||
switch (sendMode) {
|
||
case "startBet": //开始游戏
|
||
if (data.game_id == 6) {
|
||
showToningResult.value = false
|
||
}
|
||
if (data.game_id == 7) {
|
||
hideVideo.value = true
|
||
}
|
||
if (data.game_id == 8) {
|
||
hideVideo.value = true
|
||
store.commit("config/rouletteLockTable", false)
|
||
}
|
||
closeDialog()
|
||
showToast(Lang.value[Type.value].msg_start_bet)
|
||
if (data.game_id != 5) {
|
||
audioMp3(["start_betting"]).Play()
|
||
} else {
|
||
audioMp3(["tc_banker_stop", "start_betting"]).Play()
|
||
}
|
||
break
|
||
case "startRob": //开始抢庄
|
||
showToast(Lang.value[Type.value].msg_accept_grab)
|
||
audioMp3(["tc_start_banker"]).Play()
|
||
break
|
||
case "toRobResult": //抢庄后通知
|
||
if (data.RobMsg.rob_banker_id == userInfo.value.id) {
|
||
audioMp3(["tc_banker_success"]).Play()
|
||
}
|
||
break
|
||
case "startRobCountDown":
|
||
break
|
||
case "startBetCountDown": //倒计时
|
||
if (data.count_down == 10) {
|
||
audioMp3(["last_10_seconds"]).Play()
|
||
} else if (data.count_down < 9) {
|
||
audioMp3(["time"]).Play()
|
||
}
|
||
break
|
||
case "toBet":
|
||
showToast({
|
||
message: Lang.value[Type.value].msg_bet_success,
|
||
position: "top"
|
||
})
|
||
if (data.game_id == 8) {
|
||
store.commit("config/rouletteLockTable", true)
|
||
}
|
||
break
|
||
case "toBetFlase":
|
||
audioMp3(["alert"]).Play()
|
||
cancelChip()
|
||
break
|
||
case "sendScanResult":
|
||
if (data.game_id == 1) {
|
||
const position = parseInt(data.round.position)
|
||
if (position == 23) {
|
||
audioMp3(["baccarat_b_draw"]).Play()
|
||
} else if (position == 13) {
|
||
audioMp3(["baccarat_p_draw"]).Play()
|
||
} else {
|
||
audioMp3(["show_card"]).Play()
|
||
}
|
||
} else if (data.game_id == 2) {
|
||
audioMp3(["show_card"]).Play()
|
||
} else if (data.game_id == 4 || data.game_id == 5) {
|
||
playNNsound(data)
|
||
} else {
|
||
audioMp3(["show_card"]).Play()
|
||
}
|
||
|
||
break
|
||
case "cancelBet":
|
||
showToast(Lang.value[Type.value].msg_cancel_success)
|
||
break
|
||
case "endBet":
|
||
if (data.game_id == 6) {
|
||
showToningResult.value = true
|
||
} else if (data.game_id == 7) {
|
||
showDiceResult.value = true
|
||
} else if (data.game_id == 8) {
|
||
showRouletteResult.value = true
|
||
}
|
||
if (
|
||
(data.game_id == 7 || data.game_id == 8) &&
|
||
switchVideo.value == true
|
||
) {
|
||
hideVideo.value = false
|
||
}
|
||
showToast(Lang.value[Type.value].endBet)
|
||
audioMp3(["stop_betting"]).Play()
|
||
break
|
||
case "openingBaccaratResult":
|
||
baccaratResult(data)
|
||
break
|
||
case "openingDtResult":
|
||
longhuResult(data)
|
||
break
|
||
case "openingNnResult":
|
||
nnResult(data)
|
||
break
|
||
case "openingTcResult":
|
||
nnResult(data)
|
||
break
|
||
case "openingToningResult":
|
||
toningResult(data)
|
||
break
|
||
case "openingDiceResult":
|
||
diceResult(data)
|
||
if (data.game_id == 7) {
|
||
hideVideo.value = true
|
||
}
|
||
break
|
||
case "openingRouletteResult":
|
||
rouletteResult(data)
|
||
if (data.game_id == 8) {
|
||
hideVideo.value = true
|
||
}
|
||
break
|
||
case "retreated":
|
||
break
|
||
case "changeBoot":
|
||
showToast(Lang.value[Type.value].changeBoot)
|
||
clearChip()
|
||
break
|
||
case "resetBoot":
|
||
showToast(Lang.value[Type.value].resetBoot)
|
||
clearChip()
|
||
break
|
||
case "resetNumberTab":
|
||
showToast(Lang.value[Type.value].msg_council)
|
||
clearChip()
|
||
break
|
||
}
|
||
},
|
||
{ immediate: true, deep: true }
|
||
)
|
||
return {
|
||
Type,
|
||
audio,
|
||
videoConfig,
|
||
hideVideo,
|
||
userInfo,
|
||
tableData,
|
||
switchVideo,
|
||
router,
|
||
circle,
|
||
currentRate,
|
||
switchtabshow,
|
||
isSwitchtab,
|
||
switchCameraShow,
|
||
isSwitchCamera,
|
||
chipTable,
|
||
baccaratType,
|
||
rouletteType,
|
||
foxVideo,
|
||
videoDom,
|
||
phoneModel,
|
||
routerStack,
|
||
winArray,
|
||
showToningResult,
|
||
showDiceResult,
|
||
showRouletteResult,
|
||
showSwitchtab,
|
||
showSwitchCamera,
|
||
offCamera,
|
||
toggleAplayer,
|
||
clearChip,
|
||
handleBack,
|
||
cancelChip,
|
||
showMenu,
|
||
showSetFree,
|
||
showBaccaratPlayType,
|
||
showTableInfo,
|
||
showOnLine,
|
||
closeSwitchView,
|
||
toggleVide,
|
||
switchRouletteType,
|
||
videoUrl
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
/* 深色豪华主题配色 */
|
||
$dark-bg: #0d0d0d;
|
||
$dark-bg-secondary: #000;
|
||
$card-bg: #000;
|
||
$border-color: #333;
|
||
$gold: #c5a059;
|
||
|
||
.play {
|
||
width: 100%;
|
||
height: 100%;
|
||
background: $dark-bg;
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
box-sizing: border-box;
|
||
overflow: hidden;
|
||
|
||
|
||
|
||
/* Navigation Bar - Redesigned */
|
||
.nav {
|
||
position: relative;
|
||
z-index: 100;
|
||
width: 100%;
|
||
height: 36px; /* Slightly compact */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
background: #000; /* Pure black as per ref */
|
||
border-bottom: 1px solid #222;
|
||
flex-shrink: 0;
|
||
padding: 0 10px;
|
||
box-sizing: border-box;
|
||
|
||
.nav-item {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 100%;
|
||
color: #fff;
|
||
font-size: 13px;
|
||
|
||
.icon {
|
||
width: 16px;
|
||
height: 16px;
|
||
background-size: contain;
|
||
background-repeat: no-repeat;
|
||
background-position: center;
|
||
margin-right: 6px;
|
||
}
|
||
|
||
&.user-info {
|
||
.user-icon { background-image: url("~@/assets/images/icon/user.png"); }
|
||
.text { font-weight: bold; }
|
||
}
|
||
|
||
&.balance-info {
|
||
.money-icon { background-image: url("~@/assets/images/icon/money.png"); }
|
||
.text { color: $gold; font-family: monospace; font-size: 14px; }
|
||
}
|
||
|
||
&.limit-info {
|
||
/* Use switch_tab icon as placeholder for limit arrows if specific icon invalid,
|
||
or styling css borders for arrows */
|
||
.limit-icon {
|
||
width: 12px; height: 12px;
|
||
background-image: url("~@/assets/images/icon/switch_tab.png"); /* Placeholder */
|
||
transform: rotate(90deg); /* Make it look like up/down sort */
|
||
opacity: 0.7;
|
||
}
|
||
.text { color: #aaa; font-size: 12px; }
|
||
}
|
||
|
||
&.right-controls {
|
||
display: flex;
|
||
gap: 15px;
|
||
|
||
.btn {
|
||
width: 24px;
|
||
height: 24px;
|
||
background-size: contain;
|
||
background-repeat: no-repeat;
|
||
background-position: center;
|
||
|
||
&.camera {
|
||
background-image: url("~@/assets/images/icon/camera.png");
|
||
&.off { background-image: url("~@/assets/images/icon/camera_off.png"); }
|
||
}
|
||
&.muise { background-image: url("~@/assets/images/icon/musie.png"); }
|
||
&.menu { background-image: url("~@/assets/images/icon/meun.png"); }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Main View Container - Vertical Flex */
|
||
.view {
|
||
display: flex;
|
||
flex-direction: column;
|
||
width: 100%;
|
||
height: 100%; /* Full height, Nav is now inside */
|
||
position: relative;
|
||
overflow: hidden;
|
||
|
||
/* 1. Video Container (Top) - Flex Grow */
|
||
.video-container {
|
||
flex: 1; /* Grow to fill available space */
|
||
position: relative;
|
||
width: 100%;
|
||
background: #000;
|
||
overflow: hidden;
|
||
|
||
.iframe {
|
||
border: none;
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 1;
|
||
object-fit: cover; /* This won't affect iframe content but is good for semantics if it were a video tag. */
|
||
}
|
||
|
||
.game-area {
|
||
position: absolute;
|
||
width: 100%;
|
||
height: 100%;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 10;
|
||
pointer-events: none;
|
||
|
||
/* Enable clicks on children */
|
||
::v-deep .playtable, ::v-deep .rushvillage {
|
||
pointer-events: auto;
|
||
}
|
||
}
|
||
|
||
/* Switch Views (Camera/Tables)Overlay */
|
||
.switchView {
|
||
position: fixed;
|
||
width: 100%;
|
||
height: 100%;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 2010;
|
||
background: $dark-bg-secondary;
|
||
&.camera { width: 40%; position: absolute; bottom: 0; right: 0; border-top-left-radius: 0.3rem; }
|
||
}
|
||
|
||
/* Separated Video Controls */
|
||
.video-btn-back {
|
||
position: absolute;
|
||
top: 10px;
|
||
left: 10px;
|
||
z-index: 2005; /* Highest priority */
|
||
width: 30px;
|
||
height: 30px;
|
||
background-image: url("~@/assets/images/icon/back.png");
|
||
background-size: contain;
|
||
background-repeat: no-repeat;
|
||
background-position: center;
|
||
}
|
||
|
||
/* Overlay Camera Icon */
|
||
.video-overlay-camera {
|
||
position: absolute;
|
||
top: 10px;
|
||
right: 60px; /* Switch is at 10px, so this is left of it */
|
||
z-index: 2001;
|
||
width: 30px;
|
||
height: 30px;
|
||
background-size: contain;
|
||
background-repeat: no-repeat;
|
||
background-position: center;
|
||
background-image: url("~@/assets/images/icon/camera.png");
|
||
|
||
&.off {
|
||
background-image: url("~@/assets/images/icon/camera_off.png");
|
||
}
|
||
}
|
||
|
||
/* Status Overlay Styles */
|
||
.status-overlay {
|
||
position: absolute;
|
||
top: 10px;
|
||
right: 50px; /* Left of switch button (10px + 30px + 10px gap) */
|
||
z-index: 3000;
|
||
display: flex;
|
||
pointer-events: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.status-circle {
|
||
width: 40px; /* Slightly smaller for corner */
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
background: rgba(0,0,0,0.6);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #fff;
|
||
font-weight: bold;
|
||
font-size: 14px;
|
||
border: 2px solid rgba(255, 255, 255, 0.2);
|
||
backdrop-filter: blur(4px);
|
||
|
||
&.dealing {
|
||
background: rgba(46, 204, 113, 0.8); /* Green */
|
||
border-color: #2ecc71;
|
||
font-size: 12px;
|
||
}
|
||
|
||
&.countdown {
|
||
background: rgba(231, 76, 60, 0.8); /* Red/Orange for countdown */
|
||
border-color: #e74c3c;
|
||
font-size: 20px;
|
||
}
|
||
|
||
&.wait {
|
||
background: rgba(52, 152, 219, 0.8);
|
||
border-color: #3498db;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 4. Game Table Area (New Flex Item) */
|
||
.game-area-block {
|
||
width: 100%;
|
||
height: 200px; /* Fixed height for table area */
|
||
flex-shrink: 0;
|
||
position: relative;
|
||
background: transparent;
|
||
z-index: 10;
|
||
overflow: hidden;
|
||
|
||
/* NN/TC mode - same as other games */
|
||
&.nn-mode {
|
||
height: 200px;
|
||
}
|
||
|
||
/* Content wrapper that mimics old absolute positioning for internal components */
|
||
.game-area-content {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
|
||
/* Ensure PlayTable fits inside this block */
|
||
::v-deep .playtable {
|
||
.view {
|
||
bottom: 0 !important; /* Anchor to bottom of this block */
|
||
top: auto !important;
|
||
height: 100% !important; /* Fill the block */
|
||
transform: none !important; /* Reset 3D transform for flat view if needed, or keep if 3D desired within this block */
|
||
}
|
||
|
||
/* Adjust portrait mode specifically if needed */
|
||
@media screen and (orientation: portrait) {
|
||
.view {
|
||
height: 100% !important;
|
||
border-radius: 0 !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 2. Chip Control Bar (Middle) - Fixed Height */
|
||
.bet-chip-bar {
|
||
width: 100%;
|
||
height: 60px;
|
||
flex-shrink: 0;
|
||
position: relative;
|
||
z-index: 20;
|
||
background: #111;
|
||
border-top: 1px solid #333;
|
||
}
|
||
|
||
/* 3. Poker Section for NN/TC - Compact horizontal layout */
|
||
.poker-section {
|
||
width: 100%;
|
||
height: 40px; /* 减小高度 */
|
||
flex-shrink: 0;
|
||
position: relative;
|
||
z-index: 20;
|
||
background: rgba(0, 0, 0, 0.85);
|
||
border-top: 1px solid #333;
|
||
overflow: hidden;
|
||
|
||
::v-deep .nn-compact {
|
||
/* Override default poker-box styles for compact mode */
|
||
.poker-box.nn {
|
||
position: relative !important;
|
||
height: 100% !important;
|
||
width: 100% !important;
|
||
display: flex !important;
|
||
flex-direction: row !important;
|
||
align-items: center !important;
|
||
justify-content: space-around !important;
|
||
padding: 2px 4px !important;
|
||
box-sizing: border-box !important;
|
||
background: transparent !important;
|
||
|
||
.list {
|
||
flex: 1 !important;
|
||
height: 100% !important;
|
||
min-width: 0 !important;
|
||
padding: 0 2px !important;
|
||
border-left: 1px solid #444 !important;
|
||
display: flex !important;
|
||
flex-direction: row !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
position: relative !important;
|
||
|
||
&:first-child {
|
||
border-left: none !important;
|
||
}
|
||
|
||
.title {
|
||
position: relative !important;
|
||
display: block !important;
|
||
font-size: 8px !important;
|
||
padding: 2px 3px !important;
|
||
border-radius: 2px !important;
|
||
white-space: nowrap !important;
|
||
margin-right: 2px !important;
|
||
flex-shrink: 0 !important;
|
||
/* 确保颜色样式正确应用 */
|
||
&.red {
|
||
background: #ff494b !important;
|
||
color: #fff !important;
|
||
}
|
||
&.blue {
|
||
background: #00a8ff !important;
|
||
color: #fff !important;
|
||
}
|
||
}
|
||
|
||
.role {
|
||
position: absolute !important;
|
||
width: auto !important;
|
||
left: 50% !important;
|
||
top: auto !important;
|
||
bottom: 2px !important;
|
||
transform: translateX(-50%) !important;
|
||
font-size: 10px !important;
|
||
padding: 1px 4px !important;
|
||
margin: 0 !important;
|
||
background: rgba(0, 0, 0, 0.7) !important;
|
||
border-radius: 2px !important;
|
||
color: #ffd700 !important;
|
||
}
|
||
|
||
.item {
|
||
width: 16px !important;
|
||
height: 22px !important;
|
||
margin: 0 -3px !important;
|
||
margin-top: 0 !important;
|
||
padding: 0 !important;
|
||
|
||
.card {
|
||
background-size: 100% 100% !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Position card (定位牌) - show on video area left side for NN/TC */
|
||
.nn_position {
|
||
display: flex !important;
|
||
position: fixed !important;
|
||
top: 15% !important; /* 在视频区域内 */
|
||
left: 8px !important;
|
||
transform: translateY(-50%) !important;
|
||
z-index: 2000 !important;
|
||
flex-direction: column !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
background: transparent !important;
|
||
padding: 0 !important;
|
||
pointer-events: none !important; /* 让点击穿透到下注区域 */
|
||
|
||
strong {
|
||
font-size: 10px !important;
|
||
color: #fff !important;
|
||
margin-bottom: 4px !important;
|
||
padding: 0 !important;
|
||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8) !important;
|
||
}
|
||
|
||
.item {
|
||
width: 36px !important;
|
||
height: 52px !important;
|
||
transform: none !important;
|
||
margin: 0 !important;
|
||
padding: 0 !important;
|
||
|
||
.card {
|
||
display: block !important;
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
background-size: 100% 100% !important;
|
||
border-radius: 3px !important;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5) !important;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 三卡牛牛的定位牌在 poker-box 内部,需要额外选择器 */
|
||
.poker-box.nn .nn_position {
|
||
display: flex !important;
|
||
position: fixed !important;
|
||
top: 15% !important; /* 在视频区域内 */
|
||
left: 8px !important;
|
||
transform: translateY(-50%) !important;
|
||
z-index: 2000 !important;
|
||
flex-direction: column !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
background: transparent !important;
|
||
padding: 0 !important;
|
||
|
||
strong {
|
||
font-size: 10px !important;
|
||
color: #fff !important;
|
||
margin-bottom: 4px !important;
|
||
padding: 0 !important;
|
||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8) !important;
|
||
}
|
||
|
||
.item {
|
||
width: 36px !important;
|
||
height: 52px !important;
|
||
transform: none !important;
|
||
margin: 0 !important;
|
||
padding: 0 !important;
|
||
|
||
.card {
|
||
display: block !important;
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
background-size: 100% 100% !important;
|
||
border-radius: 3px !important;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5) !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 4. Roadmap Container (Bottom) - Auto Height for Aspect Ratio */
|
||
.roadmap-container {
|
||
width: 100%;
|
||
height: 160px;
|
||
flex-shrink: 0;
|
||
background: #fff;
|
||
position: relative;
|
||
z-index: 20;
|
||
overflow: hidden;
|
||
|
||
/* NN/TC mode - larger roadmap */
|
||
&.nn-mode {
|
||
height: 130px;
|
||
}
|
||
|
||
/* Deep overrides to ensure standard layout and white background support */
|
||
::v-deep .playway {
|
||
height: 100% !important;
|
||
background: transparent !important;
|
||
|
||
&.white-theme {
|
||
background: #fff !important;
|
||
}
|
||
}
|
||
|
||
::v-deep .baccarat-view {
|
||
height: 100% !important;
|
||
}
|
||
|
||
::v-deep .road-box {
|
||
background: transparent !important;
|
||
}
|
||
|
||
::v-deep .canvas {
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
display: block !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|