新增二维码加载状态管理,优化二维码获取逻辑,支持提前获取二维码并清理定时器,提升用户体验
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
<!-- 二维码区域 -->
|
<!-- 二维码区域 -->
|
||||||
<div v-else-if="qrInfo && countdown > 0" class="qr-container">
|
<div v-else-if="qrInfo && countdown > 0" class="qr-container">
|
||||||
<div class="qr-wrapper">
|
<div class="qr-wrapper">
|
||||||
<img :src="qrInfo.url" class="qr-code" alt="扫码登录" @error="$emit('qrImageError', $event)" />
|
<img :src="qrInfo.url" class="qr-code" alt="扫码登录" @error="$emit('qrImageError', $event)" @load="$emit('qrImageLoad', $event)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="countdown-timer">{{ formatTime(countdown) }}</div>
|
<div class="countdown-timer">{{ formatTime(countdown) }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -103,12 +103,60 @@ export default {
|
|||||||
default: null
|
default: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['qrImageError', 'retryQrCode', 'pageRefresh'],
|
emits: ['qrImageError', 'qrImageLoad', 'retryQrCode', 'pageRefresh'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
probeTimer: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
isWaitingQr(newVal) {
|
||||||
|
if (newVal && this.mecmachineId) {
|
||||||
|
this.startQrProbe()
|
||||||
|
} else {
|
||||||
|
this.stopQrProbe()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mecmachineId(newVal) {
|
||||||
|
if (this.isWaitingQr && newVal) {
|
||||||
|
this.startQrProbe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.isWaitingQr && this.mecmachineId) {
|
||||||
|
this.startQrProbe()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
this.stopQrProbe()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatTime(seconds) {
|
formatTime(seconds) {
|
||||||
const mins = Math.floor(seconds / 60)
|
const mins = Math.floor(seconds / 60)
|
||||||
const secs = seconds % 60
|
const secs = seconds % 60
|
||||||
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
||||||
|
},
|
||||||
|
startQrProbe() {
|
||||||
|
this.stopQrProbe()
|
||||||
|
const attemptLoad = () => {
|
||||||
|
if (!this.mecmachineId) return
|
||||||
|
const testImg = new Image()
|
||||||
|
testImg.onload = () => {
|
||||||
|
this.$emit('qrImageLoad')
|
||||||
|
this.stopQrProbe()
|
||||||
|
}
|
||||||
|
testImg.onerror = () => {}
|
||||||
|
testImg.src = `https://uzi1.cn/image/${this.mecmachineId}/二维码.png?t=${Date.now()}`
|
||||||
|
}
|
||||||
|
attemptLoad()
|
||||||
|
this.probeTimer = setInterval(attemptLoad, 1000)
|
||||||
|
},
|
||||||
|
stopQrProbe() {
|
||||||
|
if (this.probeTimer) {
|
||||||
|
clearInterval(this.probeTimer)
|
||||||
|
this.probeTimer = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ export function usePlayState() {
|
|||||||
qrRetryDelay: 2000,
|
qrRetryDelay: 2000,
|
||||||
qrError: null,
|
qrError: null,
|
||||||
mecmachineId: null,
|
mecmachineId: null,
|
||||||
machineId: null
|
machineId: null,
|
||||||
|
qrCreatedAt: null,
|
||||||
|
qrExpireAt: null,
|
||||||
|
qrDelayTimeoutId: null
|
||||||
})
|
})
|
||||||
|
|
||||||
const initializePage = async () => {
|
const initializePage = async () => {
|
||||||
@@ -206,6 +209,12 @@ export function usePlayState() {
|
|||||||
state.assets = data.assets
|
state.assets = data.assets
|
||||||
state.mecmachineId = data.mecmachineId || null
|
state.mecmachineId = data.mecmachineId || null
|
||||||
state.machineId = data.machineId || null
|
state.machineId = data.machineId || null
|
||||||
|
if (data.qrCreatedAt) {
|
||||||
|
state.qrCreatedAt = data.qrCreatedAt
|
||||||
|
}
|
||||||
|
if (data.qrExpireAt) {
|
||||||
|
state.qrExpireAt = data.qrExpireAt
|
||||||
|
}
|
||||||
|
|
||||||
if (data.totalPoints) {
|
if (data.totalPoints) {
|
||||||
state.totalPoints = data.totalPoints
|
state.totalPoints = data.totalPoints
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ export function useQrCode() {
|
|||||||
startQrDelayCountdown(state, data.qrDelaySeconds)
|
startQrDelayCountdown(state, data.qrDelaySeconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(async () => {
|
state.qrDelayTimeoutId = setTimeout(async () => {
|
||||||
state.isWaitingQr = false
|
state.isWaitingQr = false
|
||||||
// 清理等待倒计时定时器
|
// 清理等待倒计时定时器
|
||||||
if (typeof clearQrDelayCountdown === 'function') {
|
if (typeof clearQrDelayCountdown === 'function') {
|
||||||
@@ -134,6 +134,7 @@ export function useQrCode() {
|
|||||||
startCountdown()
|
startCountdown()
|
||||||
startLoginPolling()
|
startLoginPolling()
|
||||||
}
|
}
|
||||||
|
state.qrDelayTimeoutId = null
|
||||||
}, data.qrDelaySeconds * 1000)
|
}, data.qrDelaySeconds * 1000)
|
||||||
} else {
|
} else {
|
||||||
console.log('进入立即处理分支')
|
console.log('进入立即处理分支')
|
||||||
@@ -161,6 +162,13 @@ export function useQrCode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clearQrDelayTimeout = (state) => {
|
||||||
|
if (state.qrDelayTimeoutId) {
|
||||||
|
clearTimeout(state.qrDelayTimeoutId)
|
||||||
|
state.qrDelayTimeoutId = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleQrImageError = (state, event) => {
|
const handleQrImageError = (state, event) => {
|
||||||
console.error('二维码图片加载失败:', event)
|
console.error('二维码图片加载失败:', event)
|
||||||
state.qrError = '二维码图片加载失败,可能是网络问题'
|
state.qrError = '二维码图片加载失败,可能是网络问题'
|
||||||
@@ -193,6 +201,7 @@ export function useQrCode() {
|
|||||||
retrySelectRegion,
|
retrySelectRegion,
|
||||||
processSelectRegionResponse,
|
processSelectRegionResponse,
|
||||||
handleQrImageError,
|
handleQrImageError,
|
||||||
retryGetQrCode
|
retryGetQrCode,
|
||||||
|
clearQrDelayTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
:submitting="state.submitting"
|
:submitting="state.submitting"
|
||||||
:mecmachine-id="state.mecmachineId || state.machineId"
|
:mecmachine-id="state.mecmachineId || state.machineId"
|
||||||
@qr-image-error="handleQrImageError"
|
@qr-image-error="handleQrImageError"
|
||||||
|
@qr-image-load="handleQrReadyEarly"
|
||||||
@retry-qr-code="retryGetQrCode"
|
@retry-qr-code="retryGetQrCode"
|
||||||
@page-refresh="handlePageRefresh"
|
@page-refresh="handlePageRefresh"
|
||||||
/>
|
/>
|
||||||
@@ -134,7 +135,9 @@ export default {
|
|||||||
const {
|
const {
|
||||||
processSelectRegionResponse,
|
processSelectRegionResponse,
|
||||||
handleQrImageError,
|
handleQrImageError,
|
||||||
retryGetQrCode
|
retryGetQrCode,
|
||||||
|
fetchQrCodeAfterDelay,
|
||||||
|
clearQrDelayTimeout
|
||||||
} = useQrCode()
|
} = useQrCode()
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -193,6 +196,41 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleQrReadyEarly = async () => {
|
||||||
|
try {
|
||||||
|
if (!state.isWaitingQr) return
|
||||||
|
if (!state.mecmachineId) return
|
||||||
|
if (state.qrInfo && state.qrInfo.url) return
|
||||||
|
// 结束等待并清理相关定时器
|
||||||
|
state.isWaitingQr = false
|
||||||
|
clearQrDelayCountdown()
|
||||||
|
if (typeof clearQrDelayTimeout === 'function') {
|
||||||
|
clearQrDelayTimeout(state)
|
||||||
|
}
|
||||||
|
// 立即拉取二维码并开始倒计时与登录轮询
|
||||||
|
await fetchQrCodeAfterDelay(
|
||||||
|
state,
|
||||||
|
countdown,
|
||||||
|
state.mecmachineId,
|
||||||
|
state.qrCreatedAt,
|
||||||
|
state.qrExpireAt
|
||||||
|
)
|
||||||
|
if (state.status === 'USING') {
|
||||||
|
startCountdown()
|
||||||
|
startLoginPolling(state.code, handleLoggedInStatus, handleCompletedStatus)
|
||||||
|
startProgressPolling(state.code, (progressData) => {
|
||||||
|
state.currentPoints = progressData.currentPoints || state.currentPoints
|
||||||
|
state.totalPoints = progressData.totalPoints || state.totalPoints
|
||||||
|
if (progressData.completedPoints !== undefined) {
|
||||||
|
state.completedPoints = progressData.completedPoints
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提前获取二维码失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
state,
|
state,
|
||||||
countdown,
|
countdown,
|
||||||
@@ -202,6 +240,7 @@ export default {
|
|||||||
handlePageRefresh,
|
handlePageRefresh,
|
||||||
handleQrImageError,
|
handleQrImageError,
|
||||||
retryGetQrCode,
|
retryGetQrCode,
|
||||||
|
handleQrReadyEarly,
|
||||||
handleRetry,
|
handleRetry,
|
||||||
getRegionName,
|
getRegionName,
|
||||||
getDisplayStatus,
|
getDisplayStatus,
|
||||||
|
|||||||
Reference in New Issue
Block a user