fix: 皮肤站玩家列表加载失败后自动重试并显示错误状态
Sync source to CNB / Sync Git ref (push) Skipped

This commit is contained in:
AxTps committed 2026-10-20 22:05:24 +08:00
1 parent 26a29714b2
commit 0af663ac8c
4 files changed
+10450 -10366

No files matched your search

@@ -294,6 +294,9 @@ async function buildPlayer(entry: {
export function requestSkinSitePlayers(): Promise<SkinSitePlayer[]> {
if (playersRequest) return playersRequest
if (status.value !== 'signed-in' || !user.value) {
// Keep the status meaningful so the UI does not spin forever: an
// unauthenticated request means "not loaded yet", not "loading".
playersStatus.value = 'idle'
return Promise.reject(new Error('请先登录 StarLight 皮肤站。'))
}
@@ -319,6 +322,16 @@ export function requestSkinSitePlayers(): Promise<SkinSitePlayer[]> {
return playersRequest
}
/**
* Drop any in-flight or cached player request and fetch again. Used by views
* that need to recover after a failed load (e.g. signing in from the skin
* page while the first attempt raced the session check).
*/
export function reloadSkinSitePlayers(): Promise<SkinSitePlayer[]> {
playersRequest = null
return requestSkinSitePlayers()
}
export function selectSkinSitePlayer(playerId: string | null) {
if (playerId === null) {
selectedPlayerId.value = null
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+61 -8
View File
@@ -39,6 +39,7 @@ import SkinListSkeleton from '@/components/ui/skin/SkinListSkeleton.vue'
import VirtualSkinSectionList from '@/components/ui/skin/VirtualSkinSectionList.vue'
import {
openSkinSiteLogin,
reloadSkinSitePlayers,
requestSkinSitePlayers,
requestSkinSiteSkinUpdate,
selectedSkinSitePlayerId,
@@ -214,6 +215,18 @@ const messages = defineMessages({
id: 'app.skins.skin-site-account.empty-description',
defaultMessage: 'This skin site account does not have an available player profile yet.',
},
errorSkinSitePlayersTitle: {
id: 'app.skins.skin-site-account.error-title',
defaultMessage: 'Could not load your players',
},
errorSkinSitePlayersDescription: {
id: 'app.skins.skin-site-account.error-description',
defaultMessage: 'Check your connection and try again.',
},
retryButton: {
id: 'app.skins.skin-site-account.retry',
defaultMessage: 'Retry',
},
offlineCompatibility: {
id: 'app.skins.offline-account.compatibility',
defaultMessage:
@@ -982,6 +995,37 @@ watch(
},
)
// Load the player list whenever the session becomes available or the view is
// opened while the list never started loading. Without this the skin page can
// sit on "loading" forever when the first request raced the session check.
function ensureSkinSitePlayersLoaded() {
if (!skinSiteUser.value) return
if (skinSitePlayersStatus.value === 'checking') return
if (skinSitePlayersStatus.value === 'ready' && skinSitePlayers.value.length) return
if (skinSitePlayersStatus.value === 'error') return
void reloadSkinSitePlayers().catch((error) => {
console.warn('Failed to load skin site players:', error)
})
}
watch(
() => [skinSiteUser.value?.uuid, skinSiteStatus.value] as const,
([uuid, sessionStatus]) => {
if (uuid && sessionStatus === 'signed-in') ensureSkinSitePlayersLoaded()
},
{ immediate: true },
)
watch(skinSitePlayersStatus, (value) => {
if (value === 'idle' && skinSiteUser.value) ensureSkinSitePlayersLoaded()
})
function retrySkinSitePlayers() {
void reloadSkinSitePlayers().catch((error) => {
console.warn('Failed to reload skin site players:', error)
})
}
function getBakedSkinTextures(skin: Skin): RenderResult | undefined {
const key = `${skin.texture_key}+${skin.variant}+${skin.cape_id ?? 'no-cape'}`
return skinBlobUrlMap.get(key)
@@ -1436,22 +1480,26 @@ await loadSkins()
<h1 class="text-3xl font-extrabold m-0">
{{
formatMessage(
skinSiteUser
? skinSitePlayersStatus === 'checking' || skinSitePlayersStatus === 'idle'
!skinSiteUser
? messages.signInTitle
: skinSitePlayersStatus === 'error'
? messages.errorSkinSitePlayersTitle
: skinSitePlayersStatus === 'checking' || skinSitePlayersStatus === 'idle'
? messages.loadingSkinSitePlayersTitle
: messages.noSkinSitePlayersTitle
: messages.signInTitle,
: messages.noSkinSitePlayersTitle,
)
}}
</h1>
<p class="text-lg m-0">
{{
formatMessage(
skinSiteUser
? skinSitePlayersStatus === 'checking' || skinSitePlayersStatus === 'idle'
!skinSiteUser
? messages.signInDescription
: skinSitePlayersStatus === 'error'
? messages.errorSkinSitePlayersDescription
: skinSitePlayersStatus === 'checking' || skinSitePlayersStatus === 'idle'
? messages.loadingSkinSitePlayersDescription
: messages.noSkinSitePlayersDescription
: messages.signInDescription,
: messages.noSkinSitePlayersDescription,
)
}}
</p>
@@ -1462,6 +1510,11 @@ await loadSkins()
"
class="h-8 w-8 animate-spin text-brand"
/>
<ButtonStyled v-if="skinSiteUser && skinSitePlayersStatus === 'error'" color="brand">
<button @click="retrySkinSitePlayers">
{{ formatMessage(messages.retryButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-if="!offline && !skinSiteUser" color="brand">
<button @click="loginToSkinSite">
<LogInIcon />