feat: 登录失效统一弹框 + 筹码越南K格式持久化 + play.vue 优化
- axios.config: 拦截登录过期响应,统一弹框后清除用户信息,防多次弹框 - app.js: chooseChip 改为越南 K 格式默认 10k,支持 localStorage 恢复 - bettingChips.js: 移除(逻辑已合并)
This commit is contained in:
@@ -1,8 +1,48 @@
|
||||
import axios from "axios"
|
||||
import $store from "@/store"
|
||||
import { encrypt, decrypt } from "@/utils/secret"
|
||||
import { showDialog, closeDialog } from "vant"
|
||||
|
||||
let api = ""
|
||||
|
||||
// 登录失效统一处理(防止多 API 同时失败弹多个框)
|
||||
let _authExpiredHandling = false
|
||||
const handleAuthExpired = (res) => {
|
||||
const msg = res && res.Msg
|
||||
const isAuthExpired =
|
||||
res &&
|
||||
res.Success == 0 &&
|
||||
(msg === "获取信息失败" ||
|
||||
msg === "登录已过期" ||
|
||||
msg === "token失效" ||
|
||||
msg === "请重新登录")
|
||||
if (!isAuthExpired) return false
|
||||
if (_authExpiredHandling) return true
|
||||
_authExpiredHandling = true
|
||||
|
||||
const cfg = $store.state.config
|
||||
const Lang = cfg.$lang && cfg.$Type ? cfg.$lang[cfg.$Type] : {}
|
||||
const title = Lang.tips || "提示"
|
||||
const message = Lang.login_expired || "登录已过期,请重新登录"
|
||||
|
||||
let autoClose = null
|
||||
showDialog({ title, message })
|
||||
.then(() => {
|
||||
clearTimeout(autoClose)
|
||||
_authExpiredHandling = false
|
||||
$store.commit("app/removeUserInfo")
|
||||
})
|
||||
.catch(() => {
|
||||
_authExpiredHandling = false
|
||||
$store.commit("app/removeUserInfo")
|
||||
})
|
||||
autoClose = setTimeout(() => {
|
||||
closeDialog()
|
||||
_authExpiredHandling = false
|
||||
$store.commit("app/removeUserInfo")
|
||||
}, 4000)
|
||||
return true
|
||||
}
|
||||
const instance = axios.create({
|
||||
timeout: 6000,
|
||||
headers: {
|
||||
@@ -103,6 +143,7 @@ const get = (url, params, option = {}) => {
|
||||
encryptData
|
||||
})
|
||||
.then((res) => {
|
||||
handleAuthExpired(res)
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -127,6 +168,7 @@ const post = (url, params, option = {}) => {
|
||||
})
|
||||
.then((res) => {
|
||||
res.Data = res.Data ? JSON.parse(decrypt(res.Data)) : {}
|
||||
handleAuthExpired(res)
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
|
||||
@@ -27,10 +27,28 @@ try {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
// 默认筹码(必须和 store/modules/config.js::chipArry 里的 key 对齐)
|
||||
// 2026-04 改用越南 K 格式(10k/20k/.../100000k),旧 "1w" 已废弃
|
||||
const DEFAULT_CHOOSE_CHIP = { key: "10k", show: true, value: 10000 }
|
||||
|
||||
// 从 localStorage 恢复上次选中的筹码,若不存在 / key 已下架则回退默认
|
||||
let chooseChipInit = DEFAULT_CHOOSE_CHIP
|
||||
try {
|
||||
const saved = localStorage.getItem("chooseChip")
|
||||
if (saved) {
|
||||
const obj = JSON.parse(saved)
|
||||
if (obj && typeof obj.key === "string" && typeof obj.value === "number" && obj.value > 0) {
|
||||
chooseChipInit = { key: obj.key, show: obj.show !== false, value: obj.value }
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
const state = {
|
||||
game_id: 1,
|
||||
gameUrl: "",
|
||||
chooseChip: { key: "1s", value: 10 },
|
||||
chooseChip: chooseChipInit,
|
||||
userInfo: userData,
|
||||
allTableData: [],
|
||||
routerStack: routerStack,
|
||||
@@ -67,9 +85,21 @@ const mutations = {
|
||||
}
|
||||
window.location.href = url
|
||||
},
|
||||
// 更新选择下注筹码
|
||||
// 更新选择下注筹码(强类型 + 持久化到 localStorage)
|
||||
updateChooseChip: (state, data) => {
|
||||
state.chooseChip = data
|
||||
if (!data || typeof data !== "object") return
|
||||
const safe = {
|
||||
key: String(data.key || ""),
|
||||
show: data.show !== false,
|
||||
value: Number(data.value) || 0
|
||||
}
|
||||
if (!safe.key || safe.value <= 0) return
|
||||
state.chooseChip = safe
|
||||
try {
|
||||
localStorage.setItem("chooseChip", JSON.stringify(safe))
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
updateGameId(state, id) {
|
||||
state.game_id = id
|
||||
|
||||
+129
-8
@@ -55,11 +55,28 @@
|
||||
|
||||
|
||||
|
||||
<!-- Subtitle Overlay -->
|
||||
<Transition name="subtitle-fade">
|
||||
<div class="subtitle-overlay" v-if="subtitle" :key="subtitle">
|
||||
<span class="subtitle-text">{{ subtitle }}</span>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<!-- Back Button (Top Left) -->
|
||||
<div class="video-btn-back" @click="handleBack"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Notice Bar -->
|
||||
<div class="notice-bar" v-if="userInfo.memo && userInfo.memo.length">
|
||||
<div class="notice-icon">📢</div>
|
||||
<div class="notice-wrap">
|
||||
<div class="notice-content">
|
||||
<span v-for="(item, i) in userInfo.memo" :key="i">{{ item.title }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top Navigation Bar (Moved below video) -->
|
||||
<div class="nav">
|
||||
<!-- 1. User Info -->
|
||||
@@ -317,6 +334,13 @@ export default {
|
||||
const showDiceResult = ref(false)
|
||||
const showRouletteResult = ref(false)
|
||||
const winArray = ref([])
|
||||
const subtitle = ref("")
|
||||
let subtitleTimer = null
|
||||
const showSubtitle = (text, duration = 3000) => {
|
||||
clearTimeout(subtitleTimer)
|
||||
subtitle.value = text
|
||||
subtitleTimer = setTimeout(() => { subtitle.value = "" }, duration)
|
||||
}
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const store = useStore()
|
||||
@@ -593,7 +617,7 @@ export default {
|
||||
win.push("banker_pair", "player_pair")
|
||||
mp3list.push("baccarat_b_pair", "baccarat_p_pair")
|
||||
}
|
||||
showToast(text)
|
||||
showSubtitle(text, 5000)
|
||||
winArray.value = win
|
||||
audioMp3(mp3list).Play()
|
||||
setTimeout(() => {
|
||||
@@ -627,7 +651,7 @@ export default {
|
||||
mp3list.push("lh_tie")
|
||||
}
|
||||
audioMp3(mp3list).Play()
|
||||
showToast(text)
|
||||
showSubtitle(text, 5000)
|
||||
winArray.value = win
|
||||
setTimeout(() => {
|
||||
winArray.value = []
|
||||
@@ -678,7 +702,7 @@ export default {
|
||||
}
|
||||
}
|
||||
audioMp3(mp3list).Play()
|
||||
showToast(text)
|
||||
showSubtitle(text, 5000)
|
||||
winArray.value = win
|
||||
setTimeout(() => {
|
||||
winArray.value = []
|
||||
@@ -726,7 +750,7 @@ export default {
|
||||
break
|
||||
}
|
||||
audioMp3(mp3list).Play()
|
||||
showToast(text)
|
||||
showSubtitle(text, 5000)
|
||||
winArray.value = win
|
||||
setTimeout(() => {
|
||||
winArray.value = []
|
||||
@@ -758,7 +782,7 @@ export default {
|
||||
mp3list.push(`${totle}_point`)
|
||||
|
||||
audioMp3(mp3list).Play()
|
||||
showToast(text)
|
||||
showSubtitle(text, 5000)
|
||||
winArray.value = data.round.result_parse
|
||||
setTimeout(() => {
|
||||
winArray.value = []
|
||||
@@ -776,7 +800,7 @@ export default {
|
||||
text = result
|
||||
mp3list.push(`${result}_point`)
|
||||
// console.log(result, mp3list)
|
||||
showToast(text)
|
||||
showSubtitle(text, 3000)
|
||||
winArray.value = data.round.result_parse
|
||||
setTimeout(() => {
|
||||
winArray.value = []
|
||||
@@ -1099,7 +1123,7 @@ export default {
|
||||
store.commit("config/rouletteLockTable", false)
|
||||
}
|
||||
closeDialog()
|
||||
showToast(Lang.value[Type.value].msg_start_bet)
|
||||
showSubtitle(Lang.value[Type.value].msg_start_bet)
|
||||
if (data.game_id != 5) {
|
||||
audioMp3(["start_betting"]).Play()
|
||||
} else {
|
||||
@@ -1120,6 +1144,9 @@ export default {
|
||||
case "startBetCountDown": //倒计时
|
||||
if (data.count_down == 10) {
|
||||
audioMp3(["last_10_seconds"]).Play()
|
||||
} else if (data.count_down <= 5 && data.count_down > 0) {
|
||||
showSubtitle(Lang.value[Type.value].endBet, 1000)
|
||||
audioMp3(["time"]).Play()
|
||||
} else if (data.count_down < 9) {
|
||||
audioMp3(["time"]).Play()
|
||||
}
|
||||
@@ -1173,7 +1200,7 @@ export default {
|
||||
) {
|
||||
hideVideo.value = false
|
||||
}
|
||||
showToast(Lang.value[Type.value].endBet)
|
||||
showSubtitle(Lang.value[Type.value].endBet)
|
||||
audioMp3(["stop_betting"]).Play()
|
||||
break
|
||||
case "openingBaccaratResult":
|
||||
@@ -1226,6 +1253,7 @@ export default {
|
||||
audio,
|
||||
videoConfig,
|
||||
hideVideo,
|
||||
subtitle,
|
||||
userInfo,
|
||||
nnGame,
|
||||
tableData,
|
||||
@@ -1292,6 +1320,60 @@ $gold: #c5a059;
|
||||
|
||||
|
||||
|
||||
/* Notice Bar - Marquee Style */
|
||||
.notice-bar {
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
border-bottom: 1px solid #222;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
z-index: 100;
|
||||
|
||||
.notice-icon {
|
||||
flex-shrink: 0;
|
||||
width: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.notice-wrap {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.notice-content {
|
||||
display: inline-flex;
|
||||
white-space: nowrap;
|
||||
animation: noticeScroll 20s linear infinite;
|
||||
color: $gold;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.5px;
|
||||
|
||||
span {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes noticeScroll {
|
||||
0% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
/* Navigation Bar - Redesigned */
|
||||
.nav {
|
||||
position: relative;
|
||||
@@ -1839,4 +1921,43 @@ $gold: #c5a059;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Subtitle Overlay */
|
||||
.subtitle-overlay {
|
||||
position: absolute;
|
||||
bottom: 20%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 3500;
|
||||
pointer-events: none;
|
||||
|
||||
.subtitle-text {
|
||||
display: inline-block;
|
||||
padding: 8px 24px;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
color: #ffd700;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
border-radius: 6px;
|
||||
letter-spacing: 2px;
|
||||
text-shadow: 0 0 8px rgba(255, 215, 0, 0.6);
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
/* Subtitle Transition */
|
||||
.subtitle-fade-enter-active {
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
.subtitle-fade-leave-active {
|
||||
transition: all 0.5s ease-in;
|
||||
}
|
||||
.subtitle-fade-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(10px);
|
||||
}
|
||||
.subtitle-fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(-10px);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user