| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- import '../../common/aws-sdk-2.235.1.min.js'
- import { v4 as uuidv4 } from 'uuid'
- // 上传单个文件
- const uploadOneFile = (file, progressFn) => {
- return new Promise((resolve) => {
- let credentials = {
- accessKeyId: 'AKIATLPEDU37QV5CHLMH',
- secretAccessKey: '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',
- } //秘钥形式的登录上传
- window.AWS.config.update(credentials)
- window.AWS.config.region = 'cn-northwest-1' //设置区域
- let bucket = new window.AWS.S3({ params: { Bucket: 'ccrb' } }) //选择桶
- if (file) {
- var params = {
- Key:
- file.name.split('.')[0] +
- new Date().getTime() +
- '.' +
- file.name.split('.')[file.name.split('.').length - 1],
- ContentType: file.type,
- Body: file,
- 'Access-Control-Allow-Credentials': '*',
- ACL: 'public-read',
- } //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
- var options = {
- partSize: 2048 * 1024 * 1024,
- queueSize: 2,
- leavePartsOnError: true,
- }
- bucket
- .upload(params, options)
- .on('httpUploadProgress', function (evt) {
- //这里可以写进度条
- if (progressFn) {
- let _progress = {
- loaded:evt.loaded,
- total:evt.total,
- percent:(evt.loaded/evt.total*100).toFixed(2),
- }
- progressFn(_progress)
- }
- })
- .send(function (err, data) {
- if (err) {
- resolve('')
- } else {
- let fileObj = {
- name: file.name,
- url: data.Location,
- size: formatFileSize(file.size), // 格式化文件大小
- uid: uuidv4(),
- type: file.type,
- fileType:getFileType(file),
- }
- console.log('uploadFile', fileObj)
- resolve(fileObj)
- }
- })
- }
- })
- }
- // 获取文件数据
- const getFile = (url) => {
- return new Promise((resolve) => {
- var credentials = {
- accessKeyId: "AKIATLPEDU37QV5CHLMH",
- secretAccessKey: "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",
- }; //秘钥形式的登录上传
- window.AWS.config.update(credentials);
- window.AWS.config.region = "cn-northwest-1"; //设置区域
- let url2 = url;
- let _url2 = "";
- if (
- url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1
- ) {
- _url2 = url2.split(
- "https://view.officeapps.live.com/op/view.aspx?src="
- )[1];
- } else {
- _url2 = url2;
- }
- var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
- let name = decodeURIComponent(_url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1])
- var params = {
- Bucket: "ccrb",
- Key: name,
- };
- s3.getObject(params, function (err, data) {
- if (err) {
- console.log(err, err.stack)
- resolve({ data: 1 });
- } else {
- resolve({ data: data.Body });
- console.log(data);
- } // sxuccessful response
- });
- });
- };
- const getTxtFileContent = (url) => {
- return new Promise((resolve) => {
- var credentials = {
- accessKeyId: "AKIATLPEDU37QV5CHLMH",
- secretAccessKey: "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"
- }; //秘钥形式的登录上传
- window.AWS.config.update(credentials);
- window.AWS.config.region = "cn-northwest-1"; //设置区域
- let url2 = url;
- let _url2 = "";
- if (
- url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1
- ) {
- _url2 = url2.split(
- "https://view.officeapps.live.com/op/view.aspx?src="
- )[1];
- } else {
- _url2 = url2;
- }
- var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
- let name = decodeURIComponent(
- _url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1]
- );
- var params = {
- Bucket: "ccrb",
- Key: name
- };
- s3.getObject(params, function (err, data) {
- if (err) {
- console.log(err, err.stack);
- resolve({ data: 1 });
- } else {
- const fileContent = data.Body.toString("utf-8");
- resolve({ data: fileContent });
- }
- });
- });
- }
- const formatFileSize = (size) => {
- if (size < 1024) {
- return size + 'B'
- } else if (size < 1024 * 1024) {
- return (size / 1024).toFixed(2) + 'KB'
- } else if (size < 1024 * 1024 * 1024) {
- return (size / (1024 * 1024)).toFixed(2) + 'MB'
- } else if (size < 1024 * 1024 * 1024 * 1024) {
- return (size / (1024 * 1024 * 1024)).toFixed(2) + 'GB'
- } else {
- return (size / (1024 * 1024 * 1024 * 1024)).toFixed(2) + 'TB'
- }
- }
- // 常用文件类型清单
- const fileTypes = [
- { value: 'image', label: '图片', exts: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'], mime: ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp', 'image/svg+xml'] },
- { value: 'video', label: '视频', exts: ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm'], mime: ['video/mp4', 'video/x-msvideo', 'video/quicktime', 'video/x-ms-wmv', 'video/x-flv', 'video/x-matroska', 'video/webm'] },
- { value: 'audio', label: '音频', exts: ['mp3', 'wav', 'aac', 'ogg', 'flac', 'm4a'], mime: ['audio/mpeg', 'audio/x-wav', 'audio/aac', 'audio/ogg', 'audio/flac', 'audio/mp4'] },
- { value: 'doc', label: '文档', exts: ['doc', 'docx', 'pdf', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'md', 'csv'], mime: ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/pdf', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'text/plain', 'text/markdown', 'text/csv'] },
- { value: 'zip', label: '压缩包', exts: ['zip', 'rar', '7z', 'tar', 'gz'], mime: ['application/zip', 'application/x-rar-compressed', 'application/x-7z-compressed', 'application/x-tar', 'application/gzip'] },
- { value: 'other', label: '其它', exts: [], mime: [] }
- ]
- // 根据传入的文件类型(文件名/后缀或mime)获取value
- const getFileType = (file) => {
- if (!file) return 'other';
- let ext = '';
- let mime = '';
- // 允许传入 string 或 File/Blob 对象
- if (typeof file === 'string') {
- // 从文件名里提取后缀
- const match = file.match(/\.([^.]+)$/);
- ext = match ? match[1].toLowerCase() : '';
- } else if (typeof file === 'object' && file) {
- // File 或 Blob 情况,取type为mime,name取后缀
- if (file.type) mime = file.type;
- if (file.name) {
- const match = file.name.match(/\.([^.]+)$/);
- ext = match ? match[1].toLowerCase() : '';
- }
- }
- // 先按mime类型查找
- if (mime) {
- for (let type of fileTypes) {
- if (type.mime.includes(mime)) {
- return type.value;
- }
- }
- }
- // 再按扩展名查找
- if (ext) {
- for (let type of fileTypes) {
- if (type.exts.includes(ext)) {
- return type.value;
- }
- }
- }
- // 未命中则返回other
- return 'other';
- }
- // 分片上传
- /**
- * AWS S3 分片上传工具,支持进度回调及停止上传功能
- * 使用方式:
- * const uploader = new AwsMultipartUploader(options);
- * uploader.upload({ file, keyName, folderName, onProgress, onSuccess, onError });
- * uploader.stop(); // 随时可停止
- */
- class AwsMultipartUploader {
- constructor({
- bucketname = "ccrb",
- accessKeyId = "AKIATLPEDU37QV5CHLMH",
- secretAccessKey = "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",
- region = "cn-northwest-1",
- partsize = 10 * 1024 * 1024 // 10MB
- } = {}) {
- this.bucketname = bucketname;
- this.accessKeyId = accessKeyId;
- this.secretAccessKey = secretAccessKey;
- this.region = region;
- this.partsize = partsize;
- this.bucket = null;
- this.flag = true;
- this.uploadid = "";
- this.lastFilestate = null; // 缓存上次的filestate, 避免重复回调
- }
- async init() {
- const credentials = {
- accessKeyId: this.accessKeyId,
- secretAccessKey: this.secretAccessKey,
- region: this.region
- };
- window.AWS.config.update(credentials);
- this.bucket = new window.AWS.S3({ params: { Bucket: this.bucketname } });
- }
- async initMultipartUpload(key, file) {
- const params = {
- Bucket: this.bucketname,
- Key: key,
- ContentType: file.type,
- ACL: "public-read"
- };
- const data = await this.bucket.createMultipartUpload(params).promise();
- return data.UploadId;
- }
- async uploadPart(file, keyname, uploadid, pn, start, end) {
- if (!this.flag) return;
- const params = {
- Bucket: this.bucketname,
- Key: keyname,
- PartNumber: pn,
- UploadId: uploadid,
- Body: file.slice(start, end)
- };
- const result = await this.bucket.uploadPart(params).promise();
- return { ETag: result.ETag, PartNumber: pn };
- }
- async completeMultipartUpload(parts, keyname, uploadid) {
- if (!this.flag) return;
- const params = {
- Bucket: this.bucketname,
- Key: keyname,
- MultipartUpload: { Parts: parts },
- UploadId: uploadid
- };
- return await this.bucket.completeMultipartUpload(params).promise();
- }
- async abortMultipartUpload(key, uploadid) {
- const params = {
- Bucket: this.bucketname,
- Key: key,
- UploadId: uploadid
- };
- await this.bucket.abortMultipartUpload(params).promise();
- }
- async getCheckpoint(key) {
- let partsinfo;
- let uploadid = "";
- try {
- const result = await this.bucket
- .listMultipartUploads({ Bucket: this.bucketname, Prefix: key })
- .promise();
- if (result.Uploads && result.Uploads.length) {
- uploadid = result.Uploads[result.Uploads.length - 1].UploadId;
- partsinfo = await this.bucket
- .listParts({
- Bucket: this.bucketname,
- Key: key,
- UploadId: uploadid
- })
- .promise();
- }
- } catch (err) {
- console.log(err);
- }
- return { uploadid, partsinfo };
- }
- // 控制停止
- stop() {
- this.flag = false;
- }
- emitProgress(filestate, onProgress) {
- // 只回调变化
- if (typeof onProgress === "function") {
- if (
- !this.lastFilestate ||
- this.lastFilestate.percent !== filestate.percent ||
- this.lastFilestate.status !== filestate.status
- ) {
- onProgress(Object.assign({}, filestate));
- }
- }
- this.lastFilestate = Object.assign({}, filestate);
- }
- // 分段上传
- async uploadParts({ file, uploadid, parts = [], key, onProgress }) {
- let filestate = { status: "processing", percent: 0 };
- let partarr = [];
- const completeparts = parts.map((_) => {
- partarr.push(_.PartNumber);
- return { PartNumber: _.PartNumber, ETag: _.ETag };
- });
- let len = Math.ceil(file.size / this.partsize);
- if (partarr.length) {
- filestate.percent = parseInt((completeparts.length * 100) / len);
- this.emitProgress(filestate, onProgress);
- }
- for (let i = 0; i < len; i++) {
- if (!this.flag) break;
- let start = i * this.partsize;
- let end = (i + 1) * this.partsize;
- if (!partarr.includes(i + 1)) {
- const uploadpart = await this.uploadPart(
- file,
- key,
- uploadid,
- i + 1,
- start,
- end
- );
- if (uploadpart && uploadpart.ETag != null) {
- completeparts.push(uploadpart);
- partarr.push(uploadpart.PartNumber);
- filestate.percent = parseInt((completeparts.length * 100) / len);
- filestate.status = "processing";
- this.emitProgress(filestate, onProgress);
- } else {
- filestate.status = "fail";
- this.emitProgress(filestate, onProgress);
- this.stop();
- throw new Error("分片上传失败");
- }
- }
- }
- if (this.flag) {
- const data = await this.completeMultipartUpload(
- completeparts,
- key,
- uploadid
- );
- filestate.status = "success";
- filestate.percent = 100;
- this.emitProgress(filestate, onProgress);
- return data; // 返回complete后的aws数据
- } else {
- filestate.status = "stop";
- this.emitProgress(filestate, onProgress);
- throw new Error("上传已中断");
- }
- }
- // 主入口(异步,支持await)
- /**
- *
- * @param {*} param0
- * file: 要上传的File对象
- * keyName: 指定上传key(可选)
- * folderName: 文件夹(可选)
- * onProgress: function({status, percent})
- */
- async upload({
- file,
- keyName,
- folderName,
- onProgress
- }) {
- if (!file) {
- throw new Error("请上传文件");
- }
- this.flag = true;
- this.lastFilestate = null;
- await this.init();
- let key = "";
- if (keyName) {
- key = keyName;
- } else if (folderName) {
- key = `${folderName}/${file.name}`;
- } else {
- const ext = file.name.split(".").length > 1 ?
- file.name.substring(file.name.lastIndexOf(".") + 1) : "";
- key =
- `${file.name.split(".")[0]}${Date.now()}${ext ? "." + ext : ""}`;
- }
- let filestate = { percent: 0, status: "start" };
- this.emitProgress(filestate, onProgress);
- const params = {
- Bucket: this.bucketname,
- Key: key
- };
- // 用Promise包装, 使upload支持await
- return new Promise(async (resolve, reject) => {
- try {
- // 检查是否已上传
- this.bucket.headObject(params, async (err, data) => {
- if (err) {
- // 检查断点
- let { uploadid, partsinfo } = await this.getCheckpoint(key);
- let curUploadId = uploadid;
- let awsParts = [];
- if (uploadid && partsinfo) {
- awsParts = partsinfo.Parts || [];
- }
- try {
- let completeResult;
- if (curUploadId) {
- completeResult = await this.uploadParts({
- file,
- uploadid: curUploadId,
- parts: awsParts,
- key,
- onProgress
- });
- } else {
- const newUploadId = await this.initMultipartUpload(key, file);
- completeResult = await this.uploadParts({
- file,
- uploadid: newUploadId,
- parts: [],
- key,
- onProgress
- });
- }
- let url = `https://${this.bucketname}.s3.${this.region}.amazonaws.com.cn/${key}`;
- const resObj = {
- name: file.name,
- url: url,
- size: formatFileSize(file.size),
- uid: uuidv4(),
- type: file.type,
- Key: key,
- Location: url,
- ETag: completeResult.ETag,
- Bucket: this.bucketname
- };
- console.log(resObj)
- resolve(resObj);
- } catch (err) {
- console.log('分片上传失败', err)
- reject('');
- }
- } else if (data) {
- // 已经100%
- let url = `https://${this.bucketname}.s3.${this.region}.amazonaws.com.cn/${key}`;
- const resObj = {
- name: file.name,
- url: url,
- size: formatFileSize(file.size),
- uid: uuidv4(),
- type: file.type,
- Key: key,
- Location: url,
- ETag: data.ETag,
- Bucket: this.bucketname
- };
- filestate.percent = 100;
- filestate.status = "success";
- this.emitProgress(filestate, onProgress);
- resolve(resObj);
- }
- });
- } catch (err) {
- console.log('分片上传失败', err)
- reject('');
- }
- });
- }
- }
- export {
- uploadOneFile,
- getFileType,
- getFile,
- getTxtFileContent,
- AwsMultipartUploader,
- formatFileSize
- }
|