This commit is contained in:
@@ -38,7 +38,7 @@
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
<view v-else class="outdoor-map-bg">
|
||||
<view v-else class="outdoor-map-bg" :class="`variant-${props.outdoorVariant}`">
|
||||
<TencentMap
|
||||
class="outdoor-map"
|
||||
:active-floor="activeFloor"
|
||||
@@ -793,6 +793,33 @@ defineExpose({
|
||||
background: #f6f8f5;
|
||||
}
|
||||
|
||||
.outdoor-map-bg.variant-entrance {
|
||||
animation: outdoor-entrance-focus 0.38s ease-out both;
|
||||
}
|
||||
|
||||
.outdoor-map-bg.variant-entrance::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background:
|
||||
radial-gradient(circle at 52% 60%, rgba(224, 225, 0, 0.16), rgba(224, 225, 0, 0) 32%),
|
||||
linear-gradient(180deg, rgba(0, 0, 0, 0) 48%, rgba(0, 0, 0, 0.1) 100%);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes outdoor-entrance-focus {
|
||||
from {
|
||||
opacity: 0.72;
|
||||
transform: scale(1.018);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.indoor-platform-fallback {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
@@ -114,20 +114,32 @@
|
||||
v-if="showGuideFloatingActions"
|
||||
class="guide-quick-actions"
|
||||
>
|
||||
<view class="guide-quick-action primary" @tap="handleMoreRouteGuide">
|
||||
<view
|
||||
class="guide-quick-action"
|
||||
:class="{ active: is3DMode }"
|
||||
@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>
|
||||
<text class="guide-quick-action-text">馆内</text>
|
||||
</view>
|
||||
<view class="guide-quick-action" @tap="handleMoreOutdoorNav">
|
||||
<view
|
||||
class="guide-quick-action"
|
||||
:class="{ active: guideOutdoorState === 'entrance' && !is3DMode }"
|
||||
@tap="handleMoreOutdoorNav"
|
||||
>
|
||||
<view class="guide-quick-icon arrival">
|
||||
<view class="guide-quick-pin"></view>
|
||||
</view>
|
||||
<text class="guide-quick-action-text">来馆</text>
|
||||
</view>
|
||||
<view class="guide-quick-action" @tap="handleExplainQuickTap">
|
||||
<view
|
||||
class="guide-quick-action"
|
||||
:class="{ active: isExplainQuickActionActive }"
|
||||
@tap="handleExplainQuickTap"
|
||||
>
|
||||
<view class="guide-quick-icon explain">
|
||||
<view class="guide-quick-explain-wave top"></view>
|
||||
<view class="guide-quick-explain-wave middle"></view>
|
||||
@@ -637,6 +649,8 @@ const showGuideFloatingActions = computed(() => (
|
||||
&& (!showGuideHomeDock.value || !homeSearchExpanded.value)
|
||||
))
|
||||
|
||||
const isExplainQuickActionActive = computed(() => currentTab.value === 'explain')
|
||||
|
||||
const toRoutePointOption = (target: GuideRouteTarget): RoutePointOption => ({
|
||||
poiId: target.poiId,
|
||||
name: target.name,
|
||||
@@ -1319,7 +1333,24 @@ const closeOutdoorNavPanel = () => {
|
||||
clearOutdoorNavState()
|
||||
}
|
||||
|
||||
const showOutdoorEntrancePreview = () => {
|
||||
showOutdoorNavPanel.value = false
|
||||
showRoutePlanner.value = false
|
||||
selectedGuidePoi.value = null
|
||||
isPoiCardCollapsed.value = false
|
||||
isSimulatingRoute.value = false
|
||||
clearRoutePreviewState()
|
||||
clearOutdoorNavState()
|
||||
is3DMode.value = false
|
||||
guideOutdoorState.value = 'entrance'
|
||||
}
|
||||
|
||||
const handleMoreOutdoorNav = () => {
|
||||
if (!isOutdoorGuidePanelEnabled) {
|
||||
showOutdoorEntrancePreview()
|
||||
return
|
||||
}
|
||||
|
||||
openOutdoorNavPanel()
|
||||
}
|
||||
|
||||
@@ -2040,7 +2071,7 @@ const handleExplainBack = () => {
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.guide-quick-action.primary {
|
||||
.guide-quick-action.active {
|
||||
background: var(--museum-accent);
|
||||
border-color: var(--museum-accent);
|
||||
}
|
||||
@@ -2057,7 +2088,7 @@ const handleExplainBack = () => {
|
||||
color: #151713;
|
||||
}
|
||||
|
||||
.guide-quick-action.primary .guide-quick-icon {
|
||||
.guide-quick-action.active .guide-quick-icon {
|
||||
color: #0a0b08;
|
||||
}
|
||||
|
||||
@@ -2139,10 +2170,23 @@ const handleExplainBack = () => {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.guide-quick-action-text.primary {
|
||||
.guide-quick-action.active .guide-quick-action-text {
|
||||
color: #0a0b08;
|
||||
}
|
||||
|
||||
.guide-quick-action.active .guide-quick-pin::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -7px;
|
||||
top: -7px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 1.5px solid currentColor;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
animation: entrance-pin-pulse 1.6s ease-out infinite;
|
||||
}
|
||||
|
||||
.route-sim-top-pill {
|
||||
position: absolute;
|
||||
top: 126px;
|
||||
@@ -2232,6 +2276,8 @@ const handleExplainBack = () => {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border: 1px solid #e5e6de;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.14);
|
||||
animation: entrance-tip-in 0.34s ease-out both;
|
||||
z-index: 45;
|
||||
}
|
||||
|
||||
@@ -2486,6 +2532,7 @@ const handleExplainBack = () => {
|
||||
border: 1px solid #ffffff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);
|
||||
animation: entrance-card-in 0.42s cubic-bezier(0.2, 0.82, 0.2, 1) both;
|
||||
z-index: 45;
|
||||
}
|
||||
|
||||
@@ -2547,4 +2594,41 @@ const handleExplainBack = () => {
|
||||
color: var(--museum-accent);
|
||||
}
|
||||
|
||||
@keyframes entrance-tip-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate3d(-10px, 8px, 0) scale(0.96);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes entrance-card-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 28px, 0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes entrance-pin-pulse {
|
||||
0% {
|
||||
opacity: 0.42;
|
||||
transform: scale(0.68);
|
||||
}
|
||||
|
||||
72%,
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(1.36);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
const TENCENT_MAP_KEY = import.meta.env.VITE_TENCENT_MAP_KEY?.trim() || ''
|
||||
const TENCENT_MAP_BASE_URL = 'https://apis.map.qq.com/ws'
|
||||
const TENCENT_DIRECTION_BASE_URL = `${TENCENT_MAP_BASE_URL}/direction/v1`
|
||||
const isH5BrowserRuntime = typeof window !== 'undefined'
|
||||
|
||||
export interface TencentPoiResult {
|
||||
id: string
|
||||
@@ -42,6 +43,18 @@ const FALLBACK_MUSEUM_ENTRANCE: TencentPoiResult = {
|
||||
distance: 0
|
||||
}
|
||||
|
||||
const createUnavailableSearchResult = (message = 'H5 端腾讯地图 WebService 搜索需服务端代理'): TencentSearchResult => ({
|
||||
status: -1,
|
||||
message,
|
||||
count: 0,
|
||||
data: []
|
||||
})
|
||||
|
||||
const createUnavailableRouteResult = (message = 'H5 端腾讯地图路线规划需服务端代理'): RouteResult => ({
|
||||
status: -1,
|
||||
message
|
||||
})
|
||||
|
||||
/**
|
||||
* 路线规划起点/终点坐标
|
||||
*/
|
||||
@@ -158,6 +171,11 @@ export async function planWalkingRoute(
|
||||
from: RoutePoint,
|
||||
to: RoutePoint
|
||||
): Promise<RouteResult> {
|
||||
if (isH5BrowserRuntime) {
|
||||
console.info('H5 端跳过腾讯地图步行路线 WebService 请求,避免浏览器 CORS 拦截')
|
||||
return createUnavailableRouteResult()
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
uni.request({
|
||||
url: `${TENCENT_DIRECTION_BASE_URL}/walking`,
|
||||
@@ -231,6 +249,11 @@ export async function planDrivingRoute(
|
||||
from: RoutePoint,
|
||||
to: RoutePoint
|
||||
): Promise<RouteResult> {
|
||||
if (isH5BrowserRuntime) {
|
||||
console.info('H5 端跳过腾讯地图驾车路线 WebService 请求,避免浏览器 CORS 拦截')
|
||||
return createUnavailableRouteResult()
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
uni.request({
|
||||
url: `${TENCENT_DIRECTION_BASE_URL}/driving`,
|
||||
@@ -304,6 +327,11 @@ export async function planTransitRoute(
|
||||
from: RoutePoint,
|
||||
to: RoutePoint
|
||||
): Promise<RouteResult> {
|
||||
if (isH5BrowserRuntime) {
|
||||
console.info('H5 端跳过腾讯地图公交路线 WebService 请求,避免浏览器 CORS 拦截')
|
||||
return createUnavailableRouteResult()
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
uni.request({
|
||||
url: `${TENCENT_DIRECTION_BASE_URL}/transit`,
|
||||
@@ -388,6 +416,16 @@ export function searchPoi(
|
||||
pageIndex: number = 1,
|
||||
pageSize: number = 10
|
||||
): Promise<TencentSearchResult> {
|
||||
if (isH5BrowserRuntime) {
|
||||
console.info('H5 端跳过腾讯地图 POI WebService 搜索,避免浏览器 CORS 拦截:', {
|
||||
keyword,
|
||||
region,
|
||||
pageIndex,
|
||||
pageSize
|
||||
})
|
||||
return Promise.resolve(createUnavailableSearchResult())
|
||||
}
|
||||
|
||||
const boundary = `region(${region},0)`
|
||||
|
||||
return new Promise((resolve) => {
|
||||
@@ -432,6 +470,10 @@ export function searchPoi(
|
||||
* @returns 入口点位信息
|
||||
*/
|
||||
export async function searchMuseumEntrance(): Promise<TencentPoiResult | null> {
|
||||
if (isH5BrowserRuntime) {
|
||||
return FALLBACK_MUSEUM_ENTRANCE
|
||||
}
|
||||
|
||||
// 先搜索博物馆
|
||||
const museumResult = await searchPoi('深圳自然博物馆', '深圳市', 1, 5)
|
||||
|
||||
@@ -475,6 +517,16 @@ export function searchNearbyPoi(
|
||||
keyword: string,
|
||||
radius: number = 1000
|
||||
): Promise<TencentSearchResult> {
|
||||
if (isH5BrowserRuntime) {
|
||||
console.info('H5 端跳过腾讯地图周边 WebService 搜索,避免浏览器 CORS 拦截:', {
|
||||
lat,
|
||||
lng,
|
||||
keyword,
|
||||
radius
|
||||
})
|
||||
return Promise.resolve(createUnavailableSearchResult())
|
||||
}
|
||||
|
||||
const boundary = `nearby(${lat},${lng},${radius})`
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
Reference in New Issue
Block a user