com-attachment.php 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. <style scoped>
  2. .com-attachment-list {
  3. padding: 5px;
  4. width: 960px;
  5. }
  6. .com-attachment-list * {
  7. box-sizing: border-box;
  8. }
  9. .com-attachment-list:after {
  10. clear: both;
  11. display: block;
  12. content: " ";
  13. }
  14. .com-attachment-item {
  15. display: inline-block;
  16. /*box-shadow: 0 0 0 1px rgba(0, 0, 0, .15);*/
  17. cursor: pointer;
  18. position: relative;
  19. float: left;
  20. width: 120px;
  21. height: 140px;
  22. margin: 7.5px;
  23. text-align: center;
  24. padding: 10px 10px 0;
  25. }
  26. .com-attachment-active-icon {
  27. position: absolute;
  28. right: 5px;
  29. top: 5px;
  30. font-size: 28px;
  31. color: #409EFF;
  32. text-shadow: 0 0 1px rgba(255, 255, 255, 0.75);
  33. opacity: 0;
  34. }
  35. .com-attachment-item:hover {
  36. /*del-box-shadow: 0 0 0 1px rgba(84, 200, 255, 0.41);*/
  37. }
  38. .com-attachment-item.checked,
  39. .com-attachment-item.selected {
  40. box-shadow: 0 0 0 1px #1ed0ff;
  41. background: #daf5ff;
  42. border-radius: 5px;
  43. }
  44. .com-attachment-item.checked .com-attachment-active-icon,
  45. .com-attachment-item.selected .com-attachment-active-icon {
  46. opacity: 1;
  47. }
  48. .com-attachment-item .com-attachment-img {
  49. display: block;
  50. }
  51. .com-attachment-item .file-type-icon {
  52. width: 30px;
  53. height: 30px;
  54. border-radius: 30px;
  55. background: #666;
  56. color: #fff;
  57. text-align: center;
  58. line-height: 30px;
  59. font-size: 24px;
  60. }
  61. .com-attachment-upload {
  62. box-shadow: none;
  63. border: 1px dashed #b2b6bd;
  64. height: 100px;
  65. width: 100px;
  66. margin: 17.5px;
  67. padding: 0;
  68. }
  69. .com-attachment-upload i {
  70. font-size: 30px;
  71. color: #909399;
  72. }
  73. .com-attachment-upload:hover {
  74. box-shadow: none;
  75. border: 1px dashed #409EFF;
  76. }
  77. .com-attachment-upload:hover i {
  78. color: #409EFF;
  79. }
  80. .com-attachment-upload:active {
  81. border: 1px dashed #20669c;
  82. }
  83. .com-attachment-upload:active i {
  84. color: #20669c;
  85. }
  86. .com-attachment-dialog .group-menu {
  87. border-right: none;
  88. width: 230px;
  89. }
  90. .com-attachment-dialog .group-menu .el-menu-item {
  91. padding-left: 10px !important;
  92. padding-right: 10px;
  93. }
  94. .com-attachment-dialog .group-menu .el-menu-item .el-button {
  95. padding: 3px 0;
  96. }
  97. .del-com-attachment-dialog .group-menu .el-menu-item .el-button:hover {
  98. background: #e2e2e2;
  99. }
  100. .com-attachment-dialog .group-menu .el-menu-item .el-button i {
  101. margin-right: 0;
  102. }
  103. .com-attachment-simple-upload {
  104. width: 100% !important;
  105. height: 120px;
  106. border: 1px dashed #e3e3e3;
  107. cursor: pointer;
  108. }
  109. .com-attachment-simple-upload:hover {
  110. background: rgba(0, 0, 0, .05);
  111. }
  112. .com-attachment-simple-upload i {
  113. font-size: 32px;
  114. }
  115. .com-attachment-video-cover {
  116. background-size: cover;
  117. background-position: center;
  118. width: 100%;
  119. height: 100%;
  120. }
  121. .com-attachment-video-info {
  122. background: rgba(0, 0, 0, .35);
  123. color: #fff;
  124. position: absolute;
  125. left: 0;
  126. bottom: 0;
  127. padding: 1px 3px;
  128. font-size: 14px;
  129. }
  130. .com-attachment-video-name {
  131. position: absolute;
  132. top: 100%;
  133. left: 0;
  134. width: 100%;
  135. font-size: 12px;
  136. white-space: nowrap;
  137. overflow: hidden;
  138. text-overflow: ellipsis;
  139. }
  140. .com-attachment-dialog .com-attachment-name {
  141. color: #666666;
  142. margin-top: 5px;
  143. font-size: 13px;
  144. word-break: break-all;
  145. text-overflow: ellipsis;
  146. display: -webkit-box;
  147. -webkit-box-orient: vertical;
  148. -webkit-line-clamp: 1;
  149. overflow: hidden;
  150. }
  151. .com-attachment-dialog .search {
  152. margin-top: 10px;
  153. margin-left: 20px;
  154. width: 250px;
  155. }
  156. .com-attachment-dialog .search .el-input__inner {
  157. border-right: 0;
  158. }
  159. .com-attachment-dialog .search .el-input__inner:hover {
  160. border: 1px solid #dcdfe6;
  161. border-right: 0;
  162. outline: 0;
  163. }
  164. .com-attachment-dialog .search .el-input__inner:focus {
  165. border: 1px solid #dcdfe6;
  166. border-right: 0;
  167. outline: 0;
  168. }
  169. .com-attachment-dialog .search .el-input-group__append {
  170. background-color: #fff;
  171. border-left: 0;
  172. width: 10%;
  173. padding: 0;
  174. }
  175. .com-attachment-dialog .search .el-input-group__append {
  176. background-color: #fff;
  177. border-left: 0;
  178. width: 10%;
  179. padding: 0;
  180. }
  181. .com-attachment-dialog .search .el-input-group__append .el-button {
  182. padding: 0;
  183. }
  184. .com-attachment-dialog .search .el-input-group__append .el-button {
  185. margin: 0;
  186. }
  187. .com-attachment-dialog .scrollbar {
  188. height: 100%;
  189. }
  190. .com-attachment-dialog .scrollbar .el-scrollbar__wrap {
  191. overflow-y: hidden;
  192. }
  193. .features_tree{
  194. display: flex;
  195. justify-content: center;
  196. }
  197. .features_tree button{
  198. flex: 1;
  199. }
  200. .el-tree-node{
  201. margin-top: 10px;
  202. }
  203. </style>
  204. <template id="com-attachment">
  205. <div class="com-attachment">
  206. <el-dialog class="com-attachment-dialog"
  207. :title="title ? title : '选择文件'"
  208. :visible.sync="dialogVisible"
  209. @opened="dialogOpened"
  210. :close-on-click-modal="false"
  211. :width="simple?'25%':'65%'"
  212. top="10vh"
  213. append-to-body>
  214. <template v-if="simple">
  215. <com-upload
  216. class="com-attachment-simple-upload"
  217. v-loading="uploading"
  218. :disabled="uploading"
  219. @start="handleStart"
  220. @success="handleSuccess"
  221. @complete="handleComplete"
  222. :multiple="true"
  223. :max="10"
  224. :params="uploadParams"
  225. :fields="uploadFields"
  226. :accept="accept"
  227. flex="main:center cross:center">
  228. <div v-if="uploading">{{uploadCompleteFilesNum}}/{{uploadFilesNum}}</div>
  229. <i v-else class="el-icon-upload"></i>
  230. </com-upload>
  231. </template>
  232. <template v-else>
  233. <div style="height: 0;overflow: hidden;">
  234. <canvas id="com-attachment-canvas" style="border: 1px solid #ccc;visibility: hidden;"></canvas>
  235. </div>
  236. <div flex="cross:center box:last" style="margin-bottom: 12px;">
  237. <div></div>
  238. <div flex="cross:center">
  239. <el-button v-if="!showEditBlock" @click="showEditBlock=true">开启编辑</el-button>
  240. <template v-if="showEditBlock">
  241. <el-button @click="showEditBlock=false" style="margin-right: 12px">退出编辑模式</el-button>
  242. <el-checkbox border v-model="selectAll"
  243. @change="selectAllChange"
  244. label="全选"
  245. style="margin-right: 12px;margin-bottom: 0"></el-checkbox>
  246. <el-button :loading="deleteLoading"
  247. @click="deleteItems"
  248. type="danger" plain
  249. style="margin-right: 12px">删除
  250. </el-button>
  251. <el-dropdown v-loading="moveLoading"
  252. trigger="click"
  253. :split-button="true"
  254. @command="moveItems">
  255. <span>移动至</span>
  256. <el-dropdown-menu slot="dropdown">
  257. <el-dropdown-item v-for="(item, index) in groupList"
  258. :command="index"
  259. :key="index">
  260. {{item.name}}
  261. </el-dropdown-item>
  262. </el-dropdown-menu>
  263. </el-dropdown>
  264. </template>
  265. </div>
  266. </div>
  267. <div flex="box:first" style="border: 1px solid #e3e3e3;margin-bottom: 10px;min-height: 300px">
  268. <div style="border-right: 1px solid #e3e3e3">
  269. <el-menu class="group-menu"
  270. mode="vertical"
  271. v-loading="groupListLoading">
  272. <el-scrollbar style="height:450px;width:100%">
  273. <el-menu-item index="all" @click="switchGroup(-1)">
  274. <i class="el-icon-tickets"></i>
  275. <span>全部</span>
  276. </el-menu-item>
  277. <div class="features_tree">
  278. <!-- @click="addNode" -->
  279. <el-button type="text" v-if="!is_recycle" @click="addNode"><i class="el-icon-circle-plus"></i>添加</el-button>
  280. <el-button type="text" v-if="!is_recycle" @click="editNode"><i class="el-icon-edit"></i>编辑</el-button>
  281. <el-button type="text" v-if="is_recycle" @click="deleteGroups(is_recycle,2)"><i class="el-icon-refresh"></i>还原</el-button>
  282. <el-button type="text" @click="deleteGroups(is_recycle,is_recycle?3:1)"><i class="el-icon-delete"></i>删除</el-button>
  283. </div>
  284. <el-tree
  285. :data="data2"
  286. highlight-current
  287. @node-click="handleNodeClick"
  288. :props="defaultProps"
  289. >
  290. <span slot-scope="{ node, data }">
  291. <i class="el-icon-tickets"></i>
  292. <span>{{ node.label }}</span>
  293. </span>
  294. </el-tree>
  295. </el-scrollbar>
  296. </el-menu>
  297. </div>
  298. <div v-loading="loading" flex="dir:top">
  299. <el-scrollbar class="scrollbar">
  300. <div class="search" style="margin-right: 12px">
  301. <el-input placeholder="请输入名称搜索" v-model="p_keyword"
  302. @keyup.enter.native="picSearch"
  303. class="input-with-select">
  304. <el-button @click="picSearch" slot="append" icon="el-icon-search"></el-button>
  305. </el-input>
  306. </div>
  307. <div class="com-attachment-list">
  308. <div class="com-attachment-item com-attachment-upload">
  309. <com-upload
  310. v-loading="uploading"
  311. :disabled="uploading"
  312. @start="handleStart"
  313. @success="handleSuccess"
  314. @complete="handleComplete"
  315. :multiple="true"
  316. :max="10"
  317. :params="uploadParams"
  318. :fields="uploadFields"
  319. :accept="accept"
  320. flex="main:center cross:center"
  321. style="width: 100px;height: 100px">
  322. <div v-if="uploading">{{uploadCompleteFilesNum}}/{{uploadFilesNum}}</div>
  323. <i v-else class="el-icon-upload"></i>
  324. </com-upload>
  325. </div>
  326. <template v-for="(item, index) in attachments">
  327. <el-tooltip class="item" effect="dark" :content="String(item.name)" placement="top"
  328. :open-delay="1">
  329. <div
  330. :key="index"
  331. :class="'com-attachment-item'+((item.checked&&!showEditBlock)?' checked':'')+(item.selected&&showEditBlock?' selected':'')"
  332. @click="handleClick(item)">
  333. <!-- 图片 -->
  334. <img v-if="item.upload_type == 'images'" class="com-attachment-img"
  335. :src="item.url"
  336. style="width: 100px;height: 100px;">
  337. <!-- 视频 -->
  338. <div v-if="item.upload_type == 'videos'" class="com-attachment-img"
  339. style="width: 100px;height: 100px;position: relative">
  340. <div v-if="item.cover_pic_src"
  341. class="com-attachment-video-cover"
  342. :style="'background-image: url('+item.cover_pic_src+');'"></div>
  343. <video style="width: 60px;height: 100px;" error="预览图加载失败"
  344. :id="'app_attachment_'+ _uid + '_' + index"
  345. :src="item.url">
  346. </video><!-- width="60" height="100%" -->
  347. <div class="com-attachment-video-info" style="margin-left: 24px;">
  348. <i class="el-icon-video-play"></i>
  349. <span>{{item.duration?item.duration:'--:--'}}</span>
  350. </div>
  351. </div>
  352. <!-- 音频 -->
  353. <div v-if="item.upload_type == 'voices'" class="com-attachment-img"
  354. style="width: 100px;height: 100px;position: relative">
  355. <!-- <div v-if="item.cover_pic_src"
  356. class="com-attachment-video-cover"
  357. :style="'background-image: url('+item.cover_pic_src+');'">
  358. </div> -->
  359. <span>{{item.name}}</span>
  360. </div>
  361. <!-- 文件 -->
  362. <div v-if="item.upload_type == 'files'" class="com-attachment-img"
  363. style="width: 100px;height: 100px;line-height: 100px;text-align: center">
  364. <i class="file-type-icon el-icon-document"></i>
  365. </div>
  366. <div v-if="item.upload_type != 'voices'" class="com-attachment-name">{{item.name}}</div>
  367. <i v-if="false" class="com-attachment-active-icon el-icon-circle-check"></i>
  368. </div>
  369. </el-tooltip>
  370. </template>
  371. </div>
  372. </el-scrollbar>
  373. <div style="padding: 5px;text-align: right;margin-top:auto">
  374. <el-pagination
  375. v-if="pagination"
  376. background
  377. @size-change="handleLoadMore"
  378. @current-change="handleLoadMore"
  379. :current-page.sync="page"
  380. :page-size="pagination.pageSize"
  381. layout="prev, pager, next, jumper"
  382. :total="pagination.total_count">
  383. </el-pagination>
  384. </div>
  385. </div>
  386. </div>
  387. <div style="text-align: right">
  388. <span v-if="showEditBlock" style="color: #909399">请先退出编辑模式</span>
  389. <el-button @click="confirm" type="primary" :disabled="showEditBlock">选定</el-button>
  390. </div>
  391. </template>
  392. </el-dialog>
  393. <el-dialog append-to-body title="分组管理" :visible.sync="addGroupVisible" :close-on-click-modal="false"
  394. width="25%">
  395. <el-form @submit.native.prevent label-width="80px" ref="groupForm" :model="groupForm"
  396. :rules="groupFormRule">
  397. <el-form-item label="分组名称" prop="name" style="margin-bottom: 22px;">
  398. <el-input v-model="groupForm.name" maxlength="8" show-word-limit></el-input>
  399. </el-form-item>
  400. <el-form-item style="text-align: right">
  401. <el-button type="primary" @click="groupFormSubmit('groupForm')" :loading="groupFormLoading">保存
  402. </el-button>
  403. </el-form-item>
  404. </el-form>
  405. </el-dialog>
  406. <el-dialog append-to-body title="添加目录" :visible.sync="dialogFormVisible" :close-on-click-modal="false">
  407. <el-form :model="form_dir" :rules="form_dir_rule">
  408. <el-form-item label="父级目录" :label-width="formLabelWidth">
  409. <el-cascader
  410. expand-trigger="hover"
  411. :options="data2"
  412. v-model="selectedOptions2"
  413. :props="{ checkStrictly: true, value: 'id' }"
  414. clearable
  415. @change="handleChange">
  416. </el-cascader>
  417. </el-form-item>
  418. <el-form-item label="目录名称" :label-width="formLabelWidth">
  419. <el-input v-model="form_dir.name" auto-complete="off"></el-input>
  420. </el-form-item>
  421. </el-form>
  422. <div slot="footer" class="dialog-footer">
  423. <el-button @click="dialogFormVisible = false">取 消</el-button>
  424. <el-button type="primary" @click="postNode('add')">确 定</el-button>
  425. </div>
  426. </el-dialog>
  427. <el-dialog append-to-body title="编辑目录" :visible.sync="dialogFormVisibleEdit" :close-on-click-modal="false">
  428. <el-form :model="form_dir_s" :rules="form_dir_rules">
  429. <el-form-item label="父级目录" :label-width="formLabelWidth">
  430. <el-cascader
  431. expand-trigger="hover"
  432. :options="getOptions()"
  433. v-model="selectedOptions3"
  434. :props="{ checkStrictly: true, value: 'id' }"
  435. clearable
  436. @change="handleChange2">
  437. </el-cascader>
  438. </el-form-item>
  439. <el-form-item label="目录名称" :label-width="formLabelWidth">
  440. <el-input v-model="form_dir_s.name" auto-complete="off"></el-input>
  441. </el-form-item>
  442. </el-form>
  443. <div slot="footer" class="dialog-footer">
  444. <el-button @click="dialogFormVisibleEdit = false">取 消</el-button>
  445. <el-button type="primary" @click="postNode('edit')">确 定</el-button>
  446. </div>
  447. </el-dialog>
  448. <div style="line-height: normal;" @click="dialogVisible = !dialogVisible"
  449. :style="'display:'+(display?display:'inline-block')">
  450. <slot></slot>
  451. </div>
  452. </div>
  453. </template>
  454. <script>
  455. Vue.component('com-attachment', {
  456. template: '#com-attachment',
  457. props: {
  458. display: String,
  459. title: String,
  460. multiple: Boolean,
  461. max: Number,
  462. params: Object,
  463. simple: {
  464. type: Boolean,
  465. value: false,
  466. },
  467. type: {
  468. type: String,
  469. default: 'images',
  470. },
  471. value: {
  472. type: String,
  473. default: '',
  474. },
  475. openDialog: {
  476. type: Boolean,
  477. default: false,
  478. },
  479. },
  480. computed: {
  481. accept: {
  482. get() {
  483. if (this.type === 'images') {
  484. return 'image/*';
  485. }
  486. if (this.type === 'videos') {
  487. return 'video/*';
  488. }
  489. return '*/*';
  490. },
  491. },
  492. },
  493. watch: {
  494. type(newVal, oldVal) {
  495. this.type = newVal;
  496. this.uploadFields.upload_type = this.type;
  497. },
  498. openDialog(newVal, oldVal) {
  499. this.dialogVisible = newVal;
  500. },
  501. dialogVisible(newVal, oldVal) {
  502. if (!newVal) {
  503. this.$emit("closed");
  504. }
  505. },
  506. keyword(newVal, oldVal) {
  507. const groupList = this.groupList;
  508. let arr = [];
  509. groupList.map(v => {
  510. if (v.label.indexOf(newVal) !== -1) {
  511. arr.push(v);
  512. }
  513. });
  514. this.groupItem = arr;
  515. }
  516. },
  517. data() {
  518. return {
  519. canvas: null,
  520. uploading: false,
  521. dialogVisible: false,
  522. loading: true,
  523. loadingMore: false,
  524. noMore: false,
  525. attachments: [],
  526. checkedAttachments: [],
  527. uploadParams: {},
  528. uploadFields: {
  529. upload_type: this.type
  530. },
  531. uploadCompleteFilesNum: 0,
  532. uploadFilesNum: 0,
  533. page: 0,
  534. addGroupVisible: false,
  535. noMall: true,
  536. groupList: [],
  537. groupItem: [],
  538. groupListLoading: false,
  539. groupForm: {
  540. id: null,
  541. name: '',
  542. },
  543. groupFormRule: {
  544. name: [
  545. {required: true, message: '请填写分组名称。',}
  546. ],
  547. },
  548. groupFormLoading: false,
  549. showEditBlock: false,
  550. selectAll: false,
  551. deleteLoading: false,
  552. moveLoading: false,
  553. currentAttachmentGroupId: null,
  554. currentAttachmentStoreId: null,
  555. video: null,
  556. keyword: '',
  557. pagination: null,
  558. p_keyword: '',
  559. data2: [],
  560. dirTree: [],
  561. defaultProps: {
  562. children: 'children',
  563. label: 'label'
  564. },
  565. dialogFormVisible: false,
  566. dialogFormVisibleEdit: false,
  567. form_dir: {
  568. name: '',
  569. parent_id:'',
  570. },
  571. form_dir_rule: {
  572. name: [
  573. {required: true, message: '请填写名称',}
  574. ],
  575. },
  576. form_dir_s: {
  577. id:'',
  578. parent_id: '',
  579. name: '',
  580. },
  581. form_dir_rules: {
  582. name: [
  583. {required: true, message: '请填写名称',}
  584. ],
  585. },
  586. formLabelWidth: '120px',
  587. selectedOptions: [],
  588. selectedOptions2: [],
  589. select_name:'全部',
  590. is_recycle:0,
  591. pppid: [],
  592. selectedOptions3: [],
  593. };
  594. },
  595. created() {
  596. },
  597. methods: {
  598. getOptions() {
  599. let data = JSON.parse(JSON.stringify(this.data2))
  600. let id = this.form_dir_s.id
  601. let pid = this.form_dir_s.parent_id
  602. let self = this
  603. var dismap = function (v, i) {
  604. if (v.children && v.children.length > 0) {
  605. v.children.map(dismap)
  606. }
  607. if (v.id == id) {
  608. v.disabled = true
  609. }
  610. if (v.id == pid) {
  611. v.disabled = true
  612. }
  613. if (self.isChildrenId(v.id)) {
  614. v.disabled = true
  615. }
  616. return v
  617. }
  618. let mapData = data.map(dismap)
  619. // 过滤系统图标和系统图片
  620. mapData = mapData.filter(item => item.id != 2000000 && item.id != 999990)
  621. return mapData
  622. },
  623. /**
  624. * 作用是不能把当前元素选择到当前元素的子元素下面
  625. */
  626. isChildrenId(cid) {
  627. let id = this.form_dir_s.id
  628. let child = []
  629. let cids = []
  630. var getChildren = function(arr) {
  631. arr.forEach(item => {
  632. if (item.id == id) {
  633. child = item.children
  634. }
  635. if (item.children && item.children.length > 0) {
  636. getChildren(item.children)
  637. }
  638. })
  639. }
  640. var getChildrenId = function(arr) {
  641. arr.forEach(item => {
  642. if (item.id) {
  643. cids.push(item.id)
  644. }
  645. if (item.children && item.children.length > 0) {
  646. getChildrenId(item.children)
  647. }
  648. })
  649. }
  650. getChildren(this.data2)
  651. getChildrenId(child)
  652. return cids.find(function(ccc) {
  653. return ccc == cid
  654. })
  655. },
  656. picSearch() {
  657. this.page = 1;
  658. this.loading = true;
  659. this.loadGroups();
  660. this.loadList({});
  661. },
  662. dialogOpened() {
  663. if (this.simple) {
  664. return;
  665. }
  666. this.page = 1;
  667. this.loading = true;
  668. this.loadGroups();
  669. this.loadList({});
  670. },
  671. deleteItems() {
  672. const itemIds = [];
  673. for (let i in this.attachments) {
  674. if (this.attachments[i].selected) {
  675. itemIds.push(this.attachments[i].id);
  676. }
  677. }
  678. if (!itemIds.length) {
  679. this.$message.warning('请先选择需要删除的图片。');
  680. return;
  681. }
  682. this.$confirm('确认删除所选的' + itemIds.length + '张图片?', '提示', {
  683. type: 'warning'
  684. }).then(() => {
  685. this.deleteLoading = true;
  686. this.$request({
  687. params: {
  688. r: 'happiness/agent/file/delete'
  689. },
  690. method: 'post',
  691. data: {
  692. ids: itemIds,
  693. },
  694. }).then(e => {
  695. this.deleteLoading = false;
  696. if (e.data.code === 0) {
  697. this.$message.success(e.data.msg);
  698. for (let i in itemIds) {
  699. for (let j in this.attachments) {
  700. if (this.attachments[j].id == itemIds[i]) {
  701. this.attachments.splice(j, 1);
  702. break;
  703. }
  704. }
  705. }
  706. } else {
  707. this.$message.error(e.data.msg);
  708. }
  709. }).catch(e => {
  710. this.deleteLoading = false;
  711. });
  712. }).catch(() => {
  713. });
  714. },
  715. selectAllChange(value) {
  716. for (let i in this.attachments) {
  717. this.attachments[i].selected = value;
  718. }
  719. },
  720. selectItem(item) {
  721. item.selected = item.selected ? false : true;
  722. },
  723. moveItems(index) {
  724. const itemIds = [];
  725. for (let i in this.attachments) {
  726. if (this.attachments[i].selected) {
  727. itemIds.push(this.attachments[i].id);
  728. }
  729. }
  730. if (!itemIds.length) {
  731. this.$message.warning('请先选择需要移动的图片。');
  732. return;
  733. }
  734. this.$confirm('确认移动所选的' + itemIds.length + '张图片?', '提示', {
  735. type: 'warning'
  736. }).then(() => {
  737. this.moveLoading = true;
  738. this.$request({
  739. params: {
  740. r: 'happiness/agent/file/move'
  741. },
  742. method: 'post',
  743. data: {
  744. ids: itemIds,
  745. attachment_group_id: this.groupItem[index].id,
  746. },
  747. }).then(e => {
  748. this.moveLoading = false;
  749. if (e.data.code === 0) {
  750. this.$message.success(e.data.msg);
  751. this.switchGroup(index);
  752. } else {
  753. this.$message.error(e.data.msg);
  754. }
  755. }).catch(e => {
  756. this.moveLoading = false;
  757. });
  758. }).catch(() => {
  759. });
  760. },
  761. loadGroups() {
  762. this.groupListLoading = true;
  763. this.$request({
  764. params: {
  765. r: 'happiness/agent/file/group-list',
  766. is_recycle: 0,
  767. type: this.type,
  768. },
  769. }).then(e => {
  770. this.groupListLoading = false;
  771. if (e.data.code === 0) {
  772. this.noMall = e.data.data.no_mall ? e.data.data.no_mall : false;
  773. this.groupItem = e.data.data.list;
  774. this.groupList = e.data.data.list;
  775. this.data2 = e.data.data.arr;
  776. // 添加时隐藏系统图片和系统图标
  777. this.dirTree = JSON.parse(JSON.stringify(this.data2));
  778. this.dirTree = this.dirTree.filter(item => item.id != 2000000 && item.id != 999990)
  779. } else {
  780. this.$message.error(e.data.msg);
  781. }
  782. }).catch(e => {
  783. this.groupListLoading = false;
  784. });
  785. },
  786. groupFormSubmit(formName) {
  787. this.$refs[formName].validate(valid => {
  788. if (valid) {
  789. this.groupFormLoading = true;
  790. this.$request({
  791. params: {
  792. r: 'common/attachment/group-update',
  793. },
  794. method: 'post',
  795. data: Object.assign({}, this.groupForm, {'type': this.type}),
  796. }).then(e => {
  797. this.groupFormLoading = false;
  798. if (e.data.code === 0) {
  799. this.$message.success(e.data.msg);
  800. this.addGroupVisible = false;
  801. if (this.groupForm.edit_index > -1) {
  802. this.groupItem[this.groupForm.edit_index] = e.data.data;
  803. } else {
  804. this.groupItem.push(e.data.data);
  805. }
  806. } else {
  807. this.$message.error(e.data.msg);
  808. }
  809. }).catch(e => {
  810. this.groupFormLoading = false;
  811. });
  812. }
  813. })
  814. },
  815. switchGroup(index) {
  816. this.attachments = [];
  817. this.page = 0;
  818. this.noMore = false;
  819. this.loading = true;
  820. this.uploadParams = {
  821. attachment_group_id: index > -1 ? this.groupItem[index].id : null,
  822. };
  823. this.currentAttachmentGroupId = index > -1 ? this.groupItem[index].id : null;
  824. if (index < 1) {
  825. this.currentAttachmentStoreId = null
  826. }
  827. this.loadList({});
  828. },
  829. loadList(params) {
  830. this.noMore = false;
  831. this.selectAll = false;
  832. params['r'] = 'happiness/agent/file/selector';
  833. params['page'] = this.page;
  834. params['attachment_group_id'] = this.currentAttachmentGroupId;
  835. params['upload_type'] = this.type;
  836. params['is_recycle'] = 0;
  837. params['keyword'] = this.p_keyword;
  838. this.$request({
  839. params: params,
  840. }).then(e => {
  841. if (e.data.code === 0) {
  842. if (!e.data.data.list.length) {
  843. this.noMore = true;
  844. }
  845. for (let i in e.data.data.list) {
  846. e.data.data.list[i].checked = false;
  847. e.data.data.list[i].selected = false;
  848. e.data.data.list[i].duration = null;
  849. }
  850. //this.attachments = this.attachments.concat(e.data.data.list);
  851. this.attachments = e.data.data.list;
  852. this.pagination = e.data.data.pagination;
  853. this.pagination.pageSize = e.data.data.page_size;
  854. this.pagination.total_count = e.data.data.count;
  855. this.checkedAttachments = [];
  856. this.loading = false;
  857. this.loadingMore = false;
  858. this.updateVideo();
  859. } else {
  860. this.$message.error(e.data.msg);
  861. this.dialogVisible = false;
  862. }
  863. }).catch(e => {
  864. });
  865. },
  866. handleClick(item) {
  867. if (this.showEditBlock) {
  868. this.selectItem(item);
  869. return;
  870. }
  871. if (item.checked) {
  872. item.checked = false;
  873. for (let i in this.checkedAttachments) {
  874. if (item.id === this.checkedAttachments[i].id) this.checkedAttachments.splice(i, 1);
  875. }
  876. return;
  877. }
  878. if (this.multiple) {
  879. let checkedCount = 0;
  880. for (let i in this.attachments) if (this.attachments[i].checked) checkedCount++;
  881. if (this.max && !item.checked && checkedCount >= this.max) return;
  882. item.checked = true;
  883. this.checkedAttachments.push(item);
  884. } else {
  885. for (let i in this.attachments) this.attachments[i].checked = false;
  886. item.checked = true;
  887. this.checkedAttachments = [item];
  888. }
  889. },
  890. confirm() {
  891. this.$emit('selected', this.checkedAttachments, this.params);
  892. this.dialogVisible = false;
  893. const urls = [];
  894. for (let i in this.checkedAttachments) {
  895. urls.push(this.checkedAttachments[i].url);
  896. }
  897. for (let i in this.attachments) {
  898. this.attachments[i].checked = false;
  899. }
  900. this.checkedAttachments = [];
  901. if (!urls.length) {
  902. return;
  903. }
  904. if (this.multiple) {
  905. this.$emit('input', urls);
  906. } else {
  907. this.$emit('input', urls[0]);
  908. }
  909. },
  910. // 上传开始
  911. handleStart(files) {
  912. this.uploading = true;
  913. this.uploadFilesNum = files.length;
  914. this.uploadCompleteFilesNum = 0;
  915. },
  916. // 成功上传
  917. handleSuccess(file) {
  918. console.log(file, 'file')
  919. if (file.response && file.response.data && file.response.data.code === 0) {
  920. const newItem = {
  921. checked: false,
  922. selected: false,
  923. created_at: file.response.data.data.created_at,
  924. deleted_at: file.response.data.data.deleted_at,
  925. id: `${file.response.data.data.id}`,
  926. is_delete: file.response.data.data.is_delete,
  927. mall_id: file.response.data.data.mall_id,
  928. name: file.response.data.data.name,
  929. old_name: file.response.data.data.old_name,
  930. size: file.response.data.data.size,
  931. storage_id: file.response.data.data.storage_id,
  932. thumb_url: file.response.data.data.thumb_url,
  933. type: file.response.data.data.type,
  934. updated_at: file.response.data.data.updated_at,
  935. url: file.response.data.data.url,
  936. user_id: file.response.data.data.user_id,
  937. duration: null,
  938. cover_pic_src: null,
  939. upload_type: file.response.data.data.upload_type
  940. };
  941. this.attachments.unshift(newItem);
  942. this.uploadCompleteFilesNum++;
  943. this.updateVideo();
  944. }
  945. },
  946. // 上传完毕
  947. handleComplete(files) {
  948. this.uploading = false;
  949. if (this.simple) {
  950. let urls = [];
  951. let attachments = [];
  952. for (let i in files) {
  953. if (files[i].response.data && files[i].response.data.code === 0) {
  954. urls.push(files[i].response.data.data.url);
  955. attachments.push(files[i].response.data.data);
  956. }
  957. }
  958. if (!urls.length) {
  959. return;
  960. }
  961. this.dialogVisible = false;
  962. this.$emit('selected', attachments, this.params);
  963. if (this.multiple) {
  964. this.$emit('input', urls);
  965. } else {
  966. this.$emit('input', urls[0]);
  967. }
  968. }
  969. },
  970. handleLoadMore(currentPage) {
  971. if (this.noMore) {
  972. return;
  973. }
  974. this.page = currentPage;
  975. this.loading = true;
  976. this.loadingMore = true;
  977. this.loadList({});
  978. },
  979. updateVideo() {
  980. if (!this.canvas) {
  981. this.canvas = document.getElementById('com-attachment-canvas');
  982. }
  983. for (let i in this.attachments) {
  984. if (this.attachments[i].type == 2) {
  985. if (this.attachments[i].duration) {
  986. continue;
  987. }
  988. let times = 0;
  989. let video = null;
  990. const maxRetry = 10;
  991. const id = 'app_attachment_' + this._uid + '_' + i;
  992. const timer = setInterval(() => {
  993. times++;
  994. if (times >= maxRetry) {
  995. clearInterval(timer);
  996. }
  997. if (!video) {
  998. video = document.getElementById(id);
  999. }
  1000. if (!video) {
  1001. return;
  1002. }
  1003. try {
  1004. const zoom = 0.15;
  1005. this.canvas.width = video.videoWidth * zoom;
  1006. this.canvas.height = video.videoHeight * zoom;
  1007. this.canvas.getContext('2d').drawImage(video, 0, 0, this.canvas.width, this.canvas.height);
  1008. this.attachments[i].cover_pic_src = this.canvas.toDataURL('image/jpg');
  1009. } catch (e) {
  1010. console.warn('获取视频封面异常: ', e);
  1011. }
  1012. if (video.duration && !isNaN(video.duration)) {
  1013. let m = Math.trunc(video.duration / 60);
  1014. let s = Math.trunc(video.duration) % 60;
  1015. m = m < 10 ? `0${m}` : `${m}`;
  1016. s = s < 10 ? `0${s}` : `${s}`;
  1017. this.attachments[i].duration = `${m}:${s}`;
  1018. clearInterval(timer);
  1019. }
  1020. }, 500);
  1021. }
  1022. }
  1023. },
  1024. editNode() {
  1025. if(this.form_dir_s.id == '') {
  1026. this.$message.error('请选择目录');
  1027. return false;
  1028. }
  1029. // 编辑时候自动选中当前的父级
  1030. let data = JSON.parse(JSON.stringify(this.data2))
  1031. let pid = 0
  1032. let id = this.form_dir_s.id
  1033. let pids = []
  1034. let getPid = function(arr, id) {
  1035. arr.forEach(item => {
  1036. if (item.id == id) {
  1037. pid = item.parent_id
  1038. if (pid > 0) {
  1039. pids.push(pid)
  1040. getPid(data, pid)
  1041. }
  1042. }
  1043. if (item.children && item.children.length > 0) {
  1044. getPid(item.children, id)
  1045. }
  1046. })
  1047. }
  1048. getPid(data, id)
  1049. pids.reverse()
  1050. this.selectedOptions3 = pids
  1051. this.dialogFormVisibleEdit = true;
  1052. },
  1053. handleChange(val) {
  1054. this.form_dir.parent_id = val;
  1055. },
  1056. handleChange2(val) {
  1057. this.form_dir_s.parent_id = val
  1058. },
  1059. postNode(type) {
  1060. let parent_id = this.form_dir.parent_id[this.form_dir.parent_id.length - 1]
  1061. let formData = {
  1062. name: type == 'add' ? this.form_dir.name : this.form_dir_s.name
  1063. }
  1064. if (type == 'add') {
  1065. formData.parent_id = parent_id
  1066. } else {
  1067. formData.id = this.form_dir_s.id
  1068. formData.parent_id = this.form_dir_s.parent_id[this.form_dir_s.parent_id.length - 1]
  1069. }
  1070. this.$request({
  1071. params: {
  1072. r: 'happiness/agent/file/save-group',
  1073. },
  1074. method: 'post',
  1075. data: formData,
  1076. }).then(e => {
  1077. this.groupListLoading = false;
  1078. if (e.data.code === 0) {
  1079. this.dialogFormVisible = false;
  1080. this.dialogFormVisibleEdit = false;
  1081. this.groupListLoading = true;
  1082. } else {
  1083. this.$message.error(e.data.msg);
  1084. }
  1085. this.dialogOpened();
  1086. }).catch(e => {
  1087. this.groupListLoading = false;
  1088. });
  1089. },
  1090. handleNodeClick(data) {
  1091. console.log(data);
  1092. this.uploadParams = {
  1093. attachment_group_id: data.id,
  1094. }
  1095. this.currentAttachmentGroupId = data.id;
  1096. this.currentAttachmentStoreId = data.store_id === undefined ? 0 : data.store_id;
  1097. this.showEditBlock = false
  1098. this.form_dir_s.id = data.id;
  1099. this.form_dir_s.name = data.label;
  1100. this.select_name = data.label;
  1101. this.loading = true;
  1102. this.loadList({});
  1103. },
  1104. deleteGroups(is_recycle,type){ // 删除分组
  1105. let title;
  1106. let msg;
  1107. switch (type) {
  1108. case 1:
  1109. title = '是否确认将选中素材放入回收站中?删除的素材可通过回收站还原';
  1110. msg ='请选择要删除的目录';
  1111. break;
  1112. case 2:
  1113. title = '确认还原选择素材?';
  1114. msg ='请选择要还原的目录';
  1115. break;
  1116. case 3:
  1117. title = '素材删除后将无法恢复,您确认要彻底删除所选素材吗?';
  1118. msg ='请选择要删除的目录';
  1119. break;
  1120. default:
  1121. title = '';
  1122. msg = '';
  1123. break;
  1124. }
  1125. if(this.form_dir_s.id==''){
  1126. this.$message.error(msg);
  1127. return false;
  1128. }
  1129. this.$confirm(title, '提示', {
  1130. confirmButtonText: '确定',
  1131. cancelButtonText: '取消',
  1132. type: 'warning'
  1133. }).then(() => {
  1134. this.deleteLoading = true;
  1135. this.$request({
  1136. params: {r: 'happiness/agent/file/del-group'},
  1137. method: 'POST',
  1138. data: {
  1139. id: this.form_dir_s,
  1140. //type 1回收 2还原 3删除
  1141. // type:type,
  1142. }
  1143. }).then(e => {
  1144. this.deleteLoading = false;
  1145. if (e.data.code === 0) {
  1146. this.$message.success(e.data.msg);
  1147. this.dialogOpened();
  1148. } else {
  1149. this.$message.error(e.data.msg);
  1150. }
  1151. }).catch(e => {
  1152. this.deleteLoading = false;
  1153. });
  1154. }).catch(() => {
  1155. });
  1156. },
  1157. addNode() {
  1158. this.form_dir_s = {
  1159. id:'',
  1160. parent_id: '',
  1161. name: '',
  1162. }
  1163. this.dialogFormVisible = true
  1164. },
  1165. },
  1166. });
  1167. </script>