materialSelectorForManageCenter.vue 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. <template>
  2. <div class="table-select">
  3. <span class="title">{{ title }}</span>
  4. <div class="close-btn"><i class="iconfont icon-pop-ups_shut-down" @click="$emit('cancle')"></i></div>
  5. <div class="material-tab">
  6. <a v-if="selectableType.includes('image')" class="material-tab-item"
  7. @click.prevent="currentMaterialType = 'image'">
  8. <span :class="{ active: currentMaterialType === 'image' }" class="text">
  9. {{ image }}
  10. </span>
  11. <div v-if="currentMaterialType === 'image'" class="bottom-line"></div>
  12. </a>
  13. <a v-if="selectableType.includes('pano')" class="material-tab-item" @click.prevent="currentMaterialType = 'pano'">
  14. <span :class="{ active: currentMaterialType === 'pano' }" class="text">
  15. {{ panorama }}
  16. </span>
  17. <div v-if="currentMaterialType === 'pano'" class="bottom-line"></div>
  18. </a>
  19. <a v-if="selectableType.includes('audio')" class="material-tab-item"
  20. @click.prevent="currentMaterialType = 'audio'">
  21. <span :class="{ active: currentMaterialType === 'audio' }" class="text">
  22. {{ audio }}
  23. </span>
  24. <div v-if="currentMaterialType === 'audio'" class="bottom-line"></div>
  25. </a>
  26. <a v-if="selectableType.includes('video')" class="material-tab-item"
  27. @click.prevent="currentMaterialType = 'video'">
  28. <span :class="{ active: currentMaterialType === 'video' }" class="text">
  29. {{ video }}
  30. </span>
  31. <div v-if="currentMaterialType === 'video'" class="bottom-line"></div>
  32. </a>
  33. <a v-if="selectableType.includes('3D')" class="material-tab-item" @click.prevent="currentMaterialType = '3D'">
  34. <span :class="{ active: currentMaterialType === '3D' }" class="text">
  35. {{ scene }}
  36. </span>
  37. <div v-if="currentMaterialType === '3D'" class="bottom-line"></div>
  38. </a>
  39. </div>
  40. <div class="filter">
  41. <input type="text" :placeholder="keywords" v-model="searchKey" />
  42. <i v-if="!searchKey" class="iconfont icon-editor_search search-icon" />
  43. <i v-if="searchKey" @click="searchKey = ''" class="iconfont icontoast_red clear-icon"></i>
  44. </div>
  45. <div class="table table-pano" v-show="currentMaterialType === 'pano'">
  46. <div class="table-head-row">
  47. <span class="table-head">1</span>
  48. <span class="table-head" v-for="(item, i) in tableHeadersForPano" :key="i">
  49. {{ item.name && $i18n.t(`zh_key.${item.name}`) }}</span>
  50. </div>
  51. <div v-if="panoListLocalLength !== 0 || hasMorePanoData" class="table-body"
  52. v-infinite-scroll="requestMorePanoData"
  53. :infinite-scroll-disabled="!hasMorePanoData || isRequestingMorePanoData">
  54. <!-- vuex中的上传中数据 -->
  55. <div class="table-body-row" v-for="(item, i) in uploadStatusListPano" :key="item.uid" @click="onClickRow">
  56. <!-- 如果已经上传成功 -->
  57. <template v-if="item.status === 'SUCCESS'">
  58. <span class="table-data">
  59. <RadioOrCheckbox class="checkbox" :isLightTheme="true" :isMultiSelection="isMultiSelection"
  60. :isCheckedInitial="select.some(i => i[primaryKey] === item.successInfo[primaryKey])"
  61. @change="v => selectItem(item.successInfo, v)" />
  62. </span>
  63. <span class="table-data" v-for="(tableItemStructure, idx) in tableHeadersForPano" :key="idx">
  64. <div v-if="tableItemStructure.type == 'image'" class="list-img">
  65. <img
  66. :src="item.successInfo[tableItemStructure.key] + (Number(item.fileSize) > 512 ? $imgsuffix : ``)"
  67. alt="">
  68. </div>
  69. <span v-else class="ellipsis"
  70. v-title="tableItemStructure.key === 'name' ? item.successInfo[tableItemStructure.key] : ''">{{
  71. item.successInfo[tableItemStructure.key]
  72. }}</span>
  73. </span>
  74. </template>
  75. <!-- 如果还在上传或切图处理中 -->
  76. <template v-else-if="item.status = 'LOADING'">
  77. <span class="table-data">
  78. <div class="checkbox">
  79. <span class="for-outer-circle"></span>
  80. <span class="for-inner-circle disabled"></span>
  81. </div>
  82. </span>
  83. <span class="table-data" v-for="(tableItemStructure, idx) in tableHeadersForPano" :key="idx">
  84. <div v-if="tableItemStructure.type == 'image'" class="list-img">
  85. <img src="@/assets/images/icons/upload-file-type-icon-image@2x.png" alt="">
  86. </div>
  87. <span v-if="tableItemStructure.key !== 'name' && tableItemStructure.key !== 'fileSize'"></span>
  88. <span v-if="tableItemStructure.key === 'fileSize' && item.ifKnowProgress">{{$i18n.t(`gather.upload_material`)}} {{ Math.round(item.progress
  89. * 100)
  90. }}%</span>
  91. <span v-if="tableItemStructure.key === 'fileSize' && !item.ifKnowProgress">{{ item.statusText }}</span>
  92. <span v-if="tableItemStructure.key === 'name'" class="ellipsis"
  93. v-title="tableItemStructure.key === 'name' ? item.title : ''">{{ item.title }}</span>
  94. </span>
  95. </template>
  96. <!-- 如果上传失败了 -->
  97. <template v-else-if="item.status = 'FAIL'">
  98. <span class="table-data">
  99. <div class="checkbox">
  100. <span class="for-outer-circle"></span>
  101. <span class="for-inner-circle disabled"></span>
  102. </div>
  103. </span>
  104. <span class="table-data" v-for="(tableItemStructure, idx) in tableHeadersForPano" :key="idx">
  105. <div v-if="tableItemStructure.type == 'image'" class="list-img">
  106. <img src="@/assets/images/icons/upload-file-type-icon-image@2x.png" alt="">
  107. </div>
  108. <span v-if="tableItemStructure.key !== 'name' && tableItemStructure.key !== 'fileSize'"></span>
  109. <span v-if="tableItemStructure.key === 'fileSize'">{{ $i18n.t(`tips_code.FAILURE_3025`) }}</span>
  110. <span v-if="tableItemStructure.key === 'name'" class="ellipsis"
  111. v-title="tableItemStructure.key === 'name' ? item.title : ''">{{ item.title }}</span>
  112. </span>
  113. </template>
  114. </div>
  115. <!-- 本组件内的列表数据 -->
  116. <div class="table-body-row" v-for="(item, i) in panoList" :key="i" @click="onClickRow">
  117. <span class="table-data">
  118. <RadioOrCheckbox class="checkbox" :isLightTheme="true" :isMultiSelection="isMultiSelection"
  119. :isCheckedInitial="select.some(i => i[primaryKey] === item[primaryKey])"
  120. @change="v => selectItem(item, v)" />
  121. </span>
  122. <span class="table-data" v-for="(sub, idx) in tableHeadersForPano" :key="idx">
  123. <div v-if="sub.type == 'image'" class="list-img">
  124. <img
  125. :src="item[sub.key] + (Number(item.fileSize) > 512 ? $imgsuffix : ``)"
  126. alt="">
  127. </div>
  128. <span class="ellipsis" v-else v-title="sub.key === 'name' ? item[sub.key] : ''">{{ item[sub.key] }}</span>
  129. </span>
  130. </div>
  131. </div>
  132. <!-- 无数据时的提示 -->
  133. <div v-else class="no-data">
  134. <div v-if="latestUsedSearchKey">
  135. <img :src="require('@/assets/images/default/empty_04_search.png')" alt="">
  136. <span>{{ no_serch_result }}</span>
  137. </div>
  138. <div v-if="!latestUsedSearchKey">
  139. <img :src="require('@/assets/images/default/empty_04.png')" alt="">
  140. <span>{{ no_material_result }}</span>
  141. </div>
  142. </div>
  143. </div>
  144. <div class="table table-3D" v-show="currentMaterialType === '3D'">
  145. <div class="table-head-row">
  146. <span class="table-head">1</span>
  147. <span class="table-head" v-for="(item, i) in tableHeadersFor3D" :key="i">
  148. {{ item.name && $i18n.t(`zh_key.${item.name}`) }}</span>
  149. </div>
  150. <div v-if="scene3DList.length !== 0 || hasMore3DData" class="table-body" v-infinite-scroll="requestMore3DData"
  151. :infinite-scroll-disabled="!hasMore3DData || isRequestingMore3DData">
  152. <div class="table-body-row" v-for="(item, i) in scene3DList" :key="i">
  153. <span class="table-data">
  154. <RadioOrCheckbox class="checkbox" :isLightTheme="true" :isMultiSelection="isMultiSelection"
  155. :isCheckedInitial="select.some(i => i[primaryKey] === item[primaryKey])"
  156. @change="v => selectItem(item, v)" />
  157. </span>
  158. <span class="table-data" v-for="(sub, idx) in tableHeadersFor3D" :key="idx">
  159. <div v-if="sub.type == 'image'" class="list-img">
  160. <img
  161. :src="item[sub.key] + (Number(item.fileSize) > 512 ? $imgsuffix : ``)"
  162. alt="">
  163. </div>
  164. <span class="ellipsis" v-else v-title="sub.key === 'name' ? item[sub.key] : ''">{{ item[sub.key] }}</span>
  165. </span>
  166. </div>
  167. </div>
  168. <!-- 无数据时的提示 -->
  169. <div v-else class="no-data">
  170. <div v-if="latestUsedSearchKey">
  171. <img :src="require('@/assets/images/default/empty_04_search.png')" alt="">
  172. <span>{{ no_serch_result }}</span>
  173. </div>
  174. <div v-if="!latestUsedSearchKey">
  175. <img :src="require('@/assets/images/default/empty_04.png')" alt="">
  176. <span>{{ no_material_result }}</span>
  177. <a href="/#/">
  178. <button class="ui-button">{{ how_to_shoot }}</button>
  179. </a>
  180. </div>
  181. </div>
  182. </div>
  183. <div class="btns">
  184. <button v-if="currentMaterialType !== '3D'" class="ui-button upload-btn" @click="onClickUpload">
  185. <span>{{ upload_material }}</span>
  186. <i :key="currentMaterialType" class="iconfont icon-material_prompt tool-tip-for-editor" v-tooltip="
  187. currentMaterialType === 'image' ? img_size :
  188. currentMaterialType === 'pano' ? pano_size :
  189. currentMaterialType === 'audio' ? audio_size :
  190. currentMaterialType === 'video' ? video_size : ''
  191. ">
  192. </i>
  193. <FileInput ref="file-input" :failString="fileInputFailString" :limitFailStr="fileInputLimitFailStr"
  194. :acceptType="fileInputAcceptType" :mediaType="fileInputMediaType" :limit="fileInputLimit"
  195. @file-change="onFileInputChange"></FileInput>
  196. </button>
  197. <div v-else class="button-placeholder"></div>
  198. <div>
  199. <button class="ui-button cancel" @click="$emit('cancle')">{{ cancel }}</button>
  200. <button class="ui-button submit" :class="{ disable: !select.length }" @click="onClickComfirm">
  201. {{ comfirm }}
  202. </button>
  203. </div>
  204. </div>
  205. </div>
  206. </template>
  207. <script>
  208. import { mapMutations } from "vuex";
  209. import {
  210. getMaterialList,
  211. getSceneList,
  212. uploadMaterial,
  213. checkMStatus,
  214. checkUserSize,
  215. } from "@/api";
  216. import { getImgWH, changeByteUnit } from "@/utils/file";
  217. import config from "@/config";
  218. import { debounce } from "@/utils/other.js"
  219. import FileInput from "@/components/shared/uploads/UploadMultiple.vue";
  220. import { mapState } from "vuex";
  221. import RadioOrCheckbox from "@/components/shared/RadioOrCheckbox.vue";
  222. import { i18n } from "@/lang"
  223. export default {
  224. props: {
  225. title: {
  226. default: '',
  227. type: String
  228. },
  229. primaryKey: {
  230. default: 'id'
  231. },
  232. selectableType: {
  233. type: Array,
  234. default: function () {
  235. return [
  236. 'pano',
  237. '3D',
  238. ]
  239. },
  240. },
  241. initialMaterialType: {
  242. type: String,
  243. default: 'image',
  244. },
  245. isMultiSelection: {
  246. type: Boolean,
  247. default: false,
  248. },
  249. workId: {
  250. type: String,
  251. default: '',
  252. },
  253. },
  254. components: {
  255. FileInput,
  256. RadioOrCheckbox,
  257. },
  258. watch: {
  259. searchKey: {
  260. handler: function () {
  261. this.refreshMaterialList(this.currentMaterialType)
  262. },
  263. immediate: false,
  264. },
  265. currentMaterialType: {
  266. handler: function (newVal) {
  267. if (newVal === 'pano' && this.panoList.length === 0) {
  268. this.refreshMaterialList('pano')
  269. } else if (newVal === '3D' && this.scene3DList.length === 0) {
  270. this.refreshMaterialList('3D')
  271. }
  272. },
  273. immediate: false,
  274. },
  275. needLongPolling: {
  276. handler: function (newVal) {
  277. if (!newVal) {
  278. clearInterval(this.longPollingIntervalId)
  279. this.longPollingIntervalId = null
  280. } else {
  281. clearInterval(this.longPollingIntervalId)
  282. this.longPollingIntervalId = null
  283. this.longPollingIntervalId = setInterval(() => {
  284. this._checkMStatus();
  285. }, 3000);
  286. }
  287. },
  288. immediate: true,
  289. },
  290. },
  291. computed: {
  292. ...mapState({
  293. uploadStatusListAudio: 'uploadStatusListAudio',
  294. uploadStatusListImage: 'uploadStatusListImage',
  295. uploadStatusListPano: 'uploadStatusListPano',
  296. uploadStatusListVideo: 'uploadStatusListVideo',
  297. }),
  298. tableHeadersForPano() {
  299. return this.$MAPTABLEHEADER['pano'].filter(item => {
  300. return ['icon', 'name', 'fileSize'].includes(item.key)
  301. })
  302. },
  303. tableHeadersFor3D() {
  304. return this.$MAPTABLEHEADER['scene'].filter(item => {
  305. return ['thumb', 'sceneName', 'createTime'].includes(item.key)
  306. })
  307. },
  308. fileInputFailString() {
  309. let ret = ''
  310. switch (this.currentMaterialType) {
  311. case 'pano':
  312. ret = this.$i18n.t(`gather.pano_fail`)
  313. break;
  314. default:
  315. break;
  316. }
  317. return ret
  318. },
  319. fileInputLimitFailStr() {
  320. let ret = ''
  321. switch (this.currentMaterialType) {
  322. case 'pano':
  323. ret = this.$i18n.t(`gather.pano_limit`)
  324. break;
  325. default:
  326. break;
  327. }
  328. return ret
  329. },
  330. fileInputAcceptType() {
  331. let ret = ''
  332. switch (this.currentMaterialType) {
  333. case 'pano':
  334. ret = 'image/jpeg'
  335. break;
  336. default:
  337. break;
  338. }
  339. return ret
  340. },
  341. fileInputMediaType() {
  342. let ret = ''
  343. switch (this.currentMaterialType) {
  344. case 'pano':
  345. ret = 'image'
  346. break;
  347. default:
  348. break;
  349. }
  350. return ret
  351. },
  352. fileInputLimit() {
  353. let ret
  354. switch (this.currentMaterialType) {
  355. case 'pano':
  356. ret = 120
  357. break;
  358. default:
  359. break;
  360. }
  361. return ret
  362. },
  363. panoListRealLength() {
  364. return this.panoList.length + this.uploadStatusListPano.filter((item) => {
  365. return item.status === 'SUCCESS'
  366. }).length
  367. },
  368. panoListLocalLength() {
  369. return this.panoList.length + this.uploadStatusListPano.length
  370. },
  371. needLongPolling() {
  372. return this.uploadStatusListPano.some((item) => {
  373. return item.status === 'LOADING' && item.ifKnowProgress === false
  374. })
  375. },
  376. },
  377. data() {
  378. return {
  379. no_serch_result: i18n.t("gather.no_serch_result"),
  380. no_material_result: i18n.t("gather.no_material_result"),
  381. panorama: i18n.t("gather.panorama"),
  382. scene: i18n.t("gather.scene"),
  383. keywords: i18n.t("gather.keywords"),
  384. how_to_shoot: i18n.t("gather.how_to_shoot"),
  385. upload_material: i18n.t("gather.upload_material"),
  386. pano_size: i18n.t("gather.pano_size"),
  387. cancel: i18n.t("gather.cancel"),
  388. comfirm: i18n.t("gather.comfirm"),
  389. panoList: [],
  390. scene3DList: [],
  391. select: [],
  392. searchKey: '', // 搜索关键词
  393. latestUsedSearchKey: '',
  394. currentMaterialType: this.initialMaterialType,
  395. isRequestingMorePanoData: false,
  396. isRequestingMore3DData: false,
  397. hasMorePanoData: true,
  398. hasMore3DData: true,
  399. longPollingIntervalId: null,
  400. }
  401. },
  402. methods: {
  403. ...mapMutations([
  404. 'clearUploadStatusLists',
  405. ]),
  406. selectItem(item, v) {
  407. item.materialType = this.currentMaterialType // 三维场景数据没有type字段来表明自己是三维场景。所以统一加一个字段。
  408. if (this.isMultiSelection) {
  409. if (v) {
  410. this.select.push(item)
  411. } else {
  412. const toDeleteIdx = this.select.findIndex((eachSelect) => {
  413. return eachSelect.id === item.id
  414. })
  415. if (toDeleteIdx >= 0) {
  416. this.select.splice(toDeleteIdx, 1)
  417. }
  418. }
  419. } else {
  420. if (v) {
  421. this.select = [item]
  422. } else {
  423. this.select = []
  424. }
  425. }
  426. },
  427. requestMorePanoData() {
  428. this.isRequestingMorePanoData = true
  429. const latestUsedSearchKey = this.searchKey
  430. getMaterialList(
  431. {
  432. pageNum: Math.floor(this.panoListRealLength / config.PAGE_SIZE) + 1,
  433. pageSize: config.PAGE_SIZE,
  434. searchKey: this.searchKey,
  435. type: 'pano',
  436. },
  437. (data) => {
  438. const newData = data.data.list.map((i) => {
  439. i.fileSize = changeByteUnit(Number(i.fileSize));
  440. i.createTime = i.createTime.substring(0, i.createTime.length - 3)
  441. i.updateTime = i.updateTime.substring(0, i.updateTime.length - 3)
  442. return i;
  443. });
  444. this.panoList = this.panoList.concat(newData)
  445. if (this.panoListRealLength === data.data.total) {
  446. this.hasMorePanoData = false
  447. }
  448. this.isRequestingMorePanoData = false
  449. this.latestUsedSearchKey = latestUsedSearchKey
  450. },
  451. () => {
  452. this.isRequestingMorePanoData = false
  453. this.latestUsedSearchKey = latestUsedSearchKey
  454. }
  455. );
  456. },
  457. requestMore3DData() {
  458. this.isRequestingMore3DData = true
  459. const latestUsedSearchKey = this.searchKey
  460. getSceneList(
  461. {
  462. pageNum: Math.floor(this.scene3DList.length / config.PAGE_SIZE) + 1,
  463. pageSize: config.PAGE_SIZE,
  464. searchKey: this.searchKey,
  465. workId: this.workId,
  466. },
  467. (data) => {
  468. const newData = data.data.data.list.map((i) => {
  469. return i;
  470. });
  471. this.scene3DList = this.scene3DList.concat(newData)
  472. if (this.scene3DList.length === data.data.data.total) {
  473. this.hasMore3DData = false
  474. }
  475. this.isRequestingMore3DData = false
  476. this.latestUsedSearchKey = latestUsedSearchKey
  477. },
  478. () => {
  479. this.isRequestingMore3DData = false
  480. this.latestUsedSearchKey = latestUsedSearchKey
  481. }
  482. )
  483. },
  484. refreshMaterialList: debounce(function (type) {
  485. if (type === 'pano') {
  486. this.isRequestingMorePanoData = false
  487. this.hasMorePanoData = true
  488. this.panoList = []
  489. let filterResult = this.uploadStatusListPano.filter((item) => {
  490. return item.status === 'LOADING'
  491. })
  492. this.$store.commit('setUploadStatusListPano', filterResult)
  493. this.requestMorePanoData()
  494. } else if (type === '3D') {
  495. this.isRequestingMore3DData = false
  496. this.hasMore3DData = true
  497. this.scene3DList = []
  498. this.requestMore3DData()
  499. }
  500. }, 500, false),
  501. onFileInputChange(e) {
  502. switch (this.currentMaterialType) {
  503. case 'pano':
  504. this.onPanoFileInputChange(e)
  505. break;
  506. default:
  507. break;
  508. }
  509. },
  510. onPanoFileInputChange(e) {
  511. e.files.forEach(async (eachFile, i) => {
  512. if (
  513. eachFile.type.indexOf("jpeg") <= -1
  514. ) {
  515. console.log('格式不对!');
  516. setTimeout(() => {
  517. this.$msg({
  518. message: `“${eachFile.name}”${this.$i18n.t(`gather.pano_fail`)}`,
  519. type: "warning",
  520. });
  521. }, i * 100);
  522. return;
  523. }
  524. if (eachFile.name.substring(0, eachFile.name.lastIndexOf(".")).length > 50) {
  525. setTimeout(() => {
  526. this.$msg({
  527. message: `“${eachFile.name}”${this.$i18n.t(`gather.too_long_word`)}`,
  528. type: "warning",
  529. });
  530. }, i * 100);
  531. return;
  532. }
  533. let WHRate = null
  534. try {
  535. const { width, height } = await getImgWH(eachFile)
  536. WHRate = width / height
  537. } catch (e) {
  538. console.error('获取图像宽高失败:', e)
  539. setTimeout(() => {
  540. this.$msg({
  541. message: `“${eachFile.name}”${this.$i18n.t(`gather.pano_fail`)}`,
  542. type: "warning",
  543. });
  544. }, i * 100);
  545. return
  546. }
  547. if (WHRate !== 2) {
  548. setTimeout(() => {
  549. this.$msg({
  550. message: `“${eachFile.name}”${this.$i18n.t(`gather.pano_fail`)}`,
  551. type: "warning",
  552. });
  553. }, i * 100);
  554. return
  555. }
  556. let itemInUploadList = {
  557. title: eachFile.name,
  558. ifKnowProgress: true,
  559. progress: 0,
  560. status: 'LOADING',
  561. statusText: this.$i18n.t(`gather.uploading_material`),
  562. uid: `u_${this.$randomWord(true, 8, 8)}`,
  563. abortHandler: null,
  564. backendId: '',
  565. };
  566. itemInUploadList.abortHandler = uploadMaterial(
  567. {
  568. file: eachFile
  569. },
  570. {
  571. type: 'pano',
  572. uid: itemInUploadList.uid,
  573. },
  574. (response) => { // 上传成功
  575. itemInUploadList.statusText = this.$i18n.t(`gather.cutting`)
  576. itemInUploadList.ifKnowProgress = false
  577. itemInUploadList.backendId = response.data.id
  578. },
  579. (err) => {
  580. if (err.statusText === 'abort') { // 用户取消了上传任务。
  581. console.log('用户取消了任务!');
  582. const index = this.uploadStatusListPano.findIndex((eachItem) => {
  583. return eachItem.uid === itemInUploadList.uid
  584. })
  585. this.uploadStatusListPano.splice(index, 1)
  586. } else {
  587. console.log('失败!');
  588. itemInUploadList.status = 'FAIL'
  589. itemInUploadList.statusText = this.$i18n.t(`gather.material_upload_fail`)
  590. }
  591. },
  592. (progress) => {
  593. console.log('进度:', progress);
  594. itemInUploadList.progress = progress
  595. }
  596. )
  597. this.uploadStatusListPano.unshift(itemInUploadList);
  598. })
  599. },
  600. _checkMStatus() {
  601. let needPollingTaskList = this.uploadStatusListPano.filter((item) => item.status === 'LOADING' && item.ifKnowProgress === false);
  602. if (needPollingTaskList.length > 0) {
  603. checkMStatus(
  604. {
  605. ids: needPollingTaskList.map((item) => item.backendId),
  606. islongpolling: true,
  607. },
  608. (res) => {
  609. // 1切图中,2失败,3成功
  610. res.data.forEach(eachRes => {
  611. if (eachRes.status === 2) {
  612. const index = this.uploadStatusListPano.findIndex(eachTask => eachTask.backendId === eachRes.id)
  613. if (index >= 0) {
  614. const targetItem = this.uploadStatusListPano[index]
  615. targetItem.status = 'FAIL'
  616. targetItem.statusText = this.$i18n.t(`gather.material_cutting_fail`)
  617. targetItem.ifKnowProgress = true
  618. }
  619. } else if (eachRes.status === 3) {
  620. const index = this.uploadStatusListPano.findIndex(eachTask => eachTask.backendId === eachRes.id)
  621. if (index >= 0) {
  622. const targetItem = this.uploadStatusListPano[index]
  623. targetItem.status = 'SUCCESS'
  624. eachRes.fileSize = changeByteUnit(Number(eachRes.fileSize));
  625. targetItem.successInfo = eachRes
  626. }
  627. }
  628. });
  629. }
  630. );
  631. }
  632. },
  633. onClickRow(e) {
  634. const checkboxNodeList = e.currentTarget.getElementsByClassName('selection-click-target')
  635. if (checkboxNodeList && checkboxNodeList[0]) {
  636. checkboxNodeList[0].click()
  637. }
  638. },
  639. onClickUpload() {
  640. checkUserSize({}, (data) => {
  641. //判断已用是否大于3G
  642. if ((data.data / 1024 / 1024) > 3) {
  643. this.$alert({ content: this.$i18n.t('tips_code.FAILURE_3024')});
  644. } else {
  645. this.$refs['file-input'].click()
  646. }
  647. })
  648. },
  649. onClickComfirm: debounce(function () {
  650. this.$emit('submit', this.select)
  651. }, 250),
  652. },
  653. mounted() {
  654. this.clearUploadStatusLists()
  655. },
  656. beforeDestroy() {
  657. this.$store.commit('setUploadStatusListPano', this.uploadStatusListPano.filter((item) => {
  658. return item.status === 'LOADING'
  659. }))
  660. }
  661. }
  662. </script>
  663. <style lang="less" scoped>
  664. .ellipsis {
  665. text-overflow: ellipsis;
  666. overflow: hidden;
  667. white-space: nowrap;
  668. width: 100%;
  669. display: inline-block;
  670. }
  671. .table-select {
  672. position: absolute;
  673. z-index: 3;
  674. left: 50%;
  675. top: 50%;
  676. transform: translateX(-50%) translateY(-50%);
  677. width: 600px;
  678. height: 730px;
  679. border-radius: 4px;
  680. border: 1px solid #EBEDF0;
  681. padding: 26px;
  682. background: #fff;
  683. }
  684. .title {
  685. font-size: 18px;
  686. color: #323233;
  687. }
  688. .close-btn {
  689. display: inline-block;
  690. position: absolute;
  691. top: 26px;
  692. right: 20px;
  693. font-size: 12px;
  694. color: #969799;
  695. cursor: pointer;
  696. padding: 6px;
  697. }
  698. .material-tab {
  699. margin-top: 35px;
  700. >.material-tab-item {
  701. display: inline-block;
  702. margin-right: 20px;
  703. position: relative;
  704. cursor: pointer;
  705. >.text {
  706. font-size: 14px;
  707. font-family: MicrosoftYaHei;
  708. color: #969799;
  709. &.active {
  710. color: #323233;
  711. }
  712. }
  713. >.bottom-line {
  714. position: absolute;
  715. left: 50%;
  716. transform: translateX(-50%);
  717. bottom: -4px;
  718. width: 16px;
  719. height: 2px;
  720. background: #0076F6;
  721. border-radius: 1px;
  722. }
  723. }
  724. }
  725. .filter {
  726. margin-top: 28px;
  727. width: 100%;
  728. height: 36px;
  729. background: #F7F8FA;
  730. border-radius: 2px;
  731. border: 1px solid #EBEDF0;
  732. position: relative;
  733. >input {
  734. box-sizing: border-box;
  735. width: calc(100% - 42px);
  736. height: 100%;
  737. border: none;
  738. padding-left: 16px;
  739. background: transparent;
  740. color: #323233;
  741. outline: none;
  742. }
  743. >.search-icon {
  744. position: absolute;
  745. top: 50%;
  746. transform: translateY(-50%);
  747. right: 18px;
  748. color: #C8C9CC;
  749. font-size: 20px;
  750. }
  751. >.clear-icon {
  752. position: absolute;
  753. top: 50%;
  754. transform: translateY(-50%);
  755. right: 18px;
  756. color: #C8C9CC;
  757. font-size: 20px;
  758. cursor: pointer;
  759. }
  760. }
  761. @table-height: 440px;
  762. @table-head-row-height: 40px;
  763. @table-border-size: 1px;
  764. .table {
  765. margin-top: 20px;
  766. border: @table-border-size solid #EBEDF0;
  767. background: #ffffff;
  768. width: 100%;
  769. height: @table-height;
  770. >.table-head-row {
  771. width: 100%;
  772. height: @table-head-row-height;
  773. background: #F5F7FA;
  774. color: #646566;
  775. .table-head {
  776. font-size: 16px;
  777. line-height: @table-head-row-height;
  778. height: 100%;
  779. display: inline-block;
  780. }
  781. }
  782. >.table-body {
  783. height: calc(@table-height - @table-head-row-height - @table-border-size - @table-border-size);
  784. overflow: auto;
  785. display: inline-block;
  786. width: 100%;
  787. >.table-body-row {
  788. height: 50px;
  789. border-bottom: 1px solid #EBEDF0;
  790. display: flex;
  791. align-items: center;
  792. cursor: pointer;
  793. >.table-data {
  794. font-size: 14px;
  795. line-height: 50px;
  796. height: 100%;
  797. color: #323233;
  798. >.list-img {
  799. position: relative;
  800. height: 100%;
  801. display: inline-block;
  802. width: 100%;
  803. >img,
  804. .audio-player {
  805. position: absolute;
  806. top: 50%;
  807. transform: translateY(-50%);
  808. width: 40px;
  809. height: 40px;
  810. object-fit: cover;
  811. }
  812. }
  813. }
  814. }
  815. }
  816. >.no-data {
  817. height: calc(@table-height - @table-head-row-height - @table-border-size - @table-border-size);
  818. width: 100%;
  819. position: relative;
  820. >div {
  821. position: absolute;
  822. top: 50%;
  823. left: 50%;
  824. transform: translate(-50%, -50%);
  825. text-align: center;
  826. >img {
  827. width: 116px;
  828. }
  829. >span {
  830. margin-top: 20px;
  831. display: block;
  832. font-size: 14px;
  833. color: rgba(255, 255, 255, 0.6);
  834. }
  835. >a {
  836. >button {
  837. margin-top: 20px;
  838. }
  839. }
  840. }
  841. }
  842. }
  843. .table-pano .table-head,
  844. .table-pano .table-data {
  845. &:nth-of-type(1) {
  846. width: 50px;
  847. color: transparent;
  848. }
  849. &:nth-of-type(2) {
  850. width: calc(146px - 50px);
  851. }
  852. &:nth-of-type(3) {
  853. width: calc(380px - 146px);
  854. padding-right: 30px;
  855. }
  856. &:nth-of-type(4) {
  857. width: calc(100% - 380px);
  858. }
  859. }
  860. .table-3D .table-head,
  861. .table-3D .table-data {
  862. &:nth-of-type(1) {
  863. width: 50px;
  864. color: transparent;
  865. }
  866. &:nth-of-type(2) {
  867. width: calc(146px - 50px);
  868. }
  869. &:nth-of-type(3) {
  870. width: calc(380px - 146px);
  871. padding-right: 30px;
  872. }
  873. &:nth-of-type(4) {
  874. width: calc(100% - 380px);
  875. }
  876. }
  877. .checkbox {
  878. width: 100%;
  879. height: 100%;
  880. }
  881. .btns {
  882. display: flex;
  883. justify-content: space-between;
  884. margin-top: 40px;
  885. .upload-btn {
  886. display: flex;
  887. align-items: center;
  888. >span {
  889. display: inline-block;
  890. margin-right: 4px;
  891. }
  892. i.tool-tip-for-editor {
  893. font-size: 12px;
  894. transform: scale(0.923) translateY(1px);
  895. cursor: default;
  896. }
  897. }
  898. >div {
  899. .cancel {
  900. margin-right: 16px;
  901. }
  902. }
  903. }
  904. </style>