• 优化VUE Element UI的上传插件


    默认ElmentUI的文件列表只有一个删除按钮,我需要加预览、下载、编辑等,就需要优化显示结果。

    优化后没用上传进度条,又加了一个进度条效果

    代码

    1. <template>
    2. <div>
    3. <el-upload
    4. class="upload-demo"
    5. action="/"
    6. :file-list="fileList"
    7. :disabled="isUpLoading"
    8. :before-upload="beforeUpload"
    9. :http-request="handleHttpRequest"
    10. :on-remove="handleRemoveFile"
    11. :on-progress="handleLoading"
    12. :on-success="handleUploadSuccess">
    13. <el-button size="small" :loading="isUpLoading" type="primary">{{this.isUpLoading?"附件上传中...":"点击上传"}} </el-button>
    14. <div slot="tip" class="el-upload__tip">(建议上传附件大小在5M以内)</div>
    15. </el-upload>
    16. <div id="file-list">
    17. <el-progress v-if="isUpLoading" :percentage="uploadingProgress"></el-progress>
    18. <div v-for="(file,index) in fileList" :key="file.fileIdentifier" style="display: flex;justify-content: space-between;line-height: 25px;">
    19. <div>{{index+1}}、{{file.name}} </div>
    20. <div style="padding-right: 20px;">
    21. <a href="javascript:void(0)" style="cursor:pointer;" @click="fileOption(file,'down')">下载</a>
    22. <a href="javascript:void(0)" v-if = "officeFileType.includes(file.wjhz.toLowerCase())" style="margin-left: 10px;cursor:pointer;" @click="fileOption(file,'show')">查看</a>
    23. <a href="javascript:void(0)" v-if = "officeFileType.includes(file.wjhz.toLowerCase())" style="margin-left: 10px;cursor: pointer;" @click="fileOption(file,'edit')">编辑</a>
    24. <a href="javascript:void(0)" style="margin-left: 10px;cursor: pointer;" @click="fileOption(file,'del')">删除</a>
    25. </div>
    26. </div>
    27. </div>
    28. </div>
    29. </template>
    30. <style lang="scss" scoped>
    31. ::v-deep .el-upload-list{
    32. display: none;
    33. }
    34. </style>
    35. <script>
    36. import md5 from "@/api/file/md5";
    37. import { taskInfo, initTask, preSignUrl, merge, del, getFileList} from '@/api/file/api';
    38. import Queue from 'promise-queue-plus';
    39. import axios from 'axios'
    40. import VXETable from 'vxe-table'
    41. import { changeUserStatus } from '@/api/system/user'
    42. export default {
    43. name: 'upload-page',
    44. props: {
    45. // 文件类型
    46. fjlxdm: {
    47. required: true,
    48. type: String
    49. },
    50. // 业务主建
    51. ywbs: {
    52. required: true,
    53. type: String
    54. },
    55. },
    56. created(){
    57. this.initData();
    58. },
    59. data() {
    60. return {
    61. fileUploadChunkQueue:{},
    62. lastUploadedSize:0,// 上次断点续传时上传的总大小
    63. uploadedSize:0,// 已上传的大小
    64. totalSize:0,// 文件总大小
    65. startMs:'',// 开始上传的时间
    66. taskRecord:{},
    67. options:{},
    68. fileList:[],
    69. officeFileType:['.ppt', '.pptx', '.doc', '.docx', '.xls', '.xlsx','.pdf'],
    70. isUpLoading:false,
    71. uploadingProgress:0,
    72. uploadTime:null,
    73. }
    74. },
    75. methods: {
    76. handleLoading(event, file, fileList){
    77. if(this.uploadTime!=null){
    78. clearInterval(this.uploadTime);
    79. this.uploadTime=null;
    80. }
    81. this.uploadingProgress=parseFloat(event.percent);
    82. },
    83. fileOption(file,type){
    84. if(type=="down"){//下载
    85. window.open(file.url, "_blank");
    86. return;
    87. }
    88. if(type=="show"){//查看
    89. const { href } = this.$router.resolve({
    90. name: 'office',
    91. query: {
    92. fjxxbs: file.fjxxbs,
    93. viewUrl: file.viewUrl,
    94. ot: 'detail'
    95. }
    96. })
    97. window.open(href, '_blank')
    98. return;
    99. }
    100. if(type=="edit"){//编辑
    101. const { href } = this.$router.resolve({
    102. name: 'office',
    103. query: {
    104. fjxxbs: file.fjxxbs,
    105. viewUrl: file.viewUrl,
    106. ot: 'edit'
    107. }
    108. })
    109. window.open(href, '_blank')
    110. return;
    111. }
    112. if(type=="del"){//删除
    113. this.$confirm(
    114. '确认删除该附件?',
    115. "警告",
    116. {
    117. confirmButtonText: "确定",
    118. cancelButtonText: "取消",
    119. type: "warning",
    120. }
    121. )
    122. .then( () => {
    123. del(file.fjxxbs).then(ret => {
    124. const index = this.fileList.findIndex((item) => item.fjxxbs === file.fjxxbs);
    125. this.fileList.splice(index, 1);
    126. this.msgSuccess("删除成功");
    127. });
    128. })
    129. return;
    130. }
    131. },
    132. /**
    133. * 获取附件列表
    134. */
    135. initData(){
    136. this.uploadingProgress=100;
    137. getFileList(this.ywbs,this.fjlxdm).then(ret => {
    138. this.fileList = ret.data;
    139. setTimeout(()=>{
    140. this.isUpLoading=false;
    141. },500);
    142. })
    143. },
    144. /**
    145. * 获取一个上传任务,没有则初始化一个
    146. */
    147. async getTaskInfo(file){
    148. let task;
    149. const identifier = await md5(file)
    150. const { code, data, msg } = await taskInfo(identifier,this.ywbs,this.fjlxdm);
    151. if (code === 200) {
    152. task = data
    153. if (task===undefined) {
    154. const initTaskData = {
    155. identifier,
    156. fileName: file.name,
    157. totalSize: file.size,
    158. chunkSize: 5 * 1024 * 1024,
    159. ywbs:this.ywbs,
    160. fjlxdm:this.fjlxdm
    161. }
    162. const { code, data, msg } = await initTask(initTaskData)
    163. if (code === 200) {
    164. task = data
    165. } else {
    166. this.$notify({
    167. title:'提示',
    168. message: '文件上传错误',
    169. type: 'error',
    170. duration: 2000
    171. })
    172. }
    173. }
    174. } else {
    175. this.$notify({
    176. title:'提示',
    177. message: '文件上传错误',
    178. type: 'error',
    179. duration: 2000
    180. })
    181. }
    182. return task
    183. },
    184. // 获取从开始上传到现在的平均速度(byte/s)
    185. getSpeed(){
    186. // 已上传的总大小 - 上次上传的总大小(断点续传)= 本次上传的总大小(byte)
    187. const intervalSize = this.uploadedSize - this.lastUploadedSize
    188. const nowMs = new Date().getTime()
    189. // 时间间隔(s)
    190. const intervalTime = (nowMs - this.startMs) / 1000
    191. return intervalSize / intervalTime
    192. },
    193. async uploadNext(partNumber){
    194. const {chunkSize,fileIdentifier} = this.taskRecord;
    195. const start = new Number(chunkSize) * (partNumber - 1)
    196. const end = start + new Number(chunkSize)
    197. const blob = this.options.file.slice(start, end)
    198. const { code, data, msg } = await preSignUrl({ identifier: fileIdentifier, partNumber: partNumber , ywbs:this.ywbs , fjlxdm:this.fjlxdm} )
    199. if (code === 200 && data) {
    200. await axios.request({
    201. url: data,
    202. method: 'PUT',
    203. data: blob,
    204. headers: {'Content-Type': 'application/octet-stream'}
    205. })
    206. return Promise.resolve({ partNumber: partNumber, uploadedSize: blob.size })
    207. }
    208. return Promise.reject(`分片${partNumber}, 获取上传地址失败`)
    209. },
    210. /**
    211. * 更新上传进度
    212. * @param increment 为已上传的进度增加的字节量
    213. */
    214. updateProcess(increment){
    215. increment = new Number(increment)
    216. const { onProgress } = this.options
    217. let factor = 1000; // 每次增加1000 byte
    218. let from = 0;
    219. // 通过循环一点一点的增加进度
    220. while (from <= increment) {
    221. from += factor
    222. this.uploadedSize += factor
    223. const percent = Math.round(this.uploadedSize / this.totalSize * 100).toFixed(2);
    224. onProgress({percent: percent})
    225. }
    226. const speed = this.getSpeed();
    227. const remainingTime = speed != 0 ? Math.ceil((this.totalSize - this.uploadedSize) / speed) + 's' : '未知'
    228. console.log('剩余大小:', (this.totalSize - this.uploadedSize) / 1024 / 1024, 'mb');
    229. console.log('当前速度:', (speed / 1024 / 1024).toFixed(2), 'mbps');
    230. console.log('预计完成:', remainingTime);
    231. },
    232. handleUpload(file, taskRecord){
    233. this.lastUploadedSize = 0; // 上次断点续传时上传的总大小
    234. this.uploadedSize = 0 // 已上传的大小
    235. this.totalSize = file.size || 0 // 文件总大小
    236. this.startMs = new Date().getTime(); // 开始上传的时间
    237. this.taskRecord = taskRecord;
    238. const { exitPartList, chunkNum} = taskRecord
    239. return new Promise(resolve => {
    240. const failArr = [];
    241. const queue = Queue(5, {
    242. "retry": 3, //Number of retries
    243. "retryIsJump": false, //retry now?
    244. "workReject": function(reason,queue){
    245. failArr.push(reason)
    246. },
    247. "queueEnd": function(queue){
    248. resolve(failArr);
    249. }
    250. })
    251. this.fileUploadChunkQueue[file.uid] = queue
    252. for (let partNumber = 1; partNumber <= chunkNum; partNumber++) {
    253. const exitPart = (exitPartList || []).find(exitPart => exitPart.partNumber == partNumber)
    254. if (exitPart) {
    255. // 分片已上传完成,累计到上传完成的总额中,同时记录一下上次断点上传的大小,用于计算上传速度
    256. this.lastUploadedSize += new Number(exitPart.size)
    257. this.updateProcess(exitPart.size)
    258. } else {
    259. queue.push(() => this.uploadNext(partNumber).then(res => {
    260. // 单片文件上传完成再更新上传进度
    261. this.updateProcess(res.uploadedSize)
    262. }))
    263. }
    264. }
    265. if (queue.getLength() == 0) {
    266. // 所有分片都上传完,但未合并,直接return出去,进行合并操作
    267. resolve(failArr);
    268. return;
    269. }
    270. queue.start()
    271. })
    272. },
    273. async handleHttpRequest(options){
    274. this.options = options;
    275. const file = options.file
    276. const task = await this.getTaskInfo(file)
    277. const that = this;
    278. if (task) {
    279. const { finished, path, taskRecord } = task
    280. const {fileIdentifier,fjxxbs } = taskRecord
    281. if (finished) {
    282. return {fileIdentifier,fjxxbs}
    283. } else {
    284. const errorList = await this.handleUpload(file, taskRecord)
    285. if (errorList.length > 0) {
    286. this.$notify({
    287. title:'文件上传错误',
    288. message: '部分分片上传失败,请尝试重新上传文件',
    289. type: 'error',
    290. duration: 2000
    291. })
    292. return;
    293. }
    294. const { code, data, msg } = await merge(fileIdentifier,that.ywbs,that.fjlxdm)
    295. if (code === 200) {
    296. return {fileIdentifier,fjxxbs};
    297. } else {
    298. this.$notify({
    299. title:'提示',
    300. message: '文件上传错误',
    301. type: 'error',
    302. duration: 2000
    303. })
    304. }
    305. }
    306. } else {
    307. this.$notify({
    308. title:'文件上传错误',
    309. message: '获取上传任务失败',
    310. type: 'error',
    311. duration: 2000
    312. })
    313. }
    314. },
    315. /**
    316. * 重复上传
    317. * @param {} file
    318. */
    319. beforeUpload(file){
    320. return new Promise((resolve, reject) => {
    321. md5(file).then(result => {
    322. const index = this.fileList.findIndex((item) => item.fileIdentifier === result);
    323. if(index==-1){
    324. this.isUpLoading=true;
    325. this.uploadingProgress=0;
    326. this.uploadTime=setInterval(()=>{
    327. this.uploadingProgress+=1;
    328. },500)
    329. return resolve(true);
    330. }else{
    331. return reject(false);
    332. }
    333. })
    334. });
    335. },
    336. handleRemoveFile(uploadFile, uploadFiles){
    337. const queueObject = this.fileUploadChunkQueue[uploadFile.uid]
    338. if (queueObject) {
    339. queueObject.stop()
    340. this.fileUploadChunkQueue[uploadFile.uid] = undefined;
    341. }
    342. if(uploadFile.fjxxbs != undefined){
    343. del(uploadFile.fjxxbs).then(ret => {
    344. const index = this.fileList.findIndex((item) => item.fjxxbs === uploadFile.fjxxbs);
    345. this.fileList.splice(index, 1);
    346. })
    347. }
    348. },
    349. /**
    350. * 上传成功
    351. */
    352. handleUploadSuccess(res, file, fileList) {
    353. // file.fileIdentifier = res.fileIdentifier;
    354. // file.fjxxbs = res.fjxxbs;
    355. // this.fileList.push(file);
    356. this.initData();
    357. }
    358. }
    359. }
    360. </script>

  • 相关阅读:
    python中可变类型与不可变类型详细介绍
    vue2(vuecli5)+预渲染插件prerender-spa-plugin-next解决seo问题
    茶百道:门店数量狂飙,食品安全问题成最大绊脚石
    设计模式在参数校验中的使用
    目标检测YOLO实战应用案例100讲-SAR图像多尺度舰船目标检测
    两分钟打造一个转属于你的网址导航(零基础,告别广告困扰)
    数据挖掘学习笔记02——算法(分类、聚类、回归、关联)
    Prompt Learning——Template
    Git 2.37 发布,带来重大变化!!
    被环境变量虐过一遍获得的启示
  • 原文地址:https://blog.csdn.net/qq873113580/article/details/132761086