index.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. <template>
  2. <app-layout>
  3. <view class="bg">
  4. <cover-view v-if="friendModel" class="friend-box">
  5. <cover-view class="info main-center cross-center dir-top-nowrap">
  6. <cover-view class="dir-left-nowrap cross-center">
  7. <cover-image src="../../../static/image/icon/friend-v.png" class="icon"></cover-image>
  8. <cover-view class="text">文本已复制到剪贴板</cover-view>
  9. </cover-view>
  10. <cover-view class="dir-left-nowrap cross-center" style="margin-top: 30rpx">
  11. <cover-image src="../../../static/image/icon/friend-v.png" class="icon"></cover-image>
  12. <cover-view v-if="is_video" class="text">视频已保存到相册</cover-view>
  13. <cover-view v-else class="text">图片已保存到相册</cover-view>
  14. </cover-view>
  15. </cover-view>
  16. </cover-view>
  17. <view>
  18. <text id="opacity-hide" class="opacity-hide">
  19. 第一行
  20. 第二行
  21. 第三行
  22. 第四行
  23. 第五行
  24. </text>
  25. <view class="fixed">
  26. <view class="share-head-margin">
  27. <view class="share-head dir-left-nowrap">
  28. <view class="box-grow-1 main-center cross-center"
  29. :class="[`goods`, tab===`goods`? `${tab}-active`: '']"
  30. @click="tabChange(`goods`)">商品
  31. </view>
  32. <view class="box-grow-1 main-center cross-center"
  33. :class="[`dynamic`, tab===`dynamic`? `${tab}-active`: '']"
  34. @click="tabChange(`dynamic`)">动态
  35. </view>
  36. </view>
  37. </view>
  38. <view class="share-center dir-left-nowrap" v-if="tab === `goods`">
  39. <view class="dir-left-nowrap cross-center value">
  40. <view @click="sortChange(sort===1?2:1)" :class="[sort===1 || sort===2 ? `active`: ``]">最新商品
  41. </view>
  42. <icon v-if="sort === 1" class="sort-plus" type></icon>
  43. <icon v-else-if="sort === 2" class="sort-less" type></icon>
  44. <icon v-else class="sort-default" type></icon>
  45. </view>
  46. <view class="dir-left-nowrap cross-center value">
  47. <view @click="sortChange(sort===3?4:3)" :class="[sort===3 || sort===4 ? `active`: ``]">最新素材
  48. </view>
  49. <icon v-if="sort === 3" class="sort-plus" type></icon>
  50. <icon v-else-if="sort === 4" class="sort-less" type></icon>
  51. <icon v-else class="sort-default" type></icon>
  52. </view>
  53. <view class="dir-left-nowrap cross-center value">
  54. <view @click="sortChange(sort===5?6:5)" :class="[sort===5 || sort===6 ? `active`: ``]">销量
  55. </view>
  56. <icon v-if="sort === 5" class="sort-plus" type></icon>
  57. <icon v-else-if="sort === 6" class="sort-less" type></icon>
  58. <icon v-else class="sort-default" type></icon>
  59. </view>
  60. </view>
  61. </view>
  62. <view :class="tab + `-margin`">
  63. <view class="share-goods" v-for="(item,index) in list" :key="index">
  64. <view v-if="item.is_top" class="goods-top dir-left-nowrap">
  65. <icon class="top box-grow-0" type></icon>
  66. <view>置顶</view>
  67. </view>
  68. <view class="goods-head dir-left-nowrap">
  69. <view class="dir-top-nowrap">
  70. <view class="t-omit goods-name">{{item.mall_name}}</view>
  71. <view class="goods-time">{{item.format_time}}</view>
  72. </view>
  73. <view v-if="tab === `goods`" @click="navDetail(item)"
  74. class="goods-detail main-center box-grow-0 cross-center">商品详情
  75. </view>
  76. </view>
  77. <view class="goods-text">
  78. <text class="opacity-hide" space="nbsp" :id="`all_hide_text_` + index"
  79. v-text="item.share_text"></text>
  80. <text class="share-text" :class="{'limit': allTextList.indexOf(index) === -1}"
  81. space="nbsp" v-text="item.share_text"></text>
  82. <view v-if="item.is_all_btn" class="all" @click="showText(index)">
  83. <block v-if="allTextList.indexOf(index) === -1">全文</block>
  84. <block v-else>收起</block>
  85. </view>
  86. </view>
  87. <view v-if="item.goods_id ===0 && item.material_video_url" class="goods-video">
  88. <video :src="item.material_video_url" show-mute-btn
  89. :poster="item.material_cover_url"></video>
  90. </view>
  91. <view v-else class="goods-image dir-left-wrap">
  92. <view v-for="(item1,index1) in item.share_pic" :key="index1">
  93. <image @click="previewImage(item.share_pic, index1)" :src="item1.pic_url" lazy-load></image>
  94. </view>
  95. </view>
  96. <view class="goods-set cross-center dir-left-nowrap">
  97. <view class="box-grow-1 main-center">
  98. <!-- #ifdef MP-BAIDU || MP-ALIPAY -->
  99. <view class="box-grow-1 main-center" @click="copyText(item)">复制文本</view>
  100. <!-- #endif -->
  101. <!-- #ifndef MP-BAIDU || MP-ALIPAY -->
  102. <view class="box-grow-1 main-center" @click="copyText(item)">复制文本</view>
  103. <!-- #endif -->
  104. <!-- #ifdef MP-WEIXIN -->
  105. <view class="box-grow-1 main-center" @click="saveImage(item)"
  106. v-if="item.goods_id ===0 && item.material_video_url">下载视频
  107. </view>
  108. <view class="box-grow-1 main-center" v-else @click="saveImage(item)">保存图片</view>
  109. <!-- #endif -->
  110. <!-- #ifndef MP-WEIXIN -->
  111. <view class="box-grow-1 main-center" v-if="item.goods_id !==0 || !item.material_video_url" @click="saveImage(item)">保存图片</view>
  112. <!-- #endif -->
  113. <!-- #ifndef MP-BAIDU -->
  114. <view class="box-grow-1 main-center" @click="setPoster(item)">生成海报</view>
  115. <!-- #endif -->
  116. </view>
  117. <view class="line"></view>
  118. <view class="box-grow-0">分享到</view>
  119. <image @click="batchCopy(item)" class="friend box-grow-0"></image>
  120. <view style="width: 50rpx">
  121. <app-jump-button open_type="share">
  122. <image @click="shareCard(item)" class="card"></image>
  123. </app-jump-button>
  124. </view>
  125. <!-- #ifdef MP_WEIXIN || H5 -->
  126. <image v-if="item.is_video_number && tab==='goods'" @click="videoNumber(item)" class="video-number box-grow-0"></image>
  127. <!-- #endif -->
  128. </view>
  129. </view>
  130. </view>
  131. <view class="box" :class="{'app-show-hidden': posterShow}">
  132. <app-goods-preview-poster
  133. v-model="posterShow" @close="posterShow = false" :url="posterUrl"
  134. ></app-goods-preview-poster>
  135. </view>
  136. <!-- 视频号弹框 -->
  137. <app-share-video-number :goods-id="currentGoods.goods_id" :is-show="isShowVideoNumber" @close="closeVideoNumber"></app-share-video-number>
  138. </view>
  139. </view>
  140. </app-layout>
  141. </template>
  142. <script>
  143. import appGoodsPreviewPoster from '../../../components/page-component/goods/app-goods-preview-poster';
  144. import appShareVideoNumber from '../../../components/page-component/app-share-video-number/app-share-video-number.vue';
  145. export default {
  146. name: "index",
  147. components: {
  148. appGoodsPreviewPoster,
  149. appShareVideoNumber
  150. },
  151. data() {
  152. return {
  153. friendModel: false,
  154. is_video: false,
  155. tab: 'goods',
  156. sort: 1,
  157. page: 1,
  158. args: false,
  159. load: false,
  160. list: [],
  161. allTextList: [],
  162. shareData: {},
  163. posterShow: false,
  164. posterUrl: '',
  165. isShowVideoNumber: false,
  166. currentGoods: {}
  167. }
  168. },
  169. onReachBottom: function () {
  170. const self = this;
  171. if (self.args || self.load)
  172. return;
  173. self.load = true;
  174. let page = self.page + 1;
  175. self.$request({
  176. url: self.$api.quick_share.goods,
  177. data: {
  178. type: self.tab,
  179. sort: self.sort,
  180. page,
  181. }
  182. }).then(info => {
  183. if (info.code === 0) {
  184. //todo
  185. info.data.list.forEach(v => {
  186. v.is_all_btn = false;
  187. });
  188. [self.page, self.args, self.list] = [page, info.data.list.length === 0, self.list.concat(info.data.list)];
  189. self.formatList();
  190. }
  191. self.load = false;
  192. });
  193. },
  194. onLoad() { this.$commonLoad.onload();
  195. this.loadData();
  196. },
  197. // #ifdef MP
  198. onShareAppMessage(params) {
  199. if (params.from === 'button') {
  200. return this.$shareAppMessage(this.shareData);
  201. }
  202. },
  203. // #endif
  204. methods: {
  205. navDetail(column) {
  206. uni.navigateTo({url: `/pages/goods/goods?id=` + column.goods_id});
  207. },
  208. previewImage(list, index) {
  209. const urls = list.map(item => {
  210. return item.pic_url;
  211. });
  212. uni.previewImage({
  213. urls: urls,
  214. current: index,
  215. });
  216. },
  217. showText(index) {
  218. let key = this.allTextList.indexOf(index);
  219. if (key === -1) {
  220. this.allTextList.splice(-1, 0, index);
  221. } else {
  222. this.allTextList.splice(key, 1);
  223. }
  224. },
  225. sortChange(sort) {
  226. [this.list, this.allTextList] = [[], []];
  227. [this.page, this.args, this.sort] = [1, false, sort];
  228. this.loadData();
  229. },
  230. tabChange(tab) {
  231. [this.list, this.allTextList] = [[], []];
  232. [this.page, this.args, this.tab] = [1, false, tab];
  233. this.loadData();
  234. },
  235. loadData() {
  236. const self = this;
  237. self.$showLoading({text: '加载中'});
  238. self.$request({
  239. url: self.$api.quick_share.goods,
  240. data: {
  241. page: 1,
  242. type: self.tab,
  243. sort: self.sort,
  244. }
  245. }).then(info => {
  246. self.$hideLoading();
  247. if (info.code === 0) {
  248. info.data.list.forEach(v => {
  249. v.is_all_btn = false;
  250. })
  251. self.list = info.data.list;
  252. self.formatList();
  253. }
  254. }).catch(info => {
  255. self.$hideLoading();
  256. })
  257. },
  258. formatList() {
  259. const self = this;
  260. setTimeout(() => {
  261. let list = JSON.parse(JSON.stringify(self.list));
  262. const query = uni.createSelectorQuery().in(this);
  263. query.select('#opacity-hide').boundingClientRect(item => {
  264. list.forEach((v, k) => {
  265. let key = uni.createSelectorQuery().in(self);
  266. key.select(`#all_hide_text_` + k).boundingClientRect(item1 => {
  267. v.is_all_btn = item1.height + 1 >= item.height;
  268. }).exec();
  269. });
  270. self.list = list;
  271. }).exec();
  272. })
  273. },
  274. saveImage(column, customize_success = false) {
  275. let self = this;
  276. self.is_video = column.goods_id === 0 && column.material_video_url;
  277. const customize_a = function () {
  278. uni.showToast({title: '保存成功'});
  279. };
  280. const customize_b = function () {
  281. self.friendModel = true;
  282. setTimeout(() => {
  283. self.friendModel = false;
  284. }, 1500)
  285. };
  286. if (self.is_video) {
  287. const share_video = column.material_video_url;
  288. self.$utils.batchSave(share_video, 'video').then(result => {
  289. customize_success ? customize_b() : customize_a();
  290. });
  291. } else {
  292. uni.showLoading({title: `图片保存中`});
  293. self.$request({
  294. url: self.$api.quick_share.poster_list,
  295. data: {
  296. id: column.id,
  297. }
  298. }).then(info => {
  299. if (info.code === 0) {
  300. let urls = column.share_pic.map(item => {
  301. return item.pic_url;
  302. })
  303. urls.splice(-1, 1, info.data.pic_url);
  304. self.$utils.batchSave(urls, 'image').then(result => {
  305. customize_success ? customize_b() : customize_a();
  306. });
  307. }
  308. }).catch(e => {
  309. uni.hideLoading();
  310. })
  311. }
  312. },
  313. setPoster(column) {
  314. if(this.tab === 'dynamic') {
  315. this.posterUrl = this.$api.quick_share.poster + `&id=` + column.id;
  316. this.posterShow = true;
  317. } else {
  318. const posterConfig = this.$api.quick_share.poster_config + '&id=' + column.id;
  319. const posterGenerate = this.$api.quick_share.poster_generate + '&id=' + column.id;
  320. uni.navigateTo({
  321. // #ifdef MP
  322. url : `/pages/poster/goods?poster_config=${escape(posterConfig)}&poster_generate=${escape(posterGenerate)}`
  323. // #endif
  324. // #ifdef H5
  325. url : `/pages/poster/goods?poster_config=${btoa(posterConfig)}&poster_generate=${btoa(posterGenerate)}`
  326. // #endif
  327. });
  328. }
  329. },
  330. copyText(column) {
  331. this.$utils.uniCopy({
  332. data: column.share_text,
  333. success() {
  334. //#ifndef MP-WEIXIN
  335. uni.showToast({title: '复制成功'});
  336. // #endif
  337. }
  338. });
  339. },
  340. batchCopy(column) {
  341. const self = this;
  342. this.copyText(column);
  343. //#ifdef H5
  344. if (column.goods_id === 0 && column.material_video_url) {
  345. this.$request({
  346. url: this.$api.quick_share.poster + `&id=` + column.id,
  347. }).then(response => {
  348. if (response.code === 0) {
  349. let shareImage = response.data.pic_url;
  350. self.$utils.batchSave(shareImage).then(result => {
  351. self.friendModel = true;
  352. setTimeout(() => {
  353. self.friendModel = false;
  354. }, 1500)
  355. });
  356. } else {
  357. uni.showModal({
  358. content: response.msg,
  359. showCancel: false
  360. });
  361. }
  362. });
  363. return;
  364. }
  365. // #endif
  366. this.saveImage(column, true);
  367. },
  368. shareCard(column) {
  369. this.shareShow = true;
  370. const title = column.app_share_title ? column.app_share_title : column.share_text;
  371. let imageUrl = '';
  372. if (column.share_pic[0].pic_url) {
  373. imageUrl = column.share_pic[0].pic_url;
  374. }
  375. if (column.app_share_pic) {
  376. imageUrl = column.app_share_pic;
  377. }
  378. this.shareData = {
  379. title: title,
  380. imageUrl: imageUrl,
  381. path: column.goods_id === 0 ? '/pages/index/index' : '/pages/goods/goods',
  382. params: column.goods_id === 0 ? {} : {id: column.goods_id},
  383. }
  384. // #ifdef H5
  385. this.$shareAppMessage(this.shareData, true);
  386. // #endif
  387. },
  388. closeVideoNumber() {
  389. this.isShowVideoNumber = false;
  390. },
  391. videoNumber(goods) {
  392. this.currentGoods = goods;
  393. this.isShowVideoNumber = true;
  394. }
  395. }
  396. }
  397. </script>
  398. <style scoped lang="scss">
  399. .bg {
  400. background: #FFFFFF;
  401. }
  402. .friend-box {
  403. position: fixed;
  404. top: #{563rpx};
  405. width: 100%;
  406. left: 0;
  407. z-index: 88;
  408. .info > cover-view:first-child {
  409. margin-bottom: #{30rpx};
  410. }
  411. .info {
  412. width: #{413rpx};
  413. height: #{209rpx};
  414. color: #ffffff;
  415. font-size: #{28rpx};
  416. border-radius: #{16rpx};
  417. margin: 0 auto;
  418. background: rgba(0, 0, 0, 0.8);
  419. cover-view {
  420. background: rgba(0, 0, 0, 0);
  421. }
  422. .text {
  423. padding-left: #{13rpx};
  424. }
  425. .icon {
  426. display: block;
  427. height: #{28rpx};
  428. width: #{28rpx};
  429. }
  430. }
  431. }
  432. .opacity-hide {
  433. position: fixed;
  434. top: 0;
  435. z-index: -10;
  436. opacity: 0;
  437. word-break: break-all;
  438. text-overflow: ellipsis;
  439. display: -webkit-box;
  440. -webkit-box-orient: vertical;
  441. overflow: hidden;
  442. white-space: normal !important;
  443. -webkit-line-clamp: 5;
  444. }
  445. .fixed {
  446. position: fixed;
  447. top: 0;
  448. width: 100%;
  449. z-index: 10;
  450. .share-head-margin {
  451. padding: #{23rpx} 0;
  452. background: #ffffff;
  453. .share-head {
  454. text-align: center;
  455. width: #{323rpx};
  456. margin: 0 auto;
  457. font-size: #{28rpx};
  458. height: #{56rpx};
  459. color: #666666;
  460. .goods {
  461. border-top-left-radius: #{30rpx};
  462. border-bottom-left-radius: #{30rpx};
  463. border-top: 1px solid #446dfd;
  464. border-bottom: 1px solid #446dfd;
  465. border-left: 1px solid #446dfd;
  466. }
  467. .dynamic {
  468. border-top-right-radius: #{30rpx};
  469. border-bottom-right-radius: #{30rpx};
  470. border-top: 1px solid #446dfd;
  471. border-bottom: 1px solid #446dfd;
  472. border-right: 1px solid #446dfd;
  473. }
  474. .dynamic-active, .goods-active {
  475. background: #446dfd;
  476. color: #ffffff;
  477. }
  478. }
  479. }
  480. .share-center {
  481. padding: 0 #{60rpx};
  482. height: #{96rpx};
  483. font-size: #{28rpx};
  484. background: #FFFFFF;
  485. justify-content: space-between;
  486. .value > view {
  487. margin-right: #{9rpx};
  488. }
  489. .active {
  490. color: #446dfd;
  491. }
  492. icon {
  493. background-repeat: no-repeat;
  494. background-size: 100% 100%;
  495. width: #{16upx};
  496. height: #{26upx};
  497. }
  498. .sort-default {
  499. background-image: url("../image/sort-blue-default.png");
  500. }
  501. .sort-less {
  502. background-image: url("../image/sort-blue-less.png");
  503. }
  504. .sort-plus {
  505. background-image: url("../image/sort-blue-plus.png");
  506. }
  507. }
  508. }
  509. .goods-margin {
  510. margin-top: #{196rpx};
  511. }
  512. .dynamic-margin {
  513. margin-top: #{100rpx};
  514. }
  515. .box {
  516. position: fixed;
  517. z-index: 1700;
  518. left: 0;
  519. bottom: 0;
  520. width: #{750rpx};
  521. opacity: 0;
  522. visibility: hidden;
  523. height: 100%;
  524. background-color: rgba(153, 153, 153, 0.5);
  525. }
  526. .app-show-hidden {
  527. opacity: 1;
  528. visibility: visible;
  529. }
  530. .share-goods {
  531. background: #FFFFFF;
  532. margin-bottom: #{15rpx};
  533. .goods-top {
  534. background: #FFFFFF;
  535. padding: #{14rpx} #{24rpx};
  536. font-size: #{26rpx};
  537. color: #ff4544;
  538. .top {
  539. background-repeat: no-repeat;
  540. background-size: 100% 100%;
  541. background-image: url("../image/goods-top.png");
  542. height: #{32rpx};
  543. width: #{28rpx};
  544. display: block;
  545. margin-right: #{12rpx};
  546. }
  547. }
  548. .goods-head {
  549. padding: #{40rpx} #{24rpx} 0 #{24rpx};
  550. .goods-name {
  551. color: #212121;
  552. font-size: #{34rpx};
  553. max-width: #{540rpx};
  554. line-height: 1;
  555. }
  556. .goods-time {
  557. margin-top: #{20rpx};
  558. color: #a0a0a0;
  559. font-size: #{24rpx};
  560. line-height: 1;
  561. }
  562. .goods-detail {
  563. color: #446dfd;
  564. font-size: #{26rpx};
  565. border: 1px solid #446dfd;
  566. border-radius: #{6rpx};
  567. height: #{50rpx};
  568. width: #{135rpx};
  569. margin-left: auto;
  570. }
  571. }
  572. .goods-text {
  573. padding: 0 #{24rpx};
  574. font-size: #{32rpx};
  575. color: #212121;
  576. margin-top: #{40rpx};
  577. .share-text {
  578. word-break: break-all;
  579. text-overflow: ellipsis;
  580. display: -webkit-box;
  581. -webkit-box-orient: vertical;
  582. overflow: hidden;
  583. white-space: normal !important;
  584. }
  585. .share-text.limit {
  586. -webkit-line-clamp: 4;
  587. }
  588. .all {
  589. padding-top: #{10rpx};
  590. color: #5b6a91;
  591. }
  592. }
  593. .goods-video {
  594. padding-top: #{15rpx};
  595. padding-bottom: #{30rpx};
  596. video {
  597. width: 100%;
  598. height: #{422rpx};
  599. }
  600. }
  601. .goods-image {
  602. padding: #{10rpx} #{18rpx} #{30rpx} #{18rpx};
  603. view {
  604. height: #{226rpx};
  605. width: #{226rpx};
  606. margin: #{6rpx};
  607. }
  608. image {
  609. height: 100%;
  610. width: 100%;
  611. display: block;
  612. }
  613. }
  614. .goods-set {
  615. color: #a0a0a0;
  616. font-size: #{28rpx};
  617. border-top: #{1rpx} solid #e2e2e2;
  618. padding: #{15rpx} #{24rpx} #{15rpx} 0;
  619. .margin {
  620. margin: 0 auto;
  621. }
  622. .line {
  623. height: #{60rpx};
  624. width: #{1px};
  625. margin-right: #{26rpx};
  626. background: #dcdfe6;
  627. }
  628. image {
  629. background-repeat: no-repeat;
  630. background-size: 100% 100%;
  631. height: #{50rpx};
  632. width: #{50rpx};
  633. }
  634. .friend {
  635. margin-right: #{15rpx};
  636. margin-left: #{20rpx};
  637. background-image: url("../image/friend.png");
  638. }
  639. .video-number {
  640. margin-left: #{20rpx};
  641. background-image: url("../../../static/image/icon/video-number-2.png");
  642. }
  643. .card {
  644. background-image: url("../image/wechat.png");
  645. }
  646. }
  647. }
  648. </style>