com-attachment.php 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  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. >
  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: {
  461. type: Boolean,
  462. value: false,
  463. },
  464. max: Number,
  465. params: Object,
  466. simple: {
  467. type: Boolean,
  468. value: false,
  469. },
  470. type: {
  471. type: String,
  472. default: 'images',
  473. },
  474. value: {
  475. type: String,
  476. default: '',
  477. },
  478. openDialog: {
  479. type: Boolean,
  480. default: false,
  481. },
  482. },
  483. computed: {
  484. accept: {
  485. get() {
  486. if (this.type === 'images') {
  487. return 'image/*';
  488. }
  489. if (this.type === 'videos') {
  490. return 'video/*';
  491. }
  492. return '*/*';
  493. },
  494. },
  495. },
  496. watch: {
  497. type(newVal, oldVal) {
  498. this.type = newVal;
  499. this.uploadFields.upload_type = this.type;
  500. },
  501. openDialog(newVal, oldVal) {
  502. this.dialogVisible = newVal;
  503. },
  504. dialogVisible(newVal, oldVal) {
  505. if (!newVal) {
  506. this.$emit("closed");
  507. }
  508. },
  509. keyword(newVal, oldVal) {
  510. const groupList = this.groupList;
  511. let arr = [];
  512. groupList.map(v => {
  513. if (v.label.indexOf(newVal) !== -1) {
  514. arr.push(v);
  515. }
  516. });
  517. this.groupItem = arr;
  518. }
  519. },
  520. data() {
  521. return {
  522. isComGoods: false,
  523. videoType: 'videos',
  524. videoConfigInfo: {},
  525. dialogVisible: false,
  526. videoPlayVisible: false,
  527. canvas: null,
  528. uploading: false,
  529. videoPlayUrl: '',
  530. loading: true,
  531. loadingMore: false,
  532. noMore: false,
  533. attachments: [],
  534. checkedAttachments: [],
  535. uploadParams: {},
  536. uploadFields: {
  537. upload_type: this.type
  538. },
  539. uploadCompleteFilesNum: 0,
  540. uploadFilesNum: 0,
  541. page: 0,
  542. addGroupVisible: false,
  543. noMall: true,
  544. groupList: [],
  545. groupItem: [],
  546. groupListLoading: false,
  547. groupForm: {
  548. id: null,
  549. name: '',
  550. },
  551. groupFormRule: {
  552. name: [
  553. {required: true, message: '请填写分组名称。',}
  554. ],
  555. },
  556. groupFormLoading: false,
  557. showEditBlock: false,
  558. selectAll: false,
  559. deleteLoading: false,
  560. moveLoading: false,
  561. currentAttachmentGroupId: null,
  562. currentAttachmentStoreId: null,
  563. video: null,
  564. keyword: '',
  565. pagination: null,
  566. p_keyword: '',
  567. data2: [],
  568. dirTree: [],
  569. defaultProps: {
  570. children: 'children',
  571. label: 'label'
  572. },
  573. dialogFormVisible: false,
  574. dialogFormVisibleEdit: false,
  575. form_dir: {
  576. name: '',
  577. parent_id:'',
  578. },
  579. form_dir_rule: {
  580. name: [
  581. {required: true, message: '请填写名称',}
  582. ],
  583. },
  584. form_dir_s: {
  585. id:'',
  586. parent_id: '',
  587. name: '',
  588. },
  589. form_dir_rules: {
  590. name: [
  591. {required: true, message: '请填写名称',}
  592. ],
  593. },
  594. formLabelWidth: '120px',
  595. selectedOptions: [],
  596. selectedOptions2: [],
  597. select_name:'全部',
  598. is_recycle:0,
  599. pppid: [],
  600. selectedOptions3: [],
  601. };
  602. },
  603. created() {
  604. },
  605. methods: {
  606. getOptions() {
  607. let data = JSON.parse(JSON.stringify(this.data2))
  608. let id = this.form_dir_s.id
  609. let pid = this.form_dir_s.parent_id
  610. let self = this
  611. var dismap = function (v, i) {
  612. if (v.children && v.children.length > 0) {
  613. v.children.map(dismap)
  614. }
  615. if (v.id == id) {
  616. v.disabled = true
  617. }
  618. if (v.id == pid) {
  619. v.disabled = true
  620. }
  621. if (self.isChildrenId(v.id)) {
  622. v.disabled = true
  623. }
  624. return v
  625. }
  626. let mapData = data.map(dismap)
  627. // 过滤系统图标和系统图片
  628. mapData = mapData.filter(item => item.id != 2000000 && item.id != 999990)
  629. return mapData
  630. },
  631. /**
  632. * 作用是不能把当前元素选择到当前元素的子元素下面
  633. */
  634. isChildrenId(cid) {
  635. let id = this.form_dir_s.id
  636. let child = []
  637. let cids = []
  638. var getChildren = function(arr) {
  639. arr.forEach(item => {
  640. if (item.id == id) {
  641. child = item.children
  642. }
  643. if (item.children && item.children.length > 0) {
  644. getChildren(item.children)
  645. }
  646. })
  647. }
  648. var getChildrenId = function(arr) {
  649. arr.forEach(item => {
  650. if (item.id) {
  651. cids.push(item.id)
  652. }
  653. if (item.children && item.children.length > 0) {
  654. getChildrenId(item.children)
  655. }
  656. })
  657. }
  658. getChildren(this.data2)
  659. getChildrenId(child)
  660. return cids.find(function(ccc) {
  661. return ccc == cid
  662. })
  663. },
  664. picSearch() {
  665. this.page = 1;
  666. this.loading = true;
  667. this.loadGroups();
  668. this.loadList({});
  669. },
  670. dialogOpened() {
  671. if (this.simple) {
  672. return;
  673. }
  674. this.page = 1;
  675. this.loading = true;
  676. this.loadGroups();
  677. this.loadList({});
  678. },
  679. deleteItems() {
  680. const itemIds = [];
  681. for (let i in this.attachments) {
  682. if (this.attachments[i].selected) {
  683. itemIds.push(this.attachments[i].id);
  684. }
  685. }
  686. if (!itemIds.length) {
  687. this.$message.warning('请先选择需要删除的图片。');
  688. return;
  689. }
  690. this.$confirm('确认删除所选的' + itemIds.length + '张图片?', '提示', {
  691. type: 'warning'
  692. }).then(() => {
  693. this.deleteLoading = true;
  694. this.$request({
  695. params: {
  696. r: 'store/client/file/delete'
  697. },
  698. method: 'post',
  699. data: {
  700. ids: itemIds,
  701. },
  702. }).then(e => {
  703. this.deleteLoading = false;
  704. if (e.data.code === 0) {
  705. this.$message.success(e.data.msg);
  706. for (let i in itemIds) {
  707. for (let j in this.attachments) {
  708. if (this.attachments[j].id == itemIds[i]) {
  709. this.attachments.splice(j, 1);
  710. break;
  711. }
  712. }
  713. }
  714. } else {
  715. this.$message.error(e.data.msg);
  716. }
  717. }).catch(e => {
  718. this.deleteLoading = false;
  719. });
  720. }).catch(() => {
  721. });
  722. },
  723. selectAllChange(value) {
  724. for (let i in this.attachments) {
  725. this.attachments[i].selected = value;
  726. }
  727. },
  728. selectItem(item) {
  729. item.selected = item.selected ? false : true;
  730. },
  731. moveItems(index) {
  732. const itemIds = [];
  733. for (let i in this.attachments) {
  734. if (this.attachments[i].selected) {
  735. itemIds.push(this.attachments[i].id);
  736. }
  737. }
  738. if (!itemIds.length) {
  739. this.$message.warning('请先选择需要移动的图片。');
  740. return;
  741. }
  742. this.$confirm('确认移动所选的' + itemIds.length + '张图片?', '提示', {
  743. type: 'warning'
  744. }).then(() => {
  745. this.moveLoading = true;
  746. this.$request({
  747. params: {
  748. r: 'store/client/file/move'
  749. },
  750. method: 'post',
  751. data: {
  752. ids: itemIds,
  753. attachment_group_id: this.groupItem[index].id,
  754. },
  755. }).then(e => {
  756. this.moveLoading = false;
  757. if (e.data.code === 0) {
  758. this.$message.success(e.data.msg);
  759. this.switchGroup(index);
  760. } else {
  761. this.$message.error(e.data.msg);
  762. }
  763. }).catch(e => {
  764. this.moveLoading = false;
  765. });
  766. }).catch(() => {
  767. });
  768. },
  769. loadGroups() {
  770. this.groupListLoading = true;
  771. this.$request({
  772. params: {
  773. r: 'store/client/file/group-list',
  774. is_recycle: 0,
  775. type: this.type,
  776. },
  777. }).then(e => {
  778. this.groupListLoading = false;
  779. if (e.data.code === 0) {
  780. this.noMall = e.data.data.no_mall ? e.data.data.no_mall : false;
  781. this.groupItem = e.data.data.list;
  782. this.groupList = e.data.data.list;
  783. this.data2 = e.data.data.arr;
  784. // 添加时隐藏系统图片和系统图标
  785. this.dirTree = JSON.parse(JSON.stringify(this.data2));
  786. this.dirTree = this.dirTree.filter(item => item.id != 2000000 && item.id != 999990)
  787. } else {
  788. this.$message.error(e.data.msg);
  789. }
  790. }).catch(e => {
  791. this.groupListLoading = false;
  792. });
  793. },
  794. groupFormSubmit(formName) {
  795. this.$refs[formName].validate(valid => {
  796. if (valid) {
  797. this.groupFormLoading = true;
  798. this.$request({
  799. params: {
  800. r: 'common/attachment/group-update',
  801. },
  802. method: 'post',
  803. data: Object.assign({}, this.groupForm, {'type': this.type}),
  804. }).then(e => {
  805. this.groupFormLoading = false;
  806. if (e.data.code === 0) {
  807. this.$message.success(e.data.msg);
  808. this.addGroupVisible = false;
  809. if (this.groupForm.edit_index > -1) {
  810. this.groupItem[this.groupForm.edit_index] = e.data.data;
  811. } else {
  812. this.groupItem.push(e.data.data);
  813. }
  814. } else {
  815. this.$message.error(e.data.msg);
  816. }
  817. }).catch(e => {
  818. this.groupFormLoading = false;
  819. });
  820. }
  821. })
  822. },
  823. switchGroup(index) {
  824. this.attachments = [];
  825. this.page = 0;
  826. this.noMore = false;
  827. this.loading = true;
  828. this.uploadParams = {
  829. attachment_group_id: index > -1 ? this.groupItem[index].id : null,
  830. };
  831. this.currentAttachmentGroupId = index > -1 ? this.groupItem[index].id : null;
  832. if (index < 1) {
  833. this.currentAttachmentStoreId = null
  834. }
  835. this.loadList({});
  836. },
  837. loadList(params) {
  838. this.noMore = false;
  839. this.selectAll = false;
  840. params['r'] = 'store/client/file/selector';
  841. params['page'] = this.page;
  842. params['attachment_group_id'] = this.currentAttachmentGroupId;
  843. params['upload_type'] = this.type;
  844. params['is_recycle'] = 0;
  845. params['keyword'] = this.p_keyword;
  846. this.$request({
  847. params: params,
  848. }).then(e => {
  849. if (e.data.code === 0) {
  850. if (!e.data.data.list.length) {
  851. this.noMore = true;
  852. }
  853. for (let i in e.data.data.list) {
  854. e.data.data.list[i].checked = false;
  855. e.data.data.list[i].selected = false;
  856. e.data.data.list[i].duration = null;
  857. }
  858. //this.attachments = this.attachments.concat(e.data.data.list);
  859. this.attachments = e.data.data.list;
  860. this.pagination = e.data.data.pagination;
  861. this.pagination.pageSize = e.data.data.page_size;
  862. this.pagination.total_count = e.data.data.count;
  863. this.checkedAttachments = [];
  864. this.loading = false;
  865. this.loadingMore = false;
  866. this.updateVideo();
  867. } else {
  868. this.$message.error(e.data.msg);
  869. this.dialogVisible = false;
  870. }
  871. }).catch(e => {
  872. });
  873. },
  874. handleClick(item) {
  875. console.log(item, this.multiple)
  876. if (this.showEditBlock) {
  877. this.selectItem(item);
  878. return;
  879. }
  880. if (item.checked) {
  881. item.checked = false;
  882. for (let i in this.checkedAttachments) {
  883. if (item.id === this.checkedAttachments[i].id) this.checkedAttachments.splice(i, 1);
  884. }
  885. return;
  886. }
  887. if (this.multiple) {
  888. let checkedCount = 0;
  889. for (let i in this.attachments) if (this.attachments[i].checked) checkedCount++;
  890. if (this.max && !item.checked && checkedCount >= this.max) return;
  891. item.checked = true;
  892. this.checkedAttachments.push(item);
  893. } else {
  894. for (let i in this.attachments) this.attachments[i].checked = false;
  895. item.checked = true;
  896. this.checkedAttachments = [item];
  897. }
  898. },
  899. confirm() {
  900. this.$emit('selected', this.checkedAttachments, this.params);
  901. this.dialogVisible = false;
  902. const urls = [];
  903. for (let i in this.checkedAttachments) {
  904. urls.push(this.checkedAttachments[i].url);
  905. }
  906. for (let i in this.attachments) {
  907. this.attachments[i].checked = false;
  908. }
  909. this.checkedAttachments = [];
  910. if (!urls.length) {
  911. return;
  912. }
  913. if (this.multiple) {
  914. this.$emit('input', urls);
  915. } else {
  916. this.$emit('input', urls[0]);
  917. }
  918. },
  919. // 上传开始
  920. handleStart(files) {
  921. this.uploading = true;
  922. this.uploadFilesNum = files.length;
  923. this.uploadCompleteFilesNum = 0;
  924. },
  925. // 成功上传
  926. handleSuccess(file) {
  927. console.log(file, 'file')
  928. if (file.response && file.response.data && file.response.data.code === 0) {
  929. const newItem = {
  930. checked: false,
  931. selected: false,
  932. created_at: file.response.data.data.created_at,
  933. deleted_at: file.response.data.data.deleted_at,
  934. id: `${file.response.data.data.id}`,
  935. is_delete: file.response.data.data.is_delete,
  936. mall_id: file.response.data.data.mall_id,
  937. name: file.response.data.data.name,
  938. old_name: file.response.data.data.old_name,
  939. size: file.response.data.data.size,
  940. storage_id: file.response.data.data.storage_id,
  941. thumb_url: file.response.data.data.thumb_url,
  942. type: file.response.data.data.type,
  943. updated_at: file.response.data.data.updated_at,
  944. url: file.response.data.data.url,
  945. user_id: file.response.data.data.user_id,
  946. duration: null,
  947. cover_pic_src: null,
  948. upload_type: file.response.data.data.upload_type
  949. };
  950. this.attachments.unshift(newItem);
  951. this.uploadCompleteFilesNum++;
  952. this.updateVideo();
  953. }
  954. },
  955. // 上传完毕
  956. handleComplete(files) {
  957. this.uploading = false;
  958. if (this.simple) {
  959. let urls = [];
  960. let attachments = [];
  961. for (let i in files) {
  962. if (files[i].response.data && files[i].response.data.code === 0) {
  963. urls.push(files[i].response.data.data.url);
  964. attachments.push(files[i].response.data.data);
  965. }
  966. }
  967. if (!urls.length) {
  968. return;
  969. }
  970. this.dialogVisible = false;
  971. this.$emit('selected', attachments, this.params);
  972. if (this.multiple) {
  973. this.$emit('input', urls);
  974. } else {
  975. this.$emit('input', urls[0]);
  976. }
  977. }
  978. },
  979. handleLoadMore(currentPage) {
  980. if (this.noMore) {
  981. return;
  982. }
  983. this.page = currentPage;
  984. this.loading = true;
  985. this.loadingMore = true;
  986. this.loadList({});
  987. },
  988. updateVideo() {
  989. if (!this.canvas) {
  990. this.canvas = document.getElementById('com-attachment-canvas');
  991. }
  992. for (let i in this.attachments) {
  993. if (this.attachments[i].type == 2) {
  994. if (this.attachments[i].duration) {
  995. continue;
  996. }
  997. let times = 0;
  998. let video = null;
  999. const maxRetry = 10;
  1000. const id = 'app_attachment_' + this._uid + '_' + i;
  1001. const timer = setInterval(() => {
  1002. times++;
  1003. if (times >= maxRetry) {
  1004. clearInterval(timer);
  1005. }
  1006. if (!video) {
  1007. video = document.getElementById(id);
  1008. }
  1009. if (!video) {
  1010. return;
  1011. }
  1012. try {
  1013. const zoom = 0.15;
  1014. this.canvas.width = video.videoWidth * zoom;
  1015. this.canvas.height = video.videoHeight * zoom;
  1016. this.canvas.getContext('2d').drawImage(video, 0, 0, this.canvas.width, this.canvas.height);
  1017. this.attachments[i].cover_pic_src = this.canvas.toDataURL('image/jpg');
  1018. } catch (e) {
  1019. console.warn('获取视频封面异常: ', e);
  1020. }
  1021. if (video.duration && !isNaN(video.duration)) {
  1022. let m = Math.trunc(video.duration / 60);
  1023. let s = Math.trunc(video.duration) % 60;
  1024. m = m < 10 ? `0${m}` : `${m}`;
  1025. s = s < 10 ? `0${s}` : `${s}`;
  1026. this.attachments[i].duration = `${m}:${s}`;
  1027. clearInterval(timer);
  1028. }
  1029. }, 500);
  1030. }
  1031. }
  1032. },
  1033. editNode() {
  1034. if(this.form_dir_s.id == '') {
  1035. this.$message.error('请选择目录');
  1036. return false;
  1037. }
  1038. // 编辑时候自动选中当前的父级
  1039. let data = JSON.parse(JSON.stringify(this.data2))
  1040. let pid = 0
  1041. let id = this.form_dir_s.id
  1042. let pids = []
  1043. let getPid = function(arr, id) {
  1044. arr.forEach(item => {
  1045. if (item.id == id) {
  1046. pid = item.parent_id
  1047. if (pid > 0) {
  1048. pids.push(pid)
  1049. getPid(data, pid)
  1050. }
  1051. }
  1052. if (item.children && item.children.length > 0) {
  1053. getPid(item.children, id)
  1054. }
  1055. })
  1056. }
  1057. getPid(data, id)
  1058. pids.reverse()
  1059. this.selectedOptions3 = pids
  1060. this.dialogFormVisibleEdit = true;
  1061. },
  1062. handleChange(val) {
  1063. this.form_dir.parent_id = val;
  1064. },
  1065. handleChange2(val) {
  1066. this.form_dir_s.parent_id = val
  1067. },
  1068. postNode(type) {
  1069. let parent_id = this.form_dir.parent_id[this.form_dir.parent_id.length - 1]
  1070. let formData = {
  1071. name: type == 'add' ? this.form_dir.name : this.form_dir_s.name
  1072. }
  1073. if (type == 'add') {
  1074. formData.parent_id = parent_id
  1075. } else {
  1076. formData.id = this.form_dir_s.id
  1077. formData.parent_id = this.form_dir_s.parent_id[this.form_dir_s.parent_id.length - 1]
  1078. }
  1079. this.$request({
  1080. params: {
  1081. r: 'store/client/file/save-group',
  1082. },
  1083. method: 'post',
  1084. data: formData,
  1085. }).then(e => {
  1086. this.groupListLoading = false;
  1087. if (e.data.code === 0) {
  1088. this.dialogFormVisible = false;
  1089. this.dialogFormVisibleEdit = false;
  1090. this.groupListLoading = true;
  1091. } else {
  1092. this.$message.error(e.data.msg);
  1093. }
  1094. this.dialogOpened();
  1095. }).catch(e => {
  1096. this.groupListLoading = false;
  1097. });
  1098. },
  1099. handleNodeClick(data) {
  1100. console.log(data);
  1101. this.uploadParams = {
  1102. attachment_group_id: data.id,
  1103. }
  1104. this.currentAttachmentGroupId = data.id;
  1105. this.currentAttachmentStoreId = data.store_id === undefined ? 0 : data.store_id;
  1106. this.showEditBlock = false
  1107. this.form_dir_s.id = data.id;
  1108. this.form_dir_s.name = data.label;
  1109. this.select_name = data.label;
  1110. this.loading = true;
  1111. this.loadList({});
  1112. },
  1113. deleteGroups(is_recycle,type){ // 删除分组
  1114. let title;
  1115. let msg;
  1116. switch (type) {
  1117. case 1:
  1118. title = '是否确认将选中素材放入回收站中?删除的素材可通过回收站还原';
  1119. msg ='请选择要删除的目录';
  1120. break;
  1121. case 2:
  1122. title = '确认还原选择素材?';
  1123. msg ='请选择要还原的目录';
  1124. break;
  1125. case 3:
  1126. title = '素材删除后将无法恢复,您确认要彻底删除所选素材吗?';
  1127. msg ='请选择要删除的目录';
  1128. break;
  1129. default:
  1130. title = '';
  1131. msg = '';
  1132. break;
  1133. }
  1134. if(this.form_dir_s.id==''){
  1135. this.$message.error(msg);
  1136. return false;
  1137. }
  1138. this.$confirm(title, '提示', {
  1139. confirmButtonText: '确定',
  1140. cancelButtonText: '取消',
  1141. type: 'warning'
  1142. }).then(() => {
  1143. this.deleteLoading = true;
  1144. this.$request({
  1145. params: {r: 'store/client/file/del-group'},
  1146. method: 'POST',
  1147. data: {
  1148. id: this.form_dir_s,
  1149. //type 1回收 2还原 3删除
  1150. // type:type,
  1151. }
  1152. }).then(e => {
  1153. this.deleteLoading = false;
  1154. if (e.data.code === 0) {
  1155. this.$message.success(e.data.msg);
  1156. this.dialogOpened();
  1157. } else {
  1158. this.$message.error(e.data.msg);
  1159. }
  1160. }).catch(e => {
  1161. this.deleteLoading = false;
  1162. });
  1163. }).catch(() => {
  1164. });
  1165. },
  1166. addNode() {
  1167. this.form_dir_s = {
  1168. id:'',
  1169. parent_id: '',
  1170. name: '',
  1171. }
  1172. this.dialogFormVisible = true
  1173. },
  1174. playVideo() {
  1175. },
  1176. },
  1177. });
  1178. </script>