/** * 多端兼容文件保存(基于已下载的临时路径,无需重复download) * 核心:传入的url是uni.downloadFile返回的tempFilePath,直接用fs.saveFile保存 * @param {string} tempFilePath - 已下载的文件临时路径(必填,来自downloadFile返回值) * @param {string} [fileName] - 自定义保存文件名(可选,默认从临时路径提取) * @returns {Promise} - 保存结果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("当前平台暂不支持文件保存")); }