This commit is contained in:
@@ -38,7 +38,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
</template>
|
</template>
|
||||||
<view v-else class="outdoor-map-bg">
|
<view v-else class="outdoor-map-bg" :class="`variant-${props.outdoorVariant}`">
|
||||||
<TencentMap
|
<TencentMap
|
||||||
class="outdoor-map"
|
class="outdoor-map"
|
||||||
:active-floor="activeFloor"
|
:active-floor="activeFloor"
|
||||||
@@ -793,6 +793,33 @@ defineExpose({
|
|||||||
background: #f6f8f5;
|
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 {
|
.indoor-platform-fallback {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|||||||
@@ -114,20 +114,32 @@
|
|||||||
v-if="showGuideFloatingActions"
|
v-if="showGuideFloatingActions"
|
||||||
class="guide-quick-actions"
|
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 indoor">
|
||||||
<view class="guide-quick-icon-floor top"></view>
|
<view class="guide-quick-icon-floor top"></view>
|
||||||
<view class="guide-quick-icon-floor bottom"></view>
|
<view class="guide-quick-icon-floor bottom"></view>
|
||||||
</view>
|
</view>
|
||||||
<text class="guide-quick-action-text primary">馆内</text>
|
<text class="guide-quick-action-text">馆内</text>
|
||||||
</view>
|
</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-icon arrival">
|
||||||
<view class="guide-quick-pin"></view>
|
<view class="guide-quick-pin"></view>
|
||||||
</view>
|
</view>
|
||||||
<text class="guide-quick-action-text">来馆</text>
|
<text class="guide-quick-action-text">来馆</text>
|
||||||
</view>
|
</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-icon explain">
|
||||||
<view class="guide-quick-explain-wave top"></view>
|
<view class="guide-quick-explain-wave top"></view>
|
||||||
<view class="guide-quick-explain-wave middle"></view>
|
<view class="guide-quick-explain-wave middle"></view>
|
||||||
@@ -637,6 +649,8 @@ const showGuideFloatingActions = computed(() => (
|
|||||||
&& (!showGuideHomeDock.value || !homeSearchExpanded.value)
|
&& (!showGuideHomeDock.value || !homeSearchExpanded.value)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
const isExplainQuickActionActive = computed(() => currentTab.value === 'explain')
|
||||||
|
|
||||||
const toRoutePointOption = (target: GuideRouteTarget): RoutePointOption => ({
|
const toRoutePointOption = (target: GuideRouteTarget): RoutePointOption => ({
|
||||||
poiId: target.poiId,
|
poiId: target.poiId,
|
||||||
name: target.name,
|
name: target.name,
|
||||||
@@ -1319,7 +1333,24 @@ const closeOutdoorNavPanel = () => {
|
|||||||
clearOutdoorNavState()
|
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 = () => {
|
const handleMoreOutdoorNav = () => {
|
||||||
|
if (!isOutdoorGuidePanelEnabled) {
|
||||||
|
showOutdoorEntrancePreview()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
openOutdoorNavPanel()
|
openOutdoorNavPanel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2040,7 +2071,7 @@ const handleExplainBack = () => {
|
|||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.guide-quick-action.primary {
|
.guide-quick-action.active {
|
||||||
background: var(--museum-accent);
|
background: var(--museum-accent);
|
||||||
border-color: var(--museum-accent);
|
border-color: var(--museum-accent);
|
||||||
}
|
}
|
||||||
@@ -2057,7 +2088,7 @@ const handleExplainBack = () => {
|
|||||||
color: #151713;
|
color: #151713;
|
||||||
}
|
}
|
||||||
|
|
||||||
.guide-quick-action.primary .guide-quick-icon {
|
.guide-quick-action.active .guide-quick-icon {
|
||||||
color: #0a0b08;
|
color: #0a0b08;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2139,10 +2170,23 @@ const handleExplainBack = () => {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.guide-quick-action-text.primary {
|
.guide-quick-action.active .guide-quick-action-text {
|
||||||
color: #0a0b08;
|
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 {
|
.route-sim-top-pill {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 126px;
|
top: 126px;
|
||||||
@@ -2232,6 +2276,8 @@ const handleExplainBack = () => {
|
|||||||
background: rgba(255, 255, 255, 0.96);
|
background: rgba(255, 255, 255, 0.96);
|
||||||
border: 1px solid #e5e6de;
|
border: 1px solid #e5e6de;
|
||||||
border-radius: 12px;
|
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;
|
z-index: 45;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2486,6 +2532,7 @@ const handleExplainBack = () => {
|
|||||||
border: 1px solid #ffffff;
|
border: 1px solid #ffffff;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);
|
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;
|
z-index: 45;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2547,4 +2594,41 @@ const handleExplainBack = () => {
|
|||||||
color: var(--museum-accent);
|
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>
|
</style>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
const TENCENT_MAP_KEY = import.meta.env.VITE_TENCENT_MAP_KEY?.trim() || ''
|
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_MAP_BASE_URL = 'https://apis.map.qq.com/ws'
|
||||||
const TENCENT_DIRECTION_BASE_URL = `${TENCENT_MAP_BASE_URL}/direction/v1`
|
const TENCENT_DIRECTION_BASE_URL = `${TENCENT_MAP_BASE_URL}/direction/v1`
|
||||||
|
const isH5BrowserRuntime = typeof window !== 'undefined'
|
||||||
|
|
||||||
export interface TencentPoiResult {
|
export interface TencentPoiResult {
|
||||||
id: string
|
id: string
|
||||||
@@ -42,6 +43,18 @@ const FALLBACK_MUSEUM_ENTRANCE: TencentPoiResult = {
|
|||||||
distance: 0
|
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,
|
from: RoutePoint,
|
||||||
to: RoutePoint
|
to: RoutePoint
|
||||||
): Promise<RouteResult> {
|
): Promise<RouteResult> {
|
||||||
|
if (isH5BrowserRuntime) {
|
||||||
|
console.info('H5 端跳过腾讯地图步行路线 WebService 请求,避免浏览器 CORS 拦截')
|
||||||
|
return createUnavailableRouteResult()
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
uni.request({
|
uni.request({
|
||||||
url: `${TENCENT_DIRECTION_BASE_URL}/walking`,
|
url: `${TENCENT_DIRECTION_BASE_URL}/walking`,
|
||||||
@@ -231,6 +249,11 @@ export async function planDrivingRoute(
|
|||||||
from: RoutePoint,
|
from: RoutePoint,
|
||||||
to: RoutePoint
|
to: RoutePoint
|
||||||
): Promise<RouteResult> {
|
): Promise<RouteResult> {
|
||||||
|
if (isH5BrowserRuntime) {
|
||||||
|
console.info('H5 端跳过腾讯地图驾车路线 WebService 请求,避免浏览器 CORS 拦截')
|
||||||
|
return createUnavailableRouteResult()
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
uni.request({
|
uni.request({
|
||||||
url: `${TENCENT_DIRECTION_BASE_URL}/driving`,
|
url: `${TENCENT_DIRECTION_BASE_URL}/driving`,
|
||||||
@@ -304,6 +327,11 @@ export async function planTransitRoute(
|
|||||||
from: RoutePoint,
|
from: RoutePoint,
|
||||||
to: RoutePoint
|
to: RoutePoint
|
||||||
): Promise<RouteResult> {
|
): Promise<RouteResult> {
|
||||||
|
if (isH5BrowserRuntime) {
|
||||||
|
console.info('H5 端跳过腾讯地图公交路线 WebService 请求,避免浏览器 CORS 拦截')
|
||||||
|
return createUnavailableRouteResult()
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
uni.request({
|
uni.request({
|
||||||
url: `${TENCENT_DIRECTION_BASE_URL}/transit`,
|
url: `${TENCENT_DIRECTION_BASE_URL}/transit`,
|
||||||
@@ -388,6 +416,16 @@ export function searchPoi(
|
|||||||
pageIndex: number = 1,
|
pageIndex: number = 1,
|
||||||
pageSize: number = 10
|
pageSize: number = 10
|
||||||
): Promise<TencentSearchResult> {
|
): Promise<TencentSearchResult> {
|
||||||
|
if (isH5BrowserRuntime) {
|
||||||
|
console.info('H5 端跳过腾讯地图 POI WebService 搜索,避免浏览器 CORS 拦截:', {
|
||||||
|
keyword,
|
||||||
|
region,
|
||||||
|
pageIndex,
|
||||||
|
pageSize
|
||||||
|
})
|
||||||
|
return Promise.resolve(createUnavailableSearchResult())
|
||||||
|
}
|
||||||
|
|
||||||
const boundary = `region(${region},0)`
|
const boundary = `region(${region},0)`
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@@ -432,6 +470,10 @@ export function searchPoi(
|
|||||||
* @returns 入口点位信息
|
* @returns 入口点位信息
|
||||||
*/
|
*/
|
||||||
export async function searchMuseumEntrance(): Promise<TencentPoiResult | null> {
|
export async function searchMuseumEntrance(): Promise<TencentPoiResult | null> {
|
||||||
|
if (isH5BrowserRuntime) {
|
||||||
|
return FALLBACK_MUSEUM_ENTRANCE
|
||||||
|
}
|
||||||
|
|
||||||
// 先搜索博物馆
|
// 先搜索博物馆
|
||||||
const museumResult = await searchPoi('深圳自然博物馆', '深圳市', 1, 5)
|
const museumResult = await searchPoi('深圳自然博物馆', '深圳市', 1, 5)
|
||||||
|
|
||||||
@@ -475,6 +517,16 @@ export function searchNearbyPoi(
|
|||||||
keyword: string,
|
keyword: string,
|
||||||
radius: number = 1000
|
radius: number = 1000
|
||||||
): Promise<TencentSearchResult> {
|
): Promise<TencentSearchResult> {
|
||||||
|
if (isH5BrowserRuntime) {
|
||||||
|
console.info('H5 端跳过腾讯地图周边 WebService 搜索,避免浏览器 CORS 拦截:', {
|
||||||
|
lat,
|
||||||
|
lng,
|
||||||
|
keyword,
|
||||||
|
radius
|
||||||
|
})
|
||||||
|
return Promise.resolve(createUnavailableSearchResult())
|
||||||
|
}
|
||||||
|
|
||||||
const boundary = `nearby(${lat},${lng},${radius})`
|
const boundary = `nearby(${lat},${lng},${radius})`
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user