重构 Play.vue 组件,拆分为多个子组件,提升代码可维护性和可读性。
主要变更: - 将 Play.vue 拆分为 LoadingOverlay、SelectRegion、ScanPage、GamePage、RefreshWaitPage、ErrorPage 等组件 - 新增 composables 目录,分离业务逻辑(usePlayState、useTimers、useQrCode) - 优化代码结构,提升开发效率和维护性 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
185
src/composables/useQrCode.js
Normal file
185
src/composables/useQrCode.js
Normal file
@@ -0,0 +1,185 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { selectRegion as selectRegionAPI } from '@/api/play'
|
||||
|
||||
export function useQrCode() {
|
||||
|
||||
const validateQrCodeUrl = async (url) => {
|
||||
try {
|
||||
console.log('开始验证二维码URL:', url)
|
||||
|
||||
if (!url || typeof url !== 'string') {
|
||||
console.error('无效的二维码URL:', url)
|
||||
return false
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
console.log('生产环境跳过URL验证')
|
||||
return true
|
||||
}
|
||||
|
||||
const controller = new AbortController()
|
||||
const timeoutId = setTimeout(() => {
|
||||
controller.abort()
|
||||
console.log('URL验证超时')
|
||||
}, 3000)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'HEAD',
|
||||
signal: controller.signal,
|
||||
mode: 'no-cors'
|
||||
})
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
console.log('URL验证响应:', response.status)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.warn('二维码URL验证失败:', error.name, error.message)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
const fetchQrCodeAfterDelay = async (state, countdown, mecmachineId, qrCreatedAt, qrExpireAt, retryCount = 0) => {
|
||||
try {
|
||||
const qrCodeUrl = `https://2.uzi0.cc/image/${mecmachineId}/二维码.png?t=${Date.now()}`
|
||||
console.log(`尝试获取二维码 (第${retryCount + 1}次):`, qrCodeUrl)
|
||||
|
||||
const isUrlValid = await validateQrCodeUrl(qrCodeUrl)
|
||||
console.log('URL验证结果:', isUrlValid)
|
||||
|
||||
if (!isUrlValid) {
|
||||
throw new Error('二维码URL无法访问')
|
||||
}
|
||||
|
||||
console.log('设置二维码信息:', { qrCodeUrl, qrCreatedAt, qrExpireAt })
|
||||
state.qrInfo = {
|
||||
url: qrCodeUrl,
|
||||
createdAt: qrCreatedAt,
|
||||
expireAt: qrExpireAt
|
||||
}
|
||||
|
||||
const now = Date.now()
|
||||
const expireTime = new Date(qrExpireAt).getTime()
|
||||
countdown.value = Math.max(0, Math.floor((expireTime - now) / 1000))
|
||||
|
||||
state.qrRetryCount = 0
|
||||
state.isWaitingQr = false
|
||||
|
||||
console.log('二维码设置完成,countdown:', countdown.value)
|
||||
ElMessage.success('二维码已准备就绪,请扫码登录')
|
||||
|
||||
} catch (error) {
|
||||
console.error(`二维码获取失败 (第${retryCount + 1}次):`, error.message || error)
|
||||
|
||||
if (retryCount < state.maxQrRetries) {
|
||||
state.qrRetryCount = retryCount + 1
|
||||
const delay = state.qrRetryDelay * Math.pow(2, retryCount)
|
||||
|
||||
console.log(`${delay}ms后进行第${retryCount + 2}次重试`)
|
||||
ElMessage.warning(`二维码获取失败,${delay/1000}秒后重试...`)
|
||||
|
||||
setTimeout(() => {
|
||||
fetchQrCodeAfterDelay(state, countdown, mecmachineId, qrCreatedAt, qrExpireAt, retryCount + 1)
|
||||
}, delay)
|
||||
} else {
|
||||
console.error('二维码获取重试次数用完,显示错误状态')
|
||||
state.qrRetryCount = 0
|
||||
state.isWaitingQr = false
|
||||
state.qrError = `二维码获取失败,已重试${state.maxQrRetries}次。可能是网络问题或服务器繁忙,请稍后重试。`
|
||||
ElMessage.error('二维码获取失败,请点击重新获取按钮')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const retrySelectRegion = async (state, code, region) => {
|
||||
try {
|
||||
console.log('重试选择区域:', region)
|
||||
const response = await selectRegionAPI({ code, region })
|
||||
const data = response.data
|
||||
|
||||
console.log('retrySelectRegion 响应数据:', data)
|
||||
return data
|
||||
|
||||
} catch (error) {
|
||||
console.error('重试选择区域失败:', error)
|
||||
ElMessage.error('重新请求二维码失败,请手动刷新页面')
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const processSelectRegionResponse = async (state, countdown, data, startCountdown, startLoginPolling, updateStateFromResponse) => {
|
||||
if (data.qrDelaySeconds && data.qrDelaySeconds > 0 && data.mecmachineId) {
|
||||
console.log('进入延迟分支')
|
||||
await updateStateFromResponse(data, true)
|
||||
|
||||
state.qrDelaySeconds = data.qrDelaySeconds
|
||||
state.isWaitingQr = true
|
||||
console.log('设置状态:', { status: state.status, isWaitingQr: state.isWaitingQr })
|
||||
ElMessage.info(`正在准备二维码,请等待 ${data.qrDelaySeconds} 秒...`)
|
||||
|
||||
setTimeout(async () => {
|
||||
state.isWaitingQr = false
|
||||
|
||||
await fetchQrCodeAfterDelay(state, countdown, data.mecmachineId, data.qrCreatedAt, data.qrExpireAt)
|
||||
|
||||
if (state.status === 'USING') {
|
||||
startCountdown()
|
||||
startLoginPolling()
|
||||
}
|
||||
}, data.qrDelaySeconds * 1000)
|
||||
} else {
|
||||
console.log('进入立即处理分支')
|
||||
await updateStateFromResponse(data)
|
||||
state.isWaitingQr = false
|
||||
console.log('设置状态:', { status: state.status, isWaitingQr: state.isWaitingQr, qrInfo: !!state.qrInfo })
|
||||
|
||||
if (state.qrInfo && state.qrInfo.url) {
|
||||
const isUrlValid = await validateQrCodeUrl(state.qrInfo.url)
|
||||
if (!isUrlValid) {
|
||||
console.warn('立即获取的二维码URL无法访问,尝试重试')
|
||||
state.qrInfo = null
|
||||
await fetchQrCodeAfterDelay(state, countdown, data.mecmachineId, data.qrCreatedAt, data.qrExpireAt)
|
||||
}
|
||||
}
|
||||
|
||||
if (state.status === 'USING') {
|
||||
startCountdown()
|
||||
startLoginPolling()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleQrImageError = (state, event) => {
|
||||
console.error('二维码图片加载失败:', event)
|
||||
state.qrError = '二维码图片加载失败,可能是网络问题'
|
||||
ElMessage.error('二维码图片加载失败')
|
||||
}
|
||||
|
||||
const retryGetQrCode = async (state, selectRegion) => {
|
||||
if (state.submitting) return
|
||||
|
||||
state.submitting = true
|
||||
state.qrError = null
|
||||
state.isWaitingQr = true
|
||||
state.qrRetryCount = 0
|
||||
|
||||
try {
|
||||
if (state.region) {
|
||||
await selectRegion(state.region)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('重新获取二维码失败:', error)
|
||||
state.qrError = '重新获取失败,请刷新页面重试'
|
||||
} finally {
|
||||
state.submitting = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
validateQrCodeUrl,
|
||||
fetchQrCodeAfterDelay,
|
||||
retrySelectRegion,
|
||||
processSelectRegionResponse,
|
||||
handleQrImageError,
|
||||
retryGetQrCode
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user