阅行客电子档案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
3.9 KiB

  1. <template>
  2. <div>
  3. <!--上传组件-->
  4. <el-upload
  5. class="upload-demo"
  6. :action="uploadUrl"
  7. :auto-upload="false"
  8. :on-change="handleChange"
  9. :before-upload="handleBeforeUpload"
  10. :on-progress="handleProgress"
  11. >
  12. <el-button slot="trigger">选取文件</el-button>
  13. <!--上传文件按钮-->
  14. <el-button style="margin-left: 10px" type="primary" :loading="uploading" :disabled="files.length === 0" @click="handleUpload">
  15. 上传文件
  16. </el-button>
  17. <el-progress :percentage="percent" />
  18. </el-upload>
  19. </div>
  20. </template>
  21. <script>
  22. import { mapGetters } from 'vuex'
  23. import axios from 'axios'
  24. export default {
  25. data() {
  26. return {
  27. files: [], // 选中的文件列表
  28. uploading: false, // 是否正在上传
  29. percent: 0, // 上传进度
  30. uploadUrl: this.baseApi + '/api/collect/uploadFiles' // 上传地址
  31. }
  32. },
  33. computed: {
  34. ...mapGetters([
  35. 'baseApi'
  36. ])
  37. },
  38. methods: {
  39. // 切片上传
  40. async upload(file) {
  41. const chunkSize = 1024 * 1024 // 每个块的大小为 1MB
  42. const fileSize = file.size // 文件大小
  43. const chunks = Math.ceil(fileSize / chunkSize) // 总块数
  44. const tasks = [] // 上传任务数组
  45. let uploaded = 0 // 已上传块数
  46. // 文件切割
  47. for (let i = 0; i < chunks; i++) {
  48. const start = i * chunkSize
  49. const end = Math.min(start + chunkSize, fileSize)
  50. tasks.push(
  51. new Promise((resolve, reject) => {
  52. const formData = new FormData()
  53. formData.append('chunk_index', i) // 块编号
  54. formData.append('chunk_count', chunks) // 总块数
  55. formData.append('file_id', file.id) // 文件ID
  56. formData.append('chunk_data', file.slice(start, end)) // 块数据
  57. axios
  58. .post(this.uploadUrl, formData) // 上传块数据
  59. .then(res => {
  60. uploaded++
  61. this.percent = Math.floor((uploaded / chunks) * 100)
  62. console.log(this.percent)
  63. resolve()
  64. })
  65. .catch(err => {
  66. reject(err)
  67. })
  68. })
  69. )
  70. }
  71. // 待所有块上传完成后,发送合并请求
  72. await Promise.all(tasks)
  73. const res = await axios.post(this.uploadUrl, { file_id: file.id, chunks })
  74. // 上传成功,返回文件URL
  75. if (res.status === 200) {
  76. return `${this.uploadUrl}/${file.id}`
  77. } else {
  78. throw new Error(res.data.message)
  79. }
  80. },
  81. handleChange(files) {
  82. this.files = files
  83. },
  84. async handleUpload() {
  85. console.log('handleUpload')
  86. try {
  87. console.log('handleUpload2')
  88. this.uploading = true
  89. console.log(this.files)
  90. const url = await this.upload(this.files)
  91. // 文件上传成功,将url展示给用户
  92. this.$message.success(`文件${this.files.name}上传成功!URL:${url}`)
  93. // for (let i = 0; i < this.files.length; i++) {
  94. // const file = this.files[i]
  95. // console.log('file', file)
  96. // }
  97. } catch (err) {
  98. console.log('handleUpload3')
  99. this.$message.error(`文件上传失败!${err.message}`)
  100. } finally {
  101. console.log('handleUpload4')
  102. this.uploading = false
  103. }
  104. },
  105. handleBeforeUpload() {
  106. // TODO: 检查文件大小、类型等
  107. },
  108. handleProgress(event, file) {
  109. // 显示上传进度
  110. this.percent = Math.floor((event.loaded / event.total) * 100)
  111. }
  112. }
  113. }
  114. </script>
  115. <style lang="scss" scoped>
  116. .upload-demo{
  117. position: relative;
  118. display: flex;
  119. justify-content: center;
  120. width: 120px;
  121. margin: 20px 0 30px 0;
  122. .el-progress{
  123. position: absolute;
  124. left: 0;
  125. bottom: -20px;
  126. }
  127. }
  128. </style>