From a5b19db35501f4d362f66e7105c6105c733d6b8c Mon Sep 17 00:00:00 2001 From: lyf <2514544224@qq.com> Date: Fri, 10 Jul 2026 11:20:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B0=8F=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E5=86=85=E6=9D=A5=E9=A6=86=E5=9C=B0=E5=9B=BE=E5=AF=BC=E8=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/navigation/ArrivalPanel.vue | 18 +- src/pages.json | 7 + src/pages/open-location/index.vue | 184 +++++++++++++++++++++ src/services/ThirdPartyMapSearchService.ts | 96 +++++++++++ 4 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 src/pages/open-location/index.vue diff --git a/src/components/navigation/ArrivalPanel.vue b/src/components/navigation/ArrivalPanel.vue index be9676e..e568109 100644 --- a/src/components/navigation/ArrivalPanel.vue +++ b/src/components/navigation/ArrivalPanel.vue @@ -68,7 +68,7 @@ :class="{ disabled: !selectedTarget }" @tap="handleNavigateTap" > - 第三方导航 + {{ primaryActionText }} @@ -116,9 +116,11 @@ import { } from '@/data/arrivalSearchTargets' import { openThirdPartyMapSearch, + openWechatMiniProgramLocation, THIRD_PARTY_MAP_PROVIDERS, type ThirdPartyMapProviderOption } from '@/services/ThirdPartyMapSearchService' +import { isEmbeddedInWechatMiniProgram } from '@/utils/hostEnvironment' const props = withDefaults(defineProps<{ visible?: boolean @@ -142,6 +144,10 @@ const emit = defineEmits<{ const typeOptions = computed(() => ARRIVAL_TARGET_TYPES) const mapProviders = computed(() => THIRD_PARTY_MAP_PROVIDERS) +const shouldUseMiniProgramLocation = computed(() => isEmbeddedInWechatMiniProgram()) +const primaryActionText = computed(() => ( + shouldUseMiniProgramLocation.value ? '打开地图导航' : '第三方导航' +)) const arrivalPanelRef = ref(null) const isCollapsed = ref(false) const providerSheetVisible = ref(false) @@ -238,6 +244,16 @@ const handleNavigateTap = () => { return } + if (shouldUseMiniProgramLocation.value) { + void openWechatMiniProgramLocation({ + latitude: props.selectedTarget.latitude, + longitude: props.selectedTarget.longitude, + name: props.selectedTarget.title, + address: props.selectedTarget.subtitle + }) + return + } + providerSheetVisible.value = true } diff --git a/src/pages.json b/src/pages.json index 884f4df..fd65c81 100644 --- a/src/pages.json +++ b/src/pages.json @@ -53,6 +53,13 @@ "navigationBarBackgroundColor": "#FFFFFF", "navigationStyle": "custom" } + }, + { + "path": "pages/open-location/index", + "style": { + "navigationBarTitleText": "地图导航", + "navigationBarBackgroundColor": "#FFFFFF" + } } ], "globalStyle": { diff --git a/src/pages/open-location/index.vue b/src/pages/open-location/index.vue new file mode 100644 index 0000000..3833a29 --- /dev/null +++ b/src/pages/open-location/index.vue @@ -0,0 +1,184 @@ + + + + + diff --git a/src/services/ThirdPartyMapSearchService.ts b/src/services/ThirdPartyMapSearchService.ts index 8328b19..3e4eaeb 100644 --- a/src/services/ThirdPartyMapSearchService.ts +++ b/src/services/ThirdPartyMapSearchService.ts @@ -1,3 +1,5 @@ +import { isEmbeddedInWechatMiniProgram } from '@/utils/hostEnvironment' + export type ThirdPartyMapProvider = 'amap' | 'baidu' | 'tencent' export interface ThirdPartyMapSearchTarget { @@ -5,6 +7,23 @@ export interface ThirdPartyMapSearchTarget { region: string } +export interface WechatMiniProgramLocationTarget { + latitude: number + longitude: number + name: string + address?: string +} + +interface WechatMiniProgramBridge { + navigateTo?: (options: { + url: string + success?: () => void + fail?: (error: unknown) => void + }) => void +} + +let wechatJsSdkLoadPromise: Promise | null = null + export interface ThirdPartyMapProviderOption { provider: ThirdPartyMapProvider label: string @@ -55,3 +74,80 @@ export const openThirdPartyMapSearch = ( icon: 'none' }) } + +export const buildWechatMiniProgramOpenLocationUrl = ( + target: WechatMiniProgramLocationTarget +) => { + const params = new URLSearchParams({ + latitude: String(target.latitude), + longitude: String(target.longitude), + name: target.name, + address: target.address || '' + }) + + return `/pages/open-location/index?${params.toString()}` +} + +const getWechatMiniProgramBridge = (): WechatMiniProgramBridge | null => { + if (typeof window === 'undefined') return null + + return (window as Window & { + wx?: { + miniProgram?: WechatMiniProgramBridge + } + }).wx?.miniProgram || null +} + +const loadWechatJsSdk = () => { + if (typeof document === 'undefined') return Promise.resolve(false) + if (getWechatMiniProgramBridge()) return Promise.resolve(true) + if (wechatJsSdkLoadPromise) return wechatJsSdkLoadPromise + + wechatJsSdkLoadPromise = new Promise((resolve) => { + const existingScript = document.querySelector('script[data-wechat-js-sdk="true"]') + if (existingScript) { + existingScript.addEventListener('load', () => resolve(Boolean(getWechatMiniProgramBridge())), { once: true }) + existingScript.addEventListener('error', () => resolve(false), { once: true }) + return + } + + const script = document.createElement('script') + script.src = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js' + script.async = true + script.dataset.wechatJsSdk = 'true' + script.onload = () => resolve(Boolean(getWechatMiniProgramBridge())) + script.onerror = () => resolve(false) + document.head.appendChild(script) + }) + + return wechatJsSdkLoadPromise +} + +export const openWechatMiniProgramLocation = async ( + target: WechatMiniProgramLocationTarget +) => { + if (!isEmbeddedInWechatMiniProgram()) return false + + await loadWechatJsSdk() + const miniProgram = getWechatMiniProgramBridge() + if (!miniProgram?.navigateTo) { + uni.showToast({ + title: '请在小程序内打开地图', + icon: 'none' + }) + return false + } + + miniProgram.navigateTo({ + url: buildWechatMiniProgramOpenLocationUrl(target), + fail: (error) => { + console.error('跳转小程序地图页失败:', error) + uni.showToast({ + title: '无法打开地图导航', + icon: 'none' + }) + } + }) + + return true +}