提交H5业务闭环修复代码
This commit is contained in:
@@ -52,14 +52,14 @@ export class ExplainUseCase {
|
||||
) {}
|
||||
|
||||
private applyTrackAudioState(exhibit: MuseumExhibit, track?: ExplainTrack | null): MuseumExhibit {
|
||||
const hasExhibitAudio = exhibit.audioAvailable === true || Boolean(exhibit.audioUrl)
|
||||
const hasTrackAudio = track?.available === true
|
||||
const hasPlayableAudioUrl = Boolean(exhibit.audioUrl?.trim())
|
||||
const hasTrackTarget = Boolean(track?.playTargetType || track?.playTargetId)
|
||||
|
||||
if (!hasExhibitAudio && !hasTrackAudio) return exhibit
|
||||
if (!hasPlayableAudioUrl && !hasTrackTarget) return exhibit
|
||||
|
||||
return {
|
||||
...exhibit,
|
||||
audioAvailable: true,
|
||||
audioAvailable: hasPlayableAudioUrl,
|
||||
playTargetType: track?.playTargetType || exhibit.playTargetType,
|
||||
playTargetId: track?.playTargetId || exhibit.playTargetId
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type {
|
||||
GuideDataIntegrityReport,
|
||||
GuideFloorDetail,
|
||||
GuideLocationResolution,
|
||||
GuideRouteReadiness,
|
||||
GuideLocationPreviewPlan,
|
||||
GuideMapDiagnostics,
|
||||
@@ -42,6 +43,21 @@ const formatStartStepText = (startLocation: GuideStartLocation) => {
|
||||
return `起点:${startLocation.label}${floorSuffix}${sourceSuffix}`
|
||||
}
|
||||
|
||||
const normalizeLocationText = (value: string) => value
|
||||
.trim()
|
||||
.replace(/[\s()()【】[\]_-]/g, '')
|
||||
.toLowerCase()
|
||||
|
||||
const isHallLikePoi = (poi: MuseumPoi) => (
|
||||
poi.kind === 'hall'
|
||||
|| poi.primaryCategory.id === 'exhibition_hall'
|
||||
|| poi.primaryCategory.id === 'touring_poi'
|
||||
)
|
||||
|
||||
const uniqueStrings = (values: Array<string | undefined>) => Array.from(new Set(
|
||||
values.map((value) => value?.trim()).filter(Boolean) as string[]
|
||||
))
|
||||
|
||||
const createPreviewSteps = (
|
||||
poi: MuseumPoi | null,
|
||||
startLocation: GuideStartLocation | null,
|
||||
@@ -74,6 +90,14 @@ const createPreviewSteps = (
|
||||
]
|
||||
}
|
||||
|
||||
export interface GuideContentLocationRequest {
|
||||
directPoiId?: string
|
||||
location?: GuideLocationResolution | null
|
||||
hallId?: string
|
||||
hallName?: string
|
||||
targetName?: string
|
||||
}
|
||||
|
||||
export class GuideUseCase {
|
||||
private routeReadinessCache: GuideRouteReadiness | null = null
|
||||
|
||||
@@ -119,6 +143,71 @@ export class GuideUseCase {
|
||||
return this.guide.getPoiById(id)
|
||||
}
|
||||
|
||||
private async getPoiByIdIfResolvable(id: string, requireHall = false) {
|
||||
const poi = await this.guide.getPoiById(id)
|
||||
if (!poi) return null
|
||||
if (requireHall && !isHallLikePoi(poi)) return null
|
||||
return poi
|
||||
}
|
||||
|
||||
private async searchBestPoiByName(name: string, requireHall = false) {
|
||||
const normalizedTarget = normalizeLocationText(name)
|
||||
if (!normalizedTarget) return null
|
||||
|
||||
const candidates = await this.guide.searchPois(name)
|
||||
const allowedCandidates = requireHall
|
||||
? candidates.filter(isHallLikePoi)
|
||||
: candidates
|
||||
|
||||
return allowedCandidates.find((candidate) => {
|
||||
const candidateName = normalizeLocationText(candidate.name)
|
||||
const candidateHallName = normalizeLocationText(candidate.hallName || '')
|
||||
return candidateName === normalizedTarget
|
||||
|| candidateHallName === normalizedTarget
|
||||
|| candidateName.includes(normalizedTarget)
|
||||
|| normalizedTarget.includes(candidateName)
|
||||
|| candidateHallName.includes(normalizedTarget)
|
||||
|| normalizedTarget.includes(candidateHallName)
|
||||
}) || allowedCandidates[0] || null
|
||||
}
|
||||
|
||||
async resolveContentLocationPreviewTarget(request: GuideContentLocationRequest) {
|
||||
const exactLocationPoiId = request.location?.status === 'exact'
|
||||
? request.location.poiId
|
||||
: undefined
|
||||
const directIds = uniqueStrings([exactLocationPoiId, request.directPoiId])
|
||||
for (const poiId of directIds) {
|
||||
const poi = await this.getPoiByIdIfResolvable(poiId)
|
||||
if (poi) return poi
|
||||
}
|
||||
|
||||
const bridgedIds = uniqueStrings([request.location?.poiId])
|
||||
for (const poiId of bridgedIds) {
|
||||
const poi = await this.getPoiByIdIfResolvable(poiId)
|
||||
if (poi) return poi
|
||||
}
|
||||
|
||||
const hallIds = uniqueStrings([request.hallId])
|
||||
for (const hallId of hallIds) {
|
||||
const poi = await this.getPoiByIdIfResolvable(hallId, true)
|
||||
if (poi) return poi
|
||||
}
|
||||
|
||||
const hallNames = uniqueStrings([request.hallName])
|
||||
for (const hallName of hallNames) {
|
||||
const poi = await this.searchBestPoiByName(hallName, true)
|
||||
if (poi) return poi
|
||||
}
|
||||
|
||||
const targetNames = uniqueStrings([request.targetName])
|
||||
for (const targetName of targetNames) {
|
||||
const poi = await this.searchBestPoiByName(targetName)
|
||||
if (poi) return poi
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
getFloorDetail(floorId: string): Promise<GuideFloorDetail | null> {
|
||||
return this.guide.getFloorDetail
|
||||
? this.guide.getFloorDetail(floorId)
|
||||
|
||||
Reference in New Issue
Block a user