materialListInMaterialSelector.vue 28 KB

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