2025-11-13 08:41:08 +08:00

873 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container" :style="{ backgroundColor: backgroundColor }">
<!-- 分享弹窗 -->
<view class="navbox">
<view class="status_bar"></view>
<uni-nav-bar
left-icon="left"
:title="title"
@clickLeft="goBack"
color="#8B2316"
:border="false"
backgroundColor="#eeeeee"
>
<template #right>
<view class="nav-actions">
<view class="collect-img" @click="shareToggle" v-if="canShare">
<image class="share-img-icon" :src="shareIcon" mode="aspectFill" />
</view>
</view>
</template>
</uni-nav-bar>
</view>
</view>
<uni-popup ref="shareRef" type="bottom" safeArea backgroundColor="#fff">
<view class="share-popup">
<view class="share-title">分享到</view>
<view class="share-content">
<view class="share-item" @click="shareToWechat">
<view class="share-icon wechat-icon">
<image class="share-img" :src="wxImg" mode="aspectFill" />
</view>
<text class="share-text">微信</text>
</view>
<view class="share-item" @click="shareToMoments">
<view class="share-icon moments-icon">
<image class="share-img" :src="friendImg" mode="aspectFill" />
</view>
<text class="share-text">朋友圈</text>
</view>
<view class="share-item" @click="shareToWeibo">
<view class="share-icon weibo-icon">
<image class="share-img" :src="sinaImg" mode="aspectFill" />
</view>
<text class="share-text">新浪微博</text>
</view>
</view>
<view class="share-cancel" @click="closeShare">
<text>取消</text>
</view>
</view>
</uni-popup>
</template>
<script setup>
import { ref } from "vue";
import { onLoad,onHide,onShow,onUnload} from "@dcloudio/uni-app";
import navBar from "@/components/navBar/navBar.vue";
import shareIcon from "@/static/icon_share.png";
import sinaImg from "@/static/share_sina.png";
import wxImg from "@/static/share_weixin.png";
import friendImg from "@/static/share_wxc.png";
import logoImg from "@/static/weiboShare.png";
const title = ref("新闻详情");
const safeUrl = ref("");
const backgroundColor = ref("");
const hasBg = ref(false);
const canShare = ref(false);
const summary = ref("");
const shareLink = ref("");
const shareImg=ref("");
const shareTitle = ref("");
const goBack = () => {
uni.navigateBack({
fail() {
uni.redirectTo({
url: '/pages/index/index'
});
}
});
};
onShow(() => {
uni.hideLoading();
// console.log('show');
// plus.screen.lockOrientation('portrait-primary');
});
onUnload(() => {
// console.log('onUnload');
// plus.screen.lockOrientation('portrait-primary');
});
onHide(() => {
// console.log('onHide');
// plus.screen.lockOrientation('landscape-primary');
});
onLoad((query) => {
if(query.title){
title.value = query.title;
}
if(query.share == 1){
canShare.value = true;
}
if(query.bg == 1){
hasBg.value = true;
backgroundColor.value = "linear-gradient(to bottom,'#fff' , '#398775')";
}
var height = 0; //定义动态的高度变量,如高度为定值,可以直接写
uni.getSystemInfo({
success: (sysinfo) => {
height = sysinfo.windowHeight; //自行修改
},
complete: () => {}
});
const raw = query && (query.url || "");
try {
safeUrl.value = decodeURIComponent(raw);
shareImg.value = decodeURIComponent(query.imgPath);
if(query.type == "live_yugao"){
shareTitle.value = query.sharetitle;
summary.value = "分享一篇来自“肝胆相照”的会议预告:"+shareTitle.value;
}else if(query.type == "live_old"){
shareTitle.value = query.sharetitle; shareTitle.value = query.sharetitle;
summary.value = "分享一篇来自“肝胆相照”的历史会议:"+shareTitle.value;
}else if(query.type == "live"){
shareTitle.value = '肝胆相照直播:'+query.shareTitle;
summary.value = shareTitle.value;
}
// #ifdef APP-PLUS
let wv = plus.webview.create("", "custom-webview", {
top: "140rpx",
bottom:"0rpx",
});
wv.loadURL( safeUrl.value);
let pages = getCurrentPages();
let page = pages[pages.length - 1];
var currentWebview = page.$getAppWebview(); //此对象相当于html5plus里的plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效
currentWebview.append(wv);
setTimeout(function () {
wv = currentWebview.children()[0];
wv.setStyle({ top: 80,height: height- 80,bottom:0,scalable:true, videoFullscreen: 'landscape',zIndex:-1});
}, 300); //如果是页面初始化调用时,需要延时一下
wv.onloaded = (e) => {
wv.show();
};
uni.onWindowResize((res) => {
if (res.size.windowHeight < height) {
console.log(res.size.windowHeight);
console.log(height)
console.log('键盘高度',res.height);
setTimeout(function() {
wv.setStyle({ //设置web-view距离顶部的距离以及自己的高度单位为px
top:80,
videoFullscreen: 'landscape',
height: height-res.size.windowHeight+100,
scalable: true, //webview的页面是否可以缩放双指放大缩小
})
},0);
//高度缩小
//如页面初始化调用需要写延迟
} else {
setTimeout(function() {
wv.setStyle({ //设置web-view距离顶部的距离以及自己的高度单位为px
top:80,
height:height-80,
videoFullscreen: 'landscape',
scalable: true, //webview的页面是否可以缩放双指放大缩小
})
},0);
}
})
// 创建并展示原生弹窗
createNativePopup();
// #endif
} catch (e) {
safeUrl.value = raw;
}
});
const shareRef = ref(null);
shareRef.value?.open();
// 分享APP
const shareToggle = () => {
showNativePopup();
// console.log(shareRef.value);
// shareRef.value?.open();
// uni.showActionSheet({
// title:"分享",
// itemList: ['分享到微信', '分享到朋友圈', '分享到微博'],
// success: function (res) {
// if(res.tapIndex==0){
// shareToWechat()
// }else if(res.tapIndex==1){
// shareToMoments()
// }else{
// shareToWeibo()
// }
// },
// })
};
// 关闭分享弹窗
const closeShare = () => {
shareRef.value.close();
};
// ========= 原生弹窗plus.nativeObj.view============
const nativeMaskView = ref(null);
const nativePopupView = ref(null);
const popupShowing = ref(false);
// 保存弹窗尺寸信息,供事件处理使用
const popupInfo = ref({
screenW: 0,
screenH: 0,
panelH: 0,
cancelH: 0,
contentTop: 0,
iconSize: 0,
textSize: 0
});
function createNativePopup() {
// #ifdef APP-PLUS
if (nativeMaskView.value || nativePopupView.value) return;
const screenW = plus.screen.resolutionWidth;
const screenH = plus.screen.resolutionHeight;
const panelH = uni.upx2px(520); // 面板高度(含标题+内容+取消)
const radius = uni.upx2px(20);
// 保存尺寸信息
const iconSize = 50; // 图标大小80px与图标文件尺寸一致
const titleH = uni.upx2px(80);
const cancelH = uni.upx2px(100);
const contentTop = uni.upx2px(90) + titleH;
const textSize = uni.upx2px(24);
popupInfo.value = {
screenW,
screenH,
panelH,
cancelH,
contentTop,
iconSize,
textSize
};
// 遮罩
nativeMaskView.value = new plus.nativeObj.View('native-share-mask', {
left: '0px',
top: '0px',
width: screenW + 'px',
height: screenH + 'px',
zindex: 99998,
touchable: true,
interceptTouchEvent: true
}, [
{ tag: 'rect', id: 'mask', position: { left: '0px', top: '0px', width: screenW + 'px', height: screenH + 'px' }, color: 'rgba(0,0,0,0.5)' }
]);
// 面板
nativePopupView.value = new plus.nativeObj.View('native-share-panel', {
left: '0px',
top: (screenH - panelH) + 'px',
width: screenW + 'px',
height: panelH + 'px',
zindex: 99999,
touchable: true,
interceptTouchEvent: true
}, []);
// 背景+圆角
nativePopupView.value.drawRect({
color: '#FFFFFF',
radius: radius,
rectStyles: {}
}, {
left: uni.upx2px(0) + 'px',
top: uni.upx2px(0) + 'px',
width: screenW + 'px',
height: panelH + 'px'
});
// 标题
nativePopupView.value.drawText('分享到', {
left: '0px',
top: uni.upx2px(20) + 'px',
width: screenW + 'px',
height: titleH + 'px'
}, {
size: uni.upx2px(32) + 'px',
color: '#333333',
align: 'center',
verticalAlign: 'middle',
weight: '500'
});
// 三个分享项区域(使用图标)
const itemW = screenW / 3;
const iconTop = contentTop;
const textTop = iconTop + iconSize + uni.upx2px(16);
console.log('图标布局信息:', {
screenW,
itemW,
iconSize,
iconTop,
contentTop
});
// 图标文件名映射(直接使用文件名,避免路径转换问题)
const iconFiles = [
'share_weixin.png', // 微信
'share_wxc.png', // 朋友圈
'share_sina.png' // 微博
];
const items = [
{ id: 'it-wechat', text: '微信' },
{ id: 'it-moments', text: '朋友圈' },
{ id: 'it-weibo', text: '微博' }
];
items.forEach((it, idx) => {
const left = idx * itemW;
// 计算图标居中位置(确保是整数像素)
const iconLeft = Math.round(left + (itemW - iconSize) / 2);
const iconLeftPx = iconLeft;
// 确保所有图标使用相同的 top 值,保证在一行
const iconTopPx = Math.round(iconTop);
const iconSizePx = iconSize;
console.log(`图标 ${idx} (${it.text}): left=${left}, itemW=${itemW.toFixed(2)}, iconLeft=${iconLeftPx}, iconTop=${iconTopPx}, iconSize=${iconSizePx}`);
// 构建图标本地路径
let iconPath = null;
try {
// 直接使用静态资源路径
const iconFile = iconFiles[idx];
iconPath = plus.io.convertLocalFileSystemURL('_www/static/' + iconFile);
console.log(`图标 ${it.text} 路径: ${iconPath}`);
} catch (e) {
console.log('构建图标路径失败:', e);
iconPath = null;
}
// 绘制图标
if (iconPath) {
try {
console.log(`绘制图标 ${it.text}: 位置=(${iconLeftPx}, ${iconTopPx}), 大小=${iconSizePx}x${iconSizePx}`);
// 使用 drawBitmap 绘制图标
// 尝试不同的参数格式,确保图标不变形且正确显示
// 格式1: drawBitmap(src, position, options)
try {
nativePopupView.value.drawBitmap(iconPath, {}, {
left: iconLeftPx + 'px',
top: iconTopPx + 'px',
width: iconSizePx + 'px',
height: iconSizePx + 'px'
});
} catch (e1) {
// 如果格式1失败尝试格式2: drawBitmap(src, position)
try {
nativePopupView.value.drawBitmap(iconPath, {
left: iconLeftPx + 'px',
top: iconTopPx + 'px',
width: iconSizePx + 'px',
height: iconSizePx + 'px'
});
} catch (e2) {
console.log('drawBitmap 两种格式都失败:', e1, e2);
throw e2;
}
}
} catch (e) {
console.log('绘制图标失败,使用圆形色块代替:', e);
// 如果图标加载失败,使用圆形色块作为后备
const bgColor = idx === 2 ? '#E6162D' : '#07C160';
nativePopupView.value.drawRect({
color: bgColor,
radius: Math.round(iconSize / 2)
}, {
left: Math.round(iconLeft) + 'px',
top: Math.round(iconTop) + 'px',
width: Math.round(iconSize) + 'px',
height: Math.round(iconSize) + 'px'
});
}
} else {
// 如果没有图标路径,使用圆形色块
const bgColor = idx === 2 ? '#E6162D' : '#07C160';
nativePopupView.value.drawRect({
color: bgColor,
radius: Math.round(iconSize / 2)
}, {
left: Math.round(iconLeft) + 'px',
top: Math.round(iconTop) + 'px',
width: Math.round(iconSize) + 'px',
height: Math.round(iconSize) + 'px'
});
}
// 绘制文字
nativePopupView.value.drawText(it.text, {
left: left + 'px',
top: textTop + 'px',
width: itemW + 'px',
height: textSize + uni.upx2px(20) + 'px'
}, {
size: textSize + 'px',
color: '#666666',
align: 'center',
verticalAlign: 'top'
});
});
// 取消按钮分割线
const cancelTop = panelH - cancelH;
nativePopupView.value.drawRect({ color: '#F0F0F0' }, {
left: '0px',
top: (cancelTop - 1) + 'px',
width: screenW + 'px',
height: '1px'
});
nativePopupView.value.drawText('取消', {
left: '0px',
top: cancelTop + 'px',
width: screenW + 'px',
height: cancelH + 'px'
}, {
size: uni.upx2px(32) + 'px',
color: '#333333',
align: 'center',
verticalAlign: 'middle'
});
// 事件处理函数
const handleMaskClick = () => {
console.log('遮罩被点击');
closeNativePopup();
};
const handlePanelClick = (e) => {
console.log('面板被点击', e);
const info = popupInfo.value;
// 获取点击坐标
let x = 0;
let y = 0;
// 尝试多种方式获取坐标
if (e.clientX !== undefined && e.clientY !== undefined) {
x = e.clientX;
y = e.clientY;
} else if (e.pageX !== undefined && e.pageY !== undefined) {
x = e.pageX;
y = e.pageY;
} else if (e.touches && e.touches.length > 0) {
x = e.touches[0].clientX || e.touches[0].pageX || 0;
y = e.touches[0].clientY || e.touches[0].pageY || 0;
} else if (e.changedTouches && e.changedTouches.length > 0) {
x = e.changedTouches[0].clientX || e.changedTouches[0].pageX || 0;
y = e.changedTouches[0].clientY || e.changedTouches[0].pageY || 0;
}
console.log('原始坐标:', x, y);
console.log('屏幕信息:', info);
if (!x || !y) {
console.log('坐标无效');
return;
}
// 判断坐标是相对于屏幕还是相对于视图
// 如果 y 小于 panelH说明是相对于视图的坐标
// 如果 y 大于等于 screenH - panelH说明是相对于屏幕的坐标
let relativeY = y;
let relativeX = x;
if (y < info.panelH) {
// 相对于视图的坐标,直接使用
relativeY = y;
relativeX = x;
console.log('使用相对于视图的坐标:', relativeX, relativeY);
} else if (y >= (info.screenH - info.panelH)) {
// 相对于屏幕的坐标,转换为相对于视图的坐标
relativeY = y - (info.screenH - info.panelH);
relativeX = x;
console.log('使用相对于屏幕的坐标,转换为相对视图:', relativeX, relativeY);
} else {
// 可能是其他情况,尝试直接使用
console.log('坐标类型不确定,尝试直接使用');
}
// 取消区域(底部取消按钮)- 相对于视图
const cancelTop = info.panelH - info.cancelH;
console.log('取消区域判断: relativeY =', relativeY, ', cancelTop =', cancelTop);
if (relativeY >= cancelTop) {
console.log('点击了取消按钮');
closeNativePopup();
return;
}
// 分享项区域(图标+文字区域)- 相对于视图
const shareAreaTop = info.contentTop;
const shareAreaBottom = shareAreaTop + info.iconSize + info.textSize + uni.upx2px(20);
console.log('分享区域: relativeY =', relativeY, ', 范围 =', shareAreaTop, '到', shareAreaBottom);
if (relativeY >= shareAreaTop && relativeY <= shareAreaBottom) {
// 计算点击的是第几个分享项0:微信, 1:朋友圈, 2:微博)
const itemWidth = info.screenW / 3;
const idx = Math.min(2, Math.max(0, Math.floor(relativeX / itemWidth)));
console.log('点击了分享项:', idx, ', x =', relativeX, ', itemWidth =', itemWidth);
if (idx === 0) {
console.log('执行微信分享');
shareToWechat();
closeNativePopup();
} else if (idx === 1) {
console.log('执行朋友圈分享');
shareToMoments();
closeNativePopup();
} else if (idx === 2) {
console.log('执行微博分享');
shareToWeibo();
closeNativePopup();
}
} else {
console.log('点击位置不在分享区域内, relativeY =', relativeY, ', 需要范围:', shareAreaTop, '到', shareAreaBottom);
}
};
// 同时监听 click 和 touchstart 事件
nativeMaskView.value.addEventListener('click', handleMaskClick, false);
nativeMaskView.value.addEventListener('touchstart', handleMaskClick, false);
nativePopupView.value.addEventListener('click', handlePanelClick, false);
nativePopupView.value.addEventListener('touchstart', handlePanelClick, false);
nativePopupView.value.addEventListener('touchend', handlePanelClick, false);
// #endif
}
function showNativePopup() {
// #ifdef APP-PLUS
if (popupShowing.value) return;
if (!nativeMaskView.value || !nativePopupView.value) {
createNativePopup();
}
nativeMaskView.value && nativeMaskView.value.show();
nativePopupView.value && nativePopupView.value.show();
popupShowing.value = true;
// #endif
}
function closeNativePopup() {
// #ifdef APP-PLUS
if (!popupShowing.value) return;
nativeMaskView.value && nativeMaskView.value.hide();
nativePopupView.value && nativePopupView.value.hide();
popupShowing.value = false;
// #endif
}
// 分享到微信
const shareToWechat = () => {
// #ifdef APP-PLUS
// 使用系统分享
uni.share({
provider: "weixin",
scene: "WXSceneSession",
type: 0,
title: shareTitle.value,
summary:summary.value,
href: safeUrl.value,
imageUrl: shareImg.value,
success: function (res) {
console.log("success:" + JSON.stringify(res));
},
fail: function (err) {
console.log("fail:" + JSON.stringify(err));
},
});
// #endif
// #ifdef H5
// H5环境下的分享
if (navigator.share) {
navigator
.share({
title: "肝胆相照APP",
text: "专业的医疗健康平台,快来下载体验吧!",
url: shareLink.value,
})
.then(() => {
uni.showToast({
title: "分享成功",
icon: "success",
});
})
.catch(() => {
uni.showToast({
title: "分享失败",
icon: "none",
});
});
} else {
// 复制到剪贴板
uni.setClipboardData({
data:
"肝胆相照APP - 专业的医疗健康平台,快来下载体验吧!\n下载链接" +
shareLink.value,
success: () => {
uni.showToast({
title: "已复制到剪贴板",
icon: "success",
});
},
});
}
// #endif
// #ifdef MP-WEIXIN
// 微信小程序分享
uni.showShareMenu({
withShareTicket: true,
menus: ["shareAppMessage", "shareTimeline"],
});
// #endif
closeShare();
};
// 页面隐藏/销毁时清理原生弹窗
onHide(() => {
// #ifdef APP-PLUS
closeNativePopup();
// #endif
});
onUnload(() => {
// #ifdef APP-PLUS
try{
nativeMaskView.value && nativeMaskView.value.close && nativeMaskView.value.close();
nativePopupView.value && nativePopupView.value.close && nativePopupView.value.close();
}catch(e){}
nativeMaskView.value = null;
nativePopupView.value = null;
popupShowing.value = false;
// #endif
});
// 分享到朋友圈
const shareToMoments = () => {
// #ifdef APP-PLUS
uni.share({
provider: "weixin",
scene: "WXSceneTimeline",
type: 0,
title: shareTitle.value,
summary:summary.value,
href: safeUrl.value,
imageUrl: shareImg.value,
success: function (res) {
console.log("success:" + JSON.stringify(res));
},
fail: function (err) {
console.log("fail:" + JSON.stringify(err));
},
});
// #endif
// #ifdef H5
// 复制到剪贴板
uni.setClipboardData({
data: "肝胆相照APP - 专业的医疗健康平台,快来下载体验吧!\n下载链接https://www.igandan.com",
success: () => {
uni.showToast({
title: "已复制到剪贴板,可分享到朋友圈",
icon: "success",
});
},
});
// #endif
// #ifdef MP-WEIXIN
uni.showShareMenu({
withShareTicket: true,
menus: ["shareAppMessage", "shareTimeline"],
});
// #endif
closeShare();
};
// 分享到新浪微博
const shareToWeibo = () => {
// #ifdef APP-PLUS
uni.share({
provider: "sinaweibo",
type: 0,
title: shareTitle.value ,
summary:summary.value,
href: safeUrl.value,
imageUrl: logoImg,
success: function (res) {
console.log("分享成功");
},
fail: function (err) {
console.log("fail:" + JSON.stringify(err));
},
});
// plus.share.sendWithSystem({
// type: 'text',
// content: '肝胆相照APP - 专业的医疗健康平台,快来下载体验吧!\n下载链接https://www.igandan.com'
// }, () => {
// uni.showToast({
// title: '分享成功',
// icon: 'success'
// })
// }, (err) => {
// console.log('分享失败:', err)
// uni.showToast({
// title: '分享失败',
// icon: 'none'
// })
// })
// #endif
// #ifdef H5
// 复制到剪贴板
uni.setClipboardData({
data: "肝胆相照APP - 专业的医疗健康平台,快来下载体验吧!\n下载链接https://www.igandan.com",
success: () => {
uni.showToast({
title: "已复制到剪贴板,可分享到微博",
icon: "success",
});
},
});
// #endif
closeShare();
};
</script>
<style>
.mask{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 10000000;
}
/* 分享弹窗样式 */
.share-popup {
background-color: #fff;
border-radius: 20rpx 20rpx 0 0;
padding: 40rpx 0 0;
}
.share-img {
width: 100rpx;
height: 100rpx;
}
.share-title {
text-align: center;
font-size: 32rpx;
color: #333;
margin-bottom: 40rpx;
font-weight: 500;
}
.share-content {
display: flex;
justify-content: space-around;
padding: 0 40rpx 40rpx;
}
.share-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.share-icon {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
}
.wechat-icon {
background-color: #07c160;
}
.moments-icon {
background-color: #07c160;
}
.weibo-icon {
background-color: #e6162d;
}
.qq-icon {
background-color: #12b7f5;
}
.share-icon-text {
font-size: 50rpx;
color: #fff;
font-weight: bold;
}
.share-text {
font-size: 24rpx;
color: #666;
}
.share-cancel {
height: 100rpx;
display: flex;
align-items: center;
justify-content: center;
border-top: 1rpx solid #f0f0f0;
font-size: 32rpx;
color: #333;
}
.share-cancel:active {
background-color: #f5f5f5;
}
.nav-actions .share-img-icon {
width: 40rpx;
height: 40rpx;
}
.nav-actions .collect-img-icon {
width: 40rpx;
height: 40rpx;
}
.nav-actions {
display: flex;
align-items: center;
}
.container {
height: 100vh;
position: relative;
z-index:0;
overflow: scroll;
}
.tip {
padding: 24rpx;
color: #666;
font-size: 28rpx;
}
</style>