当前位置:   article > 正文

Vue结合webuploader实现文件分片断点续传_vue3 webuploader 分片

vue3 webuploader 分片

根于公司业务,封装了底层的 文件分片断点续传底层能力组件带有前端交互的UI组件

GitHub

  

目录

使用步骤

1. 基于vue-cli3,在public下创建webUploader目录

2. 引入jQuery

3. 文件分片断点续传底层能力组件

4. 文件分片断点续传UI组件

效果图


使用步骤

1. 基于vue-cli3,在public下创建webUploader目录

2. 引入jQuery

由于我司视频兼容能力业务需求,jQuery在index.html中引入。因此jQuery的引入方式有些简陋,多多包涵。。

3. 文件分片断点续传底层能力组件

大文件分片断点续传底层组件逻辑_五虎战画戟-CSDN博客基于 WebUploader,实例化 WebUploader,参数见文中注释this.uploader = WebUploader.create({ ...})注册 WebUploadernew WebUploader.Uploader.register({ beforeSend: (block) => { /** * 上传前,进行分片,分片后每一个片都有主键,然后接口验证是否已传过 * 若上传过则不再上传,若没有上传过则续传。 */ .https://blog.csdn.net/qq_41887214/article/details/114603949

  1. <template>
  2. <div class="upload" />
  3. </template>
  4. <script>
  5. import { fileUpload } from '@/api/upload-file'
  6. const qs = require('querystring')
  7. const md5 = window.md5
  8. const $ = window.$
  9. export default {
  10. name: 'VueWebuploader',
  11. props: {
  12. // 上传文件类型
  13. accept: {
  14. type: String,
  15. default: null
  16. },
  17. // 上传地址
  18. url: {
  19. required: true,
  20. type: String
  21. },
  22. // 上传文件总大小, 默认为100G
  23. fileSizeLimit: {
  24. type: Number,
  25. default: 100 * 1024 * 1024 * 1024
  26. },
  27. // 上传最大数量 默认为100个
  28. fileNumLimit: {
  29. type: Number,
  30. default: 100
  31. },
  32. // 大小限制 默认为100G
  33. fileSingleSizeLimit: {
  34. type: Number,
  35. default: 100 * 1024 * 1024 * 1024
  36. },
  37. // 上传时传给后端的参数,一般为token,key等
  38. formData: {
  39. required: true,
  40. type: Object
  41. },
  42. // 生成formData中文件的key,下面只是个例子,具体哪种形式和后端商议
  43. keyGenerator: {
  44. type: Function,
  45. default(file) {
  46. const currentTime = new Date().getTime()
  47. const key = `${currentTime}.${file.name}`
  48. return key
  49. }
  50. },
  51. multiple: {
  52. type: Boolean,
  53. default: false
  54. },
  55. // 上传按钮{Seletor|dom}
  56. uploadButton: {
  57. required: true,
  58. type: String
  59. },
  60. // 拖拽的容器{Selector}
  61. uploadDndButton: {
  62. type: String,
  63. default: ''
  64. }
  65. },
  66. data() {
  67. return {
  68. uploader: null,
  69. publicOption: {},
  70. uploadContCommon: {
  71. onUploadFileErr: null,
  72. onUploadFileSuccess: null,
  73. callbackDate: null
  74. },
  75. chunkSize: 5 * 1024 * 1024, // 分块大小
  76. fileMd5MarkMap: new Map(),
  77. uniqueFileNameMap: new Map()
  78. }
  79. },
  80. mounted() {
  81. this.initWebUpload()
  82. },
  83. methods: {
  84. initWebUpload() {
  85. const that = this
  86. new WebUploader.Uploader.register(
  87. {
  88. 'before-send-file': 'beforeSendFile',
  89. 'before-send': 'beforeSend',
  90. 'after-send-file': 'afterSendFile'
  91. },
  92. {
  93. // // 上传文件开始前触发MD5校验,用了这个会很慢很慢,因此注掉
  94. // beforeSendFile: function(file) {
  95. // if (that.publicOption.uploadProgress) {
  96. // that.publicOption.beforeSendFile(file)
  97. // }
  98. // console.log('上传文件前触发')
  99. // // return false
  100. // // 秒传验证
  101. // // const task = new $.Deferred()
  102. // that.uploader.md5File(file).progress(percentage => {
  103. // // 及时显示进度
  104. // console.log('percentage', percentage)
  105. // }).then(function(val) {
  106. // // 完成
  107. // console.log('上传文件前触发完成', val)
  108. // // $('#' + file.id + ' .operate .del_btn').show()
  109. // // $("#" + file.id + " .operate .pause_btn").show();
  110. // // console.log("总耗时: "+ ((new Date().getTime()) - start)/ 1E3);
  111. // // md5Mark = val
  112. // that.fileMd5MarkMap.set(file.id, val)
  113. // fileUpload(qs.stringify({ status: 'md5Check', md5: val }), that.url).then(res => {
  114. // const { data } = res
  115. // if (data.ifExist) {
  116. // that.uploader.skipFile(file)
  117. // file.path = res.path
  118. // that.UploadComlate(file, this.fileMd5MarkMap.get(file.id))
  119. // }
  120. // })
  121. // })
  122. // },
  123. // 开始上传分片触发
  124. beforeSend: function(block) {
  125. // 分片验证是否已传过,用于断点续传
  126. var task = new $.Deferred()
  127. var file = block.file
  128. var id = file.id
  129. that.uploader.md5File(file, block.start, block.end).then(val => {
  130. var params = {
  131. status: 'chunkCheck',
  132. name: that.uniqueFileNameMap.get(id),
  133. chunkIndex: block.chunk,
  134. size: block.end - block.start,
  135. userId: that.formData.userId,
  136. companyId: that.formData.companyId,
  137. appCode: that.formData.appCode,
  138. blockmd5: val
  139. }
  140. fileUpload(qs.stringify(params), that.url).then(res => {
  141. const { data } = res
  142. if (data.ifExist === 1) { // 若存在,返回失败给WebUploader,表明该分块不需要上传
  143. task.reject()
  144. } else {
  145. task.resolve()
  146. }
  147. }, function(jqXHR, textStatus, errorThrown) { // 任何形式的验证失败,都触发重新上传
  148. task.reject()
  149. })
  150. })
  151. return $.when(task)
  152. },
  153. // 上传文件完成触发
  154. afterSendFile: function(file) {
  155. var chunksTotal = Math.ceil(file.size / that.chunkSize)
  156. // 合并请求
  157. var task = new $.Deferred()
  158. var params = {
  159. status: 'chunksMerge',
  160. name: that.uniqueFileNameMap.get(file.id),
  161. chunks: chunksTotal,
  162. ext: file.ext,
  163. md5: that.fileMd5MarkMap.get(file.id),
  164. userId: that.formData.userId,
  165. companyId: that.formData.companyId,
  166. appCode: that.formData.appCode
  167. }
  168. fileUpload(qs.stringify(params), that.url).then(res => {
  169. const { data } = res
  170. if (data.path) {
  171. file.path = data.path
  172. // 最初的时候是在uploadSuccess发布的成功事件,后来发现有时取不到返回的file.path,因此换到了在merge文件碎片回调中发布上传成功事件
  173. that.$emit('success', file, res)
  174. }
  175. task.resolve()
  176. that.uniqueFileNameMap.delete(file.id)
  177. that.fileMd5MarkMap.delete(file.id)
  178. }).catch(err => {
  179. console.info(err)
  180. })
  181. return $.when(task)
  182. }
  183. })
  184. this.uploader = WebUploader.create({
  185. auto: true, // {Boolean} [可选] [默认值:false] 设置为 true 后,不需要手动调用上传,有文件选择即开始上传(选完文件后,是否自动上传)
  186. swf: '/public/webUploader/js/Uploader.swf', // swf文件路径
  187. server: this.url + 'fileUpload', // 文件接收服务端
  188. pick: { // 指定选择文件的按钮容器,不指定则不创建按钮
  189. id: this.uploadButton, // {Seletor|dom} 指定选择文件的按钮容器,不指定则不创建按钮。注意 这里虽然写的是 id, 但是不是只支持 id, 还支持 class, 或者 dom 节点。
  190. multiple: this.multiple, // {Boolean} 是否开启同时选择多个文件能力。
  191. label: '', // {String} 请采用 innerHTML 代替
  192. innerHTML: '' // {String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字
  193. },
  194. dnd: this.uploadDndButton, // {Selector} [可选] [默认值:undefined] 指定Drag And Drop拖拽的容器,如果不指定,则不启动。
  195. disableWidgets: 'log', // {String, Array} [可选] [默认值:undefined] 默认所有 Uploader.register 了的 widget 都会被加载,如果禁用某一部分,请通过此 option 指定黑名单。
  196. paste: document.body, // {Selector} [可选] [默认值:undefined] 指定监听paste事件的容器,如果不指定,不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为document.body.
  197. disableGlobalDnd: true, // {Selector} [可选] [默认值:false] 是否禁掉整个页面的拖拽功能,如果不禁用,图片拖进来的时候会默认被浏览器打开。
  198. thumb: { // {Object} [可选] 配置生成缩略图的选项。
  199. width: 100,
  200. height: 100,
  201. quality: 100, // // 图片质量,只有type为`image/jpeg`的时候才有效。
  202. allowMagnify: false, // // 是否允许放大,如果想要生成小图的时候不失真,此选项应该设置为false.
  203. crop: true // 是否允许裁剪。
  204. // type: 'image/jpeg' // 为空的话则保留原有图片格式,否则强制转换成指定的类型。
  205. },
  206. compress: false, // {Object} [可选] 配置压缩的图片的选项。如果此选项为false, 则图片在上传前不进行压缩。
  207. prepareNextFile: true, // {Boolean} [可选] [默认值:false] 是否允许在文件传输时提前把下一个文件准备好。 对于一个文件的准备工作比较耗时,比如图片压缩,md5序列化。 如果能提前在当前文件传输期处理,可以节省总体耗时。
  208. chunked: true, // {Boolean} [可选] [默认值:false] 是否要分片处理大文件上传。
  209. chunkSize: this.chunkSize, // {Boolean} [可选] [默认值:5242880] 如果要分片,分多大一片? 默认大小为5M.
  210. threads: 5, // {Boolean} [可选] [默认值:3] 上传并发数。允许同时最大上传进程数。
  211. formData: this.formData, // {Object} [可选] [默认值:{}] 文件上传请求的参数表,每次发送都会发送此对象中的参数。
  212. fileSizeLimit: this.fileSizeLimit, // {int} [可选] [默认值:undefined] 验证文件总大小是否超出限制, 超出则不允许加入队列。
  213. fileSingleSizeLimit: this.fileSingleSizeLimit, // {int} [可选] [默认值:undefined] 验证单个文件大小是否超出限制, 超出则不允许加入队列。
  214. fileNumLimit: this.fileNumLimit, // {int} [可选] [默认值:undefined] 限制上传个数,验证文件总数量, 超出则不允许加入队列。
  215. resize: false, // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
  216. accept: this.getAccept(this.accept), // {Arroy} [可选] [默认值:null] 指定接受哪些类型的文件。 由于目前还有ext转mimeType表,所以这里需要分开指定。
  217. duplicate: true // {Boolean} [可选] [默认值:undefined] 去重, 根据文件名字、文件大小和最后修改时间来生成hash Key.
  218. })
  219. // 当有文件被添加进队列的时候,添加到页面预览
  220. this.uploader.on('fileQueued', (file) => {
  221. const that = this
  222. // 将事件绑定到文件,保证在发生页面切换时之前已经开始上传的文件的回调事件不会发生变化
  223. file.onUploadFileErr = that.uploadContCommon.onUploadFileErr
  224. file.onUploadFileSuccess = that.uploadContCommon.onUploadFileSuccess
  225. file.callbackDate = that.uploadContCommon.callbackDate
  226. that.uploader.sort(function(a, b) { return a.size - b.size })// 多文件同时加入时小文件优先上传
  227. var uniqueFileName = md5(file.name + file.size + file.type + that.formData.userId)// 文件唯一标识
  228. that.uniqueFileNameMap.set(file.id, uniqueFileName)
  229. that.uploader.makeThumb(file, function(error, ret) {
  230. if (error) {
  231. // console.log('预览错误,上传的不是图片吧?')
  232. } else {
  233. // console.log('预览成功 base64')
  234. }
  235. })
  236. that.$emit('fileChange', file)
  237. })
  238. this.uploader.on('uploadStart', (file) => {
  239. // 在这里可以准备好formData的数据
  240. // this.uploader.options.formData.key = this.keyGenerator(file);
  241. })
  242. // 文件上传过程中创建进度条实时显示。
  243. this.uploader.on('uploadProgress', (file, percentage) => {
  244. this.$emit('progress', file, percentage)
  245. })
  246. this.uploader.on('uploadSuccess', (file, response) => {
  247. // this.$emit('success', file, response)
  248. // 最初的时候是在此处发布的成功事件,后来发现有时取不到返回的file.path,因此换到了在merge文件碎片回调中发布上传成功事件
  249. })
  250. this.uploader.on('uploadError', (file, reason) => {
  251. this.$emit('uploadError', file, reason)
  252. })
  253. this.uploader.on('error', (type) => {
  254. let errorMessage = ''
  255. if (type === 'F_EXCEED_SIZE') {
  256. errorMessage = `文件大小不能超过${this.fileSingleSizeLimit / (1024 * 1000)}M`
  257. } else if (type === 'Q_EXCEED_NUM_LIMIT') {
  258. errorMessage = '文件上传已达到最大上限数'
  259. } else {
  260. errorMessage = `上传出错!请检查后重新上传!错误代码${type}`
  261. }
  262. this.$emit('error', errorMessage)
  263. })
  264. this.uploader.on('uploadComplete', (file, response) => {
  265. this.$emit('complete', file, response)
  266. })
  267. },
  268. upload(file) {
  269. this.uploader.upload(file)
  270. },
  271. stop(file) {
  272. this.uploader.stop(file)
  273. },
  274. // 取消并中断文件上传
  275. cancelFile(file) {
  276. this.uploader.cancelFile(file)
  277. },
  278. // 在队列中移除文件
  279. removeFile(file, bool) {
  280. this.uploader.removeFile(file, bool)
  281. },
  282. // 获取上传文件类型
  283. getAccept(accept) {
  284. switch (accept) {
  285. case 'text':
  286. return {
  287. title: 'Texts',
  288. exteensions: 'doc,docx,xls,xlsx,ppt,pptx,pdf,txt', // {String} 允许的文件后缀,不带点,多个用逗号分割。
  289. mimeTypes: '.doc,docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt' // {String} 多个用逗号分割。
  290. }
  291. case 'video':
  292. return {
  293. title: 'Videos',
  294. exteensions: 'mp4',
  295. mimeTypes: '.mp4'
  296. }
  297. case 'image':
  298. return {
  299. title: 'Images',
  300. exteensions: 'gif,jpg,jpeg,bmp,png',
  301. mimeTypes: '.gif,.jpg,.jpeg,.bmp,.png'
  302. }
  303. default: return accept
  304. }
  305. }
  306. }
  307. }
  308. </script>
  309. <style lang="scss">
  310. .webuploader-container {
  311. position: relative;
  312. }
  313. .webuploader-element-invisible {
  314. position: absolute !important;
  315. clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
  316. clip: rect(1px,1px,1px,1px);
  317. }
  318. .webuploader-pick {
  319. position: relative;
  320. display: inline-block;
  321. cursor: pointer;
  322. background: #00b7ee;
  323. padding: 10px 15px;
  324. text-align: center;
  325. border-radius: 3px;
  326. overflow: hidden;
  327. }
  328. .webuploader-pick-hover {
  329. background: #00a2d4;
  330. }
  331. .webuploader-pick-disable {
  332. opacity: 0.6;
  333. pointer-events:none;
  334. }
  335. </style>

4. 文件分片断点续传UI组件

  1. <!--/**-->
  2. <!--* @Author: YanHuaKang-->
  3. <!--* @Date: 2019/11/21-->
  4. <!--* @Description: 文件分片断点续传UI组件-->
  5. <!--* @remarks:-->
  6. <!--*/-->
  7. <template>
  8. <transition :name="transitionName">
  9. <div id="mainFileUpload" :style="visibility">
  10. <div id="header" class="clearfix">
  11. <p class="fl title">上传资料</p>
  12. <div class="fr icons">
  13. <span
  14. v-if="!isMinimality"
  15. @click="minimality"
  16. ><i
  17. class="minimality iconfont iconjianhao"
  18. /></span>
  19. <span
  20. v-if="isMinimality"
  21. @click="open"
  22. ><i
  23. class="spread iconfont iconjiahao"
  24. /></span>
  25. <span @click="close"><i class="close iconfont iconguanbi" /></span>
  26. </div>
  27. </div>
  28. <div class="content">
  29. <div id="filePicker">
  30. <div class="drag-upload">
  31. <i class="iconfont iconshangchuan" />
  32. <p>可拖拽文件至此直接上传</p>
  33. </div>
  34. </div>
  35. <div id="file-panel">
  36. <div id="file-list">
  37. <el-scrollbar wrap-class="scrollbar-wrapper">
  38. <ul
  39. v-for="(file, index) in fileList"
  40. :key="file.id"
  41. class="file-item"
  42. :class="`file-${file.id}`"
  43. >
  44. <li class="file-type" :icon="fileCategory(file.ext)">
  45. <svg v-if="fileCategory(file.ext) === 'image'" class="icon" aria-hidden="true">
  46. <use xlink:href="#icontupian" />
  47. </svg>
  48. <svg v-else-if="fileCategory(file.ext) === 'video'" class="icon" aria-hidden="true">
  49. <use xlink:href="#iconvideo-" />
  50. </svg>
  51. <svg v-else-if="fileCategory(file.ext) === 'audio'" class="icon" aria-hidden="true">
  52. <use xlink:href="#iconaudio" />
  53. </svg>
  54. <svg v-else-if="fileCategory(file.ext) === 'text'" class="icon" aria-hidden="true">
  55. <use xlink:href="#icontext" />
  56. </svg>
  57. <svg v-else-if="fileCategory(file.ext) === 'excel'" class="icon" aria-hidden="true">
  58. <use xlink:href="#iconex" />
  59. </svg>
  60. <svg v-else-if="fileCategory(file.ext) === 'ppt'" class="icon" aria-hidden="true">
  61. <use xlink:href="#iconppt" />
  62. </svg>
  63. <svg v-else-if="fileCategory(file.ext) === 'pdf'" class="icon" aria-hidden="true">
  64. <use xlink:href="#iconpdf1" />
  65. </svg>
  66. <svg v-else-if="fileCategory(file.ext) === 'compressed'" class="icon" aria-hidden="true">
  67. <use xlink:href="#iconyasuobao" />
  68. </svg>
  69. <svg v-else class="icon" aria-hidden="true">
  70. <use xlink:href="#iconyemian" />
  71. </svg>
  72. </li>
  73. <el-tooltip
  74. class="file-name-tip"
  75. effect="dark"
  76. :content="file.name"
  77. placement="top-start"
  78. >
  79. <li class="file-name singleLineOmission">{{ file.name }}</li>
  80. </el-tooltip>
  81. <li class="progress">
  82. <el-progress :key="index" :percentage="progress[file.id]" :color="customColors" />
  83. </li>
  84. <li class="file-size">{{ fileSize(file.size) }}</li>
  85. <!--<li class="file-status">上传中...</li>-->
  86. <li class="file-operate">
  87. <!--<a title="开始" @click="resume(file)"><i class="iconfont iconkaishi" /></a>-->
  88. <!--<a title="暂停" @click="stop(file)"><i class="iconfont iconzanting1" /></a>-->
  89. <span
  90. class="pointer file-remove"
  91. title="移除"
  92. @click="remove(file)"
  93. ><i
  94. class=" iconfont iconguanbi"
  95. /></span>
  96. </li>
  97. </ul>
  98. <div v-if="!fileList.length" class="no-file">
  99. <i class="iconfont icon-empty-file" /> 暂无待上传文件
  100. </div>
  101. </el-scrollbar>
  102. </div>
  103. </div>
  104. </div>
  105. <div class="clearfix btnGroup">
  106. <div id="btnGroup" class="fr">
  107. <el-button type="primary" @click="clear()">清空上传</el-button>
  108. </div>
  109. </div>
  110. <vue-webuploader
  111. ref="uploader"
  112. upload-button="#filePicker"
  113. upload-dnd-button="#filePicker"
  114. multiple
  115. :form-data="formData"
  116. :url="url"
  117. @fileChange="fileChange"
  118. @progress="onProgress"
  119. @success="onSuccess"
  120. />
  121. </div>
  122. </transition>
  123. </template>
  124. <script>
  125. import store from '@/store'
  126. import { mapGetters } from 'vuex'
  127. import VueWebuploader from '@/components/VueWebuploader/VueWebuploader.vue'
  128. import { deskAddFile, knowledgeCreateFile } from '@/api/upload-file'
  129. const WebUploader = window.WebUploader
  130. export default {
  131. name: 'FileUploader',
  132. components: {
  133. VueWebuploader
  134. },
  135. props: {
  136. customStyle: {
  137. type: Object,
  138. default: function() {
  139. return {
  140. right: '50px',
  141. bottom: '0px'
  142. }
  143. }
  144. },
  145. transitionName: {
  146. type: String,
  147. default: 'fade'
  148. }
  149. },
  150. data() {
  151. return {
  152. uploadButton: 'filePicker',
  153. fileList: [], // 上传列表
  154. url: this.$store.state.user.applicationInfo.uploadUrl, // 租户上传路径
  155. formData: {
  156. // 参数
  157. userId: this.$store.state.user.applicationInfo.userId,
  158. companyId: this.$store.state.user.applicationInfo.companyId,
  159. appCode: this.$store.state.user.applicationInfo.appCode
  160. },
  161. fileQueued: new Map(), // 上传队列
  162. customColors: [
  163. { color: '#f56c6c', percentage: 20 },
  164. { color: '#e6a23c', percentage: 40 },
  165. { color: '#5cb87a', percentage: 60 },
  166. { color: '#1989fa', percentage: 80 },
  167. { color: '#20c7b3', percentage: 100 }
  168. ],
  169. progress: {} // 进度
  170. }
  171. },
  172. computed: {
  173. ...mapGetters(['visibility', 'isMinimality', 'belongs'])
  174. },
  175. watch: {},
  176. mounted() {
  177. store.dispatch('fileUpload/isVisibility', 2)
  178. },
  179. created() {},
  180. methods: {
  181. // 关闭
  182. close() {
  183. store.dispatch('fileUpload/isVisibility', 2)
  184. },
  185. // 最小化
  186. minimality() {
  187. store.dispatch('fileUpload/isVisibility', 3)
  188. },
  189. // 展开
  190. open() {
  191. store.dispatch('fileUpload/isVisibility', 1)
  192. },
  193. // 上传变化
  194. fileChange(file) {
  195. if (!file.size) return
  196. file.progress = 10
  197. this.fileList.push(file)
  198. this.$set(this.progress, file.id, 0)
  199. const sourceUid = file.source.uid // 文件上传文件唯一id
  200. const belongs = {
  201. data_type: this.belongs.data_type,
  202. ownerId: this.belongs.ownerId,
  203. parentId: this.belongs.parentId,
  204. selectCompanyId: this.belongs.selectCompanyId
  205. }
  206. this.fileQueued.set(sourceUid, belongs)
  207. },
  208. // 上传进度
  209. onProgress(file, percent) {
  210. const progress = (Math.ceil(percent * 100 * 100) / 100)
  211. this.$set(this.progress, file.id, progress)
  212. },
  213. // 上传成功
  214. onSuccess(file, response) {
  215. // console.log('file', file)
  216. // console.log('response', response)
  217. // console.log('上传成功', file)
  218. // console.log(this.belongs)
  219. // console.log('file.path', file.path)
  220. file.path = file.path || ''
  221. const fileId = file.path.split('ZmlsZUlk=')[1]
  222. const sourceUid = file.source.uid // 文件上传文件唯一id
  223. var currentFile = this.fileQueued.get(sourceUid)
  224. // console.log('sourceUid', sourceUid)
  225. // console.log('currentFile', currentFile)
  226. // console.log('this.fileQueued', this.fileQueued)
  227. // console.log('fileId', fileId)
  228. if (currentFile.data_type === 3) {
  229. const params = {
  230. fileFormat: file.ext,
  231. fileName: file.name,
  232. fileSize: file.size,
  233. fileUrl: file.path,
  234. resourceFileId: fileId
  235. }
  236. deskAddFile(params).then(res => {
  237. console.log(res)
  238. this.$message.success('上传成功!')
  239. store.dispatch('fileUpload/deskAddFileSuccess', res.data)
  240. })
  241. } else {
  242. // const currentFile = this.fileQueued.get(sourceUid)
  243. const params = {
  244. format: file.ext,
  245. name: file.name,
  246. size: file.size,
  247. url: file.path,
  248. data_type: currentFile.data_type,
  249. ownerId: currentFile.ownerId,
  250. parentId: currentFile.parentId,
  251. selectCompanyId: currentFile.selectCompanyId,
  252. fileId: fileId
  253. }
  254. knowledgeCreateFile(params).then(res => {
  255. // console.log(res)
  256. this.$message.success('上传成功!')
  257. store.dispatch('fileUpload/createFileSuccess', res.data)
  258. })
  259. }
  260. },
  261. // 开始
  262. resume(file) {
  263. this.$refs.uploader.upload(file)
  264. },
  265. // 暂停
  266. stop(file) {
  267. this.$refs.uploader.stop(file)
  268. },
  269. // 移除
  270. remove(file) {
  271. this.$confirm('确定要删除此上传任务吗?', '删除任务', {
  272. confirmButtonText: '确定',
  273. cancelButtonText: '取消',
  274. type: 'warning'
  275. })
  276. .then(() => {
  277. // 取消并中断文件上传
  278. this.$refs.uploader.cancelFile(file)
  279. // 在队列中移除文件
  280. this.$refs.uploader.removeFile(file, true)
  281. // 在ui上移除
  282. const index = this.fileList.findIndex(ele => ele.id === file.id)
  283. this.fileList.splice(index, 1)
  284. })
  285. .catch(() => {})
  286. },
  287. // 清空
  288. clear() {
  289. var that = this
  290. if (this.fileList.length) {
  291. this.$confirm('确定要清空上传任务吗?', '清空上传', {
  292. confirmButtonText: '确定',
  293. cancelButtonText: '取消',
  294. type: 'warning'
  295. })
  296. .then(() => {
  297. for (
  298. var index = 0, len = that.fileList.length;
  299. index < len;
  300. index++
  301. ) {
  302. var file = that.fileList[index]
  303. that.$refs.uploader.cancelFile(file)
  304. that.$refs.uploader.removeFile(file, true)
  305. that.fileList.splice(index--, 1)
  306. }
  307. })
  308. .catch(() => {})
  309. }
  310. },
  311. // 文件大小
  312. fileSize(size) {
  313. return WebUploader.Base.formatSize(size)
  314. },
  315. // 文件类别
  316. fileCategory(ext) {
  317. let type = ''
  318. const typeMap = {
  319. image: ['gif', 'jpg', 'jpeg', 'png', 'bmp', 'webp'],
  320. video: ['mp4', 'm3u8', 'rmvb', 'avi', 'swf', '3gp', 'mkv', 'flv'],
  321. audio: ['mp3', 'wma', 'rm', 'wav', 'midi', 'ape', 'flac'],
  322. text: [
  323. 'doc',
  324. 'txt',
  325. 'docx',
  326. 'pages',
  327. 'epub'
  328. ],
  329. excel: ['numbers', 'csv', 'xls', 'xlsx'],
  330. ppt: ['keynote', 'ppt', 'pptx'],
  331. compressed: ['zip', 'rar'],
  332. pdf: ['pdf']
  333. }
  334. Object.keys(typeMap).forEach(_type => {
  335. const extensions = typeMap[_type]
  336. if (extensions.indexOf(ext) > -1) {
  337. type = _type
  338. }
  339. })
  340. return type
  341. }
  342. }
  343. }
  344. </script>
  345. <style lang="scss" scoped>
  346. @import "~@/styles/theme.scss";
  347. #mainFileUpload {
  348. visibility: hidden;
  349. width: 38%;
  350. height: 60vh;
  351. position: fixed;
  352. bottom: -522px;
  353. right: 20px;
  354. z-index: 100;
  355. border: 1px solid #e0e0e0;
  356. border-radius: 5px;
  357. background: #ffffff;
  358. overflow: hidden;
  359. transition: bottom 1s;
  360. > #header {
  361. height: 40px;
  362. line-height: 40px;
  363. padding: 0 20px;
  364. background-color: $themeColor;
  365. > .title {
  366. color: #ffffff;
  367. margin: 0;
  368. font-size: 14px;
  369. }
  370. > .fr.icons span {
  371. width: 14px;
  372. height: 14px;
  373. background-color: #ffffff;
  374. color: $themeColor;
  375. cursor: pointer;
  376. }
  377. > .fr.icons span i {
  378. font-size: 14px;
  379. }
  380. }
  381. > .content {
  382. padding: 1.5vh 20px;
  383. > #filePicker {
  384. width: 100%;
  385. height: 15vh;
  386. background-color: #fafafa;
  387. border-radius: 5px;
  388. }
  389. }
  390. .drag-upload {
  391. width: 200px;
  392. margin: 0 auto;
  393. margin-top: 18px;
  394. color: #bbbbbb;
  395. > .iconfont {
  396. font-size: 50px;
  397. }
  398. }
  399. #file-panel {
  400. margin-top: 1.5vh;
  401. }
  402. #file-panel .el-scrollbar {
  403. height: 29vh;
  404. }
  405. #file-list {
  406. position: relative;
  407. overflow-y: auto;
  408. }
  409. .file-item {
  410. position: relative;
  411. height: 30px;
  412. line-height: 30px;
  413. padding: 0 10px;
  414. margin-bottom: 10px;
  415. border-bottom: 1px solid #ccc;
  416. background-color: #fff;
  417. z-index: 1;
  418. color: #575757;
  419. > li {
  420. display: inline-block;
  421. }
  422. > .file-type {
  423. width: 24px;
  424. height: 30px;
  425. vertical-align: top;
  426. > i {
  427. display: table-cell;
  428. }
  429. }
  430. > .file-name {
  431. width: 18%;
  432. vertical-align: top;
  433. }
  434. > .progress {
  435. width: 70%;
  436. > /deep/ .el-progress {
  437. width: 100%;
  438. height: 30px;
  439. line-height: 30px;
  440. display: table;
  441. }
  442. }
  443. > .file-size {
  444. width: 80px;
  445. position: absolute;
  446. left: 0px;
  447. right: 0px;
  448. bottom: 0px;
  449. top: 0px;
  450. margin: 0 auto;
  451. font-size: 14px;
  452. text-align: center;
  453. }
  454. }
  455. .file-remove {
  456. display: table-cell;
  457. }
  458. .no-file {
  459. text-align: center;
  460. color: #575757;
  461. font-size: 14px;
  462. }
  463. }
  464. .btnGroup {
  465. margin-right: 20px;
  466. }
  467. .file-item .progress /deep/ .el-progress-bar {
  468. width: 95%;
  469. }
  470. #filePicker /deep/ .webuploader-pick {
  471. width: 100% !important;
  472. height: 100% !important;
  473. background-color: #fafafa !important;
  474. }
  475. #filePicker /deep/ .webuploader-pick-hover {
  476. background-color: #fafafa !important;
  477. }
  478. #mainFileUpload > #header > .fr.icons span {
  479. padding: 0 1px;
  480. border-radius: 2px;
  481. }
  482. </style>

效果图

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/66652
推荐阅读
  

闽ICP备14008679号