Files
login_task_web/src/views/Play.vue

264 lines
6.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="play-container">
<!-- 加载状态 -->
<LoadingOverlay v-if="state.loading" />
<!-- 选区界面 -->
<SelectRegion
v-else-if="state.status === 'NEW' && !state.needRefresh"
:submitting="state.submitting"
:mecmachine-id="state.mecmachineId || state.machineId"
:total-points="state.totalPoints"
@select-region="handleSelectRegion"
/>
<!-- 扫码界面 -->
<ScanPage
v-else-if="state.status === 'USING'"
:region-name="getRegionName()"
:is-waiting-qr="state.isWaitingQr"
:qr-info="state.qrInfo"
:countdown="countdown"
:qr-delay-seconds="state.qrDelaySeconds"
:qr-retry-count="state.qrRetryCount"
:max-qr-retries="state.maxQrRetries"
:qr-error="state.qrError"
:submitting="state.submitting"
:mecmachine-id="state.mecmachineId || state.machineId"
@qr-image-error="handleQrImageError"
@qr-image-load="handleQrReadyEarly"
@retry-qr-code="retryGetQrCode"
@page-refresh="handlePageRefresh"
/>
<!-- 游戏界面 -->
<GamePage
v-else-if="state.status === 'LOGGED_IN' || (state.status === 'COMPLETED' && !state.isCompletedExpired)"
:region="state.region"
:region-desc="state.regionDesc"
:machine-id="state.machineId"
:display-status="getDisplayStatus()"
:completed-points="state.completedPoints"
:total-points="state.totalPoints"
:progress-display-format="state.progressDisplayFormat"
:status-message="getStatusMessage()"
:status-message-class="getStatusMessageClass()"
:assets="state.assets"
:current-points="state.currentPoints"
:code-no="state.code"
/>
<!-- 完成状态超过24小时 -->
<div v-else-if="state.status === 'COMPLETED' && state.isCompletedExpired" class="completed-page">
<div class="completed-text">已打完</div>
</div>
<!-- 刷新等待界面 -->
<RefreshWaitPage
v-else-if="state.needRefresh"
:refresh-cooldown="refreshCooldown"
:mecmachine-id="state.mecmachineId || state.machineId"
@refresh="modifiedHandleRefresh"
/>
<!-- 错误界面 -->
<ErrorPage
v-else
:error-title="getErrorTitle()"
:error-message="getErrorMessage()"
@retry="handleRetry"
/>
</div>
</template>
<script>
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { usePlayState } from '@/composables/usePlayState'
import { useTimers } from '@/composables/useTimers'
import { useQrCode } from '@/composables/useQrCode'
import LoadingOverlay from '@/components/play/LoadingOverlay.vue'
import SelectRegion from '@/components/play/SelectRegion.vue'
import ScanPage from '@/components/play/ScanPage.vue'
import GamePage from '@/components/play/GamePage.vue'
import RefreshWaitPage from '@/components/play/RefreshWaitPage.vue'
import ErrorPage from '@/components/play/ErrorPage.vue'
export default {
name: 'Play',
components: {
LoadingOverlay,
SelectRegion,
ScanPage,
GamePage,
RefreshWaitPage,
ErrorPage
},
setup() {
const route = useRoute()
const {
state,
initializePage,
updateStateFromResponse,
handleLoggedInStatus,
handleCompletedStatus,
selectRegion,
handleRefresh,
handlePageRefresh,
handleRetry,
getRegionName,
getDisplayStatus,
getStatusMessage,
getStatusMessageClass,
getProgressPercent,
getCurrentGameImage,
getGameStatus,
getStatusClass,
getErrorTitle,
getErrorMessage
} = usePlayState()
const {
countdown,
refreshCooldown,
clearAllTimers,
startCountdown,
startLoginPolling,
startRefreshCooldown,
startProgressPolling,
startQrDelayCountdown,
clearQrDelayCountdown
} = useTimers()
const {
processSelectRegionResponse,
handleQrImageError,
retryGetQrCode,
fetchQrCodeAfterDelay,
clearQrDelayTimeout
} = useQrCode()
onMounted(() => {
// 兼容两种方式:路径参数和查询参数
const code = route.params.code || route.query.code
if (!code) {
state.error = 'INVALID_CODE'
state.loading = false
return
}
state.code = code
initializePage()
})
onUnmounted(() => {
clearAllTimers()
})
const handleSelectRegion = async (region) => {
try {
const data = await selectRegion(region)
await processSelectRegionResponse(
state,
countdown,
data,
() => 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
}
})
},
updateStateFromResponse,
startQrDelayCountdown,
clearQrDelayCountdown
)
} catch (error) {
console.error('处理选择区域失败:', error)
}
}
const modifiedHandleRefresh = async () => {
try {
const data = await handleRefresh(clearAllTimers)
if (data.waitSeconds) {
startRefreshCooldown(data.waitSeconds)
}
} catch (error) {
console.error('刷新失败:', error)
}
}
const handleQrReadyEarly = async () => {
// 移除提前显示二维码的逻辑,确保必须等待指定时间后才显示
console.log('二维码提前就绪事件被忽略,必须等待指定时间后才显示')
}
return {
state,
countdown,
refreshCooldown,
handleSelectRegion,
handleRefresh: modifiedHandleRefresh,
handlePageRefresh,
handleQrImageError,
retryGetQrCode,
handleQrReadyEarly,
handleRetry,
getRegionName,
getDisplayStatus,
getStatusMessage,
getStatusMessageClass,
getProgressPercent,
getCurrentGameImage,
getGameStatus,
getStatusClass,
getErrorTitle,
getErrorMessage
}
}
}
</script>
<style scoped>
.play-container {
min-height: 100vh;
background: linear-gradient(135deg, #4776e6 0%, #8e54e9 100%);
display: flex;
flex-direction: column;
position: relative;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.completed-page {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
background: white;
min-height: 100vh;
}
.completed-text {
font-size: 48px;
font-weight: bold;
color: #28a745;
text-align: center;
}
@media (max-width: 768px) {
.completed-text {
font-size: 36px;
}
}
</style>