com-attachment.php 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232
  1. <style scoped>
  2. .com-attachment-list {
  3. padding: 5px;
  4. width: 100%;
  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: 5px 5px 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. <span slot-scope="{ node, data }">
  290. <i class="el-icon-tickets"></i>
  291. <span>{{ node.label }}</span>
  292. </span>
  293. </el-tree>
  294. </el-scrollbar>
  295. </el-menu>
  296. </div>
  297. <div v-loading="loading" flex="dir:top">
  298. <el-scrollbar class="scrollbar">
  299. <div class="search" style="margin-right: 12px">
  300. <el-input placeholder="请输入名称搜索" v-model="p_keyword"
  301. @keyup.enter.native="picSearch"
  302. class="input-with-select">
  303. <el-button @click="picSearch" slot="append" icon="el-icon-search"></el-button>
  304. </el-input>
  305. </div>
  306. <div class="com-attachment-list">
  307. <div class="com-attachment-item com-attachment-upload">
  308. <com-upload
  309. v-loading="uploading"
  310. :disabled="uploading"
  311. @start="handleStart"
  312. @success="handleSuccess"
  313. @complete="handleComplete"
  314. :multiple="true"
  315. :max="10"
  316. :params="uploadParams"
  317. :fields="uploadFields"
  318. :accept="accept"
  319. flex="main:center cross:center"
  320. style="width: 100px;height: 100px">
  321. <div v-if="uploading">{{uploadCompleteFilesNum}}/{{uploadFilesNum}}</div>
  322. <i v-else class="el-icon-upload"></i>
  323. </com-upload>
  324. </div>
  325. <template v-for="(item, index) in attachments">
  326. <el-tooltip class="item" effect="dark" :content="String(item.name)" placement="top"
  327. :open-delay="1">
  328. <div
  329. :key="index"
  330. :class="'com-attachment-item'+((item.checked&&!showEditBlock)?' checked':'')+(item.selected&&showEditBlock?' selected':'')"
  331. @click="handleClick(item)">
  332. <!-- 图片 -->
  333. <img v-if="item.upload_type == 'images'" class="com-attachment-img"
  334. :src="item.url"
  335. style="width: 100px;height: 100px;">
  336. <!-- 视频 -->
  337. <div v-if="item.upload_type == 'videos'" class="com-attachment-img"
  338. style="width: 100px;height: 100px;position: relative">
  339. <div v-if="item.cover_pic_src"
  340. class="com-attachment-video-cover"
  341. :style="'background-image: url('+item.cover_pic_src+');'"></div>
  342. <video style="width: 60px;height: 100px;" error="预览图加载失败"
  343. :id="'app_attachment_'+ _uid + '_' + index"
  344. :src="item.url">
  345. </video><!-- width="60" height="100%" -->
  346. <div class="com-attachment-video-info" style="margin-left: 24px;">
  347. <i class="el-icon-video-play"></i>
  348. <span>{{item.duration?item.duration:'--:--'}}</span>
  349. </div>
  350. </div>
  351. <!-- 音频 -->
  352. <div v-if="item.upload_type == 'voices'" class="com-attachment-img"
  353. style="width: 100px;height: 100px;position: relative">
  354. <!-- <div v-if="item.cover_pic_src"
  355. class="com-attachment-video-cover"
  356. :style="'background-image: url('+item.cover_pic_src+');'">
  357. </div> -->
  358. <span>{{item.name}}</span>
  359. </div>
  360. <!-- 文件 -->
  361. <div v-if="item.upload_type == 'files'" class="com-attachment-img"
  362. style="width: 100px;height: 100px;line-height: 100px;text-align: center">
  363. <i class="file-type-icon el-icon-document"></i>
  364. </div>
  365. <div v-if="item.upload_type != 'voices'" class="com-attachment-name">{{item.name}}</div>
  366. <i v-if="false" class="com-attachment-active-icon el-icon-circle-check"></i>
  367. </div>
  368. </el-tooltip>
  369. </template>
  370. </div>
  371. </el-scrollbar>
  372. <div style="padding: 5px;text-align: right;margin-top:auto">
  373. <el-pagination
  374. v-if="pagination"
  375. background
  376. @size-change="handleLoadMore"
  377. @current-change="handleLoadMore"
  378. :current-page.sync="page"
  379. :page-size="pagination.pageSize"
  380. layout="prev, pager, next, jumper"
  381. :total="pagination.total_count">
  382. </el-pagination>
  383. </div>
  384. </div>
  385. </div>
  386. <div style="text-align: right">
  387. <span v-if="showEditBlock" style="color: #909399">请先退出编辑模式</span>
  388. <el-button @click="confirm" type="primary" :disabled="showEditBlock">选定</el-button>
  389. </div>
  390. </template>
  391. </el-dialog>
  392. <el-dialog append-to-body title="分组管理" :visible.sync="addGroupVisible" :close-on-click-modal="false"
  393. width="25%">
  394. <el-form @submit.native.prevent label-width="80px" ref="groupForm" :model="groupForm"
  395. :rules="groupFormRule">
  396. <el-form-item label="分组名称" prop="name" style="margin-bottom: 22px;">
  397. <el-input v-model="groupForm.name" maxlength="8" show-word-limit></el-input>
  398. </el-form-item>
  399. <el-form-item style="text-align: right">
  400. <el-button type="primary" @click="groupFormSubmit('groupForm')" :loading="groupFormLoading">保存
  401. </el-button>
  402. </el-form-item>
  403. </el-form>
  404. </el-dialog>
  405. <el-dialog append-to-body title="添加目录" :visible.sync="dialogFormVisible" :close-on-click-modal="false">
  406. <el-form :model="form_dir" :rules="form_dir_rule">
  407. <el-form-item label="父级目录" :label-width="formLabelWidth">
  408. <el-cascader
  409. expand-trigger="hover"
  410. :options="data2"
  411. v-model="selectedOptions2"
  412. :props="{ checkStrictly: true, value: 'id' }"
  413. clearable
  414. @change="handleChange">
  415. </el-cascader>
  416. </el-form-item>
  417. <el-form-item label="目录名称" :label-width="formLabelWidth">
  418. <el-input v-model="form_dir.name" auto-complete="off"></el-input>
  419. </el-form-item>
  420. </el-form>
  421. <div slot="footer" class="dialog-footer">
  422. <el-button @click="dialogFormVisible = false">取 消</el-button>
  423. <el-button type="primary" @click="postNode('add')">确 定</el-button>
  424. </div>
  425. </el-dialog>
  426. <el-dialog append-to-body title="编辑目录" :visible.sync="dialogFormVisibleEdit" :close-on-click-modal="false">
  427. <el-form :model="form_dir_s" :rules="form_dir_rules">
  428. <el-form-item label="父级目录" :label-width="formLabelWidth">
  429. <el-cascader
  430. expand-trigger="hover"
  431. :options="getOptions()"
  432. v-model="selectedOptions3"
  433. :props="{ checkStrictly: true, value: 'id' }"
  434. clearable
  435. @change="handleChange2">
  436. </el-cascader>
  437. </el-form-item>
  438. <el-form-item label="目录名称" :label-width="formLabelWidth">
  439. <el-input v-model="form_dir_s.name" auto-complete="off"></el-input>
  440. </el-form-item>
  441. </el-form>
  442. <div slot="footer" class="dialog-footer">
  443. <el-button @click="dialogFormVisibleEdit = false">取 消</el-button>
  444. <el-button type="primary" @click="postNode('edit')">确 定</el-button>
  445. </div>
  446. </el-dialog>
  447. <div style="line-height: normal;" @click="dialogVisible = !dialogVisible"
  448. :style="'display:'+(display?display:'inline-block')">
  449. <slot></slot>
  450. </div>
  451. </div>
  452. </template>
  453. <script>
  454. Vue.component('com-attachment', {
  455. template: '#com-attachment',
  456. props: {
  457. display: String,
  458. title: String,
  459. multiple: Boolean,
  460. max: Number,
  461. params: Object,
  462. simple: {
  463. type: Boolean,
  464. value: false,
  465. },
  466. type: {
  467. type: String,
  468. default: 'images',
  469. },
  470. value: {
  471. type: String,
  472. default: '',
  473. },
  474. openDialog: {
  475. type: Boolean,
  476. default: false,
  477. },
  478. },
  479. computed: {
  480. accept: {
  481. get() {
  482. if (this.type === 'images') {
  483. return 'image/*';
  484. }
  485. if (this.type === 'videos') {
  486. return 'video/*';
  487. }
  488. return '*/*';
  489. },
  490. },
  491. },
  492. watch: {
  493. type(newVal, oldVal) {
  494. this.type = newVal;
  495. this.uploadFields.upload_type = this.type;
  496. },
  497. openDialog(newVal, oldVal) {
  498. this.dialogVisible = newVal;
  499. },
  500. dialogVisible(newVal, oldVal) {
  501. if (!newVal) {
  502. this.$emit("closed");
  503. }
  504. },
  505. keyword(newVal, oldVal) {
  506. const groupList = this.groupList;
  507. let arr = [];
  508. groupList.map(v => {
  509. if (v.label.indexOf(newVal) !== -1) {
  510. arr.push(v);
  511. }
  512. });
  513. this.groupItem = arr;
  514. }
  515. },
  516. data() {
  517. return {
  518. isComGoods: false,
  519. videoType: 'videos',
  520. videoConfigInfo: {},
  521. dialogVisible: false,
  522. videoPlayVisible: false,
  523. canvas: null,
  524. uploading: false,
  525. dialogVisible: false,
  526. loading: true,
  527. loadingMore: false,
  528. noMore: false,
  529. attachments: [],
  530. checkedAttachments: [],
  531. uploadParams: {},
  532. uploadFields: {
  533. upload_type: this.type
  534. },
  535. uploadCompleteFilesNum: 0,
  536. uploadFilesNum: 0,
  537. page: 0,
  538. addGroupVisible: false,
  539. noMall: true,
  540. groupList: [],
  541. groupItem: [],
  542. groupListLoading: false,
  543. groupForm: {
  544. id: null,
  545. name: '',
  546. },
  547. groupFormRule: {
  548. name: [{
  549. required: true,
  550. message: '请填写分组名称。',
  551. }],
  552. },
  553. groupFormLoading: false,
  554. showEditBlock: false,
  555. selectAll: false,
  556. deleteLoading: false,
  557. moveLoading: false,
  558. currentAttachmentGroupId: null,
  559. currentAttachmentStoreId: null,
  560. video: null,
  561. keyword: '',
  562. pagination: null,
  563. p_keyword: '',
  564. data2: [],
  565. dirTree: [],
  566. defaultProps: {
  567. children: 'children',
  568. label: 'label'
  569. },
  570. dialogFormVisible: false,
  571. dialogFormVisibleEdit: false,
  572. form_dir: {
  573. name: '',
  574. parent_id: '',
  575. },
  576. form_dir_rule: {
  577. name: [{
  578. required: true,
  579. message: '请填写名称',
  580. }],
  581. },
  582. form_dir_s: {
  583. id: '',
  584. parent_id: '',
  585. name: '',
  586. },
  587. form_dir_rules: {
  588. name: [{
  589. required: true,
  590. message: '请填写名称',
  591. }],
  592. },
  593. formLabelWidth: '120px',
  594. selectedOptions: [],
  595. selectedOptions2: [],
  596. select_name: '全部',
  597. is_recycle: 0,
  598. pppid: [],
  599. selectedOptions3: [],
  600. };
  601. },
  602. created() {},
  603. methods: {
  604. getOptions() {
  605. let data = JSON.parse(JSON.stringify(this.data2))
  606. let id = this.form_dir_s.id
  607. let pid = this.form_dir_s.parent_id
  608. let self = this
  609. var dismap = function(v, i) {
  610. if (v.children && v.children.length > 0) {
  611. v.children.map(dismap)
  612. }
  613. if (v.id == id) {
  614. v.disabled = true
  615. }
  616. if (v.id == pid) {
  617. v.disabled = true
  618. }
  619. if (self.isChildrenId(v.id)) {
  620. v.disabled = true
  621. }
  622. return v
  623. }
  624. let mapData = data.map(dismap)
  625. // 过滤系统图标和系统图片
  626. mapData = mapData.filter(item => item.id != 2000000 && item.id != 999990)
  627. return mapData
  628. },
  629. /**
  630. * 作用是不能把当前元素选择到当前元素的子元素下面
  631. */
  632. isChildrenId(cid) {
  633. let id = this.form_dir_s.id
  634. let child = []
  635. let cids = []
  636. var getChildren = function(arr) {
  637. arr.forEach(item => {
  638. if (item.id == id) {
  639. child = item.children
  640. }
  641. if (item.children && item.children.length > 0) {
  642. getChildren(item.children)
  643. }
  644. })
  645. }
  646. var getChildrenId = function(arr) {
  647. arr.forEach(item => {
  648. if (item.id) {
  649. cids.push(item.id)
  650. }
  651. if (item.children && item.children.length > 0) {
  652. getChildrenId(item.children)
  653. }
  654. })
  655. }
  656. getChildren(this.data2)
  657. getChildrenId(child)
  658. return cids.find(function(ccc) {
  659. return ccc == cid
  660. })
  661. },
  662. picSearch() {
  663. this.page = 1;
  664. this.loading = true;
  665. this.loadGroups();
  666. this.loadList({});
  667. },
  668. dialogOpened() {
  669. if (this.simple) {
  670. return;
  671. }
  672. this.page = 1;
  673. this.loading = true;
  674. this.loadGroups();
  675. this.loadList({});
  676. },
  677. deleteItems() {
  678. const itemIds = [];
  679. for (let i in this.attachments) {
  680. if (this.attachments[i].selected) {
  681. itemIds.push(this.attachments[i].id);
  682. }
  683. }
  684. if (!itemIds.length) {
  685. this.$message.warning('请先选择需要删除的图片。');
  686. return;
  687. }
  688. this.$confirm('确认删除所选的' + itemIds.length + '张图片?', '提示', {
  689. type: 'warning'
  690. }).then(() => {
  691. this.deleteLoading = true;
  692. this.$request({
  693. params: {
  694. r: 'common/file/delete'
  695. },
  696. method: 'post',
  697. data: {
  698. ids: itemIds,
  699. },
  700. }).then(e => {
  701. this.deleteLoading = false;
  702. if (e.data.code === 0) {
  703. this.$message.success(e.data.msg);
  704. for (let i in itemIds) {
  705. for (let j in this.attachments) {
  706. if (this.attachments[j].id == itemIds[i]) {
  707. this.attachments.splice(j, 1);
  708. break;
  709. }
  710. }
  711. }
  712. } else {
  713. this.$message.error(e.data.msg);
  714. }
  715. }).catch(e => {
  716. this.deleteLoading = false;
  717. });
  718. }).catch(() => {});
  719. },
  720. selectAllChange(value) {
  721. for (let i in this.attachments) {
  722. this.attachments[i].selected = value;
  723. }
  724. },
  725. selectItem(item) {
  726. item.selected = item.selected ? false : true;
  727. },
  728. moveItems(index) {
  729. const itemIds = [];
  730. for (let i in this.attachments) {
  731. if (this.attachments[i].selected) {
  732. itemIds.push(this.attachments[i].id);
  733. }
  734. }
  735. if (!itemIds.length) {
  736. this.$message.warning('请先选择需要移动的图片。');
  737. return;
  738. }
  739. this.$confirm('确认移动所选的' + itemIds.length + '张图片?', '提示', {
  740. type: 'warning'
  741. }).then(() => {
  742. this.moveLoading = true;
  743. this.$request({
  744. params: {
  745. r: 'common/file/move'
  746. },
  747. method: 'post',
  748. data: {
  749. ids: itemIds,
  750. attachment_group_id: this.groupItem[index].id,
  751. },
  752. }).then(e => {
  753. this.moveLoading = false;
  754. if (e.data.code === 0) {
  755. this.$message.success(e.data.msg);
  756. this.switchGroup(index);
  757. } else {
  758. this.$message.error(e.data.msg);
  759. }
  760. }).catch(e => {
  761. this.moveLoading = false;
  762. });
  763. }).catch(() => {});
  764. },
  765. loadGroups() {
  766. this.groupListLoading = true;
  767. this.$request({
  768. params: {
  769. r: 'common/file/group-list',
  770. is_recycle: 0,
  771. type: this.type,
  772. },
  773. }).then(e => {
  774. this.groupListLoading = false;
  775. if (e.data.code === 0) {
  776. this.noMall = e.data.data.no_mall ? e.data.data.no_mall : false;
  777. this.groupItem = e.data.data.list;
  778. this.groupList = e.data.data.list;
  779. this.data2 = e.data.data.arr;
  780. // 添加时隐藏系统图片和系统图标
  781. this.dirTree = JSON.parse(JSON.stringify(this.data2));
  782. this.dirTree = this.dirTree.filter(item => item.id != 2000000 && item.id != 999990)
  783. } else {
  784. this.$message.error(e.data.msg);
  785. }
  786. }).catch(e => {
  787. this.groupListLoading = false;
  788. });
  789. },
  790. groupFormSubmit(formName) {
  791. this.$refs[formName].validate(valid => {
  792. if (valid) {
  793. this.groupFormLoading = true;
  794. this.$request({
  795. params: {
  796. r: 'common/attachment/group-update',
  797. },
  798. method: 'post',
  799. data: Object.assign({}, this.groupForm, {
  800. 'type': this.type
  801. }),
  802. }).then(e => {
  803. this.groupFormLoading = false;
  804. if (e.data.code === 0) {
  805. this.$message.success(e.data.msg);
  806. this.addGroupVisible = false;
  807. if (this.groupForm.edit_index > -1) {
  808. this.groupItem[this.groupForm.edit_index] = e.data.data;
  809. } else {
  810. this.groupItem.push(e.data.data);
  811. }
  812. } else {
  813. this.$message.error(e.data.msg);
  814. }
  815. }).catch(e => {
  816. this.groupFormLoading = false;
  817. });
  818. }
  819. })
  820. },
  821. switchGroup(index) {
  822. this.attachments = [];
  823. this.page = 0;
  824. this.noMore = false;
  825. this.loading = true;
  826. this.uploadParams = {
  827. attachment_group_id: index > -1 ? this.groupItem[index].id : null,
  828. };
  829. this.currentAttachmentGroupId = index > -1 ? this.groupItem[index].id : null;
  830. if (index < 1) {
  831. this.currentAttachmentStoreId = null
  832. }
  833. this.loadList({});
  834. },
  835. loadList(params) {
  836. this.noMore = false;
  837. this.selectAll = false;
  838. params['r'] = 'common/file/selector';
  839. params['page'] = this.page;
  840. params['attachment_group_id'] = this.currentAttachmentGroupId;
  841. params['upload_type'] = this.type;
  842. params['is_recycle'] = 0;
  843. params['keyword'] = this.p_keyword;
  844. this.$request({
  845. params: params,
  846. }).then(e => {
  847. if (e.data.code === 0) {
  848. if (!e.data.data.list.length) {
  849. this.noMore = true;
  850. }
  851. for (let i in e.data.data.list) {
  852. e.data.data.list[i].checked = false;
  853. e.data.data.list[i].selected = false;
  854. e.data.data.list[i].duration = null;
  855. }
  856. //this.attachments = this.attachments.concat(e.data.data.list);
  857. this.attachments = e.data.data.list;
  858. this.pagination = e.data.data.pagination;
  859. this.pagination.pageSize = e.data.data.page_size;
  860. this.pagination.total_count = e.data.data.count;
  861. this.checkedAttachments = [];
  862. this.loading = false;
  863. this.loadingMore = false;
  864. this.updateVideo();
  865. } else {
  866. this.$message.error(e.data.msg);
  867. this.dialogVisible = false;
  868. }
  869. }).catch(e => {});
  870. },
  871. handleClick(item) {
  872. if (this.showEditBlock) {
  873. this.selectItem(item);
  874. return;
  875. }
  876. if (item.checked) {
  877. item.checked = false;
  878. for (let i in this.checkedAttachments) {
  879. if (item.id === this.checkedAttachments[i].id) this.checkedAttachments.splice(i, 1);
  880. }
  881. return;
  882. }
  883. if (this.multiple) {
  884. let checkedCount = 0;
  885. for (let i in this.attachments)
  886. if (this.attachments[i].checked) checkedCount++;
  887. if (this.max && !item.checked && checkedCount >= this.max) return;
  888. item.checked = true;
  889. this.checkedAttachments.push(item);
  890. } else {
  891. for (let i in this.attachments) this.attachments[i].checked = false;
  892. item.checked = true;
  893. this.checkedAttachments = [item];
  894. }
  895. },
  896. confirm() {
  897. this.$emit('selected', this.checkedAttachments, this.params);
  898. this.dialogVisible = false;
  899. const urls = [];
  900. for (let i in this.checkedAttachments) {
  901. urls.push(this.checkedAttachments[i].url);
  902. }
  903. for (let i in this.attachments) {
  904. this.attachments[i].checked = false;
  905. }
  906. this.checkedAttachments = [];
  907. if (!urls.length) {
  908. return;
  909. }
  910. if (this.multiple) {
  911. this.$emit('input', urls);
  912. } else {
  913. this.$emit('input', urls[0]);
  914. }
  915. },
  916. // 上传开始
  917. handleStart(files) {
  918. this.uploading = true;
  919. this.uploadFilesNum = files.length;
  920. this.uploadCompleteFilesNum = 0;
  921. },
  922. // 成功上传
  923. handleSuccess(file) {
  924. console.log(file, 'file')
  925. if (file.response && file.response.data && file.response.data.code === 0) {
  926. const newItem = {
  927. checked: false,
  928. selected: false,
  929. created_at: file.response.data.data.created_at,
  930. deleted_at: file.response.data.data.deleted_at,
  931. id: `${file.response.data.data.id}`,
  932. is_delete: file.response.data.data.is_delete,
  933. mall_id: file.response.data.data.mall_id,
  934. name: file.response.data.data.name,
  935. old_name: file.response.data.data.old_name,
  936. size: file.response.data.data.size,
  937. storage_id: file.response.data.data.storage_id,
  938. thumb_url: file.response.data.data.thumb_url,
  939. type: file.response.data.data.type,
  940. updated_at: file.response.data.data.updated_at,
  941. url: file.response.data.data.url,
  942. user_id: file.response.data.data.user_id,
  943. duration: null,
  944. cover_pic_src: null,
  945. upload_type: file.response.data.data.upload_type
  946. };
  947. this.attachments.unshift(newItem);
  948. this.uploadCompleteFilesNum++;
  949. this.updateVideo();
  950. }
  951. },
  952. // 上传完毕
  953. handleComplete(files) {
  954. this.uploading = false;
  955. if (this.simple) {
  956. let urls = [];
  957. let attachments = [];
  958. for (let i in files) {
  959. if (files[i].response.data && files[i].response.data.code === 0) {
  960. urls.push(files[i].response.data.data.url);
  961. attachments.push(files[i].response.data.data);
  962. }
  963. }
  964. if (!urls.length) {
  965. return;
  966. }
  967. this.dialogVisible = false;
  968. this.$emit('selected', attachments, this.params);
  969. if (this.multiple) {
  970. this.$emit('input', urls);
  971. } else {
  972. this.$emit('input', urls[0]);
  973. }
  974. }
  975. },
  976. handleLoadMore(currentPage) {
  977. if (this.noMore) {
  978. return;
  979. }
  980. this.page = currentPage;
  981. this.loading = true;
  982. this.loadingMore = true;
  983. this.loadList({});
  984. },
  985. updateVideo() {
  986. if (!this.canvas) {
  987. this.canvas = document.getElementById('com-attachment-canvas');
  988. }
  989. for (let i in this.attachments) {
  990. if (this.attachments[i].type == 2) {
  991. if (this.attachments[i].duration) {
  992. continue;
  993. }
  994. let times = 0;
  995. let video = null;
  996. const maxRetry = 10;
  997. const id = 'app_attachment_' + this._uid + '_' + i;
  998. const timer = setInterval(() => {
  999. times++;
  1000. if (times >= maxRetry) {
  1001. clearInterval(timer);
  1002. }
  1003. if (!video) {
  1004. video = document.getElementById(id);
  1005. }
  1006. if (!video) {
  1007. return;
  1008. }
  1009. try {
  1010. const zoom = 0.15;
  1011. this.canvas.width = video.videoWidth * zoom;
  1012. this.canvas.height = video.videoHeight * zoom;
  1013. this.canvas.getContext('2d').drawImage(video, 0, 0, this.canvas.width, this.canvas.height);
  1014. this.attachments[i].cover_pic_src = this.canvas.toDataURL('image/jpg');
  1015. } catch (e) {
  1016. console.warn('获取视频封面异常: ', e);
  1017. }
  1018. if (video.duration && !isNaN(video.duration)) {
  1019. let m = Math.trunc(video.duration / 60);
  1020. let s = Math.trunc(video.duration) % 60;
  1021. m = m < 10 ? `0${m}` : `${m}`;
  1022. s = s < 10 ? `0${s}` : `${s}`;
  1023. this.attachments[i].duration = `${m}:${s}`;
  1024. clearInterval(timer);
  1025. }
  1026. }, 500);
  1027. }
  1028. }
  1029. },
  1030. editNode() {
  1031. if (this.form_dir_s.id == '') {
  1032. this.$message.error('请选择目录');
  1033. return false;
  1034. }
  1035. // 编辑时候自动选中当前的父级
  1036. let data = JSON.parse(JSON.stringify(this.data2))
  1037. let pid = 0
  1038. let id = this.form_dir_s.id
  1039. let pids = []
  1040. let getPid = function(arr, id) {
  1041. arr.forEach(item => {
  1042. if (item.id == id) {
  1043. pid = item.parent_id
  1044. if (pid > 0) {
  1045. pids.push(pid)
  1046. getPid(data, pid)
  1047. }
  1048. }
  1049. if (item.children && item.children.length > 0) {
  1050. getPid(item.children, id)
  1051. }
  1052. })
  1053. }
  1054. getPid(data, id)
  1055. pids.reverse()
  1056. this.selectedOptions3 = pids
  1057. this.dialogFormVisibleEdit = true;
  1058. },
  1059. handleChange(val) {
  1060. this.form_dir.parent_id = val;
  1061. },
  1062. handleChange2(val) {
  1063. this.form_dir_s.parent_id = val
  1064. },
  1065. postNode(type) {
  1066. let parent_id = this.form_dir.parent_id[this.form_dir.parent_id.length - 1]
  1067. let formData = {
  1068. name: type == 'add' ? this.form_dir.name : this.form_dir_s.name
  1069. }
  1070. if (type == 'add') {
  1071. formData.parent_id = parent_id
  1072. } else {
  1073. formData.id = this.form_dir_s.id
  1074. formData.parent_id = this.form_dir_s.parent_id[this.form_dir_s.parent_id.length - 1]
  1075. }
  1076. this.$request({
  1077. params: {
  1078. r: 'common/file/save-group',
  1079. },
  1080. method: 'post',
  1081. data: formData,
  1082. }).then(e => {
  1083. this.groupListLoading = false;
  1084. if (e.data.code === 0) {
  1085. this.dialogFormVisible = false;
  1086. this.dialogFormVisibleEdit = false;
  1087. this.groupListLoading = true;
  1088. } else {
  1089. this.$message.error(e.data.msg);
  1090. }
  1091. this.dialogOpened();
  1092. }).catch(e => {
  1093. this.groupListLoading = false;
  1094. });
  1095. },
  1096. handleNodeClick(data) {
  1097. console.log(data);
  1098. this.uploadParams = {
  1099. attachment_group_id: data.id,
  1100. }
  1101. this.currentAttachmentGroupId = data.id;
  1102. this.currentAttachmentStoreId = data.store_id === undefined ? 0 : data.store_id;
  1103. this.showEditBlock = false
  1104. this.form_dir_s.id = data.id;
  1105. this.form_dir_s.name = data.label;
  1106. this.select_name = data.label;
  1107. this.loading = true;
  1108. this.loadList({});
  1109. },
  1110. deleteGroups(is_recycle, type) { // 删除分组
  1111. let title;
  1112. let msg;
  1113. switch (type) {
  1114. case 1:
  1115. title = '是否确认将选中素材放入回收站中?删除的素材可通过回收站还原';
  1116. msg = '请选择要删除的目录';
  1117. break;
  1118. case 2:
  1119. title = '确认还原选择素材?';
  1120. msg = '请选择要还原的目录';
  1121. break;
  1122. case 3:
  1123. title = '素材删除后将无法恢复,您确认要彻底删除所选素材吗?';
  1124. msg = '请选择要删除的目录';
  1125. break;
  1126. default:
  1127. title = '';
  1128. msg = '';
  1129. break;
  1130. }
  1131. if (this.form_dir_s.id == '') {
  1132. this.$message.error(msg);
  1133. return false;
  1134. }
  1135. this.$confirm(title, '提示', {
  1136. confirmButtonText: '确定',
  1137. cancelButtonText: '取消',
  1138. type: 'warning'
  1139. }).then(() => {
  1140. this.deleteLoading = true;
  1141. this.$request({
  1142. params: {
  1143. r: 'common/file/del-group'
  1144. },
  1145. method: 'POST',
  1146. data: {
  1147. id: this.form_dir_s,
  1148. //type 1回收 2还原 3删除
  1149. // type:type,
  1150. }
  1151. }).then(e => {
  1152. this.deleteLoading = false;
  1153. if (e.data.code === 0) {
  1154. this.$message.success(e.data.msg);
  1155. this.dialogOpened();
  1156. } else {
  1157. this.$message.error(e.data.msg);
  1158. }
  1159. }).catch(e => {
  1160. this.deleteLoading = false;
  1161. });
  1162. }).catch(() => {});
  1163. },
  1164. addNode() {
  1165. this.form_dir_s = {
  1166. id: '',
  1167. parent_id: '',
  1168. name: '',
  1169. }
  1170. this.dialogFormVisible = true
  1171. },
  1172. playVideo() {},
  1173. },
  1174. });
  1175. </script>