调整导览讲解为底部主导航

This commit is contained in:
lyf
2026-06-29 20:55:13 +08:00
parent 81b9eac2f7
commit 4c9d480cce
12 changed files with 271 additions and 64 deletions

View File

@@ -0,0 +1,173 @@
<template>
<view class="guide-bottom-nav">
<view class="guide-bottom-nav-inner">
<view
v-for="tab in GUIDE_TOP_TABS"
:key="tab.id"
class="guide-bottom-tab"
:class="[`tab-${tab.id}`, { active: activeTab === tab.id }]"
@tap="handleTabTap(tab.id)"
>
<view class="guide-bottom-icon" aria-hidden="true">
<template v-if="tab.id === 'guide'">
<view class="guide-icon-pin"></view>
<view class="guide-icon-path"></view>
</template>
<template v-else>
<view class="explain-icon-wave top"></view>
<view class="explain-icon-wave middle"></view>
<view class="explain-icon-wave bottom"></view>
</template>
</view>
<text class="guide-bottom-label">{{ tab.label }}</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import {
GUIDE_TOP_TABS,
type GuideTopTab
} from '@/utils/guideTopTabs'
withDefaults(defineProps<{
activeTab?: GuideTopTab
}>(), {
activeTab: 'guide'
})
const emit = defineEmits<{
tabChange: [tab: GuideTopTab]
}>()
const handleTabTap = (tab: GuideTopTab) => {
emit('tabChange', tab)
}
</script>
<style scoped lang="scss">
.guide-bottom-nav {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 8px 14px calc(8px + env(safe-area-inset-bottom));
box-sizing: border-box;
background: rgba(255, 255, 255, 0.96);
border-top: 1px solid #e6e8df;
box-shadow: 0 -10px 24px rgba(36, 49, 42, 0.1);
z-index: 2200;
transform: translateZ(0);
}
.guide-bottom-nav-inner {
height: 56px;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
padding: 4px;
box-sizing: border-box;
background: #f4f5ef;
border: 1px solid #dfe2d9;
border-radius: 8px;
}
.guide-bottom-tab {
min-width: 0;
height: 46px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
box-sizing: border-box;
border-radius: 6px;
color: #515151;
transition: background-color 0.18s ease, color 0.18s ease, transform 0.18s ease;
}
.guide-bottom-tab.active {
background: #000000;
color: var(--museum-accent);
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.14);
}
.guide-bottom-tab:active {
transform: translateY(1px);
}
.guide-bottom-icon {
position: relative;
width: 22px;
height: 22px;
flex: 0 0 22px;
color: currentColor;
}
.guide-icon-pin {
position: absolute;
left: 4px;
top: 1px;
width: 12px;
height: 15px;
box-sizing: border-box;
border: 2px solid currentColor;
border-radius: 8px 8px 8px 0;
transform: rotate(-45deg);
}
.guide-icon-pin::after {
content: '';
position: absolute;
left: 3px;
top: 3px;
width: 3px;
height: 3px;
background: currentColor;
border-radius: 50%;
}
.guide-icon-path {
position: absolute;
left: 1px;
right: 1px;
bottom: 2px;
height: 6px;
border-bottom: 2px solid currentColor;
border-left: 2px solid currentColor;
border-radius: 0 0 0 8px;
}
.explain-icon-wave {
position: absolute;
left: 2px;
right: 2px;
height: 4px;
border: 2px solid currentColor;
border-left: 0;
border-right: 0;
border-bottom: 0;
border-radius: 999px 999px 0 0;
}
.explain-icon-wave.top {
top: 3px;
}
.explain-icon-wave.middle {
top: 9px;
left: 5px;
}
.explain-icon-wave.bottom {
top: 15px;
right: 6px;
}
.guide-bottom-label {
font-size: 15px;
line-height: 20px;
font-weight: 700;
color: currentColor;
}
</style>

View File

