Files
login_task_web/src/composables/usePlayState.js

519 lines
14 KiB
JavaScript
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.

import { reactive } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import {
getLinkStatus,
selectRegion as selectRegionAPI,
refreshLink as refreshLinkAPI,
getGameInterface as getGameInterfaceAPI
} from '@/api/play'
export function usePlayState() {
const route = useRoute()
const router = useRouter()
const state = reactive({
code: '',
status: 'NEW',
loading: true,
submitting: false,
needRefresh: false,
region: null,
regionDesc: null,
qrInfo: null,
assets: null,
currentPoints: 0,
totalPoints: null, // 修改初始值改为null等待从API获取真实数据
completedPoints: 0,
progressDisplayFormat: '1',
error: null,
qrDelaySeconds: 0,
isWaitingQr: false,
qrRetryCount: 0,
maxQrRetries: 3,
qrRetryDelay: 2000,
qrError: null,
mecmachineId: null,
machineId: null,
qrCreatedAt: null,
qrExpireAt: null,
qrDelayTimeoutId: null,
completedAt: null,
isCompletedExpired: false
})
const initializePage = async () => {
try {
await fetchStatus()
} catch (error) {
handleError(error)
} finally {
state.loading = false
}
}
const fetchStatus = async () => {
try {
const response = await getLinkStatus(state.code)
const data = response.data
await updateStateFromResponse(data)
// 如果是NEW状态尝试获取游戏界面数据以获取totalPoints
if (data.status === 'NEW') {
try {
const gameResponse = await getGameInterfaceAPI(state.code)
const gameData = gameResponse.data
console.log('NEW状态 - 游戏界面数据:', gameData)
// 更新totalPoints和其他可用数据
if (gameData.totalPoints !== undefined && gameData.totalPoints !== null) {
state.totalPoints = gameData.totalPoints
console.log('从游戏界面获取到totalPoints:', state.totalPoints)
}
if (gameData.completedPoints !== undefined) {
state.completedPoints = gameData.completedPoints
}
if (gameData.progressDisplayFormat) {
state.progressDisplayFormat = String(gameData.progressDisplayFormat)
}
} catch (gameError) {
// 游戏界面数据获取失败不影响主流程,只记录日志
console.log('NEW状态获取游戏界面数据失败这是正常的:', gameError.message)
}
}
} catch (error) {
throw error
}
}
const getGameInterface = async () => {
try {
console.log('调用游戏界面接口code:', state.code)
const response = await getGameInterfaceAPI(state.code)
console.log('游戏界面接口响应:', response.data)
return response
} catch (error) {
console.error('获取游戏界面数据失败:', error)
ElMessage.error('获取游戏界面数据失败')
throw error
}
}
const handleLoggedInStatus = async () => {
try {
console.log('检测到LOGGED_IN状态获取游戏界面数据')
const gameResponse = await getGameInterface()
const gameData = gameResponse.data
console.log('游戏界面数据:', gameData)
state.status = 'LOGGED_IN'
state.assets = {
qrCodeUrl: gameData.mecmachineId ? `https://uzi1.cn/image/${gameData.mecmachineId}/二维码.png?t=${Date.now()}` : null,
...(gameData.assets || {})
}
console.log('更新区域信息:', {
gameDataRegion: gameData.region,
originalStateRegion: state.region
})
if (gameData.region) {
state.region = gameData.region
console.log('已设置 state.region =', state.region)
} else {
console.log('gameData.region 为空,未更新 state.region')
}
if (gameData.regionDesc) {
state.regionDesc = gameData.regionDesc
}
if (gameData.mecmachineId) {
state.mecmachineId = gameData.mecmachineId
}
if (gameData.machineId) {
state.machineId = gameData.machineId
}
if (gameData.totalPoints) {
state.totalPoints = gameData.totalPoints
} else if (gameData.assets && gameData.assets.totalPoints) {
state.totalPoints = gameData.assets.totalPoints
}
state.completedPoints = gameData.completedPoints || 0
if (gameData.progressDisplayFormat) {
state.progressDisplayFormat = String(gameData.progressDisplayFormat)
}
state.currentPoints = 0
console.log('handleLoggedInStatus 执行完成,最终状态:', {
status: state.status,
region: state.region,
totalPoints: state.totalPoints,
completedPoints: state.completedPoints,
mecmachineId: state.mecmachineId
})
ElMessage.success('登录成功,正在进入游戏界面...')
} catch (error) {
console.error('获取游戏界面数据失败:', error)
ElMessage.error('获取游戏数据失败,请稍后重试')
}
}
const handleCompletedStatus = async () => {
try {
const gameResponse = await getGameInterfaceAPI(state.code)
const gameData = gameResponse.data
console.log('已完成状态 - 游戏界面数据:', gameData)
state.status = 'COMPLETED'
// 保存完成时间戳
if (gameData.completedAt) {
state.completedAt = gameData.completedAt
// 判断是否超过24小时
const now = Math.floor(Date.now() / 1000) // 当前时间戳(秒)
const completedTime = gameData.completedAt
const hoursPassed = (now - completedTime) / 3600 // 转换为小时
state.isCompletedExpired = hoursPassed > 24
console.log('完成时间判断:', {
completedAt: completedTime,
now: now,
hoursPassed: hoursPassed.toFixed(2),
isExpired: state.isCompletedExpired
})
}
// 更新区域和机器信息
if (gameData.region) {
state.region = gameData.region
}
if (gameData.regionDesc) {
state.regionDesc = gameData.regionDesc
}
if (gameData.mecmachineId) {
state.mecmachineId = gameData.mecmachineId
}
if (gameData.machineId) {
state.machineId = gameData.machineId
}
state.assets = {
qrCodeUrl: gameData.mecmachineId ? `https://uzi1.cn/image/${gameData.mecmachineId}/二维码.png?t=${Date.now()}` : null
}
state.totalPoints = gameData.totalPoints || 50
state.completedPoints = gameData.completedPoints || state.totalPoints
if (gameData.progressDisplayFormat) {
state.progressDisplayFormat = String(gameData.progressDisplayFormat)
}
state.currentPoints = state.totalPoints
console.log('已完成状态更新完成:', {
status: state.status,
totalPoints: state.totalPoints,
completedPoints: state.completedPoints,
currentPoints: state.currentPoints,
completedAt: state.completedAt,
isCompletedExpired: state.isCompletedExpired,
assets: !!state.assets
})
} catch (error) {
console.error('获取已完成状态游戏数据失败:', error)
state.status = 'COMPLETED'
ElMessage.error('获取游戏数据失败,但订单已完成')
}
}
const updateStateFromResponse = async (data, skipQrProcessing = false) => {
if (data.status === 'LOGGED_IN') {
await handleLoggedInStatus()
return
}
if (data.status === 'COMPLETED') {
await handleCompletedStatus()
return
}
state.status = data.status
state.needRefresh = data.needRefresh || false
state.region = data.region
state.regionDesc = data.regionDesc || null
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
}
// 优先使用 data.totalPoints确保在NEW状态也能获取到目标点数
if (data.totalPoints !== undefined && data.totalPoints !== null) {
state.totalPoints = data.totalPoints
}
if (data.completedPoints !== undefined) {
state.completedPoints = data.completedPoints
}
if (data.progressDisplayFormat) {
state.progressDisplayFormat = String(data.progressDisplayFormat)
}
// 如果assets中有totalPoints也更新
if (data.assets && data.assets.totalPoints !== undefined && data.assets.totalPoints !== null) {
state.totalPoints = data.assets.totalPoints
if (state.currentPoints === undefined) {
state.currentPoints = 0
}
}
console.log('updateStateFromResponse:', {
status: data.status,
dataRegion: data.region,
stateRegion: state.region,
mecmachineId: data.mecmachineId,
dataTotalPoints: data.totalPoints,
stateTotalPoints: state.totalPoints,
completedPoints: state.completedPoints,
skipQrProcessing
})
if (skipQrProcessing) {
return
}
if (data.mecmachineId) {
const qrUrl = `https://uzi1.cn/image/${data.mecmachineId}/二维码.png?t=${Date.now()}`
state.qrInfo = {
url: qrUrl,
createdAt: data.qrCreatedAt,
expireAt: data.qrExpireAt
}
} else if (data.qr) {
state.qrInfo = data.qr
}
}
const selectRegion = async (region) => {
if (state.submitting) return
state.submitting = true
state.qrRetryCount = 0
try {
const response = await selectRegionAPI({ code: state.code, region })
const data = response.data
console.log('selectRegion 响应数据:', data)
return data
} catch (error) {
handleError(error)
throw error
} finally {
state.submitting = false
}
}
const handleRefresh = async (clearAllTimers) => {
try {
const response = await refreshLinkAPI(state.code)
const data = response.data
if (clearAllTimers) {
clearAllTimers()
}
state.needRefresh = false
state.status = 'NEW'
return data
} catch (error) {
handleError(error)
throw error
}
}
const handlePageRefresh = () => {
window.location.reload()
}
const handleRetry = () => {
state.error = null
state.loading = true
initializePage()
}
const handleError = (error) => {
console.error('API错误:', error)
const status = error?.response?.status
if (status === 401) {
console.log('检测到401错误跳转到登录页面')
router.replace({
name: 'Login',
query: { redirect: route.fullPath }
})
return
}
if (status === 400 || status === 403) {
state.error = 'INVALID_CODE'
} else if (status === 410) {
state.error = 'EXPIRED'
} else {
state.error = 'NETWORK_ERROR'
}
}
const formatTime = (seconds) => {
const mins = Math.floor(seconds / 60)
const secs = seconds % 60
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}
const getRegionName = () => {
return state.region === 'Q' ? 'QQ区' : state.region === 'V' ? '微信区' : ''
}
const getCurrentUrl = () => {
return window.location.href
}
const getGameStatus = () => {
if (state.currentPoints >= state.totalPoints) {
return '已打完'
} else if (state.currentPoints > 0) {
return '代练中'
} else {
return '空闲'
}
}
const getStatusClass = () => {
const status = getGameStatus()
return {
'status-completed': status === '已打完',
'status-playing': status === '代练中',
'status-idle': status === '空闲'
}
}
const getDisplayStatus = () => {
if (state.status === 'COMPLETED') {
return '已完成'
} else if (state.status === 'LOGGED_IN') {
return '代练中'
} else {
return '状态'
}
}
const getStatusMessage = () => {
if (state.status === 'COMPLETED') {
return '代练已完成!感谢您的使用,订单已结束。'
} else if (state.status === 'LOGGED_IN') {
return '正在代练中,期间请勿操号,耐心等待代练完成......'
} else {
return '正在代练中,期间请勿操号,耐心等待代练完成......'
}
}
const getStatusMessageClass = () => {
if (state.status === 'COMPLETED') {
return 'status-message-completed'
} else {
return ''
}
}
const getProgressPercent = () => {
if (!state.totalPoints) return 0
return Math.min(100, (state.currentPoints / state.totalPoints) * 100)
}
const getCurrentGameImage = () => {
if (!state.machineId) return null
const progress = getProgressPercent()
const baseUrl = 'https://uzi1.cn/image'
if (progress === 0) {
return `${baseUrl}/${state.machineId}/首次主页.png`
} else if (progress < 50) {
return `${baseUrl}/${state.machineId}/首次赏金.png`
} else if (progress < 100) {
return `${baseUrl}/${state.machineId}/中途赏金.png`
} else {
return `${baseUrl}/${state.machineId}/结束赏金.png`
}
}
const getErrorTitle = () => {
const titles = {
'INVALID_CODE': '链接无效',
'EXPIRED': '链接已过期',
'REFUNDED': '订单已退单',
'NETWORK_ERROR': '网络错误'
}
return titles[state.error] || '出现错误'
}
const getErrorMessage = () => {
const messages = {
'INVALID_CODE': '请联系商家获取有效链接',
'EXPIRED': '请联系商家重新获取链接',
'REFUNDED': '该订单已被退单,无法继续使用',
'NETWORK_ERROR': '网络连接失败,请检查网络后重试'
}
return messages[state.error] || '请稍后重试或联系客服'
}
return {
state,
initializePage,
fetchStatus,
updateStateFromResponse,
handleLoggedInStatus,
handleCompletedStatus,
selectRegion,
handleRefresh,
handlePageRefresh,
handleRetry,
handleError,
formatTime,
getRegionName,
getCurrentUrl,
getGameStatus,
getStatusClass,
getDisplayStatus,
getStatusMessage,
getStatusMessageClass,
getProgressPercent,
getCurrentGameImage,
getErrorTitle,
getErrorMessage
}
}