perf(dashboard): restore media cards from snapshots (#573)

This commit is contained in:
InfinityPacer
2026-07-22 17:55:54 +08:00
committed by GitHub
parent 4405a69d59
commit 103472404f
9 changed files with 637 additions and 81 deletions
+2 -2
View File
@@ -105,6 +105,7 @@ async function goPlay() {
>
<VImg
:src="imageUrl"
crossorigin="anonymous"
class="playing-card__image"
:class="{ 'playing-card__image--loaded': imageLoaded }"
cover
@@ -216,8 +217,7 @@ async function goPlay() {
}
.playing-card__bottom-scrim {
background:
linear-gradient(180deg, rgba(2, 6, 12, 0%) 24%, rgba(2, 6, 12, 72%) 68%, rgba(2, 6, 12, 96%) 100%);
background: linear-gradient(180deg, rgba(2, 6, 12, 0%) 24%, rgba(2, 6, 12, 72%) 68%, rgba(2, 6, 12, 96%) 100%);
}
.playing-card__percent,
+39 -38
View File
@@ -37,7 +37,7 @@ const getImgUrl = computed(() => {
let url = `${import.meta.env.VITE_API_BASE_URL}system/img/0?imgurl=${encodeURIComponent(image)}`
const use_cookies = props.media?.use_cookies
if (use_cookies) {
url += `&use_cookies=${encodeURIComponent(use_cookies)}`
url += `&use_cookies=${encodeURIComponent(use_cookies)}`
}
return url
})
@@ -63,43 +63,44 @@ async function goPlay(isHovering: boolean | null = false) {
'ring-1': isImageLoaded,
}"
>
<VImg
aspect-ratio="2/3"
:src="getImgUrl"
class="poster-card-image object-cover aspect-w-2 aspect-h-3"
:class="{ 'poster-card-image--loaded': isImageLoaded }"
cover
@load="isImageLoaded = true"
@error="imageLoadError = true"
>
<template #placeholder>
<div class="w-full h-full">
<VSkeletonLoader class="object-cover aspect-w-2 aspect-h-3" />
</div>
</template>
</VImg>
<!-- 类型角标 -->
<VChip
v-show="isImageLoaded"
variant="elevated"
size="small"
:class="getChipColor(props.media?.type || '')"
class="poster-card-chip absolute left-2 top-2 bg-opacity-80 text-white font-bold"
>
{{ props.media?.type }}
</VChip>
<!-- 详情 -->
<VCardText
v-show="hover.isHovering || imageLoadError"
class="w-full h-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 cursor-pointer pa-2 pb-5"
style="background: linear-gradient(rgba(45, 55, 72, 40%) 0%, rgba(45, 55, 72, 90%) 100%)"
@click.stop="goPlay(hover.isHovering)"
>
<span class="font-semibold text-sm">{{ props.media?.subtitle }}</span>
<h1 class="mb-1 text-white font-bold text-lg line-clamp-2 overflow-hidden text-ellipsis ...">
{{ props.media?.title }}
</h1>
</VCardText>
<VImg
aspect-ratio="2/3"
:src="getImgUrl"
crossorigin="anonymous"
class="poster-card-image object-cover aspect-w-2 aspect-h-3"
:class="{ 'poster-card-image--loaded': isImageLoaded }"
cover
@load="isImageLoaded = true"
@error="imageLoadError = true"
>
<template #placeholder>
<div class="w-full h-full">
<VSkeletonLoader class="object-cover aspect-w-2 aspect-h-3" />
</div>
</template>
</VImg>
<!-- 类型角标 -->
<VChip
v-show="isImageLoaded"
variant="elevated"
size="small"
:class="getChipColor(props.media?.type || '')"
class="poster-card-chip absolute left-2 top-2 bg-opacity-80 text-white font-bold"
>
{{ props.media?.type }}
</VChip>
<!-- 详情 -->
<VCardText
v-show="hover.isHovering || imageLoadError"
class="w-full h-full flex flex-col flex-wrap justify-end align-left text-white absolute bottom-0 cursor-pointer pa-2 pb-5"
style="background: linear-gradient(rgba(45, 55, 72, 40%) 0%, rgba(45, 55, 72, 90%) 100%)"
@click.stop="goPlay(hover.isHovering)"
>
<span class="font-semibold text-sm">{{ props.media?.subtitle }}</span>
<h1 class="mb-1 text-white font-bold text-lg line-clamp-2 overflow-hidden text-ellipsis ...">
{{ props.media?.title }}
</h1>
</VCardText>
</VCard>
</div>
</template>
@@ -0,0 +1,39 @@
import type { MediaServerPlayItem } from '@/api/types'
import PlayingBackdropCard from '@/components/cards/PlayingBackdropCard.vue'
import PosterCard from '@/components/cards/PosterCard.vue'
import { renderWithProviders } from '@tests/support/render'
import { defineComponent, h } from 'vue'
import { describe, expect, it, vi } from 'vitest'
vi.mock('@/utils/appDeepLink', () => ({
openMediaServerItem: vi.fn(),
}))
const media: MediaServerPlayItem = {
id: 'media-1',
image: 'https://media.example.com/poster.jpg',
title: 'Test media',
}
const VImgStub = defineComponent({
inheritAttrs: false,
props: {
crossorigin: String,
src: String,
},
setup: props => () => h('img', { crossorigin: props.crossorigin, src: props.src }),
})
describe.each([
['PosterCard', PosterCard],
['PlayingBackdropCard', PlayingBackdropCard],
])('%s image request mode', (_name, component) => {
it('loads the media server image anonymously', async () => {
const { container } = await renderWithProviders(component, {
global: { stubs: { VImg: VImgStub } },
props: { media },
})
expect(container.querySelector('img')).toHaveAttribute('crossorigin', 'anonymous')
})
})