复制及预览优化

This commit is contained in:
Dev
2026-09-30 18:19:25 +08:00
parent 2ed3d48717
commit 379d29a356
4 changed files with 206 additions and 27 deletions
@@ -240,6 +240,19 @@ Page({
});
},
// 取文件扩展名对应的 openDocument 类型(默认 pdf)
getFileType(url) {
const ext = String(url || '').split('?')[0].split('#')[0].split('.').pop().toLowerCase();
const support = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'];
return support.indexOf(ext) > -1 ? ext : 'pdf';
},
// 取域名,用于下载失败时提示配置合法域名
getUrlHost(url) {
const match = String(url || '').match(/^https?:\/\/([^/:?#]+)/);
return match ? match[1] : '';
},
// 附件预览:客户点击开发者上传的附件进行查看
handlePreviewAttach(e) {
// 仅客户侧可预览;开发者侧附件可删除,避免删除时误触预览
@@ -260,16 +273,22 @@ Page({
return;
}
// 其他文件下载后打开
const fileType = this.getFileType(fileUrl);
// 指定带扩展名的保存路径:安卓/鸿蒙靠扩展名识别文件类型,默认 tempFilePath 无扩展名易失败
const filePath = `${wx.env.USER_DATA_PATH}/contract_file_${Date.now()}.${fileType}`;
wx.showLoading({ title: '加载中...' });
wx.downloadFile({
url: fileUrl,
filePath: filePath,
success: (res) => {
wx.hideLoading();
if (res.statusCode === 200) {
wx.openDocument({
filePath: res.tempFilePath,
filePath: res.filePath || res.tempFilePath || filePath,
fileType: fileType,
showMenu: true,
fail: () => {
fail: (err) => {
console.error('openDocument fail', err);
wx.showToast({ title: '该文件类型暂不支持预览', icon: 'none' });
}
});
@@ -277,9 +296,16 @@ Page({
wx.showToast({ title: '附件加载失败', icon: 'none' });
}
},
fail: () => {
fail: (err) => {
wx.hideLoading();
wx.showToast({ title: '附件加载失败', icon: 'none' });
console.error('downloadFile fail', err);
// 真机常见原因:downloadFile 合法域名未配置
const host = this.getUrlHost(fileUrl);
wx.showModal({
title: '预览失败',
showCancel: false,
content: '附件下载失败,请检查网络' + (host ? ';若为体验版/真机,请确认已配置 downloadFile 合法域名:' + host : '')
});
}
});
},
+114 -23
View File
@@ -12,7 +12,8 @@ Page({
remark: '',
actualAccount: 0,
activeValues: [0, 1, 2, 3, 4],
demandInfo: null
demandInfo: null,
copyUrl: '' // 剪贴板复制失败时,弹出可长按选择的链接
},
/**
@@ -41,41 +42,131 @@ Page({
);
});
},
// 取文件扩展名对应的 openDocument 类型(默认 pdf)
getFileType(url) {
const ext = String(url || '').split('?')[0].split('#')[0].split('.').pop().toLowerCase();
const support = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'];
return support.indexOf(ext) > -1 ? ext : 'pdf';
},
// 取域名,用于下载失败时提示配置合法域名
getUrlHost(url) {
const match = String(url || '').match(/^https?:\/\/([^/:?#]+)/);
return match ? match[1] : '';
},
//文件预览
fileView(e) {
const fileUrl = e.currentTarget.dataset.url;
if (!fileUrl) {
wx.showToast({
title: '文件链接为空',
icon: 'none'
});
return;
}
const fileType = this.getFileType(fileUrl);
// 指定带扩展名的保存路径:安卓/鸿蒙靠扩展名识别文件类型,
// downloadFile 默认的 tempFilePath 无扩展名,容易打开失败
const filePath = `${wx.env.USER_DATA_PATH}/demand_file_${Date.now()}.${fileType}`;
wx.showLoading({
title: '加载中...',
mask: true
});
wx.downloadFile({
url: fileUrl,
success: function (res) {
const filePath = res.tempFilePath
filePath: filePath,
success: (res) => {
wx.hideLoading();
if (res.statusCode !== 200) {
wx.showToast({
title: '文件加载失败(' + res.statusCode + ')',
icon: 'none'
});
return;
}
const openPath = res.filePath || res.tempFilePath || filePath;
console.log('openDocument', { openPath, fileType });
wx.openDocument({
filePath: filePath,
success: function (res) {
console.log('打开文档成功')
filePath: openPath,
fileType: fileType,
showMenu: true, // 支持转发/用其他应用打开
success: () => {
console.log('打开文档成功');
},
fail: (err) => {
console.error('openDocument fail', err);
// 安卓/鸿蒙部分机型无法直接预览,降级为复制链接到浏览器打开
wx.showModal({
title: '预览失败',
content: '当前系统无法直接预览该文件,是否复制链接后在浏览器中打开?',
confirmText: '复制链接',
cancelText: '关闭',
success: (res2) => {
if (res2.confirm) {
this.copyUrlToClipboard(fileUrl);
}
}
});
}
})
}
})
},
//文件复制
fileUrlCopy(e) {
const url = e.currentTarget.dataset.url;
wx.setClipboardData({
data: url,
success: function () {
wx.showToast({
title: '下载链接已复制',
icon: 'success'
});
},
fail: function () {
wx.showToast({
title: '下载链接复制失败',
icon: 'none'
fail: (err) => {
wx.hideLoading();
console.error('downloadFile fail', err);
// 真机/体验版常见原因:downloadFile 合法域名未配置(开发者工具可关闭校验,真机不行)
const host = this.getUrlHost(fileUrl);
wx.showModal({
title: '预览失败',
showCancel: false,
content: '文件下载失败(' + (err && err.errMsg ? err.errMsg : '未知错误') + '),请检查网络' + (host ? ';请确认已配置 downloadFile 合法域名:' + host : '')
});
}
});
},
// 复制链接(失败自动重试一次,仍失败则弹出可长按选择的链接供手动复制)
copyUrlToClipboard(url) {
if (!url) {
wx.showToast({
title: '文件链接为空',
icon: 'none'
});
return;
}
const doCopy = (retry) => {
wx.setClipboardData({
data: String(url),
success: () => {
wx.showToast({
title: '下载链接已复制',
icon: 'success'
});
},
fail: (err) => {
console.error('setClipboardData fail', err);
if (retry > 0) {
// 系统剪贴板偶发写入失败,短暂延迟后重试一次
setTimeout(() => doCopy(retry - 1), 200);
return;
}
// 降级:展示可长按选择的链接,用户手动复制
this.setData({ copyUrl: String(url) });
}
});
};
doCopy(1);
},
//文件复制
fileUrlCopy(e) {
this.copyUrlToClipboard(e.currentTarget.dataset.url);
},
// 关闭手动复制弹层
closeCopyModal() {
this.setData({ copyUrl: '' });
},
handleChange(e) {
console.log(e.detail.value);
this.setData({
@@ -114,4 +114,14 @@
<t-button wx:elif="{{_calc.canConfirmReceipt(demandInfo)}}" theme="danger" size="large" bind:tap="confirmReceipt" block>确认收货</t-button>
<t-button wx:elif="{{_calc.isWaitingDeliver(demandInfo)}}" theme="light" size="large" disabled block>待发货(等待开发者交付)</t-button>
</block>
</view>
<!-- 复制失败兜底:长按手动选择链接复制 -->
<view class="copy-mask" wx:if="{{copyUrl}}" bindtap="closeCopyModal">
<view class="copy-dialog" catchtap="">
<view class="copy-title">自动复制失败,请长按下方链接手动复制</view>
<text class="copy-url" user-select>{{copyUrl}}</text>
<view class="copy-tip">可粘贴到手机浏览器打开下载</view>
<t-button theme="primary" size="medium" block bind:tap="closeCopyModal">关闭</t-button>
</view>
</view>
@@ -102,6 +102,58 @@ page {
word-break: break-all;
}
/* 复制失败兜底弹层 */
.copy-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 100;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
padding: 48rpx;
box-sizing: border-box;
}
.copy-dialog {
width: 100%;
background: var(--bg-card);
border-radius: var(--radius-lg);
padding: 32rpx;
box-sizing: border-box;
}
.copy-title {
font-size: 28rpx;
font-weight: 600;
line-height: 44rpx;
color: var(--text-primary);
margin-bottom: 20rpx;
}
.copy-url {
display: block;
max-height: 320rpx;
overflow-y: auto;
padding: 20rpx;
background: var(--bg-grey);
border-radius: 12rpx;
font-size: 24rpx;
line-height: 36rpx;
color: var(--text-secondary);
word-break: break-all;
}
.copy-tip {
margin: 16rpx 0 24rpx;
font-size: 24rpx;
line-height: 36rpx;
color: var(--text-tertiary);
}
.button-submit {
margin: 32rpx;
}