修复搜索与点位定位闭环
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-12 03:07:49 +08:00
parent e006333c0a
commit d8420fc7c2
18 changed files with 2961 additions and 621 deletions

View File

@@ -28,6 +28,8 @@
:indoor-view="indoorView"
:layer-mode="indoorLayerMode"
:active-floor="activeGuideFloor"
:visible-poi-ids="searchVisiblePoiIds"
:target-focus-request="searchTargetFocusRequest"
layer-mode-toggle-top="154px"
floor-bottom="193px"
floor-max-height="206px"
@@ -162,17 +164,20 @@
></view>
<view
v-if="showGuideHomeDock"
v-show="showGuideHomeDock"
class="guide-home-dock"
:class="{ expanded: homeSearchExpanded }"
@mousedown.capture="handleHomeDockActivate"
@click.capture="handleHomeDockActivate"
@tap.capture="handleHomeDockActivate"
>
<PoiSearchPanel
ref="homeSearchPanelRef"
variant="home"
:current-floor-id="activeGuideFloor"
:current-floor-label="getGuideFloorLabel(activeGuideFloor)"
@expanded-change="handleHomeSearchExpandedChange"
@category-mode-change="handleHomeCategoryModeChange"
@results-change="handleHomeSearchResultsChange"
@result-tap="handleHomeSearchResultTap"
@cancel="handleHomeSearchCancel"
/>
</view>
@@ -299,8 +304,8 @@
</template>
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import GuideMapShell from '@/components/navigation/GuideMapShell.vue'
import RoutePlannerPanel from '@/components/navigation/RoutePlannerPanel.vue'
@@ -326,12 +331,17 @@ import {
import {
explainUseCase
} from '@/usecases/explainUseCase'
import {
normalizeExplainDetailTargetFromGuideStop
} from '@/domain/explainDetailTarget'
import type {
GuideRenderPoi
} from '@/domain/guideModel'
import type {
PoiCategoryResultState,
PoiSearchContext
} from '@/domain/poiSearch'
import {
toTargetFocusRequestViewModel,
type TargetPoiFocusRequestViewModel
} from '@/view-models/guideViewModels'
import {
ARRIVAL_TARGETS_BY_TYPE,
type ArrivalSearchTarget,
@@ -341,7 +351,8 @@ import type {
GuideRouteResult,
GuideRouteTarget,
MuseumFloor,
MuseumHall
MuseumHall,
MuseumPoi
} from '@/domain/museum'
type GuideIndoorView = 'overview' | 'floor' | 'multi'
@@ -424,10 +435,15 @@ const guideMapShellRef = ref<{
showOverview?: () => Promise<void> | void
} | null>(null)
const homeSearchPanelRef = ref<{
expandHomePanel?: () => void
collapseHomePanel?: () => void
resetSearchState?: () => void
restoreResultListScroll?: () => Promise<void>
} | null>(null)
const homeSearchExpanded = ref(false)
const homeCategoryModeActive = ref(false)
const searchVisiblePoiIds = ref<string[] | null>(null)
const searchTargetFocusRequest = ref<TargetPoiFocusRequestViewModel | null>(null)
let searchTargetFocusRequestId = 0
let launchOverlayFallbackTimer: ReturnType<typeof setTimeout> | null = null
let launchOverlayFadeTimer: ReturnType<typeof setTimeout> | null = null
@@ -732,7 +748,7 @@ const selectedGuidePoiIsHall = computed(() => {
})
const selectedGuidePoiCollapsedSubtitle = computed(() => (
selectedGuidePoiIsHall.value ? '已定位展厅 · 点按展开操作' : '已定位点位'
selectedGuidePoiIsHall.value ? '点按展开查看展厅' : selectedGuidePoiSubtitle.value
))
const routeSimulationStepText = computed(() => {
@@ -999,7 +1015,7 @@ const handleGuidePoiClick = (poi: GuideRenderPoi) => {
isSimulatingRoute.value = false
activeGuideFloor.value = poi.floorId
renderedFloorId.value = poi.floorId
showIndoorHint('已在当前楼层标出点位', 3000)
showIndoorHint(`${poi.name} · ${getGuideFloorLabel(poi.floorId)}`, 3000)
}
const handleGuideSelectionClear = () => {
@@ -1390,6 +1406,11 @@ const closeHomeSearchDock = () => {
homeSearchExpanded.value = false
}
onShow(async () => {
await nextTick()
await homeSearchPanelRef.value?.restoreResultListScroll?.()
})
const handleMoreOutdoorNav = () => {
if (showArrivalPanel.value && showArrivalPanelCollapsed.value) {
arrivalPanelRef.value?.expandPanel()
@@ -1417,15 +1438,110 @@ const handleHomeSearchExpandedChange = (expanded: boolean) => {
homeSearchExpanded.value = expanded
}
const handleHomeSearchOutsideTap = () => {
closeHomeSearchDock()
const clearHomeSearchMapState = () => {
homeCategoryModeActive.value = false
searchVisiblePoiIds.value = null
searchTargetFocusRequest.value = null
}
const handleHomeDockActivate = () => {
if (homeSearchExpanded.value) return
const handleHomeCategoryModeChange = (active: boolean) => {
homeCategoryModeActive.value = active
if (!active) {
searchVisiblePoiIds.value = null
return
}
homeSearchPanelRef.value?.expandHomePanel?.()
homeSearchExpanded.value = true
closeArrivalPanel()
showRoutePlanner.value = false
isSimulatingRoute.value = false
selectedGuidePoi.value = null
isPoiCardCollapsed.value = false
is3DMode.value = true
indoorView.value = 'floor'
}
const handleHomeSearchResultsChange = (state: PoiCategoryResultState) => {
if (!state.active) {
searchVisiblePoiIds.value = null
return
}
searchVisiblePoiIds.value = [...state.visiblePoiIds]
if (state.floorId) {
activeGuideFloor.value = state.floorId
}
}
const createSearchDetailUrl = (poi: MuseumPoi, context: PoiSearchContext) => {
const resultCount = homeCategoryModeActive.value
? context.floorResultCount
: context.resultCount
const params = new URLSearchParams({
source: 'search',
searchOrigin: context.origin,
searchKeyword: context.keyword,
searchCategoryId: context.categoryId,
searchFloorId: context.floorId,
searchFloorLabel: context.floorLabel,
resultCount: String(Math.max(1, resultCount)),
floorResultCount: String(context.floorResultCount),
visiblePoiIds: context.visiblePoiIds.join(','),
listScrollTop: String(context.listScrollTop),
id: poi.id,
target: poi.name,
floorId: poi.floorId,
floorLabel: poi.floorLabel
})
return `/pages/facility/detail?${params.toString()}`
}
const handleHomeSearchResultTap = async (poi: MuseumPoi, context: PoiSearchContext) => {
closeArrivalPanel()
showRoutePlanner.value = false
isSimulatingRoute.value = false
selectedGuidePoi.value = null
isPoiCardCollapsed.value = false
is3DMode.value = true
indoorView.value = 'floor'
activeGuideFloor.value = poi.floorId
searchTargetFocusRequestId += 1
searchTargetFocusRequest.value = toTargetFocusRequestViewModel({
poiId: poi.id,
name: poi.name,
floorId: poi.floorId,
floorLabel: poi.floorLabel,
primaryCategoryZh: poi.primaryCategory.label,
positionGltf: poi.positionGltf,
sourceObjectName: poi.sourceObjectName,
kind: poi.kind,
hallId: poi.hallId,
hallName: poi.hallName,
entrances: poi.entrances
}, searchTargetFocusRequestId)
// 先把楼层与目标请求交给地图,再进入详情页;返回时列表组件仍保持原状态。
await nextTick()
uni.navigateTo({
url: createSearchDetailUrl(poi, context),
fail: () => {
uni.showToast({
title: '点位详情打开失败,请重试',
icon: 'none'
})
}
})
}
const handleHomeSearchCancel = () => {
clearHomeSearchMapState()
selectedGuidePoi.value = null
isPoiCardCollapsed.value = false
homeSearchExpanded.value = false
}
const handleHomeSearchOutsideTap = () => {
closeHomeSearchDock()
}
const guideShellMode = computed(() => (is3DMode.value ? '3d' : '2d'))