AbilityUpload.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <template>
  2. <div class="base-upload-container">
  3. <Upload :multiple="!singleUpload" type="drag" action="" :before-upload="onBeforeUpload"
  4. :show-upload-list="false">
  5. <div style="padding: 40px 0">
  6. <Icon type="ios-cloud-upload" size="100" style="color: #a3a3a3;margin: 40px 0;"></Icon>
  7. <p style="color: #a3a3a3">{{ $t('ability.uploadTip') }}</p>
  8. <p style="color: #a3a3a3" v-if="acceptTypes.length">({{ $t('knowledge.import.tip2') }}:
  9. {{ acceptTypes.join(' / ') }} )</p>
  10. </div>
  11. </Upload>
  12. <div class="file-list-box">
  13. <div class="file-item" v-for="(item,index) in fileArr" :key="index">
  14. <p>
  15. <span>{{ item.name }}</span>
  16. <span class="tool-remove" v-if="isShowTool">
  17. <Icon type="md-close" @click="onRemoveFile(index)" />
  18. </span>
  19. </p>
  20. <Progress :percent="progressArr[index]" :stroke-width="12" />
  21. </div>
  22. </div>
  23. <Button type="success" @click="onConfirmUpload" style="width: 100%;height: 40px;" :loading="isLoading"
  24. class="modal-btn" :disabled="!fileArr.length"
  25. v-if="mode === 'modal'">{{ $t('ability.confirmUpload') }}</Button>
  26. </div>
  27. </template>
  28. <script>
  29. import excel from '@/utils/excel.js'
  30. import FileSaver from "file-saver";
  31. import BlobTool from '@/utils/blobTool.js'
  32. export default {
  33. props: {
  34. auth: {
  35. type: Object,
  36. default: () => {
  37. return {
  38. sas: '',
  39. url: '',
  40. name: ''
  41. }
  42. }
  43. },
  44. scope: {
  45. type: String,
  46. default: 'school'
  47. },
  48. prefix: {
  49. type: String,
  50. default: ''
  51. },
  52. mode: {
  53. type: String,
  54. default: 'modal'
  55. },
  56. maxSize: {
  57. type: Number,
  58. default: -1
  59. },
  60. acceptTypes: {
  61. type: Array,
  62. default: () => []
  63. },
  64. // 简易上传,只返回选择的fileArr,不做操作处理
  65. simpleUpload: {
  66. type: Boolean,
  67. default: false
  68. },
  69. // 只能上传单个
  70. singleUpload: {
  71. type: Boolean,
  72. default: false
  73. },
  74. },
  75. data() {
  76. return {
  77. isLoading: false,
  78. isShowTool: true,
  79. containerClient: null,
  80. fileArr: [],
  81. progressArr: []
  82. }
  83. },
  84. created() {
  85. console.log(this.acceptTypes);
  86. },
  87. methods: {
  88. onRemoveFile(index) {
  89. this.fileArr.splice(index, 1)
  90. },
  91. /* 转换size */
  92. getSizeByBytes(bytes) {
  93. return bytes / 1024 < 1024 ? (bytes / 1024).toFixed(1) + 'KB' : bytes / 1024 / 1024 < 1024 ? (bytes /
  94. 1024 / 1024).toFixed(1) + 'M' : (bytes / 1024 / 1024 / 1024).toFixed(1) + 'G'
  95. },
  96. async onBeforeUpload(file) {
  97. console.log(this.$GLOBAL.NotSupport);
  98. console.log(this.acceptTypes);
  99. console.log(file);
  100. console.log(file.type);
  101. let nameType = file.name.split('.')[file.name.split('.').length - 1]
  102. if (this.maxSize > 0 && file.size > this.maxSize) {
  103. this.$Message.warning(this.$t('ability.sizeTip') + this.getSizeByBytes(this.maxSize) + '!');
  104. return false
  105. }
  106. if (this.acceptTypes.length && !this.acceptTypes.includes(file.type.split('/')[file.type.split('/')
  107. .length - 1].toLowerCase()) && !this.acceptTypes.includes(nameType.toLowerCase())) {
  108. this.$Message.warning(this.$t('ability.typeTip') + this.acceptTypes.join(','));
  109. return false
  110. } else if (this.$GLOBAL.NotSupport.includes(nameType.toUpperCase()) && !this.acceptTypes.length) {
  111. this.$Message.warning(this.$t('learnActivity.notSupportType')); // 黑名单文件格式不能上传
  112. return false
  113. }
  114. if (this.mode === 'import') {
  115. let excelResult = []
  116. this.readExcel(file, data => {
  117. if (data.results.length) {
  118. console.log(data);
  119. data.results.forEach(item => {
  120. excelResult.push({
  121. question: item.Question || '',
  122. answer: item.Answer ? (item.Type === 'multiple' ? item
  123. .Answer
  124. .split(',') : [item.Answer]) : [],
  125. type: item.Type,
  126. options: this.getItemOptions(item)
  127. })
  128. })
  129. console.log(excelResult);
  130. this.fileArr = []
  131. this.progressArr = []
  132. this.$emit('uploadFinish', excelResult)
  133. this.isLoading = false
  134. }
  135. })
  136. return false
  137. }
  138. file.progress = 0
  139. this.fileArr.push(file)
  140. this.progressArr.push(0)
  141. return false
  142. },
  143. /* 解析excel表格 */
  144. readExcel(file, callback) {
  145. var reader = new FileReader();
  146. reader.onload = function(e) {
  147. var data = e.target.result;
  148. var workbook = excel.read(data, 'binary');
  149. if (callback) callback(workbook);
  150. };
  151. reader.readAsBinaryString(file);
  152. },
  153. /* 获取表格解析试题的选项 */
  154. getItemOptions(item) {
  155. let options = []
  156. let optionIndex = 0
  157. if (item.Type === 'judge') {
  158. return [{
  159. code: 'A',
  160. value: this.$t('ability.true')
  161. }, {
  162. code: 'B',
  163. value: this.$t('ability.false')
  164. }]
  165. } else {
  166. for (let key in item) {
  167. if (key.includes('Option')) {
  168. options.push({
  169. code: String.fromCharCode(64 + parseInt(optionIndex + 1)),
  170. value: item[key]
  171. })
  172. optionIndex++
  173. }
  174. }
  175. return options
  176. }
  177. },
  178. /* 确认上传 */
  179. async onConfirmUpload() {
  180. if (this.simpleUpload) {
  181. this.$emit('uploadFinish', this.fileArr)
  182. return
  183. }
  184. this.isShowTool = false
  185. this.isLoading = true
  186. let result = []
  187. let containerClient = this.containerClient
  188. let list = this.fileArr
  189. let that = this
  190. let path = this.prefix === '' ? `yxpt/${this.curStandard}/jyzx` :
  191. (this.mode === 'video' ? `yxpt/${this.curStandard}/jyzx/${this.prefix}/video` : `yxpt/${this.curStandard}/jyzx/${this.prefix}`)
  192. for (let i = 0; i < list.length; i++) {
  193. let file = list[i]
  194. try {
  195. let blobFile = await containerClient.upload(file, { path:path,checkSize:false }, {
  196. onProgress: function(e) {
  197. that.$set(that.progressArr, i, parseInt(e.loadedBytes * 100 / file.size))
  198. }
  199. });
  200. // 如果上传的是视频文件 则需要获取视频的时长信息和MD5信息
  201. if (blobFile.type === 'video') {
  202. await this.uploadVideoPoster(blobFile, path, containerClient)
  203. blobFile.duration = await this.$tools.getVideoDuration(file)
  204. }
  205. let fileMD5 = await this.$tools.getFileMD5(file)
  206. blobFile.hash = this.$tools.convertFileMD5ToString(fileMD5)
  207. console.log('getFileMD5 > convertFileMD5ToString >', blobFile)
  208. result.push(blobFile)
  209. } catch (e) {
  210. this.$Message.error(e.spaceError ? e.spaceError : 'upload Fail')
  211. return
  212. }
  213. }
  214. this.fileArr = []
  215. this.progressArr = []
  216. this.$emit('uploadFinish', result)
  217. this.isLoading = false
  218. },
  219. /* 上传视频封面 */
  220. uploadVideoPoster(blobJson, path, containerClient) {
  221. return new Promise(async (r, j) => {
  222. try {
  223. let fileFullUrl = await this.$tools.getFileSas(blobJson.url)
  224. let n = blobJson.name.substring(0, blobJson.name.lastIndexOf('.'))
  225. let dataUrl = await this.$jsFn.createVideoPoster(fileFullUrl.url,blobJson.name)
  226. let f = this.$jsFn.dataURLtoFile(dataUrl, n + '.png')
  227. let blobFile = await containerClient.upload(f, { path:path,checkSize:false });
  228. r(blobFile)
  229. } catch (e) {
  230. this.$Message.error('当前视频可能无法播放,请检查视频编码格式')
  231. r(e)
  232. }
  233. })
  234. }
  235. },
  236. mounted() {
  237. if (this.auth.sas) {
  238. let n = this.auth
  239. this.containerClient = new BlobTool(n.url, n.name, n.sas, this.scope)
  240. }
  241. },
  242. computed: {
  243. curStandard() {
  244. return sessionStorage.getItem('standard') || this.$store.state.user.schoolProfile.school_base.standard
  245. },
  246. isAreaMgmt() {
  247. return this.$route.name === 'areaAbilityMgmt'
  248. }
  249. },
  250. watch: {
  251. auth: {
  252. handler(n, o) {
  253. this.containerClient = new BlobTool(n.url, n.name, n.sas, this.scope)
  254. }
  255. }
  256. }
  257. }
  258. </script>
  259. <style lang="less">
  260. .base-upload-container {
  261. .file-list-box {
  262. margin: 20px 5px;
  263. width: 100%;
  264. max-height: 200px;
  265. overflow: auto;
  266. .file-item {
  267. margin: 10px 0;
  268. .tool-remove {
  269. color: #b3b3b3;
  270. margin-left: 15px;
  271. font-size: 14px;
  272. cursor: pointer;
  273. }
  274. }
  275. .ivu-progress {
  276. margin-top: 10px;
  277. }
  278. .ivu-progress-inner {
  279. background-color: #e1e1e1;
  280. }
  281. .ivu-progress-text-inner {
  282. color: #969696;
  283. }
  284. &::-webkit-scrollbar-thumb {
  285. background: #dadada !important;
  286. }
  287. }
  288. }
  289. </style>