diff --git a/src/components/play/ScanPage.vue b/src/components/play/ScanPage.vue
index 37b7473..2e3c609 100644
--- a/src/components/play/ScanPage.vue
+++ b/src/components/play/ScanPage.vue
@@ -16,7 +16,7 @@
-
![扫码登录]()
+
{{ formatTime(countdown) }}
@@ -103,12 +103,60 @@ export default {
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: {
formatTime(seconds) {
const mins = Math.floor(seconds / 60)
const secs = seconds % 60
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
+ }
}
}
}
diff --git a/src/composables/usePlayState.js b/src/composables/usePlayState.js
index bfb6592..580b3d5 100644
--- a/src/composables/usePlayState.js
+++ b/src/composables/usePlayState.js
@@ -34,7 +34,10 @@ export function usePlayState() {
qrRetryDelay: 2000,
qrError: null,
mecmachineId: null,
- machineId: null
+ machineId: null,
+ qrCreatedAt: null,
+ qrExpireAt: null,
+ qrDelayTimeoutId: null
})
const initializePage = async () => {
@@ -206,6 +209,12 @@ export function usePlayState() {
state.assets = data.assets
state.mecmachineId = data.mecmachineId || null
state.machineId = data.machineId || null
+ if (data.qrCreatedAt) {
+ state.qrCreatedAt = data.qrCreatedAt
+ }
+ if (data.qrExpireAt) {
+ state.qrExpireAt = data.qrExpireAt
+ }
if (data.totalPoints) {
state.totalPoints = data.totalPoints
diff --git a/src/composables/useQrCode.js b/src/composables/useQrCode.js
index b4e3d91..58e5c10 100644
--- a/src/composables/useQrCode.js
+++ b/src/composables/useQrCode.js
@@ -121,7 +121,7 @@ export function useQrCode() {
startQrDelayCountdown(state, data.qrDelaySeconds)
}
- setTimeout(async () => {
+ state.qrDelayTimeoutId = setTimeout(async () => {
state.isWaitingQr = false
// 清理等待倒计时定时器
if (typeof clearQrDelayCountdown === 'function') {
@@ -134,6 +134,7 @@ export function useQrCode() {
startCountdown()
startLoginPolling()
}
+ state.qrDelayTimeoutId = null
}, data.qrDelaySeconds * 1000)
} else {
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) => {
console.error('二维码图片加载失败:', event)
state.qrError = '二维码图片加载失败,可能是网络问题'
@@ -193,6 +201,7 @@ export function useQrCode() {
retrySelectRegion,
processSelectRegionResponse,
handleQrImageError,
- retryGetQrCode
+ retryGetQrCode,
+ clearQrDelayTimeout
}
}
\ No newline at end of file
diff --git a/src/views/Play.vue b/src/views/Play.vue
index 1ba514a..12bb938 100644
--- a/src/views/Play.vue
+++ b/src/views/Play.vue
@@ -25,6 +25,7 @@
:submitting="state.submitting"
:mecmachine-id="state.mecmachineId || state.machineId"
@qr-image-error="handleQrImageError"
+ @qr-image-load="handleQrReadyEarly"
@retry-qr-code="retryGetQrCode"
@page-refresh="handlePageRefresh"
/>
@@ -134,7 +135,9 @@ export default {
const {
processSelectRegionResponse,
handleQrImageError,
- retryGetQrCode
+ retryGetQrCode,
+ fetchQrCodeAfterDelay,
+ clearQrDelayTimeout
} = useQrCode()
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 {
state,
countdown,
@@ -202,6 +240,7 @@ export default {
handlePageRefresh,
handleQrImageError,
retryGetQrCode,
+ handleQrReadyEarly,
handleRetry,
getRegionName,
getDisplayStatus,