@@ -18,6 +18,7 @@
:target-focus-distance-factor="targetFocusDistanceFactor"
:route-preview="routePreview"
:show-route="showRoute"
:disable-auto-exit="disableAutoExit"
:auto-switch-threshold-low="autoSwitchThresholdLow"
:auto-switch-threshold-high="autoSwitchThresholdHigh"
@floor-change="handleThreeFloorChange"
@@ -29,7 +30,7 @@
<!-- #endif -->
<!-- #ifndef H5 -->
<view class="indoor-platform-fallback">
<text class="indoor-platform-title">内三维导览</text>
<text class="indoor-platform-title">内三维导览</text>
<text class="indoor-platform-desc">当前端暂不支持 WebGL 三维展示请在 H5 端查看</text>
</view>
<!-- #endif -->
@@ -81,14 +82,14 @@
:class="{ active: activeMode === '2d' }"
@tap="handleModeChange('2d')"
>
<text class="mode-label">外2D</text>
<text class="mode-label">外2D</text>
</view>
<view
class="mode-option"
:class="{ active: activeMode === '3d' }"
@tap="handleModeChange('3d')"
>
<text class="mode-label">内3D</text>
<text class="mode-label">内3D</text>
</view>
</template>
<template v-else>
@@ -98,14 +99,14 @@
:class="{ active: activeMode === '2d' }"
@tap="handleModeChange('2d')"
>
<text class="mode-label">外2D</text>
<text class="mode-label">外2D</text>
</view>
<view
class="mode-option"
:class="{ active: activeMode === '3d' }"
@tap="handleModeChange('3d')"
>
<text class="mode-label">内3D</text>
<text class="mode-label">内3D</text>
</view>
</view>
<view class="mode-status-chip" :class="`tone-${modeStatusTone}`">
@@ -316,6 +317,7 @@ const props = withDefaults(defineProps<{
targetFocusDistanceFactor?: number
routePreview?: GuideRouteResult | null
showRoute?: boolean
disableAutoExit?: boolean
autoSwitchThresholdLow?: number
autoSwitchThresholdHigh?: number
outdoorNavPolylines?: OutdoorNavPolyline[]
@@ -363,6 +365,7 @@ const props = withDefaults(defineProps<{
targetFocusDistanceFactor: 0.22,
routePreview: null,
showRoute: false,
disableAutoExit: false,
autoSwitchThresholdLow: 1.0,
autoSwitchThresholdHigh: 1.3,
outdoorNavPolylines: () => [] as OutdoorNavPolyline[]
@@ -590,8 +593,7 @@ defineExpose({
position: relative;
z-index: 0;
width: 100%;
height: 100vh;
height: 100dvh;
height: 100%;
overflow: hidden;
background: #ffffff;
color: #000000;

View File

@@ -1,7 +1,7 @@
<template>
<view
class="guide-page-frame"
:class="[`variant-${variant}`, { 'no-top-tabs': !showTopTabs }]"
:class="[`variant-${variant}`, { 'no-top-tabs': !showTopTabs, 'has-bottom-nav': showBottomNav }]"
>
<GuideTopTabs
v-if="showTopTabs"
@@ -32,10 +32,16 @@
<view class="guide-page-frame-body">
<slot></slot>
</view>
<GuideBottomNav
v-if="showBottomNav"
:active-tab="activeTab"
@tab-change="handleTabChange"
/>
</view>
</template>
<script setup lang="ts">
import GuideBottomNav from '@/components/navigation/GuideBottomNav.vue'
import GuideTopTabs from '@/components/navigation/GuideTopTabs.vue'
import type { GuideTopTab } from '@/utils/guideTopTabs'
@@ -45,6 +51,7 @@ withDefaults(defineProps<{
topTabsVariant?: 'underline' | 'segmented'
topTabsTop?: string
showTopTabs?: boolean
showBottomNav?: boolean
showBack?: boolean
showCancel?: boolean
backLabel?: string
@@ -55,6 +62,7 @@ withDefaults(defineProps<{
topTabsVariant: 'underline',
topTabsTop: '0',
showTopTabs: true,
showBottomNav: false,
showBack: false,
showCancel: false,
backLabel: '返回',

View File

@@ -14,7 +14,7 @@
<view v-if="isCollapsed" class="panel-collapsed" @tap="expandPanel">
<view class="panel-collapsed-copy">
<text class="panel-title">外导览</text>
<text class="panel-title">外导览</text>
<text class="panel-summary">{{ collapsedSummary }}</text>
</view>
<view class="panel-expand">
@@ -25,7 +25,7 @@
<template v-else>
<view class="panel-header">
<view class="panel-title-group">
<text class="panel-title">外导览</text>
<text class="panel-title">外导览</text>
<text v-if="routeSummary" class="panel-summary">{{ routeSummary }}</text>
</view>
<view class="panel-actions">
@@ -244,7 +244,7 @@ const collapsedSummary = computed(() => {
if (effectiveStartMode.value === 'gps') {
return '使用 GPS 定位'
}
return '外导览到馆'
return '外导览到馆'
})
const formatStartPointName = () => {
@@ -411,7 +411,7 @@ const handlePanelMouseEnd = (event: MouseEvent) => {
position: absolute;
left: 15px;
right: 15px;
bottom: calc(env(safe-area-inset-bottom) + 24px);
bottom: calc(env(safe-area-inset-bottom) + 106px);
padding: 12px 15px 15px;
display: flex;
flex-direction: column;

View File

@@ -14,7 +14,7 @@
<view v-if="isCollapsed" class="panel-collapsed" @tap="expandPanel">
<view class="panel-collapsed-copy">
<text class="panel-title">内导览</text>
<text class="panel-title">内导览</text>
<text class="panel-summary">{{ collapsedSummary }}</text>
</view>
<view class="panel-expand">
@@ -25,7 +25,7 @@
<template v-else>
<view class="panel-header">
<view class="panel-title-group">
<text class="panel-title">内导览</text>
<text class="panel-title">内导览</text>
<text v-if="summary" class="panel-summary">{{ summary }}</text>
</view>
<view class="panel-actions">
@@ -201,10 +201,10 @@ const primaryActionText = computed(() => (
: (props.routeReady ? '查看路线' : '查看位置关系')
))
const routeOptionsTitle = computed(() => '内导览')
const routeOptionsTitle = computed(() => '内导览')
const loadingText = computed(() => (
props.routeReady ? '正在规划内导览路线' : '正在生成内位置关系'
props.routeReady ? '正在规划内导览路线' : '正在生成内位置关系'
))
const collapsedSummary = computed(() => {
@@ -403,7 +403,7 @@ const handlePrimaryAction = () => {
position: absolute;
left: 12px;
right: 12px;
bottom: calc(env(safe-area-inset-bottom) + 30px);
bottom: calc(env(safe-area-inset-bottom) + 112px);
padding: 10px 14px 14px;
display: flex;
flex-direction: column;