@@ -26,17 +26,32 @@
|
||||
<template v-else>
|
||||
<view v-if="stage === 'hall' && filteredHalls.length" class="hall-list">
|
||||
<view
|
||||
v-for="hall in filteredHalls"
|
||||
v-for="(hall, index) in filteredHalls"
|
||||
:key="hall.id"
|
||||
class="hall-card"
|
||||
@tap="handleHallClick(hall.id)"
|
||||
>
|
||||
<image
|
||||
<view
|
||||
v-if="hallPreviewUrl(hall)"
|
||||
class="hall-thumb"
|
||||
:src="hallPreviewUrl(hall)"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
class="hall-thumb hall-thumb-shell"
|
||||
:class="{
|
||||
'is-image-loaded': isHallPreviewLoaded(hall.id),
|
||||
'is-image-error': isHallPreviewError(hall.id)
|
||||
}"
|
||||
>
|
||||
<view class="hall-thumb-fallback">
|
||||
<text class="hall-thumb-text">{{ hallIconText(hall.name) }}</text>
|
||||
</view>
|
||||
<image
|
||||
v-if="!isHallPreviewError(hall.id)"
|
||||
class="hall-thumb-image"
|
||||
:src="hallPreviewUrl(hall)"
|
||||
mode="aspectFill"
|
||||
:lazy-load="isHallPreviewLazy(index)"
|
||||
@load="handleHallPreviewLoad(hall.id)"
|
||||
@error="handleHallPreviewError(hall.id)"
|
||||
/>
|
||||
</view>
|
||||
<view v-else class="hall-thumb placeholder">
|
||||
<text class="hall-thumb-text">{{ hallIconText(hall.name) }}</text>
|
||||
</view>
|
||||
@@ -202,6 +217,9 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const HALL_PREVIEW_BASE = '/static/explain/hall-previews'
|
||||
const HALL_PREVIEW_EAGER_COUNT = 4
|
||||
const loadedHallPreviewIds = ref(new Set<string>())
|
||||
const failedHallPreviewIds = ref(new Set<string>())
|
||||
const failedUnitPreviewIds = ref(new Set<string>())
|
||||
|
||||
const hallPreviewMap: Record<string, string> = {
|
||||
@@ -249,6 +267,30 @@ const hallPreviewUrl = (hall: ExplainHallSelectItem) => {
|
||||
|
||||
const hallIconText = (name: string) => name.trim().slice(0, 1) || '讲'
|
||||
|
||||
const isHallPreviewLoaded = (hallId: string) => loadedHallPreviewIds.value.has(hallId)
|
||||
|
||||
const isHallPreviewError = (hallId: string) => failedHallPreviewIds.value.has(hallId)
|
||||
|
||||
const isHallPreviewLazy = (index: number) => index >= HALL_PREVIEW_EAGER_COUNT
|
||||
|
||||
const handleHallPreviewLoad = (hallId: string) => {
|
||||
loadedHallPreviewIds.value = new Set([...loadedHallPreviewIds.value, hallId])
|
||||
if (failedHallPreviewIds.value.has(hallId)) {
|
||||
const nextFailedIds = new Set(failedHallPreviewIds.value)
|
||||
nextFailedIds.delete(hallId)
|
||||
failedHallPreviewIds.value = nextFailedIds
|
||||
}
|
||||
}
|
||||
|
||||
const handleHallPreviewError = (hallId: string) => {
|
||||
failedHallPreviewIds.value = new Set([...failedHallPreviewIds.value, hallId])
|
||||
if (loadedHallPreviewIds.value.has(hallId)) {
|
||||
const nextLoadedIds = new Set(loadedHallPreviewIds.value)
|
||||
nextLoadedIds.delete(hallId)
|
||||
loadedHallPreviewIds.value = nextLoadedIds
|
||||
}
|
||||
}
|
||||
|
||||
const unitPreviewImageUrl = (unit: ExplainBusinessUnitSelectItem) => (
|
||||
failedUnitPreviewIds.value.has(unit.id)
|
||||
? EXPLAIN_UNIT_PREVIEW_FALLBACK
|
||||
@@ -408,13 +450,52 @@ const handleBack = () => {
|
||||
flex-shrink: 0;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
background: #ffffff;
|
||||
background:
|
||||
radial-gradient(circle at 70% 24%, rgba(224, 225, 0, 0.28), rgba(224, 225, 0, 0) 42%),
|
||||
linear-gradient(135deg, #f4f6ed 0%, #e4eadc 100%);
|
||||
border: 1px solid rgba(36, 49, 42, 0.06);
|
||||
box-sizing: border-box;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.hall-thumb-shell.is-image-loaded {
|
||||
background: #eef0e4;
|
||||
}
|
||||
|
||||
.hall-thumb-fallback {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.hall-thumb-shell.is-image-loaded .hall-thumb-fallback {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hall-thumb-shell.is-image-error .hall-thumb-fallback {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hall-thumb-image {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.22s ease;
|
||||
}
|
||||
|
||||
.hall-thumb-shell.is-image-loaded .hall-thumb-image {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hall-thumb.placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user