feat: refine guide explain UX and QA docs

This commit is contained in:
lyf
2026-06-12 17:20:39 +08:00
parent 2055b13b90
commit a7c1879f60
27 changed files with 2831 additions and 1362 deletions

View File

@@ -1,26 +1,50 @@
<template>
<view class="exhibit-card" @tap="handleClick">
<image v-if="exhibit.image" class="exhibit-image" :src="exhibit.image" mode="aspectFill" />
<image
v-if="coverImage"
class="exhibit-image"
:src="coverImage"
mode="aspectFill"
/>
<view v-else class="exhibit-image placeholder">
<text class="placeholder-text"></text>
</view>
<view class="exhibit-content">
<text class="exhibit-name">{{ exhibit.name }}</text>
<text v-if="exhibit.artist" class="exhibit-artist">{{ exhibit.artist }}</text>
<view v-if="exhibit.hall" class="exhibit-meta">
<text class="meta-text">📍 {{ exhibit.hall }}</text>
<text class="exhibit-name">{{ title }}</text>
<text v-if="subtitle" class="exhibit-subtitle">{{ subtitle }}</text>
<view class="exhibit-meta">
<svg class="meta-icon" width="14" height="14" viewBox="0 0 24 24" fill="none">
<path d="M12 21C12 21 18 14.9 18 9.8C18 6.5 15.3 4 12 4C8.7 4 6 6.5 6 9.8C6 14.9 12 21 12 21Z" stroke="currentColor" stroke-width="1.8"/>
<circle cx="12" cy="10" r="2.2" stroke="currentColor" stroke-width="1.8"/>
</svg>
<text class="meta-text">{{ metaText }}</text>
</view>
</view>
<view v-if="exhibit.hasAudio" class="audio-badge">
<text class="audio-icon">🎧</text>
<view class="audio-badge" :class="`status-${audioStatus}`">
<text class="audio-text">{{ audioStatusText }}</text>
</view>
</view>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type {
ExplainAudioStatus
} from '@/view-models/explainViewModels'
interface Exhibit {
id: string
name: string
artist?: string
title?: string
name?: string
subtitle?: string
hall?: string
hallName?: string
floor?: string
floorLabel?: string
coverImage?: string
image?: string
audioStatus?: ExplainAudioStatus
audioStatusText?: string
hasAudio?: boolean
}
@@ -32,6 +56,18 @@ const emit = defineEmits<{
click: [exhibit: Exhibit]
}>()
const title = computed(() => props.exhibit.title || props.exhibit.name || '讲解内容')
const subtitle = computed(() => props.exhibit.subtitle || props.exhibit.hall || props.exhibit.hallName)
const coverImage = computed(() => props.exhibit.coverImage || props.exhibit.image)
const audioStatus = computed<ExplainAudioStatus>(() => (
props.exhibit.audioStatus || (props.exhibit.hasAudio ? 'playable' : 'unavailable')
))
const audioStatusText = computed(() => props.exhibit.audioStatusText || (audioStatus.value === 'playable' ? '音频' : '图文'))
const metaText = computed(() => [
props.exhibit.floorLabel || props.exhibit.floor,
audioStatusText.value
].filter(Boolean).join(' · '))
const handleClick = () => {
emit('click', props.exhibit)
}
@@ -40,12 +76,16 @@ const handleClick = () => {
<style scoped lang="scss">
.exhibit-card {
position: relative;
display: flex;
min-height: 104px;
padding: 10px;
box-sizing: border-box;
background-color: var(--museum-bg-surface);
border-radius: var(--radius-card);
border: 1px solid #ebece5;
border-radius: 8px;
overflow: hidden;
box-shadow: var(--shadow-sm);
cursor: pointer;
transition: all 0.3s;
transition: all 0.2s;
}
.exhibit-card:active {
@@ -53,33 +93,59 @@ const handleClick = () => {
}
.exhibit-image {
width: 100%;
height: 160px;
flex-shrink: 0;
width: 76px;
height: 84px;
border-radius: 8px;
background-color: var(--museum-bg-light);
}
.exhibit-image.placeholder {
display: flex;
align-items: center;
justify-content: center;
background: #eef1e8;
}
.placeholder-text {
font-size: 18px;
font-weight: 700;
color: #68725d;
}
.exhibit-content {
padding: var(--space-md);
flex: 1;
min-width: 0;
padding-left: 10px;
}
.exhibit-name {
font-size: 15px;
font-weight: 600;
line-height: 21px;
font-weight: 700;
color: var(--museum-text-primary);
margin-bottom: var(--space-xs);
display: block;
}
.exhibit-artist {
font-size: 13px;
.exhibit-subtitle {
margin-top: 4px;
font-size: 12px;
line-height: 17px;
color: var(--museum-text-secondary);
margin-bottom: var(--space-sm);
display: block;
}
.exhibit-meta {
margin-top: 10px;
display: flex;
align-items: center;
min-width: 0;
}
.meta-icon {
flex-shrink: 0;
color: #68725d;
margin-right: 4px;
}
.meta-text {
@@ -89,19 +155,30 @@ const handleClick = () => {
.audio-badge {
position: absolute;
top: 8px;
right: 8px;
width: 32px;
height: 32px;
background-color: var(--museum-accent);
border-radius: 50%;
right: 10px;
bottom: 10px;
min-width: 44px;
height: 24px;
padding: 0 8px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: var(--shadow-sm);
box-sizing: border-box;
background-color: #eef1e8;
border-radius: 6px;
}
.audio-icon {
font-size: 16px;
.audio-badge.status-playable {
background-color: var(--museum-accent);
}
.audio-text {
font-size: 11px;
color: #4f574b;
}
.audio-badge.status-playable .audio-text {
color: #151713;
font-weight: 600;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -117,7 +117,7 @@ const emit = defineEmits<{
// POI ID: 7043042949572197975
const mapCenter = ref<MapCenter>({
latitude: 22.692763, // 深圳自然博物馆纬度
longitude: 114.363987 // 深圳自然博物馆经度(向右偏移,让建筑显示在左侧
longitude: 114.363572 // 深圳自然博物馆经度(调整到室外 2D 视觉中心
})
// 地图缩放级别(调整为适中比例,既能看到建筑全貌又能看清细节)