uploadFile.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. <template>
  2. <div class="uploadBox"></div>
  3. </template>
  4. <script>
  5. import "../../../utils/aws-sdk-2.235.1.min.js";
  6. export default {
  7. emits: ["progressUpdate"],
  8. data() {
  9. return {
  10. bucket: "", //aws上传接口
  11. bucketname: "ccrb", //桶
  12. uploadid: "",
  13. partsize: 10 * 1024 * 1024, //10MB 分片
  14. filestate: {
  15. status: "", //有 error(直接报错) 和 fail(上传的时候报错) 和 success(上传成功) 和 processing(上传中)
  16. percent: "", //(0-100的进度)
  17. },
  18. file: null,
  19. flag:true,
  20. };
  21. },
  22. watch: {
  23. filestate: {
  24. handler(newValue) {
  25. this.$emit("progressUpdate", newValue);
  26. },
  27. immediate: true,
  28. deep: true,
  29. },
  30. },
  31. methods: {
  32. //--------------------------分断上传保证稳定性
  33. //初始化上传
  34. // async init(){
  35. // const credentials = {
  36. // accessKeyId: "AKIATLPEDU37QV5CHLMH",
  37. // secretAccessKey: "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",
  38. // }; //秘钥形式的登录上传
  39. // window.AWS.config.update(credentials);
  40. // window.AWS.config.region = "cn-northwest-1"; //设置区域
  41. // //桶的设置
  42. // bucket = new window.AWS.S3({
  43. // params: {
  44. // Bucket: this.bucketname
  45. // }
  46. // });
  47. // return bucket;
  48. // },
  49. // 初始化上传入口
  50. async initMultipartUpload(key, file) {
  51. const params = {
  52. Bucket: this.bucketname,
  53. Key: key,
  54. ContentType: file.type,
  55. ACL: "public-read",
  56. };
  57. //创建一个续传通道
  58. const data = await this.bucket.createMultipartUpload(params).promise();
  59. return data.UploadId;
  60. },
  61. // 上传文件的某一部分
  62. async uploadPart(file, keyname, uploadid, pn, start, end) {
  63. //key可以设置为桶的相对路径,Body为文件, ACL最好要设置
  64. if(!this.flag)return;
  65. var params = {
  66. Bucket: this.bucketname,
  67. Key: keyname,
  68. // ContentType: file.type,
  69. PartNumber: pn,
  70. UploadId: uploadid,
  71. Body: file.slice(start, end),
  72. // "Access-Control-Allow-Credentials": "*",
  73. // ACL: "public-read",
  74. };
  75. const result = await this.bucket.uploadPart(params).promise();
  76. return { ETag: result.ETag, PartNumber: pn };
  77. },
  78. //完成分块上传
  79. async completeMultipartUpload(parts, keyname, uploadid) {
  80. if(!this.flag)return;
  81. const params = {
  82. Bucket: this.bucketname,
  83. Key: keyname,
  84. MultipartUpload: { Parts: parts },
  85. UploadId: uploadid,
  86. };
  87. return await this.bucket.completeMultipartUpload(params).promise();
  88. },
  89. async abortMultipartUpload(key, uploadid) {
  90. const params = {
  91. Bucket: this.bucketname,
  92. Key: key,
  93. UploadId: uploadid,
  94. };
  95. let data = await this.bucket.abortMultipartUpload(params).promise();
  96. this.$emit("delUpload")
  97. },
  98. //--------------------------------下面支持断点续传
  99. //初始化亚马逊参数
  100. async init() {
  101. //秘钥形式的登录上传
  102. const credentials = {
  103. accessKeyId: "AKIATLPEDU37QV5CHLMH",
  104. secretAccessKey: "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",
  105. region: "cn-northwest-1",
  106. };
  107. window.AWS.config.update(credentials);
  108. // window.AWS.config.region = "cn-northwest-1"; //设置区域
  109. //桶的设置
  110. this.bucket = new window.AWS.S3({
  111. params: {
  112. Bucket: this.bucketname,
  113. },
  114. });
  115. return this.bucket;
  116. },
  117. //获取当前文件是否有已上传断点信息
  118. async getawscheckpoint(key) {
  119. let partsinfo;
  120. try {
  121. const result = await this.bucket
  122. .listMultipartUploads({ Bucket: this.bucketname, Prefix: key })
  123. .promise();
  124. //获取具体分片信息
  125. if (result.Uploads.length) {
  126. this.uploadid = result.Uploads[result.Uploads.length - 1].UploadId;
  127. partsinfo = await this.bucket
  128. .listParts({
  129. Bucket: this.bucketname,
  130. Key: key,
  131. UploadId: this.uploadid,
  132. })
  133. .promise();
  134. }
  135. } catch (err) {
  136. console.log(err);
  137. }
  138. return { uploadid: this.uploadid, partsinfo };
  139. },
  140. //分段上传
  141. async awsuploadpart(filestate, file, uploadid, parts, key) {
  142. var partarr = []; //已完成的数组
  143. //已完成的分片,转化成提交格式
  144. const completeparts = parts.map((_) => {
  145. partarr.push(_.PartNumber);
  146. return { PartNumber: _.PartNumber, ETag: _.ETag };
  147. });
  148. // 分块上传文件
  149. // parts = [];
  150. let uploadpart;
  151. let start = 0;
  152. let end = 0;
  153. let len = Math.ceil(file.size / this.partsize); //循环的长度
  154. if (partarr.length) {
  155. this.filestate.status = "processing";
  156. this.filestate.percent = parseInt((completeparts.length * 100) / len);
  157. }
  158. //循环上传
  159. for (let i = 0; i < len; i++) {
  160. if(!this.flag)break;
  161. start = i * this.partsize;
  162. end = (i + 1) * this.partsize;
  163. if (!partarr.includes(i+1)) {
  164. uploadpart = await this.uploadPart(
  165. file,
  166. key,
  167. uploadid,
  168. i + 1,
  169. start,
  170. end
  171. );
  172. if (uploadpart.ETag != null) {
  173. completeparts.push(uploadpart);
  174. partarr.push(uploadpart.PartNumber);
  175. this.filestate.status = "processing";
  176. this.filestate.percent = parseInt(
  177. (completeparts.length * 100) / len
  178. );
  179. } else {
  180. this.filestate.status = "fail";
  181. this.stopUpload();
  182. return;
  183. }
  184. }
  185. }
  186. //提交上传成功信息
  187. if(this.flag){
  188. let data = await this.completeMultipartUpload(
  189. completeparts,
  190. key,
  191. uploadid
  192. );
  193. this.filestate.status = "success";
  194. return data;
  195. }
  196. },
  197. //上传的接口
  198. async awsupload({ file = this.file, keyName, folderName }) {
  199. if (!file) return this.$message.error("请上传文件");
  200. this.init(); //初始化桶
  201. // const key = (folderid || uuidv4()) + "/" + file.name; //需要上传的文件名
  202. let key = "";
  203. if (keyName) {
  204. key = keyName;
  205. } else {
  206. if (folderName) {
  207. key = `${folderName}/${file.name}`;
  208. } else {
  209. key = `${file.name.split(".")[0] +
  210. new Date().getTime() +
  211. "." +
  212. file.name.split(".")[file.name.split(".").length - 1]}`;
  213. }
  214. }
  215. this.filestate = {
  216. percent: 0,
  217. status: "start",
  218. };
  219. this.filestate.percent = 0;
  220. this.filestate.status = "start";
  221. this.file = file;
  222. //上传的参数
  223. var params = {
  224. Bucket: this.bucketname,
  225. Key: key,
  226. };
  227. this.flag = true;
  228. //设置桶上传文件
  229. try {
  230. //检查文件是否已上传
  231. this.bucket.headObject(params, async (err, data) => {
  232. // 没有上传成功,head方法会返回失败
  233. if (err) {
  234. //检查是否部分上传
  235. const { uploadid, partsinfo } = await this.getawscheckpoint(
  236. key,
  237. this.bucket
  238. );
  239. //如果已经部分存在,那么直接在节点续传
  240. if (uploadid) {
  241. //断点续传
  242. this.$emit("startUpload", { key, uploadid });
  243. this.flag = true;
  244. let data = await this.awsuploadpart(
  245. this.filestate,
  246. file,
  247. uploadid,
  248. partsinfo.Parts,
  249. key
  250. );
  251. if(this.flag || this.filestate.percent==100)return this.$emit("success", { data, key, uploadid });
  252. // return {data,key,uploadid}
  253. }
  254. //不存在,上传新的
  255. else {
  256. const uploadid = await this.initMultipartUpload(key, file); //初始化文件上传
  257. this.$emit("startUpload", { key, uploadid });
  258. this.flag = true;
  259. let data = await this.awsuploadpart(
  260. this.filestate,
  261. file,
  262. uploadid,
  263. [],
  264. key
  265. );
  266. if(this.flag || this.filestate.percent==100)return this.$emit("success", { data, key, uploadid });
  267. // return {data,key,uploadid}
  268. }
  269. }
  270. //如果已经上传成功了,那么直接返回状态百分百
  271. else if (data) {
  272. //data存在,上传成功
  273. this.filestate.percent = 100;
  274. this.filestate.status = "success";
  275. let url = `https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/${key}`
  276. this.file = null;
  277. if(this.flag)return this.$emit("success", { data:{
  278. Key:key,
  279. Location:url,
  280. ETag:data.ETag,
  281. size:data.ContentLength,
  282. ServerSideEncryption:data.ServerSideEncryption,
  283. Bucket:this.bucketname
  284. } });
  285. // return {data,key,uploadid}
  286. }
  287. });
  288. } catch (err) {
  289. this.filestate.status = "error";
  290. this.stopUpload();
  291. console.log(err);
  292. }
  293. },
  294. // 停止上传
  295. stopUpload(){
  296. this.filestate.status = "stop";
  297. this.flag = false;
  298. }
  299. },
  300. mounted() {
  301. this.bucket = "";
  302. this.file = null;
  303. },
  304. };
  305. </script>
  306. <style scoped>
  307. .uploadBox {
  308. display: none;
  309. }
  310. </style>