200 lines
6.7 KiB
JavaScript
200 lines
6.7 KiB
JavaScript
/**
|
||
* 多端兼容文件保存(基于已下载的临时路径,无需重复download)
|
||
* 核心:传入的url是uni.downloadFile返回的tempFilePath,直接用fs.saveFile保存
|
||
* @param {string} tempFilePath - 已下载的文件临时路径(必填,来自downloadFile返回值)
|
||
* @param {string} [fileName] - 自定义保存文件名(可选,默认从临时路径提取)
|
||
* @returns {Promise<void>} - 保存结果Promise
|
||
*/
|
||
export function saveFileFromTemp(args) {
|
||
const {tempFilePath, fileName,isNowOpen=false}=args
|
||
// 前置校验:临时路径必填
|
||
if (!tempFilePath) {
|
||
uni.showToast({ title: "文件临时路径不能为空", icon: "none" });
|
||
return Promise.reject(new Error("临时路径不能为空"));
|
||
}
|
||
|
||
// 共用逻辑:从临时路径/URL提取默认文件名(适配各端临时路径格式)
|
||
const getDefaultFileName = () => {
|
||
let name = `文件_${Date.now()}`;
|
||
try {
|
||
// 处理微信小程序临时路径(如:wxfile://tmp/xxx.pdf)
|
||
if (
|
||
tempFilePath.includes("wxfile://") ||
|
||
tempFilePath.includes("/tmp/")
|
||
) {
|
||
const lastSlashIndex = tempFilePath.lastIndexOf("/");
|
||
if (lastSlashIndex !== -1) {
|
||
name = tempFilePath.slice(lastSlashIndex + 1);
|
||
}
|
||
}
|
||
// 处理App临时路径(如:_doc/tmp/xxx.png)或普通URL
|
||
else {
|
||
const urlObj = new URL(tempFilePath, window.location.origin); // 兼容相对路径
|
||
const pathname = urlObj.pathname;
|
||
const lastSlashIndex = pathname.lastIndexOf("/");
|
||
if (lastSlashIndex !== -1) {
|
||
name = pathname.slice(lastSlashIndex + 1).split("?")[0];
|
||
}
|
||
}
|
||
// 补充文件后缀(如果没有)
|
||
if (!name.includes(".")) {
|
||
name += ".bin"; // 兜底后缀,可根据实际业务调整(如:.pdf/.png)
|
||
}
|
||
} catch (e) {
|
||
name = `文件_${Date.now()}.bin`;
|
||
}
|
||
return fileName || name;
|
||
};
|
||
const targetFileName = getDefaultFileName();
|
||
|
||
// -------------------------- H5端处理(临时路径直接触发下载) --------------------------
|
||
// #ifdef H5
|
||
return new Promise((resolve, reject) => {
|
||
// H5的临时路径可能是blob:xxx格式,直接用a标签下载
|
||
const link = document.createElement("a");
|
||
link.href = tempFilePath;
|
||
link.download = targetFileName;
|
||
link.target = "_blank";
|
||
link.style.display = "none";
|
||
|
||
link.addEventListener("error", () => {
|
||
uni.showToast({
|
||
title: "保存失败:H5临时路径无效或跨域",
|
||
icon: "none",
|
||
duration: 3000,
|
||
});
|
||
reject(new Error("H5临时路径保存失败"));
|
||
});
|
||
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
document.body.removeChild(link);
|
||
|
||
uni.showToast({ title: "保存成功,请查看浏览器下载列表", icon: "none" });
|
||
resolve();
|
||
});
|
||
// #endif
|
||
|
||
// -------------------------- 微信小程序端处理(fs.saveFile 保存临时路径) --------------------------
|
||
// #ifdef MP-WEIXIN
|
||
return new Promise((resolve, reject) => {
|
||
const fs = uni.getFileSystemManager();
|
||
// 微信小程序保存路径(沙箱目录)
|
||
const saveFilePath = `${wx.env.USER_DATA_PATH}/${targetFileName}`;
|
||
|
||
// 直接保存临时路径(无需下载)
|
||
fs.saveFile({
|
||
tempFilePath: tempFilePath, // 传入已下载的临时路径
|
||
filePath: saveFilePath,
|
||
success: (saveRes) => {
|
||
if(isNowOpen){
|
||
uni.openDocument({
|
||
filePath: saveRes.savedFilePath,
|
||
showMenu:true,
|
||
success: (openRes) => {
|
||
uni.showToast({
|
||
title: "文件已打开",
|
||
icon: "none",
|
||
duration: 1500,
|
||
});
|
||
},
|
||
fail: (openErr) => {
|
||
uni.showToast({
|
||
title: `打开文件失败:${openErr.errMsg}`,
|
||
icon: "none",
|
||
duration: 1500,
|
||
});
|
||
},
|
||
});
|
||
}else{
|
||
uni.showModal({
|
||
title: "保存成功",
|
||
content: `文件已保存至:微信 → 我 → 文件 → 下载管理`,
|
||
showCancel: false,
|
||
});
|
||
}
|
||
|
||
resolve(saveRes);
|
||
},
|
||
fail: (saveErr) => {
|
||
uni.showToast({ title: `保存失败:${saveErr.errMsg}`, icon: "none" });
|
||
reject(saveErr);
|
||
},
|
||
});
|
||
});
|
||
// #endif
|
||
|
||
// -------------------------- App端处理(fs.saveFile 保存临时路径) --------------------------
|
||
// #ifdef APP
|
||
return new Promise(async (resolve, reject) => {
|
||
const fs = uni.getFileSystemManager();
|
||
// App保存路径(沙箱目录)
|
||
const saveFilePath = `${uni.env.USER_DATA_PATH}/${targetFileName}`;
|
||
|
||
// Android 6.0+ 申请存储权限
|
||
if (uni.getSystemInfoSync().platform === "android") {
|
||
try {
|
||
const permRes = await uni.requestPermissions({
|
||
scope: "scope.writeExternalStorage",
|
||
});
|
||
if (!permRes[0].authSetting["scope.writeExternalStorage"]) {
|
||
uni.showModal({
|
||
title: "权限不足",
|
||
content: "请授予存储权限后重试(设置 → 应用 → 权限管理)",
|
||
showCancel: false,
|
||
});
|
||
return reject(new Error("存储权限未授予"));
|
||
}
|
||
} catch (permErr) {
|
||
uni.showToast({
|
||
title: `权限申请失败:${permErr.errMsg}`,
|
||
icon: "none",
|
||
});
|
||
return reject(permErr);
|
||
}
|
||
}
|
||
|
||
// 直接保存临时路径(无需下载)
|
||
fs.saveFile({
|
||
tempFilePath: tempFilePath, // 传入已下载的临时路径
|
||
filePath: saveFilePath,
|
||
success: (saveRes) => {
|
||
const platform = uni.getSystemInfoSync().platform;
|
||
uni.showModal({
|
||
title: "保存成功",
|
||
content:
|
||
platform === "ios"
|
||
? "文件已保存至应用沙箱,点击「查看」打开"
|
||
: `文件路径:内部存储/Android/data/应用包名/files/${targetFileName}`,
|
||
confirmText: "查看",
|
||
cancelText: "取消",
|
||
success: (modalRes) => {
|
||
if (modalRes.confirm) {
|
||
uni.openDocument({
|
||
filePath: saveRes.savedFilePath,
|
||
showMenu: true,
|
||
fail: (openErr) => {
|
||
uni.showToast({
|
||
title: `无法打开:${openErr.errMsg}`,
|
||
icon: "none",
|
||
});
|
||
},
|
||
});
|
||
}
|
||
},
|
||
});
|
||
resolve(saveRes);
|
||
},
|
||
fail: (saveErr) => {
|
||
uni.showToast({ title: `保存失败:${saveErr.errMsg}`, icon: "none" });
|
||
reject(saveErr);
|
||
},
|
||
});
|
||
});
|
||
// #endif
|
||
|
||
// 其他未适配平台
|
||
return Promise.reject(new Error("当前平台暂不支持文件保存"));
|
||
}
|
||
|