Commit 29a20ad7 by renmanyi

Merge branch 'feature/renmanyi/20260121/tx-upload' into 'master'

Feature/renmanyi/20260121/tx upload

See merge request !97
parents 0e333b1d 97c09c43
...@@ -137,7 +137,8 @@ module.exports = function (webpackEnv) { ...@@ -137,7 +137,8 @@ module.exports = function (webpackEnv) {
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development', mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
// Stop compilation early in production // Stop compilation early in production
bail: isEnvProduction, bail: isEnvProduction,
devtool: isEnvProduction ? (shouldUseSourceMap ? 'source-map' : false) : isEnvDevelopment && 'cheap-module-source-map', devtool: false,
// devtool: isEnvProduction ? (shouldUseSourceMap ? 'source-map' : false) : isEnvDevelopment && 'cheap-module-source-map',
// These are the "entry points" to our application. // These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle. // This means they will be the "root" imports that are included in JS bundle.
entry: [ entry: [
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
"@types/underscore": "^1.10.22", "@types/underscore": "^1.10.22",
"@typescript-eslint/eslint-plugin": "^2.10.0", "@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0", "@typescript-eslint/parser": "^2.10.0",
"ali-oss": "6.17.1", "ali-oss": "^6.23.0",
"cos-js-sdk-v5": "^1.10.1",
"antd": "^4.16.3", "antd": "^4.16.3",
"array-move": "^3.0.1", "array-move": "^3.0.1",
"axios": "^0.20.0", "axios": "^0.20.0",
......
...@@ -9,6 +9,7 @@ import { ...@@ -9,6 +9,7 @@ import {
FILR_VERIFY_MAP, FILR_VERIFY_MAP,
UPLOAD_PART_SIZE, UPLOAD_PART_SIZE,
UPLOAD_PARALLEL, UPLOAD_PARALLEL,
TX_UPLOAD_REGION,
} from "@/domains/resource-disk/constants"; } from "@/domains/resource-disk/constants";
import { getFileTypeByName } from '@/domains/resource-disk/utils'; import { getFileTypeByName } from '@/domains/resource-disk/utils';
import UploadFileService from '@/domains/resource-disk/UploadFileService'; import UploadFileService from '@/domains/resource-disk/UploadFileService';
...@@ -72,15 +73,17 @@ class UploadProgressModal extends React.Component { ...@@ -72,15 +73,17 @@ class UploadProgressModal extends React.Component {
accessTypeEnum: 'PUBLIC', accessTypeEnum: 'PUBLIC',
bizCode: 'UPLOAD_FOLDER', bizCode: 'UPLOAD_FOLDER',
}).then((result) => { }).then((result) => {
const { ossClient, resourceId, callBack, callbackBody, ossUri } = result; const { ossClient, resourceId, ossUri, vendorType,bucket,callbackData,callback} = result;
this.setState({ this.setState({
ossClient, ossClient,
resourceId, resourceId,
callBack, callbackData,
callbackBody, callback,
ossUri ossUri,
bucket,
vendorType
}); });
resolve({ ossClient, resourceId, callBack, callbackBody, ossUri }); resolve({ ossClient, resourceId, vendorType, bucket, callbackData, callback, ossUri });
}) })
}) })
} }
...@@ -97,29 +100,62 @@ class UploadProgressModal extends React.Component { ...@@ -97,29 +100,62 @@ class UploadProgressModal extends React.Component {
// 开始上传之前初始化OssClient // 开始上传之前初始化OssClient
this.initOssClient(id, resourceName).then((result) => { this.initOssClient(id, resourceName).then((result) => {
const { ossClient, resourceId, callBack, callbackBody, ossUri } = result; const { ossClient, resourceId, ossUri, vendorType,bucket,callbackData,callback} = result;
ossClient.multipartUpload(ossUri, fileContent, { if (vendorType === 'TENCENT_COS') {
// 腾讯云分片上传
ossClient.sliceUploadFile({
Bucket: bucket,
Region: TX_UPLOAD_REGION,
Key:ossUri,
Body: fileContent,
SliceSize: UPLOAD_PART_SIZE,
// 回调配置
Callback: callback,
onProgress: (progressData) => {
const progress = progressData.percent;
this.onMultipartUploadProgress(progress, { uploadId: randomString(16), file: fileContent }, file);
},
onTaskReady: (taskId) => {
// 记录任务ID,用于取消上传
file.taskId = taskId;
},
})
.then(res => {
file.status = 'success';
this.setState({ fileList });
this.props.onUpload(fileContent, resourceId);
})
.catch(err => {
file.status = 'fail';
this.setState({ fileList });
});
} else {
// 阿里云分片上传
ossClient
.multipartUpload(ossUri, fileContent, {
callback: { callback: {
url: callBack, url: callbackData.url,
body: callbackBody, body: callbackData.body,
contentType: 'application/json', callbackSNI: true,
contentType: callbackData.contentType
}, },
parallel: UPLOAD_PARALLEL, parallel: UPLOAD_PARALLEL,
partSize: UPLOAD_PART_SIZE, partSize: UPLOAD_PART_SIZE,
progress: (progress, checkpoint) => { progress: (progress, checkpoint) => {
this.onMultipartUploadProgress(progress, checkpoint, file) this.onMultipartUploadProgress(progress, checkpoint, file);
}, },
mime: type mime: type
}).then(url => { })
console.log('1111'); .then(url => {
file.status = 'success'; file.status = 'success';
this.setState({ fileList }); this.setState({ fileList });
this.props.onUpload(fileContent, resourceId); this.props.onUpload(fileContent, resourceId);
}).catch(err => { })
.catch(err => {
file.status = 'fail'; file.status = 'fail';
this.setState({ fileList }); this.setState({ fileList });
}); });
}
}); });
} }
...@@ -133,42 +169,79 @@ class UploadProgressModal extends React.Component { ...@@ -133,42 +169,79 @@ class UploadProgressModal extends React.Component {
// 如果文件小于100KB,不用记录断点,直接上传 // 如果文件小于100KB,不用记录断点,直接上传
const { fileContent } = file; const { fileContent } = file;
const { size } = fileContent; const { size } = fileContent;
if (size > 100 * 1024) { if (size > 100 * 1024 && checkpoint && checkpoint.uploadId) {
// 确保checkpoint和uploadId存在时才记录
if (!file.checkpoints) {
file.checkpoints = {};
}
file.checkpoints[checkpoint.uploadId] = checkpoint; file.checkpoints[checkpoint.uploadId] = checkpoint;
} }
} }
// 断点续传 // 断点续传
handleReUpload = (index) => { handleReUpload = (index) => {
const { fileList, ossClient, resourceId, callBack, callbackBody } = this.state; const { fileList, bucket,ossUri, ossClient, callback, resourceId, callbackData, vendorType } = this.state;
const currentFile = fileList[index]; const currentFile = fileList[index];
const { checkpoints, fileContent } = currentFile const { checkpoints, fileContent } = currentFile;
if ( vendorType === 'TENCENT_COS') {
// 腾讯云重新上传
ossClient.sliceUploadFile({
Bucket: bucket,
Region: TX_UPLOAD_REGION,
Key: ossUri,
Body: fileContent,
SliceSize: UPLOAD_PART_SIZE,
// 回调配置
Callback: callback,
onProgress: (progressData) => {
const progress = progressData.percent;
this.onMultipartUploadProgress(progress, { uploadId: uuid(), file: fileContent }, currentFile);
},
onTaskReady: (taskId) => {
currentFile.taskId = taskId;
},
})
.then(res => {
currentFile.status = 'success';
this.setState({ fileList });
this.props.onUpload(fileContent, resourceId);
})
.catch(err => {
currentFile.status = 'fail';
this.setState({ fileList });
});
} else {
Object.values(checkpoints).forEach(checkpoint => { Object.values(checkpoints).forEach(checkpoint => {
const { uploadId, file } = checkpoint; const { uploadId, file } = checkpoint;
const { type } = file; const { type } = file;
ossClient.multipartUpload(uploadId, file, { ossClient
.multipartUpload(uploadId, file, {
callback: { callback: {
url: callBack, url: callbackData.url,
body: callbackBody, body: callbackData.body,
contentType: 'application/json', callbackSNI: true,
contentType: callbackData.contentType
}, },
checkpoint, checkpoint,
parallel: UPLOAD_PARALLEL, parallel: UPLOAD_PARALLEL,
partSize: UPLOAD_PART_SIZE, partSize: UPLOAD_PART_SIZE,
progress: (progress, checkpoint) => { progress: (progress, checkpoint) => {
this.onMultipartUploadProgress(progress, checkpoint, currentFile) this.onMultipartUploadProgress(progress, checkpoint, currentFile);
}, },
mime: type, mime: type
}).then(url => { })
.then(url => {
currentFile.status = 'success'; currentFile.status = 'success';
this.setState({ fileList }); this.setState({ fileList });
this.props.onUpload(fileContent, resourceId); this.props.onUpload(fileContent, resourceId);
}).catch(err => { })
.catch(err => {
currentFile.status = 'fail'; currentFile.status = 'fail';
this.setState({ fileList }); this.setState({ fileList });
}); });
}) });
}
} }
// 显示/隐藏上传进度 // 显示/隐藏上传进度
...@@ -181,7 +254,7 @@ class UploadProgressModal extends React.Component { ...@@ -181,7 +254,7 @@ class UploadProgressModal extends React.Component {
// 取消上传 // 取消上传
handleCancelAllUpload = () => { handleCancelAllUpload = () => {
// 判断是否有正在上传或者待上传的文件,有的话弹出二次提示框 // 判断是否有正在上传或者待上传的文件,有的话弹出二次提示框
const { fileList, ossClient } = this.state; const { fileList, ossClient, vendorType } = this.state;
const uploadingFileList = fileList.filter(file => file.status === 'uploading' || file.status === 'waiting'); const uploadingFileList = fileList.filter(file => file.status === 'uploading' || file.status === 'waiting');
if (uploadingFileList.length) { if (uploadingFileList.length) {
Modal.confirm({ Modal.confirm({
...@@ -190,11 +263,19 @@ class UploadProgressModal extends React.Component { ...@@ -190,11 +263,19 @@ class UploadProgressModal extends React.Component {
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>, icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
onOk: () => { onOk: () => {
uploadingFileList.forEach((uploadingFile, index) => { uploadingFileList.forEach((uploadingFile, index) => {
if (vendorType === 'TENCENT_COS') {
// 腾讯云取消上传
if (uploadingFile.taskId) {
ossClient.cancelTask(uploadingFile.taskId);
}
} else {
// 阿里云取消上传
const { checkpoints } = uploadingFile; const { checkpoints } = uploadingFile;
Object.values(checkpoints).forEach(checkpoint => { Object.values(checkpoints).forEach(checkpoint => {
const { uploadId, name } = checkpoint; const { uploadId, name } = checkpoint;
ossClient.abortMultipartUpload(name, uploadId); ossClient.abortMultipartUpload(name, uploadId);
}); });
}
fileList.splice(index, 1); fileList.splice(index, 1);
}); });
this.setState({ fileList: [] }); this.setState({ fileList: [] });
...@@ -209,15 +290,20 @@ class UploadProgressModal extends React.Component { ...@@ -209,15 +290,20 @@ class UploadProgressModal extends React.Component {
// 取消单个文件上传 // 取消单个文件上传
handleCancelUpload = (currentFile, index) => { handleCancelUpload = (currentFile, index) => {
const { fileList, ossClient } = this.state; const { fileList, ossClient, vendorType } = this.state;
if (vendorType === 'TENCENT_COS') {
// 腾讯云取消上传
if (currentFile.taskId) {
ossClient.cancelTask(currentFile.taskId);
}
} else {
// 阿里云取消上传
const { checkpoints } = currentFile; const { checkpoints } = currentFile;
Object.values(checkpoints).forEach(checkpoint => { Object.values(checkpoints).forEach(checkpoint => {
const { uploadId, name } = checkpoint; const { uploadId, name } = checkpoint;
ossClient.abortMultipartUpload(name, uploadId); ossClient.abortMultipartUpload(name, uploadId);
}); });
}
fileList.splice(index, 1); fileList.splice(index, 1);
this.setState({ fileList }); this.setState({ fileList });
......
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-31 09:34:51 * @Date: 2020-08-31 09:34:51
* @LastEditors: wufan * @LastEditors: renmanyi
* @LastEditTime: 2021-01-06 20:18:46 * @LastEditTime: 2026-02-03 15:29:54
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -35,9 +35,6 @@ class Service { ...@@ -35,9 +35,6 @@ class Service {
return Axios.post('GET', url, params, option); return Axios.post('GET', url, params, option);
} }
static MFS(url: string, params: any, option: any) {
return Axios.post('POST', `mfs/${url}`, params, option);
}
} }
export default Service; export default Service;
\ No newline at end of file
import { func } from "prop-types";
import Service from '@/common/js/service'; import Service from '@/common/js/service';
import User from '@/common/js/user'; import User from '@/common/js/user';
import { message } from 'antd'; import { message } from 'antd';
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-11 11:47:14 * @Date: 2020-08-11 11:47:14
* @LastEditors: wufan * @LastEditors: renmanyi
* @LastEditTime: 2021-01-03 21:04:30 * @LastEditTime: 2026-02-03 15:28:25
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -22,73 +21,29 @@ class Upload { ...@@ -22,73 +21,29 @@ class Upload {
return Service.Hades('public/hades/commonOssAuthority', param).then((res) => { return Service.Hades('public/hades/commonOssAuthority', param).then((res) => {
const signInfo = res.result; const signInfo = res.result;
const { fileUrl } = res.result const { fileUrl } = res.result
return this.uploadBlobToNewOSS(Blob, name, dir, signInfo.signatureVO || signInfo).then(() => { if (signInfo.vendorType === 'TENCENT_COS') {
console.log('url2222222',fileUrl); return this.uploadBlobToNewOSSTx(Blob, name, signInfo.signatureVO || signInfo).then(() => {
return dataType === 'url' ? fileUrl : signInfo return dataType === 'url' ? fileUrl : signInfo
});
}) })
};
static asyncUploadVideoToOSS(Blob, name, complete, dir, needSize) {
name = window.encodeURI(name.toLowerCase());
let ossSignServerAddress = UPLOAD + 'xm/oss/web/token?bucket=v';
const xhr = new XMLHttpRequest();
xhr.open('GET', ossSignServerAddress, true);
xhr.onload = () => {
const signInfo = JSON.parse(xhr.responseText);
const fd = new FormData();
fd.append('Filename', name);
fd.append('callback', signInfo.callback);
fd.append('expire', signInfo.expire);
fd.append('policy', signInfo.policy);
fd.append('signature', signInfo.signature);
fd.append('OSSAccessKeyId', signInfo.accessid);
fd.append('success_action_status', 200);
if (!dir) {
dir = Blob.type == 'text/html' ? 'html/' : '';
}
fd.append('key', signInfo.dir + dir + name);
fd.append('file', Blob);
xhr.open('POST', signInfo.host, true);
xhr.onload = () => {
const result = JSON.parse(xhr.responseText);
if (needSize) {
complete(result);
} else { } else {
complete((result.url || false).replace(/http:/, "https:")); return this.uploadBlobToNewOSS(
Blob,
name,
signInfo.signatureVO || signInfo
).then(() => {
return dataType === 'url' ? fileUrl : signInfo
});
} }
})
}; };
xhr.send(fd);
};
xhr.onerror = () => {
complete(false);
}
xhr.send(null);
return xhr;
}
static getVideoParseRoute(videoUrl) { static getVideoParseRoute(videoUrl) {
return Service.MFS('anon/video/parse', { videoUrl }).then((res) => { return Service.Sales('anon/resource/parseVideo', { videoUrl }).then((res) => {
return res.result.sdUrl || videoUrl; return res.result.sdUrl || videoUrl;
}) })
} }
// mfs上传文件 static uploadBlobToNewOSS(Blob, name, signInfo) {
static uploadBlobToMFSOSS(signInfoUrl, signInfoParams, Blob, name, dir) {
return Service.post(signInfoUrl, signInfoParams).then(res => {
var signInfo = res.result;
return this.uploadBlobToNewOSS(Blob, name, dir, signInfo.signatureVO || signInfo).then((res) => {
return signInfo;
});
})
}
static uploadBlobToNewOSS(Blob, name, dir, signInfo) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
var fd = new FormData(); var fd = new FormData();
...@@ -102,6 +57,9 @@ class Upload { ...@@ -102,6 +57,9 @@ class Upload {
// dir = Blob.type == 'text/html' ? 'html/' : ''; // dir = Blob.type == 'text/html' ? 'html/' : '';
// } // }
fd.append('key', signInfo.key); fd.append('key', signInfo.key);
if(signInfo.securityToken) {
fd.append("x-oss-security-token", signInfo.securityToken);
}
fd.append('file', Blob); fd.append('file', Blob);
fd.append('success_action_status', 200); fd.append('success_action_status', 200);
xhr.open('POST', signInfo.host.replace(/http:/, "https:"), true); xhr.open('POST', signInfo.host.replace(/http:/, "https:"), true);
...@@ -119,33 +77,36 @@ class Upload { ...@@ -119,33 +77,36 @@ class Upload {
}; };
static uploadBlobToNewOSSTx(Blob, name, signInfo={}) {
// 监听多媒体上传进度 return new Promise(function (resolve, reject) {
static uploadToOSSEvent(Blob, name, onInit=()=>{}, onProgress=()=>{}, onLoad=()=>{}, onError=()=>{}) { var xhr = new XMLHttpRequest();
Service.MFS('anon/mfs/webTokenWithAccessUrl', { resourceName: name, instId: (!!window.currentUserInstInfo && window.currentUserInstInfo.instId) || LS.get('instId') || '' }).then((res) => { var fd = new FormData();
const signInfo = res.result; let timeVal = JSON.parse(signInfo.extAttrs)['q-key-time'];
const { url } = res.result; fd.append('q-sign-algorithm', 'sha1');
const xhr = new XMLHttpRequest(); fd.append('key', signInfo.key);
const fd = new FormData(); fd.append('q-ak', signInfo.accessKeyId);
fd.append('OSSAccessKeyId', signInfo.accessId);
fd.append('policy', signInfo.policy); fd.append('policy', signInfo.policy);
fd.append('callback', signInfo.callback); fd.append('q-signature', signInfo.signature);
fd.append('success_action_status', '200');
fd.append('x-cos-callback', signInfo.callback);
signInfo.securityToken && fd.append("x-cos-security-token", signInfo.securityToken);
fd.append('q-key-time', timeVal);
fd.append('Filename', name); fd.append('Filename', name);
fd.append('expire', signInfo.expire);
fd.append('signature', signInfo.signature);
fd.append('key', signInfo.key);
fd.append('file', Blob); fd.append('file', Blob);
fd.append('success_action_status', 200); xhr.open('POST', signInfo.host, true);
xhr.onload = () => {
onInit(url,xhr,signInfo) if (xhr.readyState === 4) {
xhr.open('POST', signInfo.host); if (xhr.status === 200) {
xhr.upload.addEventListener("progress", onProgress, false); const res = JSON.parse(xhr.responseText);
xhr.onload = onLoad; resolve(res.result.url);
xhr.onerror = onError; } else {
xhr.send(fd); console.error('Error: ' + xhr.status);
}) }
} }
};
xhr.send(fd);
});
};
static uploadTextToOSS(string, name, success, error) { static uploadTextToOSS(string, name, success, error) {
if (!string) return success(); if (!string) return success();
...@@ -156,7 +117,18 @@ class Upload { ...@@ -156,7 +117,18 @@ class Upload {
resourceName: name, resourceName: name,
} }
Service.Hades('/public/hades/ossAuthority', params).then((res) => { Service.Hades('/public/hades/ossAuthority', params).then((res) => {
const { resourceId, accessId, policy, callback, signature,key, host } = res.result; const signInfo = res.result;
const { resourceId } = res.result;
if (signInfo.vendorType === 'TENCENT_COS') {
// 腾讯云 COS 上传
this.uploadBlobToNewOSSTx(new Blob([string]), name, signInfo.signatureVO || signInfo).then(() => {
success(resourceId);
}).catch(() => {
error();
});
} else {
// 阿里云 OSS 上传
const { accessId, policy, callback, signature, key, host } = signInfo;
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
const formData = new FormData(); const formData = new FormData();
formData.append("OSSAccessKeyId", accessId); formData.append("OSSAccessKeyId", accessId);
...@@ -164,6 +136,9 @@ class Upload { ...@@ -164,6 +136,9 @@ class Upload {
formData.append("callback", callback); formData.append("callback", callback);
formData.append("Signature", signature); formData.append("Signature", signature);
formData.append("key", key); formData.append("key", key);
if(signInfo.securityToken) {
formData.append("x-oss-security-token", signInfo.securityToken);
}
formData.append("file", new Blob([string])); formData.append("file", new Blob([string]));
formData.append("success_action_status", 200); formData.append("success_action_status", 200);
xhr.open("POST", host); xhr.open("POST", host);
...@@ -174,7 +149,10 @@ class Upload { ...@@ -174,7 +149,10 @@ class Upload {
error(); error();
} }
xhr.send(formData); xhr.send(formData);
}) }
}).catch(() => {
error();
});
} }
} }
......
/* /*
* @Author: wufan * @Author: wufan
* @Date: 2020-12-01 17:21:21 * @Date: 2020-12-01 17:21:21
* @LastEditors: Please set LastEditors * @LastEditors: renmanyi
* @LastEditTime: 2021-07-09 15:33:33 * @LastEditTime: 2026-02-03 15:38:02
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -72,11 +72,12 @@ export const getOssClient = ( ...@@ -72,11 +72,12 @@ export const getOssClient = (
resourceName: string, resourceName: string,
accessTypeEnum: string accessTypeEnum: string
) => { ) => {
return Service.postJSON('mfs/anon/mfs/multiPartUpload', { return Service.postJSON('business/public/mfs/commonUpload', {
data, data,
instId, instId,
bizCode, bizCode,
resourceName, resourceName,
needSecret: true,
accessTypeEnum accessTypeEnum
}); });
} }
......
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-10-10 18:21:47 * @Date: 2020-10-10 18:21:47
* @LastEditors: wufan * @LastEditors: renmanyi
* @LastEditTime: 2020-12-09 16:05:24 * @LastEditTime: 2026-02-03 15:38:06
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -15,11 +15,12 @@ export const getOssClient = ( ...@@ -15,11 +15,12 @@ export const getOssClient = (
resourceName: string, resourceName: string,
accessTypeEnum: string accessTypeEnum: string
) => { ) => {
return Service.postJSON('mfs/anon/mfs/multiPartUpload', { return Service.postJSON('business/public/mfs/commonUpload', {
data, data,
instId, instId,
bizCode, bizCode,
resourceName, resourceName,
needSecret: true,
accessTypeEnum accessTypeEnum
}); });
} }
\ No newline at end of file
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-10-10 18:19:34 * @Date: 2020-10-10 18:19:34
* @LastEditors: 吴文洁 * @LastEditors: renmanyi
* @LastEditTime: 2020-10-13 18:09:39 * @LastEditTime: 2026-02-03 15:39:33
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import OSS from 'ali-oss'; import OSS from 'ali-oss';
import COS from 'cos-js-sdk-v5';
import { UPLOAD_REGION } from '@/domains/resource-disk/constants'; import { UPLOAD_REGION } from '@/domains/resource-disk/constants';
import { getOssClient } from '@/data-source/basic/basic-apis'; import { getOssClient } from '@/data-source/basic/basic-apis';
...@@ -31,32 +32,26 @@ export default class UploadFileService { ...@@ -31,32 +32,26 @@ export default class UploadFileService {
accessTypeEnum accessTypeEnum
).then((res) => { ).then((res) => {
const { result = {} } = res; const { result = {} } = res;
const { const { bucket, resourceId, accessKeyId, securityToken, accessKeySecret, key, vendorType, callbackData, callback } = result;
bucket, let client;
callBack, if (vendorType === 'TENCENT_COS') {
resourceId, // 腾讯云配置
accessKeyId, client = new COS({
securityToken, SecretId: accessKeyId,
accessKeySecret, SecretKey: accessKeySecret,
callbackBody, SecurityToken: securityToken
ossUri });
} = result; } else {
// 阿里云配置
const ossClient = new OSS({ client = new OSS({
bucket, bucket,
accessKeyId, accessKeyId,
accessKeySecret, accessKeySecret,
region: UPLOAD_REGION, region: UPLOAD_REGION,
stsToken: securityToken, stsToken: securityToken
});
resolve({
ossClient,
resourceId,
callBack,
callbackBody,
ossUri
}); });
}
resolve({ ossClient: client, resourceId, ossUri:key, vendorType,bucket,callbackData,callback });
}) })
}) })
} }
......
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-20 09:21:40 * @Date: 2020-08-20 09:21:40
* @LastEditors: yuananting * @LastEditors: renmanyi
* @LastEditTime: 2021-07-15 11:48:58 * @LastEditTime: 2026-02-03 15:45:43
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -172,6 +172,7 @@ const NON_COMPLIANT_FILE_MAP = { ...@@ -172,6 +172,7 @@ const NON_COMPLIANT_FILE_MAP = {
// 文件上传 // 文件上传
const UPLOAD_REGION = 'oss-cn-hangzhou'; const UPLOAD_REGION = 'oss-cn-hangzhou';
const TX_UPLOAD_REGION = 'ap-shanghai';
const UPLOAD_PART_SIZE = 1024 * 1024; // 每个分片大小(byte) const UPLOAD_PART_SIZE = 1024 * 1024; // 每个分片大小(byte)
const UPLOAD_PARALLEL = 5; // 同时上传的分片数 const UPLOAD_PARALLEL = 5; // 同时上传的分片数
...@@ -185,6 +186,7 @@ export { ...@@ -185,6 +186,7 @@ export {
DISK_MAP, DISK_MAP,
SUFFIX_MAP, SUFFIX_MAP,
UPLOAD_REGION, UPLOAD_REGION,
TX_UPLOAD_REGION,
UPLOAD_PART_SIZE, UPLOAD_PART_SIZE,
UPLOAD_PARALLEL, UPLOAD_PARALLEL,
} }
\ No newline at end of file
import React from 'react'; import React from 'react';
import { Modal } from 'antd'; import { Modal } from 'antd';
import OSS from 'ali-oss'; import OSS from 'ali-oss';
import COS from 'cos-js-sdk-v5';
import Service from '@/common/js/service'; import Service from '@/common/js/service';
import { getEllipsText } from "@/core/util"; import { getEllipsText, randomString } from "@/core/util";
import { DEFAULT_SIZE_UNIT, FileTypeIcon, FileVerifyMap } from "@/common/constants/academic/lessonEnum"; import { DEFAULT_SIZE_UNIT, FileTypeIcon, FileVerifyMap } from "@/common/constants/academic/lessonEnum";
import { getFileTypeByName } from '../components/FolderManage'; import { getFileTypeByName } from '../components/FolderManage';
...@@ -10,6 +11,7 @@ import User from '@/common/js/user'; ...@@ -10,6 +11,7 @@ import User from '@/common/js/user';
import './UploadProgressModal.less'; import './UploadProgressModal.less';
const UPLOAD_REGION = 'oss-cn-hangzhou'; const UPLOAD_REGION = 'oss-cn-hangzhou';
const TX_UPLOAD_REGION = 'ap-shanghai';
const UPLOAD_PART_SIZE = 1024 * 1024; // 每个分片大小(byte) const UPLOAD_PART_SIZE = 1024 * 1024; // 每个分片大小(byte)
const UPLOAD_PARALLEL = 5; // 同时上传的分片数 const UPLOAD_PARALLEL = 5; // 同时上传的分片数
...@@ -61,9 +63,10 @@ class UploadProgressModal extends React.Component { ...@@ -61,9 +63,10 @@ class UploadProgressModal extends React.Component {
const instId = User.getStoreId(); const instId = User.getStoreId();
return new Promise(resolve => { return new Promise(resolve => {
Service.postJSON('mfs/anon/mfs/multiPartUpload', { Service.postJSON('business/public/mfs/commonUpload', {
instId, instId,
resourceName, resourceName,
needSecret: true,
data: { folderId: id }, data: { folderId: id },
accessTypeEnum: 'PUBLIC', accessTypeEnum: 'PUBLIC',
bizCode: 'UPLOAD_FOLDER', bizCode: 'UPLOAD_FOLDER',
...@@ -71,30 +74,45 @@ class UploadProgressModal extends React.Component { ...@@ -71,30 +74,45 @@ class UploadProgressModal extends React.Component {
const { result = {} } = res; const { result = {} } = res;
const { const {
bucket, bucket,
callBack,
resourceId, resourceId,
accessKeyId, accessKeyId,
securityToken, securityToken,
accessKeySecret, accessKeySecret,
callbackBody, key,
ossUri vendorType,
callbackData,
callback
} = result; } = result;
const ossClient = new OSS({ let ossClient;
if (vendorType === 'TENCENT_COS') {
// 腾讯云 COS 客户端配置
ossClient = new COS({
SecretId: accessKeyId,
SecretKey: accessKeySecret,
SecurityToken: securityToken
});
} else {
// 阿里云 OSS 客户端配置
ossClient = new OSS({
bucket, bucket,
accessKeyId, accessKeyId,
accessKeySecret, accessKeySecret,
region: UPLOAD_REGION, region: UPLOAD_REGION,
stsToken: securityToken, stsToken: securityToken,
}); });
}
this.setState({ this.setState({
ossClient, ossClient,
resourceId, resourceId,
callBack, ossUri: key,
callbackBody, vendorType,
ossUri bucket,
callback,
callbackData,
}); });
resolve({ ossClient, resourceId, callBack, callbackBody, ossUri }); resolve({ ossClient, resourceId, ossUri: key, vendorType, bucket, callback, callbackData });
}) })
}) })
} }
...@@ -107,17 +125,48 @@ class UploadProgressModal extends React.Component { ...@@ -107,17 +125,48 @@ class UploadProgressModal extends React.Component {
const { id = 0 } = currentFolder; const { id = 0 } = currentFolder;
const { name, type } = fileContent; const { name, type } = fileContent;
const resourceName = window.random_string(16) + name.slice(name.lastIndexOf('.')); const resourceName = randomString(16) + name.slice(name.lastIndexOf('.'));
const { instId } = window.currentUserInstInfo;
// 开始上传之前初始化OssClient // 开始上传之前初始化OssClient
this.initOssClient(id, resourceName).then((result) => { this.initOssClient(id, resourceName).then((result) => {
const { ossClient, resourceId, callBack, callbackBody, ossUri } = result; const { ossClient, resourceId, ossUri, vendorType, bucket, callback, callbackData } = result;
if (vendorType === 'TENCENT_COS') {
// 腾讯云分片上传
ossClient.sliceUploadFile({
Bucket: bucket,
Region: TX_UPLOAD_REGION,
Key: ossUri,
Body: fileContent,
SliceSize: UPLOAD_PART_SIZE,
// 回调配置
Callback: callback,
onProgress: (progressData) => {
const progress = progressData.percent;
this.onMultipartUploadProgress(progress, { uploadId: randomString(16), file: fileContent }, file);
},
onTaskReady: (taskId) => {
// 记录任务ID,用于取消上传
file.taskId = taskId;
},
})
.then(res => {
file.status = 'success';
this.setState({ fileList });
this.props.onUpload(fileContent, resourceId);
})
.catch(err => {
file.status = 'fail';
this.setState({ fileList });
});
} else {
// 阿里云分片上传
ossClient.multipartUpload(ossUri, fileContent, { ossClient.multipartUpload(ossUri, fileContent, {
callback: { callback: {
url: callBack, url: callbackData.url,
body: callbackBody, body: callbackData.body,
contentType: 'application/json', callbackSNI: true,
contentType: callbackData.contentType
}, },
parallel: UPLOAD_PARALLEL, parallel: UPLOAD_PARALLEL,
partSize: UPLOAD_PART_SIZE, partSize: UPLOAD_PART_SIZE,
...@@ -133,6 +182,7 @@ class UploadProgressModal extends React.Component { ...@@ -133,6 +182,7 @@ class UploadProgressModal extends React.Component {
file.status = 'fail'; file.status = 'fail';
this.setState({ fileList }); this.setState({ fileList });
}); });
}
}); });
} }
...@@ -146,25 +196,58 @@ class UploadProgressModal extends React.Component { ...@@ -146,25 +196,58 @@ class UploadProgressModal extends React.Component {
// 如果文件小于100KB,不用记录断点,直接上传 // 如果文件小于100KB,不用记录断点,直接上传
const { fileContent } = file; const { fileContent } = file;
const { size } = fileContent; const { size } = fileContent;
if (size > 100 * 1024) { if (size > 100 * 1024 && checkpoint && checkpoint.uploadId) {
// 确保checkpoint和uploadId存在时才记录
if (!file.checkpoints) {
file.checkpoints = {};
}
file.checkpoints[checkpoint.uploadId] = checkpoint; file.checkpoints[checkpoint.uploadId] = checkpoint;
} }
} }
// 断点续传 // 断点续传
handleReUpload = (index) => { handleReUpload = (index) => {
const { fileList, ossClient, resourceId, callBack, callbackBody } = this.state; const { fileList, ossClient, resourceId, callbackData, vendorType, bucket, callback, ossUri } = this.state;
const currentFile = fileList[index]; const currentFile = fileList[index];
const { checkpoints, fileContent } = currentFile const { checkpoints, fileContent } = currentFile;
if (vendorType === 'TENCENT_COS') {
// 腾讯云重新上传
ossClient.sliceUploadFile({
Bucket: bucket,
Region: TX_UPLOAD_REGION,
Key: ossUri,
Body: fileContent,
SliceSize: UPLOAD_PART_SIZE,
// 回调配置
Callback: callback,
onProgress: (progressData) => {
const progress = progressData.percent;
this.onMultipartUploadProgress(progress, { uploadId: randomString(16), file: fileContent }, currentFile);
},
onTaskReady: (taskId) => {
currentFile.taskId = taskId;
},
})
.then(res => {
currentFile.status = 'success';
this.setState({ fileList });
this.props.onUpload(fileContent, resourceId);
})
.catch(err => {
currentFile.status = 'fail';
this.setState({ fileList });
});
} else {
// 阿里云断点续传
Object.values(checkpoints).forEach(checkpoint => { Object.values(checkpoints).forEach(checkpoint => {
const { uploadId, file } = checkpoint; const { uploadId, file } = checkpoint;
ossClient.multipartUpload(uploadId, file, { ossClient.multipartUpload(uploadId, file, {
callback: { callback: {
url: callBack, url: callbackData.url,
body: callbackBody, body: callbackData.body,
contentType: 'application/json', callbackSNI: true,
contentType: callbackData.contentType
}, },
checkpoint, checkpoint,
parallel: UPLOAD_PARALLEL, parallel: UPLOAD_PARALLEL,
...@@ -181,7 +264,8 @@ class UploadProgressModal extends React.Component { ...@@ -181,7 +264,8 @@ class UploadProgressModal extends React.Component {
currentFile.status = 'fail'; currentFile.status = 'fail';
this.setState({ fileList }); this.setState({ fileList });
}); });
}) });
}
} }
// 显示/隐藏上传进度 // 显示/隐藏上传进度
...@@ -194,7 +278,7 @@ class UploadProgressModal extends React.Component { ...@@ -194,7 +278,7 @@ class UploadProgressModal extends React.Component {
// 取消上传 // 取消上传
handleCancelAllUpload = () => { handleCancelAllUpload = () => {
// 判断是否有正在上传或者待上传的文件,有的话弹出二次提示框 // 判断是否有正在上传或者待上传的文件,有的话弹出二次提示框
const { fileList, ossClient } = this.state; const { fileList, ossClient, vendorType } = this.state;
const uploadingFileList = fileList.filter(file => file.status === 'uploading' || file.status === 'waiting'); const uploadingFileList = fileList.filter(file => file.status === 'uploading' || file.status === 'waiting');
if (uploadingFileList.length) { if (uploadingFileList.length) {
Modal.confirm({ Modal.confirm({
...@@ -203,15 +287,22 @@ class UploadProgressModal extends React.Component { ...@@ -203,15 +287,22 @@ class UploadProgressModal extends React.Component {
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>, icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
onOk: () => { onOk: () => {
uploadingFileList.forEach((uploadingFile, index) => { uploadingFileList.forEach((uploadingFile, index) => {
if (vendorType === 'TENCENT_COS') {
// 腾讯云取消上传
if (uploadingFile.taskId) {
ossClient.cancelTask(uploadingFile.taskId);
}
} else {
// 阿里云取消上传
const { checkpoints } = uploadingFile; const { checkpoints } = uploadingFile;
Object.values(checkpoints).forEach(checkpoint => { Object.values(checkpoints).forEach(checkpoint => {
const { uploadId, name } = checkpoint; const { uploadId, name } = checkpoint;
ossClient.abortMultipartUpload(name, uploadId); ossClient.abortMultipartUpload(name, uploadId);
}); });
}
fileList.splice(index, 1); fileList.splice(index, 1);
}) });
this.setState({ fileList: [] });
this.setState({ fileList });
this.props.onCancel(); this.props.onCancel();
} }
}) })
...@@ -223,12 +314,21 @@ class UploadProgressModal extends React.Component { ...@@ -223,12 +314,21 @@ class UploadProgressModal extends React.Component {
// 取消单个文件上传 // 取消单个文件上传
handleCancelUpload = (currentFile, index) => { handleCancelUpload = (currentFile, index) => {
const { fileList, ossClient } = this.state; const { fileList, ossClient, vendorType } = this.state;
if (vendorType === 'TENCENT_COS') {
// 腾讯云取消上传
if (currentFile.taskId) {
ossClient.cancelTask(currentFile.taskId);
}
} else {
// 阿里云取消上传
const { checkpoints } = currentFile; const { checkpoints } = currentFile;
Object.values(checkpoints).forEach(checkpoint => { Object.values(checkpoints).forEach(checkpoint => {
const { uploadId, name } = checkpoint; const { uploadId, name } = checkpoint;
ossClient.abortMultipartUpload(name, uploadId); ossClient.abortMultipartUpload(name, uploadId);
}); });
}
fileList.splice(index, 1); fileList.splice(index, 1);
this.setState({ fileList }); this.setState({ fileList });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment