1062 lines
29 KiB
Vue
1062 lines
29 KiB
Vue
<template>
|
||
<view class="ppt-detail-page">
|
||
<!-- 顶部导航栏 -->
|
||
<view class="navbox">
|
||
<view class="status_bar"></view>
|
||
<uni-nav-bar
|
||
left-icon="left"
|
||
title="课件详情"
|
||
@clickLeft="goBack"
|
||
|
||
color="#8B2316"
|
||
|
||
:border="false"
|
||
backgroundColor="#eeeeee"
|
||
>
|
||
<template v-slot:right>
|
||
<view class="nav-actions">
|
||
<view class="collect-img" @click="shareToggle" style="margin-right: 20rpx;">
|
||
<image class="share-img-icon" :src="shareIcon" mode="aspectFill" />
|
||
</view>
|
||
<view class="collect-img" @click="toggleCollection" style="margin-left: 20rpx;">
|
||
<image
|
||
class="collect-img-icon"
|
||
:src="isCollection==1 ? collectImg : discollectImg"
|
||
mode="aspectFill"
|
||
/>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
</uni-nav-bar>
|
||
</view>
|
||
|
||
<!-- 下载提示条 -->
|
||
|
||
|
||
<view
|
||
class="download-bar"
|
||
@click="goView"
|
||
v-if="order && order.order_status == 'paid' && hasDownload && downLoadStatus == 'completed'"
|
||
>
|
||
<view class="download-inner">
|
||
<text class="download-text">查看课件</text>
|
||
</view>
|
||
</view>
|
||
<view
|
||
class="download-bar"
|
||
@click="alertDownloading"
|
||
v-else-if="order && order.order_status == 'paid' && hasDownload && downLoadStatus == 'loading'"
|
||
>
|
||
<view class="download-inner">
|
||
<text class="download-text">下载中...</text>
|
||
</view>
|
||
</view>
|
||
<view
|
||
class="download-bar"
|
||
@click="downloadGanDanFile"
|
||
v-else-if="order && order.order_status == 'paid' && !hasDownload"
|
||
>
|
||
<view class="download-inner">
|
||
<text class="download-text">重新下载本课件</text>
|
||
</view>
|
||
</view>
|
||
<view class="download-bar" @click="goPay" v-else-if="!order && price>0">
|
||
<view class="download-inner">
|
||
<u-icon name="download" color="#fff" size="28"></u-icon>
|
||
<text class="download-text">本课件下载</text>
|
||
<text class="download-price">{{ price }}</text>
|
||
<text class="download-unit">元</text>
|
||
</view>
|
||
</view>
|
||
<view class="download-bar" v-else-if="!order && price<0">
|
||
<view class="download-inner">
|
||
<u-icon name="download" color="#fff" size="28"></u-icon>
|
||
<text class="download-text">本课件不支持下载</text>
|
||
</view>
|
||
</view>
|
||
<view class="download-bar" @click="downloadGanDanFile" v-else>
|
||
<view class="download-inner">
|
||
<u-icon name="download" color="#fff" size="28"></u-icon>
|
||
<text class="download-text">本课件</text>
|
||
<text class="download-price">免费</text>
|
||
<text class="download-unit">下载</text>
|
||
</view>
|
||
</view>
|
||
<!-- <web-view :src="src"></web-view> -->
|
||
<!-- 图片浏览 -->
|
||
<!-- <view class="viewer">
|
||
<swiper
|
||
class="ppt-swiper"
|
||
:indicator-dots="false"
|
||
:circular="true"
|
||
:autoplay="false"
|
||
@change="onSwiperChange"
|
||
>
|
||
<swiper-item v-for="(img, idx) in images" :key="idx">
|
||
<view class="slide">
|
||
<image :src="img" mode="widthFix" class="slide-image" />
|
||
</view>
|
||
</swiper-item>
|
||
</swiper>
|
||
<view class="page-indicator">{{ currentIndex + 1 }}/{{ images.length }}</view>
|
||
</view> -->
|
||
</view>
|
||
<unidialog
|
||
:visible="freeVisible"
|
||
:content="freeContent"
|
||
@close="freeClose"
|
||
@confirm="freeConfirm"
|
||
></unidialog>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, nextTick } from "vue";
|
||
import { onShow, onLoad, onHide, onUnload } from "@dcloudio/uni-app";
|
||
import api from "@/api/api";
|
||
import navTo from "@/utils/navTo.js";
|
||
import collectImg from "@/static/icon_book_collect_sel.png";
|
||
import discollectImg from "@/static/icon_book_collect_nor.png";
|
||
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";
|
||
import downloadStore from "@/store/downloadStorePpt.js";
|
||
import unidialog from "@/components/dialog/dialog.vue";
|
||
const freeVisible = ref(false);
|
||
const freeContent = ref('');
|
||
const freeConfirm = () => {
|
||
freeVisible.value = false;
|
||
downloadGanDanFile();
|
||
};
|
||
|
||
|
||
const downloadTasks=ref([]);
|
||
const downLoadtaskList=computed(()=>{
|
||
return downloadTasks.value.filter((item)=>item.status == "completed" && item.type == "ppt").map((item)=>item.id);
|
||
});
|
||
const uuid = ref("");
|
||
const hcp_token = ref("");
|
||
const order = ref(null);
|
||
const isCollection = ref(0);
|
||
const hasDownload = ref(false);
|
||
const downLoadStatus = ref('start');
|
||
const orderInfo = ref(null);
|
||
// ===== 分享相关 =====
|
||
const summary = ref("");
|
||
const shareLink = ref("");
|
||
const shareImg = ref(logoImg);
|
||
const shareTitle = ref("课件分享");
|
||
onLoad((options) => {
|
||
console.log(options);
|
||
uuid.value = options.uuid;
|
||
checkUser(options);
|
||
});
|
||
onShow(() => {
|
||
hasDownload.value = false;
|
||
downLoadStatus.value = 'start';
|
||
syncTasksFromStore();
|
||
// 监听store变化
|
||
downloadStore.addListener((tasks) => {
|
||
downloadTasks.value = tasks;
|
||
});
|
||
// 恢复正在下载的任务
|
||
resumeDownloadingTasks();
|
||
ganDanFileDetials();
|
||
if(downloadTasks.value.length > 0) {
|
||
for(let i = 0; i < downloadTasks.value.length; i++) {
|
||
if(downloadTasks.value[i].id == uuid.value) {
|
||
hasDownload.value = true;
|
||
if(downloadTasks.value[i].status == 'completed') {
|
||
downLoadStatus.value = 'completed';
|
||
}else if(downloadTasks.value[i].status == 'downloading') {
|
||
downLoadStatus.value = 'loading';
|
||
}else if(downloadTasks.value[i].status == 'paused') {
|
||
downLoadStatus.value = 'paused';
|
||
}else if(downloadTasks.value[i].status == 'failed') {
|
||
downLoadStatus.value = 'failed';
|
||
}
|
||
}
|
||
}
|
||
};
|
||
});
|
||
// ===== 原生分享弹窗(复制自 webview.vue 并适配)=====
|
||
// 分享弹窗引用(这里只用原生弹窗,不使用 uni-popup)
|
||
const shareToggle = () => {
|
||
showNativePopup();
|
||
};
|
||
|
||
// 原生弹窗相关
|
||
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 items = [
|
||
{ id: 'it-wechat', text: '微信' },
|
||
{ id: 'it-moments', text: '朋友圈' },
|
||
// { id: 'it-weibo', text: '微博' }
|
||
];
|
||
// 三个分享项区域(使用图标)
|
||
const itemW = screenW / items.length;
|
||
const iconTop = contentTop;
|
||
const textTop = iconTop + iconSize + uni.upx2px(16);
|
||
|
||
// 图标文件名映射(直接使用文件名,避免路径转换问题)
|
||
const iconFiles = [
|
||
'share_weixin.png', // 微信
|
||
'share_wxc.png', // 朋友圈
|
||
'share_sina.png' // 微博
|
||
];
|
||
|
||
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;
|
||
|
||
// 构建图标本地路径
|
||
let iconPath = null;
|
||
try {
|
||
const iconFile = iconFiles[idx];
|
||
// 使用 _www 相对路径,避免 iOS 下 file:// 路径导致图片不显示
|
||
iconPath = '_www/static/' + iconFile;
|
||
} catch (e) {
|
||
iconPath = null;
|
||
}
|
||
|
||
// 绘制图标
|
||
if (iconPath) {
|
||
try {
|
||
try {
|
||
nativePopupView.value.drawBitmap(iconPath, {}, {
|
||
left: iconLeftPx + 'px',
|
||
top: iconTopPx + 'px',
|
||
width: iconSizePx + 'px',
|
||
height: iconSizePx + 'px'
|
||
});
|
||
} catch (e1) {
|
||
nativePopupView.value.drawBitmap(iconPath, {
|
||
left: iconLeftPx + 'px',
|
||
top: iconTopPx + 'px',
|
||
width: iconSizePx + 'px',
|
||
height: iconSizePx + 'px'
|
||
});
|
||
}
|
||
} catch (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 = () => {
|
||
closeNativePopup();
|
||
};
|
||
|
||
const handlePanelClick = (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;
|
||
}
|
||
|
||
if (!x || !y) {
|
||
return;
|
||
}
|
||
|
||
// 相对坐标换算
|
||
let relativeY = y;
|
||
let relativeX = x;
|
||
|
||
if (y < info.panelH) {
|
||
relativeY = y;
|
||
relativeX = x;
|
||
} else if (y >= (info.screenH - info.panelH)) {
|
||
relativeY = y - (info.screenH - info.panelH);
|
||
relativeX = x;
|
||
}
|
||
|
||
// 取消区域
|
||
const cancelTop = info.panelH - info.cancelH;
|
||
if (relativeY >= cancelTop) {
|
||
closeNativePopup();
|
||
return;
|
||
}
|
||
|
||
// 分享区域
|
||
const shareAreaTop = info.contentTop;
|
||
const shareAreaBottom = shareAreaTop + info.iconSize + info.textSize + uni.upx2px(20);
|
||
|
||
if (relativeY >= shareAreaTop && relativeY <= shareAreaBottom) {
|
||
const itemWidth = info.screenW / 2; // 目前只有两个:微信、朋友圈
|
||
const idx = Math.min(1, Math.max(0, Math.floor(relativeX / itemWidth)));
|
||
|
||
if (idx === 0) {
|
||
shareToWechat();
|
||
closeNativePopup();
|
||
} else if (idx === 1) {
|
||
shareToMoments();
|
||
closeNativePopup();
|
||
}
|
||
}
|
||
};
|
||
|
||
// 同时监听 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
|
||
}
|
||
|
||
// 统一关闭方法,方便后面扩展 H5 等
|
||
const closeShare = () => {
|
||
closeNativePopup();
|
||
};
|
||
const goView = () => {
|
||
for(let i = 0; i < downloadTasks.value.length; i++) {
|
||
if(downloadTasks.value[i].id == uuid.value) {
|
||
plus.runtime.openFile(downloadTasks.value[i].localPath, function(e) {
|
||
console.log('打开成功');
|
||
}, function(e) {
|
||
uni.showToast({
|
||
title: '打开失败:' + e.message,
|
||
icon: "none",
|
||
});
|
||
});
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
|
||
const collection = () => {
|
||
api
|
||
.collection({
|
||
other_uuid: uuid.value,
|
||
type: 6,
|
||
})
|
||
.then((res) => {
|
||
if (res.code == 200) {
|
||
uni.showToast({
|
||
title: "收藏成功",
|
||
icon: "none",
|
||
});
|
||
ganDanFileDetials();
|
||
}
|
||
});
|
||
};
|
||
const toggleCollection = () => {
|
||
if (isCollection.value == 1) {
|
||
discollection();
|
||
} else {
|
||
collection();
|
||
}
|
||
};
|
||
const discollection = () => {
|
||
api.discollection({
|
||
other_uuid: uuid.value,
|
||
type: 6,
|
||
})
|
||
.then((res) => {
|
||
console.log(res);
|
||
if (res.code == 200) {
|
||
uni.showToast({
|
||
title: "取消收藏成功",
|
||
icon: "none",
|
||
});
|
||
ganDanFileDetials();
|
||
}
|
||
});
|
||
};
|
||
const checkUser = async (options) => {
|
||
const res = await api.checkUser();
|
||
if (res.code == 200) {
|
||
hcp_token.value = res.data.hcp_token;
|
||
const resInfo = uni.getSystemInfoSync(); // 或者使用 uni.getSystemInfo({...}).then(res => {...})
|
||
let statusBarHeight = resInfo.statusBarHeight;
|
||
// #ifdef APP-PLUS
|
||
let wv = plus.webview.create("", "custom-webview", {
|
||
top:(statusBarHeight+44+50)+"px",
|
||
});
|
||
shareLink.value = decodeURIComponent(options.src);
|
||
|
||
let newstr = `document.cookie="hcp_token=${hcp_token.value};domain=.igandan.com;path=/;"`;
|
||
/* 获取屏幕信息 */
|
||
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);
|
||
wv.loadURL(decodeURIComponent(options.src))
|
||
setTimeout(function () {
|
||
wv = currentWebview.children()[0];
|
||
wv.setStyle({ top:(statusBarHeight+44+50)+"px", height: 1000 });
|
||
},1000); //如果是页面初始化调用时,需要延时一下
|
||
|
||
|
||
|
||
wv.onloaded = (e) => {
|
||
wv.evalJS(newstr);
|
||
wv.evalJS(
|
||
`document.cookie="hcp_from=expert_app;domain=.igandan.com;path=/"`
|
||
);
|
||
wv.show();
|
||
setTimeout(function () {
|
||
if(wv.getURL().indexOf('hcp') > -1){
|
||
wv.loadURL(decodeURIComponent(options.src));
|
||
}
|
||
},2000);
|
||
|
||
};
|
||
|
||
// #endif
|
||
}
|
||
};
|
||
const freeClose = () => {
|
||
freeVisible.value = false;
|
||
goPay();
|
||
};
|
||
const goPay = () => {
|
||
navTo({
|
||
url: "/pages_app/pay/pay?uuid=" + uuid.value + "&type=ganDanFile",
|
||
});
|
||
};
|
||
|
||
const downLoadByType=()=>{
|
||
if(orderInfo.value.price==0){
|
||
downloadGanDanFile();
|
||
}else if(orderInfo.value.price>0){
|
||
if(orderInfo.value.welfareNum>0){
|
||
freeVisible.value = true;
|
||
freeContent.value = '您还有'+orderInfo.value.welfareNum+'次免费下载机会,希望本次下载免费吗?';
|
||
}else if(orderInfo.value.freeRecord>0){
|
||
freeVisible.value = true;
|
||
freeContent.value = '您还有'+orderInfo.value.freeRecord+'次免费下载机会,希望本次下载免费吗?';
|
||
}else if(orderInfo.value.order && orderInfo.value.order.order_status == 'paid'){
|
||
downloadGanDanFile()
|
||
}
|
||
|
||
}
|
||
}
|
||
const downloadGanDanFile = () => {
|
||
let order_id='';
|
||
if(orderInfo.value.price==0){
|
||
order_id='Free';
|
||
}else if(orderInfo.value.price>0){
|
||
if(orderInfo.value.welfareNum>0){
|
||
order_id='USEWELFARENUM';
|
||
}else if(orderInfo.value.freeRecord>0){
|
||
order_id='FREERECORD';
|
||
}else if(orderInfo.value.order && orderInfo.value.order.order_status == 'paid'){
|
||
order_id=uuid.value+"&R";
|
||
}
|
||
|
||
}
|
||
if(downLoadStatus.value == 'loading'){
|
||
uni.showToast({
|
||
title: "正在下载中",
|
||
icon: "none",
|
||
});
|
||
return false;
|
||
};
|
||
|
||
|
||
// 使用store添加任务
|
||
const taskIndex = downloadStore.addTask({
|
||
title: orderInfo.value.name,
|
||
id: uuid.value,
|
||
type: 'ppt',
|
||
status: 'downloading',
|
||
});
|
||
hasDownload.value = true;
|
||
downLoadStatus.value = 'loading';
|
||
// 同步任务列表
|
||
syncTasksFromStore();
|
||
// 开始下载
|
||
// startDownload(taskIndex);
|
||
api.downloadGanDanFile({
|
||
file_uuid: uuid.value,
|
||
order_id: order_id,
|
||
}).then((res) => {
|
||
|
||
console.log(res);
|
||
const base64 = uni.arrayBufferToBase64(res);
|
||
base64ToFile(base64, orderInfo.value.name+'.pdf', (path) => {
|
||
downLoadStatus.value = 'completed';
|
||
uni.showToast({
|
||
title: "下载成功",
|
||
icon: "none",
|
||
});
|
||
downloadStore.updateTask(taskIndex, {
|
||
status: "completed",
|
||
localPath: path,
|
||
});
|
||
|
||
|
||
});
|
||
});
|
||
};
|
||
|
||
const base64ToFile=(base64Str, fileName, callback)=>{
|
||
// #ifdef H5
|
||
// 去除base64前缀
|
||
var index = base64Str.indexOf(',');
|
||
base64Str = base64Str.slice(index + 1, base64Str.length);
|
||
|
||
// 创建Blob对象
|
||
var blob = dataURItoBlob(base64Str);
|
||
|
||
// 创建一个新的Blob URL
|
||
var blobUrl = window.URL.createObjectURL(blob);
|
||
|
||
// 创建一个新的a标签用于下载
|
||
var a = document.createElement('a');
|
||
a.href = blobUrl;
|
||
a.download = fileName;
|
||
document.body.appendChild(a);
|
||
|
||
// 模拟点击a标签触发下载
|
||
a.click();
|
||
|
||
// 移除a标签和Blob URL
|
||
document.body.removeChild(a);
|
||
window.URL.revokeObjectURL(blobUrl);
|
||
|
||
// 回调
|
||
callback && callback(blobUrl);
|
||
|
||
// 将base64字符串转换为Blob对象
|
||
function dataURItoBlob(dataURI) {
|
||
var byteString = atob(dataURI);
|
||
var arrayBuffer = new ArrayBuffer(byteString.length);
|
||
var uint8Array = new Uint8Array(arrayBuffer);
|
||
for (var i = 0; i < byteString.length; i++) {
|
||
uint8Array[i] = byteString.charCodeAt(i);
|
||
}
|
||
return new Blob([uint8Array], {
|
||
type: 'application/octet-stream'
|
||
});
|
||
}
|
||
// #endif
|
||
// #ifdef APP-PLUS
|
||
// 去除base64前缀
|
||
var index = base64Str.indexOf(',')
|
||
var base64Str = base64Str.slice(index + 1, base64Str.length)
|
||
|
||
plus.io.requestFileSystem(plus.io.PRIVATE_DOC, function(fs) {
|
||
fs.root.getFile(fileName, {
|
||
create: true
|
||
}, function(entry) {
|
||
// 获得本地路径URL,file:///xxx/doc/1663062980631.xlsx
|
||
var fullPath = entry.fullPath;
|
||
let platform = uni.getSystemInfoSync().platform;
|
||
if (platform == 'android') {
|
||
var FileOutputStream = plus.android.importClass("java.io.FileOutputStream");
|
||
try {
|
||
function base64ToByteArray(base64Str) {
|
||
const binaryString = atob(base64Str);
|
||
const uint8Array = new Uint8Array(binaryString.length);
|
||
|
||
for (let i = 0; i < binaryString.length; i++) {
|
||
uint8Array[i] = binaryString.charCodeAt(i);
|
||
}
|
||
let arr = []
|
||
Array.from(uint8Array).map(num => {
|
||
arr.push(num >= 128 ? (num - 256) : num)
|
||
})
|
||
return arr;
|
||
}
|
||
var out = new FileOutputStream(fullPath);
|
||
let bytes = base64ToByteArray(base64Str);
|
||
if (bytes == null || bytes.length == 0) {
|
||
out.close();
|
||
uni.hideLoading();
|
||
uni.showModal({
|
||
title: "生成失败",
|
||
content: "nativeJS限制参数长度无法获取文件!",
|
||
showCancel: false
|
||
})
|
||
return
|
||
} else {
|
||
out.write(bytes);
|
||
out.close();
|
||
// 回调
|
||
callback && callback(entry.toLocalURL());
|
||
return
|
||
}
|
||
} catch (e) {
|
||
console.log(e.message);
|
||
}
|
||
} else if (platform == 'ios') {
|
||
var NSData = plus.ios.importClass('NSData');
|
||
var nsData = new NSData();
|
||
nsData = nsData.initWithBase64EncodedStringoptions(base64Str, 0);
|
||
if (nsData) {
|
||
nsData.plusCallMethod({
|
||
writeToFile: fullPath,
|
||
atomically: true
|
||
});
|
||
plus.ios.deleteObject(nsData);
|
||
}
|
||
// 回调
|
||
callback && callback(entry.toLocalURL());
|
||
}
|
||
})
|
||
})
|
||
// #endif
|
||
};
|
||
|
||
|
||
|
||
const ganDanFileDetials = async () => {
|
||
const res = await api.ganDanFileDetials({
|
||
file_uuid: uuid.value,
|
||
});
|
||
if (res.code == 200) {res.data
|
||
orderInfo.value = res.data;
|
||
// 设置分享文案
|
||
shareTitle.value = res.data.name || "课件分享";
|
||
summary.value = "分享一份来自“肝胆相照”的课件:" + shareTitle.value;
|
||
// H5 或其他平台可以用统一分享链接
|
||
shareLink.value = "https://www.igandan.com";
|
||
// 分享图片:接口若返回封面图可替换此处
|
||
if (res.data.cover) {
|
||
shareImg.value = res.data.cover;
|
||
}
|
||
isCollection.value = res.data.iscollection;
|
||
order.value = res.data.order;
|
||
let money = res.data.price/ 100;
|
||
price.value = money > 1 ? money.toFixed(1) : money.toFixed(2);
|
||
|
||
downloadTasks.value.forEach(item => {
|
||
if (item.id == uuid.value) {
|
||
uni.getSavedFileInfo({
|
||
filePath: item.localPath, //仅做示例用,非真正的文件路径
|
||
success: function (res) {
|
||
hasDownload.value = true;
|
||
downLoadStatus.value = 'completed';
|
||
},
|
||
fail: function (err) {
|
||
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
const images = ref([
|
||
"/static/big_background_my.png",
|
||
"/static/big_background_my.png",
|
||
"/static/big_background_my.png",
|
||
]);
|
||
const currentIndex = ref(1); // 对应截图显示 2/23 的第二页效果
|
||
const price = ref("1.0");
|
||
|
||
const onSwiperChange = (e) => {
|
||
currentIndex.value = e.detail.current;
|
||
};
|
||
|
||
const goBack = () => {
|
||
uni.navigateBack({
|
||
delta: 1,
|
||
fail: (err) => {
|
||
uni.redirectTo({
|
||
url: "/pages/index/index",
|
||
});
|
||
},
|
||
});
|
||
};
|
||
|
||
const alertDownloading = () => {
|
||
uni.showToast({
|
||
title: "文件正在下载中...",
|
||
icon: "none",
|
||
});
|
||
};
|
||
const syncTasksFromStore = () => {
|
||
downloadTasks.value = downloadStore.getTasks();
|
||
};
|
||
// 恢复正在下载的任务
|
||
const resumeDownloadingTasks = () => {
|
||
// 使用 nextTick 确保在页面渲染后再恢复下载任务
|
||
nextTick(() => {
|
||
downloadStore.resumeDownloadingTasks((index) => {
|
||
// 重新开始下载(uni.downloadFile不支持断点续传,所以从0开始)
|
||
console.log("恢复下载任务:", downloadStore.getTask(index)?.url);
|
||
startDownload(index);
|
||
});
|
||
});
|
||
};
|
||
|
||
// ===== 分享到微信 =====
|
||
const shareToWechat = () => {
|
||
// #ifdef APP-PLUS
|
||
uni.share({
|
||
provider: "weixin",
|
||
scene: "WXSceneSession",
|
||
type: 0,
|
||
title: shareTitle.value,
|
||
summary: summary.value,
|
||
href: shareLink.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
|
||
if (navigator.share) {
|
||
navigator
|
||
.share({
|
||
title: shareTitle.value,
|
||
text: summary.value,
|
||
url: shareLink.value,
|
||
})
|
||
.then(() => {
|
||
uni.showToast({
|
||
title: "分享成功",
|
||
icon: "success",
|
||
});
|
||
})
|
||
.catch(() => {
|
||
uni.showToast({
|
||
title: "分享失败",
|
||
icon: "none",
|
||
});
|
||
});
|
||
} else {
|
||
uni.setClipboardData({
|
||
data: summary.value + "\n链接:" + shareLink.value,
|
||
success: () => {
|
||
uni.showToast({
|
||
title: "已复制到剪贴板",
|
||
icon: "success",
|
||
});
|
||
},
|
||
});
|
||
}
|
||
// #endif
|
||
|
||
closeShare();
|
||
};
|
||
|
||
// ===== 分享到朋友圈 =====
|
||
const shareToMoments = () => {
|
||
// #ifdef APP-PLUS
|
||
uni.share({
|
||
provider: "weixin",
|
||
scene: "WXSceneTimeline",
|
||
type: 0,
|
||
title: shareTitle.value,
|
||
summary: summary.value,
|
||
href: shareLink.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: summary.value + "\n链接:" + shareLink.value,
|
||
success: () => {
|
||
uni.showToast({
|
||
title: "已复制到剪贴板,可分享到朋友圈",
|
||
icon: "success",
|
||
});
|
||
},
|
||
});
|
||
// #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
|
||
});
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.navbox {
|
||
:deep(.uni-navbar__header-btns-right) {
|
||
width: 100px !important;
|
||
}
|
||
:deep(.uni-navbar__header-btns-left) {
|
||
min-width: 100px;
|
||
width: 100px !important;
|
||
}
|
||
}
|
||
.share-img-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
.collect-img-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
.ppt-detail-page {
|
||
background-color: #ffffff;
|
||
min-height: 100vh;
|
||
}
|
||
.collect-img-icon{
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
.nav-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.download-bar {
|
||
position: fixed;
|
||
top:calc(var(--status-bar-height) + 44px);
|
||
z-index: 89;
|
||
width: 100%;
|
||
background-color: #6f6f6f; // 接近截图灰条
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.download-inner {
|
||
padding: 0 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #fff;
|
||
}
|
||
.download-text {
|
||
margin-left: 12rpx;
|
||
font-size: 28rpx;
|
||
}
|
||
.download-price {
|
||
margin-left: 8rpx;
|
||
color: #ff3b30; // 红色价格
|
||
|
||
font-size: 30rpx;
|
||
}
|
||
.download-unit {
|
||
margin-left: 4rpx;
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.viewer {
|
||
padding: 24rpx 0;
|
||
}
|
||
|
||
.ppt-swiper {
|
||
width: 100%;
|
||
min-height: 400rpx;
|
||
background-color: #fff;
|
||
}
|
||
.slide {
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
.slide-image {
|
||
width: 100%;
|
||
}
|
||
|
||
.page-indicator {
|
||
margin-top: 20rpx;
|
||
text-align: center;
|
||
font-size: 32rpx;
|
||
color: #333;
|
||
}
|
||
</style>
|