218 lines
5.5 KiB
Vue
218 lines
5.5 KiB
Vue
<template>
|
||
<view class="card-share">
|
||
<!-- #ifdef MP-HARMONY -->
|
||
<!-- 鸿蒙元服务:web-view 是原生全屏组件,必须用 cover-view 盖在上面(cover-view 不支持 iconfont,用文本) -->
|
||
<cover-view class="mp-header">
|
||
<cover-view class="mp-status-bar" :style="{ height: statusBarHeight + 'px' }"></cover-view>
|
||
<cover-view class="mp-header-inner">
|
||
<cover-view class="nav-btn" @click="goBack">
|
||
<cover-view class="nav-back-text">‹</cover-view>
|
||
</cover-view>
|
||
<cover-view class="header-title">名片分享</cover-view>
|
||
<cover-view class="nav-btn nav-btn-placeholder"></cover-view>
|
||
</cover-view>
|
||
</cover-view>
|
||
<!-- web-view 是全屏原生组件,父容器 padding 对它无效,用等高占位 view 顶下去 -->
|
||
<view class="mp-spacer" :style="{ height: headerTotalHeightPx + 'px' }"></view>
|
||
<!-- #endif -->
|
||
|
||
<!-- 小程序/鸿蒙:web-view 加载 wap H5 名片页(客户视角,含留资表单) -->
|
||
<!-- #ifdef MP-WEIXIN || MP-HARMONY -->
|
||
<web-view v-if="cardUrl" :src="cardUrl"></web-view>
|
||
<view v-else class="empty-tip">链接无效</view>
|
||
<!-- #endif -->
|
||
|
||
<!-- #ifdef H5 -->
|
||
<!-- H5 直接就是浏览器,onLoad 时已 location 跳转,这里仅兜底展示 -->
|
||
<view class="h5-fallback">
|
||
<view class="h5-fallback-tip">正在打开名片…</view>
|
||
<button class="h5-fallback-btn" @tap="openUrl">如未自动跳转,点此打开</button>
|
||
</view>
|
||
<!-- #endif -->
|
||
|
||
<!-- #ifdef APP-PLUS -->
|
||
<web-view v-if="cardUrl" :src="cardUrl"></web-view>
|
||
<view v-else class="empty-tip">链接无效</view>
|
||
<!-- #endif -->
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
/**
|
||
* 名片分享中转页
|
||
*
|
||
* 背景: 小程序 onShareAppMessage 的 path 只能指向小程序页面, 不能直接分享 H5 链接,
|
||
* 而名片客户页(wap detail)是 H5。因此员工转发名片给微信好友时, 分享的是本页,
|
||
* 本页再用 web-view 把客户带到 wap 名片页(含留资表单)。
|
||
* H5 端分享就是普通 URL, 不需要中转, onLoad 直接跳转。
|
||
* 鸿蒙元服务(MP-HARMONY): web-view 同为原生全屏组件(参考 pages_tool/webview/webview.vue
|
||
* 的 cover-view 返回键方案), 与微信小程序共用同一套头部+占位+web-view 结构;
|
||
* 无 onShareAppMessage 生命周期, 鸿蒙端分享入口是名片详情页内「分享」按钮。
|
||
* 注意: web-view 加载的外链域名需在 manifest → HarmonyOS 网络配置里放行(元服务要求)。
|
||
*/
|
||
export default {
|
||
data() {
|
||
return {
|
||
cardUrl: '',
|
||
statusBarHeight: 20,
|
||
windowWidth: 375
|
||
};
|
||
},
|
||
computed: {
|
||
// #ifdef MP-HARMONY
|
||
headerTotalHeightPx() {
|
||
const rpxToPx = this.windowWidth / 750;
|
||
return this.statusBarHeight + Math.round(88 * rpxToPx);
|
||
}
|
||
// #endif
|
||
},
|
||
onLoad(options) {
|
||
this.cardUrl = options.url ? decodeURIComponent(options.url) : '';
|
||
// #ifdef MP-WEIXIN || MP-HARMONY
|
||
try {
|
||
const sys = uni.getSystemInfoSync();
|
||
this.statusBarHeight = sys.statusBarHeight || 20;
|
||
this.windowWidth = sys.windowWidth || 375;
|
||
} catch (e) {
|
||
// 鸿蒙个别版本 getSystemInfoSync 可能抛错, 用默认值兜底(头部高度略差不错位)
|
||
console.warn('[card/share] getSystemInfoSync fail, use fallback', e);
|
||
}
|
||
// #endif
|
||
// #ifdef H5
|
||
// H5 端无 web-view 中转必要,直接跳转到名片页
|
||
if (this.cardUrl) {
|
||
window.location.href = this.cardUrl;
|
||
}
|
||
// #endif
|
||
},
|
||
methods: {
|
||
goBack() {
|
||
const pages = getCurrentPages();
|
||
if (pages && pages.length > 1) {
|
||
uni.navigateBack();
|
||
} else {
|
||
// 栈底回首页必须走 $util.redirectTo: 鸿蒙元服务上 uni.switchTab 会静默失败
|
||
// (success/fail 都不触发, .catch 兜底失效), util 内部有
|
||
// switchTab → 500ms 强制 reLaunch 的兜底(见 util.js#redirectTo tabBar 分支)
|
||
this.$util.redirectTo('/pages/index/index');
|
||
}
|
||
},
|
||
// #ifdef H5
|
||
openUrl() {
|
||
if (this.cardUrl) window.location.href = this.cardUrl;
|
||
}
|
||
// #endif
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.card-share {
|
||
min-height: 100vh;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.empty-tip {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 60vh;
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
/* #ifdef MP-HARMONY */
|
||
.mp-header {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 9999;
|
||
background-color: #ffffff;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||
|
||
.mp-status-bar {
|
||
width: 100%;
|
||
}
|
||
|
||
.mp-header-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
height: 88rpx;
|
||
padding: 0 20rpx;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.nav-btn {
|
||
flex-shrink: 0;
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.nav-back-text {
|
||
font-size: 48rpx;
|
||
color: #333;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
|
||
.nav-btn-placeholder {
|
||
visibility: hidden;
|
||
}
|
||
|
||
.header-title {
|
||
flex: 1;
|
||
min-width: 0;
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
text-align: center;
|
||
margin: 0 16rpx;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
}
|
||
|
||
.mp-spacer {
|
||
width: 100%;
|
||
}
|
||
/* #endif */
|
||
|
||
/* #ifdef H5 */
|
||
.h5-fallback {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 80vh;
|
||
|
||
.h5-fallback-tip {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.h5-fallback-btn {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
border: 1rpx solid #dcdfe6;
|
||
border-radius: 36rpx;
|
||
padding: 0 40rpx;
|
||
height: 72rpx;
|
||
line-height: 72rpx;
|
||
background: #fff;
|
||
margin: 0;
|
||
|
||
&::after {
|
||
border: none;
|
||
}
|
||
}
|
||
}
|
||
/* #endif */
|
||
</style>
|