修复讲解业务 API 数据源配置

This commit is contained in:
lyf
2026-07-07 18:05:42 +08:00
parent eaec80bdc3
commit 349f9b03e5
9 changed files with 140 additions and 20 deletions

View File

@@ -71,7 +71,16 @@
<view class="content-section">
<text class="section-title">讲解内容</text>
<text class="section-text">{{ exhibit.body || exhibit.summary }}</text>
<text class="section-text">{{ detailBodyText }}</text>
<view
v-if="isTextLoadActionVisible"
class="text-load-btn"
:class="{ disabled: detailTextLoading }"
@tap="handleLoadDetailText"
>
<text class="text-load-btn-text">{{ detailTextLoading ? '正在加载' : '查看图文讲解' }}</text>
</view>
<text v-if="detailTextUnavailableMessage" class="section-hint">{{ detailTextUnavailableMessage }}</text>
</view>
<view v-if="visibleLinkedExhibits.length" class="content-section">
@@ -192,6 +201,9 @@ const resolvedHallId = ref('')
const retryingAudio = ref(false)
const selectedAudioLanguage = ref<AudioLanguage>('zh-CN')
const languageLoading = ref(false)
const detailTextLoaded = ref(false)
const detailTextLoading = ref(false)
const detailTextUnavailableMessage = ref('')
const detailEntryRequest = ref<{
exhibitId: string
targetType?: AudioPlayTargetType
@@ -227,6 +239,16 @@ const visibleLanguageOptions = computed(() => (
languageOptions.filter((option) => supportedDetailLanguages.value.has(option.value))
))
const isLanguageSwitchVisible = computed(() => visibleLanguageOptions.value.length > 1)
const isTextLoadActionVisible = computed(() => (
exhibit.value.audio.hasText === true
&& !detailTextLoaded.value
&& !detailTextUnavailableMessage.value
))
const detailBodyText = computed(() => (
detailTextLoaded.value
? exhibit.value.body || exhibit.value.summary
: exhibit.value.summary
))
// 讲解详情页只定位到所属展厅,不再追踪具体展品点位。
const resolveHallGuidePoi = async () => {
@@ -258,6 +280,8 @@ const loadExplainDetail = async (
exhibit.value = toExplainDetailPageViewModel(exhibitData)
selectedAudioLanguage.value = lang
detailTextLoaded.value = Boolean(exhibitData.audioText)
detailTextUnavailableMessage.value = ''
if (exhibitData.hallId) {
resolvedHallId.value = exhibitData.hallId
@@ -329,6 +353,44 @@ const handleLanguageSwitch = async (lang: AudioLanguage) => {
}
}
const handleLoadDetailText = async () => {
if (detailTextLoading.value || detailTextLoaded.value) return
detailTextLoading.value = true
detailTextUnavailableMessage.value = ''
try {
const selection = await explainUseCase.loadExplainDetailText({
id: exhibit.value.id,
name: exhibit.value.title,
hallId: exhibit.value.hallId,
hallName: exhibit.value.hallName,
floorId: exhibit.value.floorId,
floorLabel: exhibit.value.floorLabel,
image: heroImage.value,
description: exhibit.value.summary,
guideText: exhibit.value.summary,
audioLanguage: exhibit.value.audio.language,
audioHasText: exhibit.value.audio.hasText,
playTargetType: exhibit.value.audio.playTargetType,
playTargetId: exhibit.value.audio.playTargetId
})
if (selection.available) {
exhibit.value = toExplainDetailPageViewModel(selection.exhibit)
detailTextLoaded.value = true
return
}
detailTextUnavailableMessage.value = selection.unavailableMessage || '当前语言暂无讲解词'
} catch (error) {
console.error('讲解正文加载失败:', error)
detailTextUnavailableMessage.value = '讲解词服务暂不可用,请稍后重试'
} finally {
detailTextLoading.value = false
}
}
const handlePlayAudio = async () => {
const selection = exhibit.value.id
? await explainUseCase.selectAudioForExplainDetail({
@@ -733,6 +795,43 @@ const handleBack = () => {
white-space: pre-line;
}
.text-load-btn {
width: 100%;
height: 44px;
margin-top: 14px;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
background: #151713;
border-radius: 8px;
color: #e0df00;
}
.text-load-btn.disabled {
opacity: 0.62;
}
.text-load-btn-text {
display: block;
max-width: 100%;
font-size: 15px;
line-height: 21px;
font-weight: 800;
color: currentColor;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.section-hint {
display: block;
margin-top: 12px;
font-size: 14px;
line-height: 20px;
color: #68725d;
}
.linked-exhibit-list {
margin-top: 14px;
display: flex;

View File

@@ -114,7 +114,9 @@ const explainGuideStopItems = computed<ExplainGuideStopSelectItem[]>(() => (
description: stop.description,
hasAudio: stop.hasAudio,
audioStatus: stop.audioStatus,
guideLevel: stop.guideLevel
guideLevel: stop.guideLevel,
playTargetType: stop.playTargetType,
playTargetId: stop.playTargetId
})) || []
))
@@ -191,10 +193,15 @@ const handleExplainBusinessUnitClick = (unitId: string) => {
explainStage.value = 'stop'
}
const handleExplainGuideStopClick = (stopId: string) => {
const target = normalizeExplainDetailTargetFromGuideStop({ id: stopId })
const handleExplainGuideStopClick = (stop: ExplainGuideStopSelectItem) => {
const target = stop.playTargetType && stop.playTargetId
? {
targetType: stop.playTargetType,
targetId: stop.playTargetId
}
: normalizeExplainDetailTargetFromGuideStop({ id: stop.id })
const params = new URLSearchParams({
id: target.targetId,
id: stop.id,
tab: 'explain',
targetType: target.targetType,
targetId: target.targetId

View File

@@ -730,7 +730,9 @@ const explainGuideStopItems = computed<ExplainGuideStopSelectItem[]>(() => (
description: stop.description,
hasAudio: stop.hasAudio,
audioStatus: stop.audioStatus,
guideLevel: stop.guideLevel
guideLevel: stop.guideLevel,
playTargetType: stop.playTargetType,
playTargetId: stop.playTargetId
})) || []
))
@@ -1551,10 +1553,15 @@ const handleExplainBusinessUnitClick = (unitId: string) => {
explainStage.value = 'stop'
}
const handleExplainGuideStopClick = (stopId: string) => {
const target = normalizeExplainDetailTargetFromGuideStop({ id: stopId })
const handleExplainGuideStopClick = (stop: ExplainGuideStopSelectItem) => {
const target = stop.playTargetType && stop.playTargetId
? {
targetType: stop.playTargetType,
targetId: stop.playTargetId
}
: normalizeExplainDetailTargetFromGuideStop({ id: stop.id })
const params = new URLSearchParams({
id: target.targetId,
id: stop.id,
tab: 'explain',
targetType: target.targetType,
targetId: target.targetId