Update guide presentation and route preview gating
This commit is contained in:
@@ -270,7 +270,7 @@ const props = withDefaults(defineProps<{
|
||||
routePreview?: GuideRouteResult | null
|
||||
showRoute?: boolean
|
||||
}>(), {
|
||||
searchText: '搜索设施、展厅、入口',
|
||||
searchText: '请输入地点进行搜索',
|
||||
activeMode: '3d',
|
||||
activeFloor: '1F',
|
||||
indoorView: 'floor',
|
||||
@@ -579,12 +579,12 @@ const handleAutoSwitch = (event: { from: 'overview' | 'floor'; to: 'overview' |
|
||||
.guide-search-field.variant-home {
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
height: 48px;
|
||||
height: 46px;
|
||||
padding: 0 14px;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border: 1px solid #d7dad3;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 22px rgba(36, 49, 42, 0.08);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 18px rgba(36, 49, 42, 0.08);
|
||||
}
|
||||
|
||||
.search-field-text {
|
||||
@@ -792,7 +792,7 @@ const handleAutoSwitch = (event: { from: 'overview' | 'floor'; to: 'overview' |
|
||||
overflow: visible;
|
||||
background: rgba(255, 255, 255, 0.84);
|
||||
border: 1px solid #dde5df;
|
||||
border-radius: 10px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 18px rgba(110, 127, 115, 0.12);
|
||||
z-index: 35;
|
||||
}
|
||||
@@ -851,7 +851,7 @@ const handleAutoSwitch = (event: { from: 'overview' | 'floor'; to: 'overview' |
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
border: 1px solid #dde5df;
|
||||
border-radius: 10px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 18px rgba(110, 127, 115, 0.12);
|
||||
z-index: 36;
|
||||
}
|
||||
@@ -944,7 +944,7 @@ const handleAutoSwitch = (event: { from: 'overview' | 'floor'; to: 'overview' |
|
||||
overflow: hidden;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
border: 1px solid #dde5df;
|
||||
border-radius: 10px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 18px rgba(110, 127, 115, 0.12);
|
||||
z-index: 35;
|
||||
}
|
||||
@@ -978,7 +978,7 @@ const handleAutoSwitch = (event: { from: 'overview' | 'floor'; to: 'overview' |
|
||||
box-sizing: border-box;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border: 1px solid #dde5df;
|
||||
border-radius: 10px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 18px rgba(110, 127, 115, 0.12);
|
||||
z-index: 35;
|
||||
}
|
||||
|
||||
@@ -67,12 +67,12 @@ const handleTabTap = (tab: GuideTopTab) => {
|
||||
left: 50%;
|
||||
right: auto;
|
||||
width: 174px;
|
||||
height: 38px;
|
||||
height: 36px;
|
||||
padding: 2px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #151713;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border: 1px solid #d7dad3;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 20px rgba(36, 49, 42, 0.08);
|
||||
box-shadow: 0 8px 18px rgba(36, 49, 42, 0.08);
|
||||
transform: translateX(-50%) translateZ(0);
|
||||
}
|
||||
|
||||
@@ -88,12 +88,12 @@ const handleTabTap = (tab: GuideTopTab) => {
|
||||
.variant-segmented .guide-top-tab {
|
||||
flex: 1;
|
||||
width: auto;
|
||||
height: 32px;
|
||||
height: 30px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.variant-segmented .guide-top-tab.active {
|
||||
background: #000000;
|
||||
background: #151713;
|
||||
}
|
||||
|
||||
.guide-top-tab-label {
|
||||
|
||||
@@ -1,53 +1,89 @@
|
||||
<template>
|
||||
<view v-if="visible" class="route-planner-panel">
|
||||
<view class="panel-handle"></view>
|
||||
<view class="panel-header">
|
||||
<view class="panel-title-group">
|
||||
<view v-if="visible" class="route-planner-panel" :class="{ collapsed: isCollapsed }">
|
||||
<view class="panel-handle" @tap.stop="toggleCollapsed"></view>
|
||||
|
||||
<view v-if="isCollapsed" class="panel-collapsed" @tap="expandPanel">
|
||||
<view class="panel-collapsed-copy">
|
||||
<text class="panel-title">室内到室内</text>
|
||||
<text v-if="summary" class="panel-summary">{{ summary }}</text>
|
||||
<text class="panel-summary">{{ collapsedSummary }}</text>
|
||||
</view>
|
||||
<view class="panel-clear" @tap="handleClear">
|
||||
<text class="panel-clear-text">清除</text>
|
||||
<view class="panel-expand">
|
||||
<text class="panel-expand-text">展开</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="point-row">
|
||||
<view class="point-card" @tap="openPicker('start')">
|
||||
<view class="point-dot start"></view>
|
||||
<text class="point-label">起点</text>
|
||||
<text class="point-name" :class="{ placeholder: !startPoint }">
|
||||
{{ startPoint?.name || '选择起点' }}
|
||||
</text>
|
||||
<text v-if="startPoint" class="point-meta">{{ pointMeta(startPoint) }}</text>
|
||||
<template v-else>
|
||||
<view class="panel-header">
|
||||
<view class="panel-title-group">
|
||||
<text class="panel-title">室内到室内</text>
|
||||
<text v-if="summary" class="panel-summary">{{ summary }}</text>
|
||||
</view>
|
||||
<view class="panel-actions">
|
||||
<view class="panel-light-action" @tap="collapsePanel">
|
||||
<text class="panel-light-action-text">收起</text>
|
||||
</view>
|
||||
<view class="panel-light-action" @tap="handleClear">
|
||||
<text class="panel-light-action-text">清除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="swap-btn" @tap="handleSwap">
|
||||
<text class="swap-text">⇅</text>
|
||||
<view class="point-row">
|
||||
<view class="point-card" @tap="openPicker('start')">
|
||||
<view class="point-dot start"></view>
|
||||
<text class="point-label">起点</text>
|
||||
<text class="point-name" :class="{ placeholder: !startPoint }">
|
||||
{{ startPoint?.name || '选择起点' }}
|
||||
</text>
|
||||
<text v-if="startPoint" class="point-meta">{{ pointMeta(startPoint) }}</text>
|
||||
</view>
|
||||
|
||||
<view class="swap-btn" @tap="handleSwap">
|
||||
<text class="swap-text">⇅</text>
|
||||
</view>
|
||||
|
||||
<view class="point-card" @tap="openPicker('end')">
|
||||
<view class="point-dot end"></view>
|
||||
<text class="point-label">终点</text>
|
||||
<text class="point-name" :class="{ placeholder: !endPoint }">
|
||||
{{ endPoint?.name || '选择终点' }}
|
||||
</text>
|
||||
<text v-if="endPoint" class="point-meta">{{ pointMeta(endPoint) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="point-card" @tap="openPicker('end')">
|
||||
<view class="point-dot end"></view>
|
||||
<text class="point-label">终点</text>
|
||||
<text class="point-name" :class="{ placeholder: !endPoint }">
|
||||
{{ endPoint?.name || '选择终点' }}
|
||||
</text>
|
||||
<text v-if="endPoint" class="point-meta">{{ pointMeta(endPoint) }}</text>
|
||||
<view v-if="startPoint && endPoint" class="route-options">
|
||||
<view class="route-options-header">
|
||||
<text class="route-options-title">线路预览</text>
|
||||
<text class="route-options-note">偏好选择</text>
|
||||
</view>
|
||||
<view class="route-option-list">
|
||||
<view
|
||||
v-for="option in routeOptions"
|
||||
:key="option.id"
|
||||
class="route-option"
|
||||
:class="{ active: option.active, disabled: option.disabled }"
|
||||
>
|
||||
<text class="route-option-title">{{ option.title }}</text>
|
||||
<text class="route-option-meta">{{ option.meta }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="loading || error || summary" class="panel-status">
|
||||
<text v-if="loading" class="panel-status-text">路径加载中</text>
|
||||
<text v-else-if="error" class="panel-status-text error">{{ error }}</text>
|
||||
<text v-else class="panel-status-text">{{ summary }}</text>
|
||||
</view>
|
||||
<view v-if="loading || error || summary" class="panel-status">
|
||||
<text v-if="loading" class="panel-status-text">线路预览生成中</text>
|
||||
<text v-else-if="error" class="panel-status-text error">{{ error }}</text>
|
||||
<text v-else class="panel-status-text">{{ summary }}</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="view-route-btn"
|
||||
:class="{ disabled: !canViewRoute }"
|
||||
@tap="handlePrimaryAction"
|
||||
>
|
||||
<text class="view-route-text">{{ primaryActionText }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="view-route-btn"
|
||||
:class="{ disabled: !canPrimaryAction }"
|
||||
@tap="handlePrimaryAction"
|
||||
>
|
||||
<text class="view-route-text">{{ primaryActionText }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<RoutePointPicker
|
||||
:visible="pickerMode !== ''"
|
||||
@@ -67,7 +103,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import RoutePointPicker, {
|
||||
type RoutePointOption
|
||||
} from '@/components/navigation/RoutePointPicker.vue'
|
||||
@@ -115,6 +151,7 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const pickerMode = ref<PickerMode>('')
|
||||
const isCollapsed = ref(false)
|
||||
|
||||
const pickerTitle = computed(() => (
|
||||
pickerMode.value === 'start' ? '选择起点' : '选择终点'
|
||||
@@ -137,10 +174,59 @@ const canViewRoute = computed(() => Boolean(
|
||||
&& props.startPoint.poiId !== props.endPoint.poiId
|
||||
))
|
||||
|
||||
const canPrimaryAction = computed(() => canViewRoute.value && !props.error)
|
||||
|
||||
const primaryActionText = computed(() => (
|
||||
props.hasRoutePreview ? '模拟导览' : '生成线路'
|
||||
props.hasRoutePreview ? '模拟导览' : '线路预览'
|
||||
))
|
||||
|
||||
const collapsedSummary = computed(() => {
|
||||
if (props.startPoint && props.endPoint) {
|
||||
return `${props.startPoint.name} → ${props.endPoint.name}`
|
||||
}
|
||||
|
||||
return '手动选择起点和终点'
|
||||
})
|
||||
|
||||
const routeOptions = computed(() => {
|
||||
const unavailable = Boolean(props.error)
|
||||
const summaryText = props.summary || '选择后查看位置关系'
|
||||
return [
|
||||
{
|
||||
id: 'recommended',
|
||||
title: '推荐路线',
|
||||
meta: unavailable ? '当前为路线示意状态' : props.hasRoutePreview ? summaryText : '优先展示位置关系',
|
||||
active: !unavailable,
|
||||
disabled: unavailable
|
||||
},
|
||||
{
|
||||
id: 'stairs',
|
||||
title: '少走楼梯',
|
||||
meta: '偏好预览,待路线数据验证',
|
||||
active: false,
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
id: 'elevator',
|
||||
title: '电梯优先',
|
||||
meta: '偏好预览,待路线数据验证',
|
||||
active: false,
|
||||
disabled: true
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
isCollapsed.value = false
|
||||
} else {
|
||||
pickerMode.value = ''
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const pointMeta = (point: RoutePointOption) => {
|
||||
return point.categoryLabel
|
||||
? `${point.floorLabel} · ${point.categoryLabel}`
|
||||
@@ -188,6 +274,18 @@ const handleClear = () => {
|
||||
emit('clear')
|
||||
}
|
||||
|
||||
const collapsePanel = () => {
|
||||
isCollapsed.value = true
|
||||
}
|
||||
|
||||
const expandPanel = () => {
|
||||
isCollapsed.value = false
|
||||
}
|
||||
|
||||
const toggleCollapsed = () => {
|
||||
isCollapsed.value = !isCollapsed.value
|
||||
}
|
||||
|
||||
const handleViewRoute = () => {
|
||||
if (!canViewRoute.value || !props.startPoint || !props.endPoint) return
|
||||
|
||||
@@ -218,13 +316,17 @@ const handlePrimaryAction = () => {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
border: 1px solid #ffffff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 10px 28px rgba(36, 49, 42, 0.12);
|
||||
background: rgba(255, 255, 255, 0.97);
|
||||
border: 1px solid #e5e6de;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 24px rgba(36, 49, 42, 0.12);
|
||||
z-index: 1003;
|
||||
}
|
||||
|
||||
.route-planner-panel.collapsed {
|
||||
padding: 8px 10px 10px;
|
||||
}
|
||||
|
||||
.panel-handle {
|
||||
width: 38px;
|
||||
height: 4px;
|
||||
@@ -233,6 +335,39 @@ const handlePrimaryAction = () => {
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.panel-collapsed {
|
||||
min-height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.panel-collapsed-copy {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.panel-expand {
|
||||
flex: 0 0 auto;
|
||||
height: 30px;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #151713;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.panel-expand-text {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--museum-accent);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@@ -251,7 +386,7 @@ const handlePrimaryAction = () => {
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
font-weight: 700;
|
||||
color: #000000;
|
||||
color: #151713;
|
||||
}
|
||||
|
||||
.panel-summary {
|
||||
@@ -263,7 +398,13 @@ const handlePrimaryAction = () => {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.panel-clear {
|
||||
.panel-actions {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.panel-light-action {
|
||||
flex: 0 0 auto;
|
||||
height: 28px;
|
||||
padding: 0 10px;
|
||||
@@ -276,7 +417,7 @@ const handlePrimaryAction = () => {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.panel-clear-text {
|
||||
.panel-light-action-text {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
font-weight: 500;
|
||||
@@ -304,7 +445,7 @@ const handlePrimaryAction = () => {
|
||||
box-sizing: border-box;
|
||||
background: #f6f7f4;
|
||||
border: 1px solid #e5e6de;
|
||||
border-radius: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.point-dot {
|
||||
@@ -369,7 +510,7 @@ const handlePrimaryAction = () => {
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
border: 1px solid #d7dad3;
|
||||
border-radius: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.swap-text {
|
||||
@@ -400,8 +541,8 @@ const handlePrimaryAction = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #000000;
|
||||
border-radius: 10px;
|
||||
background: #151713;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.view-route-btn.disabled {
|
||||
@@ -418,4 +559,84 @@ const handlePrimaryAction = () => {
|
||||
.view-route-btn.disabled .view-route-text {
|
||||
color: #8b8b84;
|
||||
}
|
||||
|
||||
.route-options {
|
||||
margin-top: 12px;
|
||||
padding: 10px;
|
||||
background: #f9fafb;
|
||||
border: 1px solid #ecede7;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.route-options-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.route-options-title {
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
font-weight: 700;
|
||||
color: #151713;
|
||||
}
|
||||
|
||||
.route-options-note {
|
||||
font-size: 11px;
|
||||
line-height: 15px;
|
||||
color: #8b8b84;
|
||||
}
|
||||
|
||||
.route-option-list {
|
||||
margin-top: 8px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.route-option {
|
||||
min-width: 0;
|
||||
min-height: 56px;
|
||||
padding: 8px 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 3px;
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e6de;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.route-option.active {
|
||||
border-color: #151713;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.route-option.disabled {
|
||||
opacity: 0.68;
|
||||
}
|
||||
|
||||
.route-option-title {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
font-weight: 700;
|
||||
color: #151713;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.route-option-meta {
|
||||
font-size: 10px;
|
||||
line-height: 14px;
|
||||
color: #696962;
|
||||
text-align: center;
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user