@@ -26,17 +26,32 @@
|
|||||||
<template v-else>
|
<template v-else>
|
||||||
<view v-if="stage === 'hall' && filteredHalls.length" class="hall-list">
|
<view v-if="stage === 'hall' && filteredHalls.length" class="hall-list">
|
||||||
<view
|
<view
|
||||||
v-for="hall in filteredHalls"
|
v-for="(hall, index) in filteredHalls"
|
||||||
:key="hall.id"
|
:key="hall.id"
|
||||||
class="hall-card"
|
class="hall-card"
|
||||||
@tap="handleHallClick(hall.id)"
|
@tap="handleHallClick(hall.id)"
|
||||||
>
|
>
|
||||||
<image
|
<view
|
||||||
v-if="hallPreviewUrl(hall)"
|
v-if="hallPreviewUrl(hall)"
|
||||||
class="hall-thumb"
|
class="hall-thumb hall-thumb-shell"
|
||||||
:src="hallPreviewUrl(hall)"
|
:class="{
|
||||||
mode="aspectFill"
|
'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">
|
<view v-else class="hall-thumb placeholder">
|
||||||
<text class="hall-thumb-text">{{ hallIconText(hall.name) }}</text>
|
<text class="hall-thumb-text">{{ hallIconText(hall.name) }}</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -202,6 +217,9 @@ const emit = defineEmits<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
const HALL_PREVIEW_BASE = '/static/explain/hall-previews'
|
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 failedUnitPreviewIds = ref(new Set<string>())
|
||||||
|
|
||||||
const hallPreviewMap: Record<string, string> = {
|
const hallPreviewMap: Record<string, string> = {
|
||||||
@@ -249,6 +267,30 @@ const hallPreviewUrl = (hall: ExplainHallSelectItem) => {
|
|||||||
|
|
||||||
const hallIconText = (name: string) => name.trim().slice(0, 1) || '讲'
|
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) => (
|
const unitPreviewImageUrl = (unit: ExplainBusinessUnitSelectItem) => (
|
||||||
failedUnitPreviewIds.value.has(unit.id)
|
failedUnitPreviewIds.value.has(unit.id)
|
||||||
? EXPLAIN_UNIT_PREVIEW_FALLBACK
|
? EXPLAIN_UNIT_PREVIEW_FALLBACK
|
||||||
@@ -408,13 +450,52 @@ const handleBack = () => {
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: 68px;
|
width: 68px;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
border-radius: 8px;
|
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);
|
border: 1px solid rgba(36, 49, 42, 0.06);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
object-fit: contain;
|
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 {
|
.hall-thumb.placeholder {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user