优化导览页图标与快捷入口展示
This commit is contained in:
@@ -170,9 +170,48 @@
|
||||
v-for="tool in tools"
|
||||
:key="tool"
|
||||
class="tool-btn"
|
||||
:aria-label="tool"
|
||||
:title="tool"
|
||||
@tap="handleToolClick(tool)"
|
||||
>
|
||||
<text class="tool-label">{{ tool }}</text>
|
||||
<svg
|
||||
v-if="toolIconType(tool) === 'reset'"
|
||||
class="tool-icon-svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path d="M5 7v5h5" />
|
||||
<path d="M6.2 13.4A6.2 6.2 0 1 0 7.4 6.7L5 9.1" />
|
||||
</svg>
|
||||
<svg
|
||||
v-else-if="toolIconType(tool) === 'top'"
|
||||
class="tool-icon-svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<rect x="6" y="6" width="12" height="12" rx="2" />
|
||||
<path d="M9 9h6v6H9z" />
|
||||
</svg>
|
||||
<svg
|
||||
v-else-if="toolIconType(tool) === 'oblique'"
|
||||
class="tool-icon-svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path d="M5 9.5 12 5l7 4.5-7 4.5-7-4.5Z" />
|
||||
<path d="M5 9.5v5L12 19l7-4.5v-5" />
|
||||
<path d="M12 14v5" />
|
||||
</svg>
|
||||
<svg
|
||||
v-else-if="toolIconType(tool) === 'clear'"
|
||||
class="tool-icon-svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path d="M7 7l10 10" />
|
||||
<path d="M17 7 7 17" />
|
||||
</svg>
|
||||
<text v-else class="tool-label">{{ tool }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -364,7 +403,7 @@ const indoorRendererRef = ref<{
|
||||
showMultiFloor?: () => Promise<void> | void
|
||||
resetCamera?: () => void
|
||||
setCameraPreset?: (preset: 'top' | 'oblique') => void
|
||||
zoomCamera?: (direction: 'in' | 'out') => void
|
||||
zoomCamera?: (direction: 'in' | 'out', options?: { source?: 'button' | 'gesture' }) => void
|
||||
clearSelection?: (shouldEmit?: boolean) => void
|
||||
clearRoute?: () => Promise<void> | void
|
||||
disableAutoSwitchTemporarily?: (durationMs: number) => void
|
||||
@@ -477,7 +516,7 @@ const handleToolClick = (tool: string) => {
|
||||
if (props.mapType === 'indoor') {
|
||||
indoorRendererRef.value?.disableAutoSwitchTemporarily?.(10000)
|
||||
|
||||
if (tool === '重置') {
|
||||
if (tool === '复位') {
|
||||
indoorRendererRef.value?.resetCamera?.()
|
||||
} else if (tool === '俯视') {
|
||||
indoorRendererRef.value?.setCameraPreset?.('top')
|
||||
@@ -491,8 +530,16 @@ const handleToolClick = (tool: string) => {
|
||||
emit('toolClick', tool)
|
||||
}
|
||||
|
||||
const toolIconType = (tool: string) => {
|
||||
if (tool === '复位') return 'reset'
|
||||
if (tool === '俯视') return 'top'
|
||||
if (tool === '斜视') return 'oblique'
|
||||
if (tool === '清除') return 'clear'
|
||||
return 'text'
|
||||
}
|
||||
|
||||
const handleZoomClick = (direction: 'in' | 'out') => {
|
||||
indoorRendererRef.value?.zoomCamera?.(direction)
|
||||
indoorRendererRef.value?.zoomCamera?.(direction, { source: 'button' })
|
||||
emit('toolClick', direction === 'in' ? '放大' : '缩小')
|
||||
}
|
||||
|
||||
@@ -892,9 +939,37 @@ defineExpose({
|
||||
}
|
||||
|
||||
.floor-header-icon {
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
position: relative;
|
||||
display: block;
|
||||
color: #151713;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.floor-header-icon::before,
|
||||
.floor-header-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
border: 1.8px solid currentColor;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.floor-header-icon::before {
|
||||
left: 2px;
|
||||
top: 4px;
|
||||
width: 12px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.floor-header-icon::after {
|
||||
left: 5px;
|
||||
top: 1px;
|
||||
width: 12px;
|
||||
height: 10px;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.floor-header.active .floor-header-icon {
|
||||
@@ -1001,6 +1076,20 @@ defineExpose({
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tool-btn:active {
|
||||
background: #f6f7f4;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.tool-icon-svg {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
stroke: #151713;
|
||||
stroke-width: 1.8;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.tool-label {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
show-floor-header
|
||||
:show-layer-mode-toggle="false"
|
||||
:show-floor="is3DMode"
|
||||
:tools="indoorCameraTools"
|
||||
tools-top=""
|
||||
tools-bottom="54px"
|
||||
show-zoom-controls
|
||||
zoom-controls-top="calc(100vh - 284px)"
|
||||
@@ -57,6 +59,9 @@
|
||||
<view v-if="guideOutdoorState === 'entrance' && !is3DMode" class="entrance-tip">
|
||||
<text class="entrance-tip-text">主入口 约 4 分钟</text>
|
||||
</view>
|
||||
<view v-if="is3DMode && showIndoorGestureHint" class="indoor-gesture-hint">
|
||||
<text class="indoor-gesture-text">{{ indoorGestureHintText }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view
|
||||
@@ -111,9 +116,16 @@
|
||||
class="guide-quick-actions"
|
||||
>
|
||||
<view class="guide-quick-action primary" @tap="handleMoreRouteGuide">
|
||||
<view class="guide-quick-icon indoor">
|
||||
<view class="guide-quick-icon-floor top"></view>
|
||||
<view class="guide-quick-icon-floor bottom"></view>
|
||||
</view>
|
||||
<text class="guide-quick-action-text primary">室内导览</text>
|
||||
</view>
|
||||
<view class="guide-quick-action" @tap="handleMoreOutdoorNav">
|
||||
<view class="guide-quick-icon arrival">
|
||||
<view class="guide-quick-pin"></view>
|
||||
</view>
|
||||
<text class="guide-quick-action-text">来馆</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -325,6 +337,24 @@ const normalizeGuideFloorId = (labelOrId: string) => guideUseCase.normalizeFloor
|
||||
const indoorLayerMode = computed<LayerDisplayMode>(() => (
|
||||
indoorView.value === 'multi' ? 'multi' : 'single'
|
||||
))
|
||||
const indoorCameraTools = computed(() => (is3DMode.value ? ['复位', '俯视', '斜视'] : []))
|
||||
const showIndoorGestureHint = ref(true)
|
||||
const indoorGestureHintText = ref('拖动旋转 · 双指缩放 · 点选标记查看位置')
|
||||
let indoorGestureHintTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
const showIndoorHint = (text = '拖动旋转 · 双指缩放 · 点选标记查看位置', durationMs = 5200) => {
|
||||
indoorGestureHintText.value = text
|
||||
showIndoorGestureHint.value = is3DMode.value
|
||||
|
||||
if (indoorGestureHintTimer) {
|
||||
clearTimeout(indoorGestureHintTimer)
|
||||
}
|
||||
|
||||
indoorGestureHintTimer = setTimeout(() => {
|
||||
showIndoorGestureHint.value = false
|
||||
indoorGestureHintTimer = null
|
||||
}, durationMs)
|
||||
}
|
||||
|
||||
const routePlanSummary = computed(() => {
|
||||
if (activeRoutePreview.value) {
|
||||
@@ -446,6 +476,8 @@ const syncTopTabFromHash = () => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
showIndoorHint()
|
||||
|
||||
if (typeof window === 'undefined') return
|
||||
|
||||
syncTopTabFromHash()
|
||||
@@ -453,6 +485,11 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (indoorGestureHintTimer) {
|
||||
clearTimeout(indoorGestureHintTimer)
|
||||
indoorGestureHintTimer = null
|
||||
}
|
||||
|
||||
if (typeof window === 'undefined') return
|
||||
|
||||
window.removeEventListener('hashchange', syncTopTabFromHash)
|
||||
@@ -584,6 +621,7 @@ const handleFloorChange = (floor: string) => {
|
||||
indoorView.value = 'floor'
|
||||
selectedGuidePoi.value = null
|
||||
isPoiCardCollapsed.value = false
|
||||
showIndoorHint(`已切换到 ${floor},可拖动旋转查看`, 3200)
|
||||
console.log('切换楼层:', floor)
|
||||
}
|
||||
|
||||
@@ -593,6 +631,12 @@ const handleIndoorViewChange = (view: GuideIndoorView) => {
|
||||
selectedGuidePoi.value = null
|
||||
isPoiCardCollapsed.value = false
|
||||
}
|
||||
|
||||
if (view === 'multi') {
|
||||
showIndoorHint('已切换多层视图,可点选楼层查看', 3200)
|
||||
} else if (view === 'floor') {
|
||||
showIndoorHint('已切换单层视图,可点选标记查看位置', 3200)
|
||||
}
|
||||
}
|
||||
|
||||
const handleAutoSwitch = (event: { from: 'overview' | 'floor'; to: 'overview' | 'floor'; trigger: string; distance: number }) => {
|
||||
@@ -602,6 +646,7 @@ const handleAutoSwitch = (event: { from: 'overview' | 'floor'; to: 'overview' |
|
||||
selectedGuidePoi.value = null
|
||||
isPoiCardCollapsed.value = false
|
||||
}
|
||||
showIndoorHint(event.to === 'floor' ? '已进入单层视图,可点选标记查看位置' : '已返回建筑外观', 3600)
|
||||
}
|
||||
|
||||
const handleGuidePoiClick = (poi: GuideRenderPoi) => {
|
||||
@@ -611,6 +656,7 @@ const handleGuidePoiClick = (poi: GuideRenderPoi) => {
|
||||
isSimulatingRoute.value = false
|
||||
const matchedFloor = guideFloors.value.find((floor) => floor.id === poi.floorId)
|
||||
activeGuideFloor.value = matchedFloor?.label || poi.floorId
|
||||
showIndoorHint('已选中标记,可查看位置预览', 3200)
|
||||
}
|
||||
|
||||
const handleGuideSelectionClear = () => {
|
||||
@@ -839,6 +885,7 @@ const handleEnter3DMode = () => {
|
||||
indoorView.value = 'overview'
|
||||
is3DMode.value = true
|
||||
guideOutdoorState.value = 'home'
|
||||
showIndoorHint()
|
||||
if (!routePointOptions.value.length) {
|
||||
void loadRouteTargets()
|
||||
}
|
||||
@@ -857,6 +904,7 @@ const handleModeChange = (mode: '2d' | '3d') => {
|
||||
clearRoutePreviewState()
|
||||
} else {
|
||||
indoorView.value = 'overview'
|
||||
showIndoorHint()
|
||||
if (!routePointOptions.value.length) {
|
||||
void loadRouteTargets()
|
||||
}
|
||||
@@ -1273,12 +1321,14 @@ const handleExplainBack = () => {
|
||||
}
|
||||
|
||||
.guide-quick-action {
|
||||
width: 84px;
|
||||
min-height: 38px;
|
||||
padding: 0 12px;
|
||||
width: 88px;
|
||||
min-height: 48px;
|
||||
padding: 7px 8px 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
box-sizing: border-box;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border: 1px solid #dde5df;
|
||||
@@ -1291,9 +1341,66 @@ const handleExplainBack = () => {
|
||||
border-color: #151713;
|
||||
}
|
||||
|
||||
.guide-quick-action:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.guide-quick-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
position: relative;
|
||||
color: #151713;
|
||||
}
|
||||
|
||||
.guide-quick-action.primary .guide-quick-icon {
|
||||
color: var(--museum-accent);
|
||||
}
|
||||
|
||||
.guide-quick-icon-floor {
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
width: 16px;
|
||||
height: 9px;
|
||||
box-sizing: border-box;
|
||||
border: 1.7px solid currentColor;
|
||||
border-radius: 2px;
|
||||
transform: skewY(-18deg);
|
||||
}
|
||||
|
||||
.guide-quick-icon-floor.top {
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.guide-quick-icon-floor.bottom {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.guide-quick-pin {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 2px;
|
||||
width: 12px;
|
||||
height: 16px;
|
||||
box-sizing: border-box;
|
||||
border: 1.8px solid currentColor;
|
||||
border-radius: 7px 7px 7px 0;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.guide-quick-pin::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
top: 3px;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: currentColor;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.guide-quick-action-text {
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
font-weight: 600;
|
||||
color: #151713;
|
||||
text-align: center;
|
||||
@@ -1402,6 +1509,35 @@ const handleExplainBack = () => {
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
.indoor-gesture-hint {
|
||||
position: absolute;
|
||||
top: clamp(174px, 23vh, 228px);
|
||||
left: 50%;
|
||||
max-width: calc(100% - 136px);
|
||||
min-height: 34px;
|
||||
padding: 7px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
background: rgba(21, 23, 19, 0.76);
|
||||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||||
border-radius: 8px;
|
||||
transform: translateX(-50%);
|
||||
pointer-events: none;
|
||||
z-index: 34;
|
||||
}
|
||||
|
||||
.indoor-gesture-text {
|
||||
min-width: 0;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.home-shortcuts-card {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
|
||||
Reference in New Issue
Block a user