|
@@ -1,5 +1,6 @@
|
|
|
'use strict';
|
|
|
import FileApi from '@/sheep/api/infra/file';
|
|
|
+import CryptoJS from 'crypto-js';
|
|
|
|
|
|
const ERR_MSG_OK = 'chooseAndUploadFile:ok';
|
|
|
const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
|
|
@@ -106,7 +107,7 @@ function normalizeChooseAndUploadFileRes(res, fileType) {
|
|
|
item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
|
|
|
}
|
|
|
if (fileType) {
|
|
|
- item.fileType = fileType;
|
|
|
+ item.type = fileType;
|
|
|
}
|
|
|
item.cloudPath = Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
|
|
|
});
|
|
@@ -116,6 +117,28 @@ function normalizeChooseAndUploadFileRes(res, fileType) {
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
+function convertToArrayBuffer(uniFile) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const fs = uni.getFileSystemManager();
|
|
|
+
|
|
|
+ fs.readFile({
|
|
|
+ filePath: uniFile.path, // 确保路径正确
|
|
|
+ success: (fileRes) => {
|
|
|
+ try {
|
|
|
+ // 将读取的内容转换为 ArrayBuffer
|
|
|
+ const arrayBuffer = new Uint8Array(fileRes.data).buffer;
|
|
|
+ resolve(arrayBuffer);
|
|
|
+ } catch (error) {
|
|
|
+ reject(new Error(`转换为 ArrayBuffer 失败: ${error.message}`));
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: (error) => {
|
|
|
+ reject(new Error(`读取文件失败: ${error.errMsg}`));
|
|
|
+ },
|
|
|
+ });
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
function uploadCloudFiles(files, max = 5, onUploadProgress) {
|
|
|
files = JSON.parse(JSON.stringify(files));
|
|
|
const len = files.length;
|
|
@@ -165,36 +188,61 @@ function uploadCloudFiles(files, max = 5, onUploadProgress) {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-function uploadFiles(choosePromise, { onChooseFile, onUploadProgress }) {
|
|
|
- return choosePromise
|
|
|
- .then((res) => {
|
|
|
- if (onChooseFile) {
|
|
|
- const customChooseRes = onChooseFile(res);
|
|
|
- if (typeof customChooseRes !== 'undefined') {
|
|
|
- return Promise.resolve(customChooseRes).then((chooseRes) =>
|
|
|
- typeof chooseRes === 'undefined' ? res : chooseRes,
|
|
|
- );
|
|
|
- }
|
|
|
- }
|
|
|
- return res;
|
|
|
- })
|
|
|
- .then((res) => {
|
|
|
- if (res === false) {
|
|
|
- return {
|
|
|
- errMsg: ERR_MSG_OK,
|
|
|
- tempFilePaths: [],
|
|
|
- tempFiles: [],
|
|
|
- };
|
|
|
- }
|
|
|
- return res;
|
|
|
- })
|
|
|
- .then(async (files) => {
|
|
|
- for (let file of files.tempFiles) {
|
|
|
- const { data } = await FileApi.uploadFile(file.path);
|
|
|
- file.url = data;
|
|
|
+async function uploadFiles(choosePromise, { onChooseFile, onUploadProgress }) {
|
|
|
+ // 获取选择的文件
|
|
|
+ const res = await choosePromise;
|
|
|
+ // 处理文件选择回调
|
|
|
+ let files = res.tempFiles || [];
|
|
|
+ if (onChooseFile) {
|
|
|
+ const customChooseRes = onChooseFile(res);
|
|
|
+ if (typeof customChooseRes !== 'undefined') {
|
|
|
+ files = await Promise.resolve(customChooseRes);
|
|
|
+ if (typeof files === 'undefined') {
|
|
|
+ files = res.tempFiles || []; // Fallback
|
|
|
}
|
|
|
- return files;
|
|
|
- });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果是前端直连上传
|
|
|
+ if (UPLOAD_TYPE.CLIENT === import.meta.env.SHOPRO_UPLOAD_TYPE) {
|
|
|
+ for (const file of files) {
|
|
|
+ // 获取二进制文件对象
|
|
|
+ const fileBuffer = await convertToArrayBuffer(file);
|
|
|
+ // 1.1 生成文件名称
|
|
|
+ const fileName = await generateFileName(fileBuffer, file.name);
|
|
|
+ // 1.2 获取文件预签名地址
|
|
|
+ const { data: presignedInfo } = await FileApi.getFilePresignedUrl(file.name);
|
|
|
+ // 1.3 上传文件
|
|
|
+ await uni.request({
|
|
|
+ url: presignedInfo.uploadUrl, // 预签名的上传 URL
|
|
|
+ method: 'PUT', // 使用 PUT 方法
|
|
|
+ header: {
|
|
|
+ 'Content-Type': file.type + '/' + file.name.substring(file.name.lastIndexOf('.') + 1), // 设置内容类型
|
|
|
+ },
|
|
|
+ data: fileBuffer, // 文件的路径,适用于小程序
|
|
|
+ success: (res) => {
|
|
|
+ // 1.4. 记录文件信息到后端(异步)
|
|
|
+ createFile(presignedInfo, fileName, file);
|
|
|
+ // 1.5. 重新赋值
|
|
|
+ file.url = presignedInfo.url;
|
|
|
+ file.name = fileName;
|
|
|
+ console.log('上传成功:', res);
|
|
|
+ },
|
|
|
+ fail: (err) => {
|
|
|
+ console.error('上传失败:', err);
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return files;
|
|
|
+ } else {
|
|
|
+ // 后端上传
|
|
|
+ for (let file of files) {
|
|
|
+ const { data } = await FileApi.uploadFile(file.path);
|
|
|
+ file.url = data;
|
|
|
+ }
|
|
|
+
|
|
|
+ return files;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function chooseAndUploadFile(
|
|
@@ -210,4 +258,54 @@ function chooseAndUploadFile(
|
|
|
return uploadFiles(chooseAll(opts), opts);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 生成文件名称(使用算法SHA256)
|
|
|
+ * @param arrayBuffer 二进制文件对象
|
|
|
+ * @param fileName 文件名称
|
|
|
+ */
|
|
|
+async function generateFileName(arrayBuffer, fileName) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ try {
|
|
|
+ // 创建 WordArray
|
|
|
+ const wordArray = CryptoJS.lib.WordArray.create(new Uint8Array(arrayBuffer));
|
|
|
+ // 计算SHA256
|
|
|
+ const sha256 = CryptoJS.SHA256(wordArray).toString();
|
|
|
+ // 拼接后缀
|
|
|
+ const ext = fileName.substring(fileName.lastIndexOf('.'));
|
|
|
+ resolve(`${sha256}${ext}`);
|
|
|
+ } catch (error) {
|
|
|
+ reject(new Error('计算SHA256失败: ' + error.message));
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 创建文件信息
|
|
|
+ * @param vo 文件预签名信息
|
|
|
+ * @param name 文件名称
|
|
|
+ * @param file 文件
|
|
|
+ */
|
|
|
+function createFile(vo, name, file) {
|
|
|
+ const fileVo = {
|
|
|
+ configId: vo.configId,
|
|
|
+ url: vo.url,
|
|
|
+ path: name,
|
|
|
+ name: file.name,
|
|
|
+ type: file.fileType,
|
|
|
+ size: file.size,
|
|
|
+ };
|
|
|
+ FileApi.createFile(fileVo);
|
|
|
+ return fileVo;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 上传类型
|
|
|
+ */
|
|
|
+const UPLOAD_TYPE = {
|
|
|
+ // 客户端直接上传(只支持S3服务)
|
|
|
+ CLIENT: 'client',
|
|
|
+ // 客户端发送到后端上传
|
|
|
+ SERVER: 'server',
|
|
|
+};
|
|
|
+
|
|
|
export { chooseAndUploadFile, uploadCloudFiles };
|