material.html 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport"
  7. content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
  8. <title>添加素材</title>
  9. <!-- 引入样式文件 -->
  10. <link rel="stylesheet"
  11. href="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012584633/vant.css" />
  12. <!-- 必须先引入vue, 后使用vant-ui -->
  13. <link rel="stylesheet" href="../css/select-tag.css">
  14. <link rel="stylesheet" href="../css/page-return.css">
  15. <script
  16. src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1742017957144/vue.js"></script>
  17. <!-- 引入vant的组件库-->
  18. <!-- 引入 Vant 的 JS 文件 -->
  19. <script
  20. src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758012748487/vant.min.js"></script>
  21. <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
  22. <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
  23. <script src="../js/page-return.js"></script>
  24. <!-- <script src="js/vconsole.min.js"></script>
  25. <script>
  26. var vConsole = new window.VConsole();
  27. </script> -->
  28. </head>
  29. <style>
  30. body {
  31. margin: 0;
  32. padding: 0;
  33. }
  34. .box {
  35. width: 100vw;
  36. height: 100vh;
  37. box-sizing: border-box;
  38. background: #F7F9FC;
  39. }
  40. .page5 {
  41. width: 100vw;
  42. box-sizing: border-box;
  43. }
  44. .page_top {
  45. width: 100%;
  46. height: 144px;
  47. position: absolute;
  48. top: 0;
  49. left: 0;
  50. z-index: 1;
  51. background: #FFFFFF;
  52. border-radius: 0px 0px 15px 15px;
  53. }
  54. .client_top_box {
  55. padding: 15px 15px 0px;
  56. }
  57. .search_icon {
  58. width: 24px;
  59. height: 24px;
  60. }
  61. .search_input {
  62. padding: 0;
  63. }
  64. .search_input .van-search__content {
  65. padding: 0;
  66. border-radius: 19px;
  67. }
  68. .search_input .van-cell {
  69. padding: 0;
  70. }
  71. .search_input .van-field__body {
  72. display: flex;
  73. align-items: center;
  74. position: relative;
  75. }
  76. .search_input .van-field__body input{
  77. border: none;
  78. width: 100%;
  79. height: 40px;
  80. background: #FAFAFA;
  81. padding: 10px 36px 10px 15px;
  82. border-radius: 19px;
  83. }
  84. .search_input .van-field__body input:focus {
  85. outline: none;
  86. }
  87. .search_input .van-field__body .van-field__right-icon{
  88. position: absolute;
  89. right: 12px;
  90. }
  91. .type_list {
  92. display: flex;
  93. align-items: flex-end;
  94. gap: 25px;
  95. padding: 15px 0px 13px 15px;
  96. overflow-x: auto;
  97. }
  98. .type_list img {
  99. width: 40px;
  100. height: 40px;
  101. }
  102. .type_item {
  103. display: flex;
  104. flex-direction: column;
  105. align-items: center;
  106. }
  107. .type_title {
  108. font-size: 12px;
  109. line-height: 17px;
  110. white-space: nowrap;
  111. color: #999999;
  112. }
  113. .type_active {
  114. color: #222222;
  115. padding-top: 8px;
  116. }
  117. .page_content {
  118. background: #FFFFFF;
  119. border-radius: 15px 15px 0px 0px;
  120. position: absolute;
  121. top: 156px;
  122. left: 0;
  123. z-index: 1;
  124. width: 100%;
  125. }
  126. .page_box {
  127. padding: 15px 15px 0;
  128. }
  129. .path_list {
  130. display: flex;
  131. align-items: center;
  132. flex-wrap: nowrap;
  133. white-space: nowrap;
  134. width: 100%;
  135. overflow-x: auto;
  136. margin-bottom: 25px;
  137. }
  138. .path_span {
  139. font-size: 12px;
  140. color: #999999;
  141. line-height: 17px;
  142. }
  143. .page_foot {
  144. position: absolute;
  145. bottom: 39px;
  146. left: 0;
  147. width: 100%;
  148. }
  149. .filter_list {
  150. display: flex;
  151. flex-wrap: nowrap;
  152. white-space: nowrap;
  153. overflow-x: auto;
  154. padding: 10px 0px 10px 15px;
  155. background: #FAFAFA;
  156. }
  157. .filter_span {
  158. font-size: 12px;
  159. color: #999999;
  160. }
  161. .filter_count_blue {
  162. color: #136DFB;
  163. }
  164. .foot_btn {
  165. display: flex;
  166. justify-content: space-between;
  167. gap: 10px;
  168. padding: 10px 30px;
  169. background: #FFFFFF;
  170. box-shadow: 0px -3px 6px 1px rgba(0,0,0,0.05);
  171. }
  172. .btn_reset {
  173. border-radius: 20px;
  174. border: 1px solid #CCCCCC;
  175. font-weight: 500;
  176. font-size: 14px;
  177. color: #999999;
  178. padding: 15px 0;
  179. width: 100%;
  180. text-align: center;
  181. }
  182. .btn_confirm {
  183. border-radius: 20px;
  184. background: #1677FF;
  185. font-weight: 500;
  186. font-size: 14px;
  187. color: #FFFFFF;
  188. padding: 15px 0;
  189. width: 100%;
  190. text-align: center;
  191. }
  192. .data_list {
  193. gap: 25px;
  194. overflow-y: auto;
  195. }
  196. .data_item {
  197. display: flex;
  198. align-items: center;
  199. padding: 0 5px;
  200. margin-bottom: 25px;
  201. }
  202. .data_item img {
  203. width: 40px;
  204. height: 40px;
  205. }
  206. .data_title {
  207. font-size: 14px;
  208. color: #222222;
  209. line-height: 20px;
  210. display: -webkit-box;
  211. -webkit-line-clamp: 2;
  212. -webkit-box-orient: vertical;
  213. overflow: hidden;
  214. text-overflow: ellipsis;
  215. padding-right: 43px;
  216. padding-left: 12px;
  217. max-width: 279px;
  218. box-sizing: border-box;
  219. }
  220. .check_div {
  221. width: 16px;
  222. height: 16px;
  223. border-radius: 50%;
  224. border: 1px solid #CCCCCC;
  225. box-sizing: border-box;
  226. }
  227. .fold_item {
  228. display: flex;
  229. align-items: center;
  230. }
  231. .check_div_active {
  232. width: 16px;
  233. height: 16px;
  234. border-radius: 50%;
  235. border: 1px solid #136DFB;
  236. box-sizing: border-box;
  237. }
  238. .check_div_active:after{
  239. content: "";
  240. display: block;
  241. width: 10px;
  242. height: 10px;
  243. border-radius: 50%;
  244. background: #136DFB;
  245. position: relative;
  246. top: 2px;
  247. left: 2px;
  248. }
  249. .path_line {
  250. font-size: 12px;
  251. color: #999999;
  252. line-height: 17px;
  253. padding: 0 10px;
  254. }
  255. .path_item:last-child {
  256. color: #222222;
  257. }
  258. .filter_list1 {
  259. display: flex;
  260. flex-wrap: nowrap;
  261. white-space: nowrap;
  262. height: 146px;
  263. overflow-y: auto;
  264. background: #FFFFFF;
  265. box-sizing: border-box;
  266. padding: 5px 15px 20px;
  267. gap: 15px;
  268. }
  269. .filter_list1 img {
  270. width: 60px;
  271. height: 60px;
  272. font-size: 14px;
  273. line-height: 20px;
  274. margin-bottom: 10px;
  275. }
  276. .filter_img {
  277. width: 100%;
  278. color: #136DFB;
  279. background: rgba(19, 109, 251, 0.05);
  280. display: flex;
  281. flex-direction: column;
  282. align-items: center;
  283. justify-content: center;
  284. border-radius: 15px;
  285. }
  286. .filter_exc {
  287. width: 100%;
  288. color: #999999;
  289. background: #FAFAFA;
  290. display: flex;
  291. flex-direction: column;
  292. align-items: center;
  293. justify-content: center;
  294. border-radius: 15px;
  295. }
  296. .imgList_list {
  297. display: flex;
  298. flex-wrap: wrap;
  299. overflow-x: auto;
  300. padding: 5px 15px 0;
  301. background: #FFFFFF;
  302. height: 446px;
  303. overflow-y: auto;
  304. box-sizing: border-box;
  305. gap: 15px;
  306. align-content: flex-start;
  307. }
  308. .imgList_list div {
  309. width: 105px;
  310. height: 140px;
  311. border-radius: 10px;
  312. position: relative;
  313. }
  314. .imgList_item {
  315. width: 105px;
  316. height: 140px;
  317. border-radius: 10px;
  318. object-fit: cover;
  319. }
  320. .imgList_select {
  321. width: 16px;
  322. height: 16px;
  323. position: absolute;
  324. top: 5px;
  325. right: 5px;
  326. }
  327. </style>
  328. <body>
  329. <div id="box" class="box">
  330. <div class="page5">
  331. <!-- 选择视频格式 -->
  332. <van-popup v-model="showVideoType" duration="0.2" round position="bottom" :close-on-click-overlay="false"
  333. :style="{ width: '100%', height: '266px' }">
  334. <div class="clientTag_title">
  335. <div class="close_icon"></div>
  336. <div>选择视频格式</div>
  337. <img class="close_icon" src="../img/qw/close_icon.png" alt="" @click="showVideoType = false">
  338. </div>
  339. <div class="filter_list1">
  340. <div :class="filterIndex ? 'filter_img' : 'filter_exc'" @click="filterIndex = 1">
  341. <img :src="filterIndex ? '../img/qw/video_type.png' : '../img/qw/video_type1.png'" alt="">
  342. <div>视频</div>
  343. </div>
  344. <div :class="filterIndex ? 'filter_exc' : 'filter_img'" @click="filterIndex = 0">
  345. <img :src="filterIndex ? '../img/qw/videoLink_type1.png' : '../img/qw/videoLink_type.png'" alt="">
  346. <div>视频链接</div>
  347. </div>
  348. </div>
  349. <div class="tag_footers">
  350. <div class="tag_re_btn" @click="showVideoType = false">取消</div>
  351. <div class="tag_ok_btn" @click="handleVideoType">确定</div>
  352. </div>
  353. </van-popup>
  354. <!-- 选择图集格式 -->
  355. <van-popup v-model="showImgType" duration="0.2" round position="bottom" :close-on-click-overlay="false"
  356. :style="{ width: '100%', height: '266px' }">
  357. <div class="clientTag_title">
  358. <div class="close_icon"></div>
  359. <div>选择图集格式</div>
  360. <img class="close_icon" src="../img/qw/close_icon.png" alt="" @click="showImgType = false">
  361. </div>
  362. <div class="filter_list1">
  363. <div :class="filterIndex ? 'filter_img' : 'filter_exc'" @click="filterIndex = 1">
  364. <img :src="filterIndex ? '../img/qw/img_type.png' : '../img/qw/img_type1.png'" alt="">
  365. <div>选择图片</div>
  366. </div>
  367. <div :class="filterIndex ? 'filter_exc' : 'filter_img'" @click="filterIndex = 0">
  368. <img :src="filterIndex ? '../img/qw/imgList_type1.png' : '../img/qw/imgList_type.png'" alt="">
  369. <div>图集链接</div>
  370. </div>
  371. </div>
  372. <div class="tag_footers">
  373. <div class="tag_re_btn" @click="showImgType = false">取消</div>
  374. <div class="tag_ok_btn" @click="handleImgType">确定</div>
  375. </div>
  376. </van-popup>
  377. <!-- 选择图集图片 -->
  378. <van-popup v-model="showImgList" duration="0.2" round position="bottom" :close-on-click-overlay="false"
  379. :style="{ width: '100%', height: '566px' }">
  380. <div class="clientTag_title">
  381. <div class="close_icon"></div>
  382. <div>选择图片</div>
  383. <img class="close_icon" src="../img/qw/close_icon.png" alt="" @click="handleCancel">
  384. </div>
  385. <div class="imgList_list">
  386. <div v-for="(item, index) in imgList" :key="item.id" @click="handleSelect(item)">
  387. <img class="imgList_item" :src="item.url" alt="">
  388. <img class="imgList_select" :src="item.selected ? '../img/qw/select_img.png' : '../img/qw/noselect_img.png'" alt="">
  389. </div>
  390. </div>
  391. <div class="tag_footers">
  392. <div class="tag_re_btn" @click="handleCancel">取消</div>
  393. <div class="tag_ok_btn" @click="handleImgList">保存</div>
  394. </div>
  395. </van-popup>
  396. <div class="page_top">
  397. <div class="client_top_box">
  398. <van-search class="search_input" placeholder="搜索素材名称" v-model="keyword" :clearable="false" left-icon=""
  399. @search="handleSearch">
  400. <!-- 自定义右侧图标 -->
  401. <template v-slot:right-icon>
  402. <img class="search_icon" src="../img/qw/search_icon.png" @click="handleSearch" />
  403. </template>
  404. </van-search>
  405. </div>
  406. <div class="type_list">
  407. <div class="type_item" v-for="item in typeList" :key="item.contentType" @click="handleTypeClick(item.contentType)">
  408. <img :src="item.contentType === contentType ? item.icon : item.icon1" alt="">
  409. <div :class="{'type_active': item.contentType === contentType}" class="type_title">{{item.title}}</div>
  410. </div>
  411. </div>
  412. </div>
  413. <div class="page_content">
  414. <div class="page_box">
  415. <div class="path_list">
  416. <div class="path_span">
  417. <span @click="getTreeData">全部</span>
  418. <span class="path_item" v-for="(item, index) in pathList" :key="index" @click="handlePathClick(item)">
  419. <span class="path_line">/</span>{{item.text}}</span>
  420. </div>
  421. </div>
  422. <div class="data_list" :style="{height: selectedMaters.length > 0 ? 'calc(100vh - 356px)' : 'calc(100vh - 213px)'}">
  423. <div class="data_item" v-for="item in treeData" :key="item.id" @click="handleFolderClick(item)">
  424. <img src="../img/qw/folder.png" alt="" />
  425. <div class="data_title">{{item.text}}</div>
  426. </div>
  427. <van-checkbox-group v-model="checkedMaterIds" @change="onChangeChecked">
  428. <div class="data_item fold_data_item" v-for="item in itemList" :key="item.id">
  429. <div class="fold_item">
  430. <img v-if="contentType === 0" src="../img/qw/article.png" alt="" />
  431. <img v-else-if="contentType === 2" src="../img/qw/form.png" alt="" />
  432. <img v-else-if="contentType === 3" src="../img/qw/file.png" alt="" />
  433. <img v-else-if="contentType === 15" src="../img/qw/video.png" alt="" />
  434. <img v-else-if="contentType === 17" src="../img/qw/imgList.png" alt="" />
  435. <img v-else-if="contentType === 4" src="../img/qw/link.png" alt="" />
  436. <div class="data_title">{{item.title || item.name}}</div>
  437. </div>
  438. <van-checkbox :name="item.id" @click="handleCheckboxClick(item)">
  439. <template #icon="props">
  440. <div :class="props.checked ? 'check_div_active' : 'check_div'"></div>
  441. </template>
  442. </van-checkbox>
  443. </div>
  444. </van-checkbox-group>
  445. </div>
  446. </div>
  447. </div>
  448. <div class="page_foot">
  449. <div class="filter_list"><span class="filter_span">全部:</span>
  450. <div class="filter_span" v-html="formatcontentTypes()"></div>
  451. </div>
  452. <div class="foot_btn">
  453. <div class="btn_reset" @click="handleReset">重置</div>
  454. <div class="btn_confirm" @click="handleConfirm">确定</div>
  455. </div>
  456. </div>
  457. </div>
  458. <!-- 底部返回栏 -->
  459. <page-return></page-return>
  460. </div>
  461. </body>
  462. <script>
  463. new Vue({
  464. el: '#box',
  465. data() {
  466. return {
  467. httpUrl: '',
  468. bId: null,
  469. env: '',
  470. memberId: null,
  471. tenancyId: null,
  472. keyword: '',
  473. contentType: 0, // 当前选中的类型
  474. typeList: [
  475. {
  476. contentType: 0,
  477. icon: '../img/qw/article.png',
  478. icon1: '../img/qw/article1.png',
  479. title: '文章'
  480. },
  481. {
  482. contentType: 2,
  483. icon: '../img/qw/form.png',
  484. icon1: '../img/qw/form1.png',
  485. title: '表单'
  486. },
  487. {
  488. contentType: 3,
  489. icon: '../img/qw/file.png',
  490. icon1: '../img/qw/file1.png',
  491. title: '文件'
  492. },
  493. {
  494. contentType: 15,
  495. icon: '../img/qw/video.png',
  496. icon1: '../img/qw/video1.png',
  497. title: '视频'
  498. },
  499. {
  500. contentType: 17,
  501. icon: '../img/qw/imgList.png',
  502. icon1: '../img/qw/imgList1.png',
  503. title: '图集'
  504. },
  505. {
  506. contentType: 4,
  507. icon: '../img/qw/link.png',
  508. icon1: '../img/qw/link1.png',
  509. title: '外部链接'
  510. },
  511. ],
  512. materTypeList: [
  513. {
  514. contentType: 0,
  515. title: '文章'
  516. },
  517. {
  518. contentType: 2,
  519. title: '表单'
  520. },
  521. {
  522. contentType: 3,
  523. title: '文件'
  524. },
  525. {
  526. contentType: 15,
  527. title: '视频'
  528. },
  529. {
  530. contentType: 17,
  531. title: '图集'
  532. },
  533. {
  534. contentType: 4,
  535. title: '外部链接'
  536. },
  537. {
  538. contentType: 19,
  539. title: '图集项图片'
  540. },
  541. ],
  542. treeData: [], // 总树数据
  543. allTreeData: [], // 总树扁平化数据
  544. loading: false,
  545. itemList: [], // 当前树下的数据
  546. checkedMaterIds: [],
  547. selectedMaters: [], // 当前选中的所有素材数据
  548. pathList: [], // 当前路径
  549. contentTypeCount: {}, // 当前选中的类型数量
  550. filterIndex: 1,
  551. showImgType: false,
  552. showImgList: false,
  553. imgList: [], // 图集图片列表
  554. showVideoType: false
  555. }
  556. },
  557. created() {
  558. this.bId = this.getQueryParam('bId')
  559. this.env = this.getQueryParam('env')
  560. if (!this.env || this.env === 'prod') {
  561. this.httpUrl = 'https://wlapi.wefanbot.com'
  562. } else {
  563. this.httpUrl = 'http://test.wefanbot.com:18993'
  564. }
  565. this.selectedMaters = localStorage.getItem('selectedMaters') ? JSON.parse(localStorage.getItem('selectedMaters')) : []
  566. this.contentTypeCount = this.countByType(this.selectedMaters)
  567. if (this.getQueryParam('memberId')) {
  568. // 已授权
  569. this.memberId = this.getQueryParam('memberId')
  570. this.getCpH5Login()
  571. }
  572. },
  573. methods: {
  574. getCpH5Login() {
  575. fetch(this.httpUrl + '/scrm/v1/wxcp-workbench/p/cpH5Login', {
  576. method: 'post',
  577. body: JSON.stringify({
  578. bid: this.bId,
  579. memberId: this.memberId,
  580. }),
  581. headers: {
  582. 'Content-Type': 'application/json'
  583. }
  584. }).then(res => {
  585. return res.json()
  586. }).then(result => {
  587. let { data, code, msg } = result
  588. if (code === 1) {
  589. this.tenancyId = data.tenancyId
  590. this.getTreeData()
  591. } else {
  592. vant.Toast.fail(msg)
  593. }
  594. })
  595. },
  596. // 获取树数据
  597. getTreeData() {
  598. this.treeData = []
  599. this.allTreeData = []
  600. this.itemList = []
  601. this.pathList = []
  602. let url = ''
  603. if (this.contentType === 0) {
  604. url = '/scrm/v1/wxcp-chat-tool/p/ctArticleGroupTree'
  605. } else if (this.contentType === 2) {
  606. url = '/scrm/v1/wxcp-chat-tool/p/ctFormGroupTree'
  607. } else if (this.contentType === 3) {
  608. url = '/scrm/v1/wxcp-chat-tool/p/ctFileGroupTree'
  609. } else if (this.contentType === 15) {
  610. url = '/scrm/v1/wxcp-chat-tool/p/ctVideoGroupTree'
  611. } else if (this.contentType === 17) {
  612. url = '/scrm/v1/wxcp-chat-tool/p/ctImgGroupTree'
  613. } else if (this.contentType === 4) {
  614. url = '/scrm/v1/wxcp-chat-tool/p/ctUrlGroupTree'
  615. }
  616. this.loading = true
  617. fetch(this.httpUrl + url, {
  618. method: 'post',
  619. body: JSON.stringify({
  620. keyword: '',
  621. }),
  622. headers: {
  623. 'Content-Type': 'application/json',
  624. 'tenancyId': this.tenancyId,
  625. }
  626. }).then(res => {
  627. return res.json()
  628. }).then(result => {
  629. let { data, code, msg } = result
  630. if (code === 1) {
  631. this.treeData = data || []
  632. this.allTreeData = this.flattenTreeData(data, true)
  633. } else {
  634. vant.Toast.fail(msg)
  635. }
  636. }).finally(() => {
  637. this.loading = false
  638. })
  639. },
  640. handlePathClick (item) {
  641. // 找到目标元素的索引
  642. const index = this.pathList.findIndex(arr => arr.id === item.id)
  643. // 如果找到了该元素
  644. if (index !== -1) {
  645. // 从该索引位置开始删除到数组末尾
  646. this.pathList.splice(index)
  647. this.handleFolderClick(item)
  648. }
  649. },
  650. // 点击文件夹,获取子文件夹数据
  651. handleFolderClick(item) {
  652. this.pathList.push(item)
  653. this.getMaterData(item)
  654. },
  655. getMaterData (item) {
  656. this.treeData = []
  657. this.itemList = []
  658. let url = ''
  659. if (this.contentType === 0) {
  660. url = '/scrm/v1/wxcp-chat-tool/p/pageArticle'
  661. } else if (this.contentType === 2) {
  662. url = '/scrm/v1/wxcp-chat-tool/p/pageForm'
  663. } else if (this.contentType === 3) {
  664. url = '/scrm/v1/wxcp-chat-tool/p/pageFile'
  665. } else if (this.contentType === 15) {
  666. url = '/scrm/v1/wxcp-chat-tool/p/pageVideo'
  667. } else if (this.contentType === 17) {
  668. url = '/scrm/v1/wxcp-chat-tool/p/pageImg'
  669. } else if (this.contentType === 4) {
  670. url = '/scrm/v1/wxcp-chat-tool/p/pageUrl'
  671. }
  672. fetch(this.httpUrl + url, {
  673. method: 'post',
  674. body: JSON.stringify({
  675. groupId: item ? item.id : null,
  676. keyword: this.keyword,
  677. page: 1,
  678. pageCount: 1000,
  679. }),
  680. headers: {
  681. 'Content-Type': 'application/json',
  682. 'tenancyId': this.tenancyId,
  683. }
  684. }).then(res => {
  685. return res.json()
  686. }).then(result => {
  687. let { data, code, msg } = result
  688. if (code === 1) {
  689. this.itemList = data.records || []
  690. if (this.itemList.length > 0) {
  691. // 回显已选择的数据
  692. this.checkedMaterIds = this.extractSameIds(this.itemList, this.selectedMaters)
  693. }
  694. if (this.keyword === '' && this.allTreeData.filter(all => all.id === item.id)[0] && this.allTreeData.filter(all => all.id === item.id)[0].children) {
  695. this.treeData = this.allTreeData.filter(all => all.id === item.id)[0].children
  696. } else {
  697. this.treeData = []
  698. }
  699. } else {
  700. vant.Toast.fail(msg)
  701. }
  702. })
  703. },
  704. handleSearch() {
  705. if (this.keyword === '') {
  706. this.getTreeData()
  707. } else {
  708. this.getMaterData()
  709. }
  710. },
  711. extractSameIds(itemList, selectedMaters) {
  712. const arr2Ids = new Set(selectedMaters.map(item => item.id))
  713. return itemList.filter(item => arr2Ids.has(item.id))
  714. .map(item => item.id)
  715. },
  716. // 点击类型,获取树数据
  717. handleTypeClick(type) {
  718. this.keyword = '' // 点击谁,就把谁的图标变成item.icon,其余的变成icon1
  719. this.contentType = type
  720. this.getTreeData()
  721. },
  722. onChangeChecked(value) {
  723. // 更新当前页面的勾选状态
  724. // this.checkedMaterIds = value
  725. // 当前页面选中的,并标记类型
  726. const currentSelected = this.itemList
  727. .filter(item => this.checkedMaterIds.includes(item.id))
  728. .map(item => ({
  729. ...item,
  730. contentType: this.contentType // 标记素材类型
  731. }))
  732. // 先删除当前页面未选中的数据
  733. const currentPageIds = new Set(this.itemList.map(item => item.id))
  734. this.selectedMaters = this.selectedMaters.filter(item => {
  735. // 如果是当前页面的数据,但未选中,则删除
  736. if (currentPageIds.has(item.id)) {
  737. return this.checkedMaterIds.includes(item.id)
  738. }
  739. // 如果不是当前页面的数据,保留
  740. return true
  741. })
  742. // 合并当前选中的和之前选中的,基于 id 去重(当前选中的优先,使用最新的类型)
  743. const existingIdsMap = new Map()
  744. this.selectedMaters.forEach(item => {
  745. existingIdsMap.set(item.id, item)
  746. })
  747. // 更新或添加当前选中的数据(优先使用当前页面的数据和类型)
  748. currentSelected.forEach(item => {
  749. existingIdsMap.set(item.id, item)
  750. })
  751. this.selectedMaters = Array.from(existingIdsMap.values())
  752. console.log('当前选中的所有素材数据: ', this.selectedMaters)
  753. this.contentTypeCount = this.countByType(this.selectedMaters)
  754. },
  755. // 统计数组中每个类型的数量
  756. countByType(arr) {
  757. return arr.reduce((countMap, item) => {
  758. const type = item.contentType;
  759. countMap[type] = (countMap[type] || 0) + 1;
  760. return countMap;
  761. }, {});
  762. },
  763. // 格式化选中类型的显示文本,格式:文章 x1、文件 x2(数字部分为蓝色)
  764. formatcontentTypes() {
  765. const typeCountArr = []
  766. // 遍历 typeList 的顺序,确保显示顺序一致
  767. this.materTypeList.forEach(typeItem => {
  768. const count = this.contentTypeCount[typeItem.contentType] || 0
  769. if (count > 0) {
  770. // 将数字部分用span包裹,添加蓝色样式类
  771. typeCountArr.push(`${typeItem.title} <span class="filter_count_blue">x${count}</span>`)
  772. }
  773. })
  774. return typeCountArr.length > 0 ? typeCountArr.join('、') : ''
  775. },
  776. // 递归扁平化树数据
  777. flattenTreeData(data, keepChildren = true) {
  778. const result = []
  779. function traverse(nodes) {
  780. if (!Array.isArray(nodes)) return
  781. nodes.forEach(node => {
  782. const flatNode = { ...node }
  783. // 如果不保留children,删除该属性
  784. if (!keepChildren) {
  785. delete flatNode.children
  786. }
  787. result.push(flatNode)
  788. // 递归遍历子节点
  789. if (node.children && node.children.length > 0) {
  790. traverse(node.children)
  791. }
  792. })
  793. }
  794. traverse(data)
  795. return result
  796. },
  797. handleConfirm() {
  798. if (this.selectedMaters.length === 0) {
  799. vant.Toast.fail('请选择素材')
  800. return
  801. }
  802. localStorage.setItem('selectedMaters', JSON.stringify(this.selectedMaters))
  803. if (this.selectedMaters.length > 9) {
  804. vant.Toast.fail('最多选择9个素材')
  805. return
  806. }
  807. window.history.back()
  808. },
  809. handleCheckboxClick (item) {
  810. // if (this.contentType === 16) {
  811. // if (this.selectedMaters.some(s => s.id === item.id)) {
  812. // this.showVideoType = true
  813. // }
  814. // } else
  815. if (this.contentType === 17) {
  816. if (this.selectedMaters.some(s => s.id === item.id)) {
  817. this.showImgType = true
  818. }
  819. }
  820. },
  821. handleVideoType () {
  822. // this.showVideoType = false
  823. // let obj = this.selectedMaters[this.selectedMaters.length - 1]
  824. // this.selectedMaters.push({
  825. // contentType: this.filterIndex === 1 ? 15 : 16,
  826. // ...obj,
  827. // })
  828. // this.contentTypeCount = this.countByType(this.selectedMaters)
  829. },
  830. handleImgType () {
  831. if (this.filterIndex === 0) {
  832. this.showImgType = false
  833. } else {
  834. this.showImgType = false
  835. this.imgList = this.selectedMaters[this.selectedMaters.length-1].imgList
  836. this.selectedMaters.pop() // 删除最后一条数据(点击自动添加进去的图集项链接)
  837. this.checkedMaterIds.pop()
  838. this.selectedMaters.forEach(s => {
  839. this.imgList.forEach(item => {
  840. if (s.id === item.id) {
  841. this.$set(item, 'selected', true)
  842. } else {
  843. this.$set(item, 'selected', false)
  844. }
  845. })
  846. })
  847. this.showImgList = true
  848. }
  849. },
  850. handleSelect(data) {
  851. this.imgList.forEach(item => {
  852. if (item.id === data.id) {
  853. this.$set(item, 'selected', !item.selected)
  854. }
  855. })
  856. },
  857. handleCancel () {
  858. this.showImgList = false
  859. },
  860. handleImgList () {
  861. this.imgList.forEach(item => {
  862. if (item.selected) {
  863. this.selectedMaters.push({
  864. contentType: 19,
  865. ...item,
  866. })
  867. }
  868. })
  869. this.showImgList = false
  870. this.contentTypeCount = this.countByType(this.selectedMaters)
  871. },
  872. handleReset() {
  873. this.selectedMaters = []
  874. this.checkedMaterIds = []
  875. this.contentTypeCount = {}
  876. localStorage.removeItem('selectedMaters')
  877. },
  878. // 截取url中的数据
  879. getQueryParam(paramName) {
  880. // 获取当前URL的查询字符串部分
  881. const queryString = window.location.search;
  882. // 创建一个URLSearchParams对象
  883. const urlParams = new URLSearchParams(queryString);
  884. // 返回指定参数的值,如果不存在则返回null
  885. return urlParams.get(paramName);
  886. },
  887. }
  888. })
  889. </script>
  890. </html>