goods.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. <template>
  2. <app-layout>
  3. <view v-if="goods.id == ''" class="u-goods-detail"></view>
  4. <view class="app-goods" v-else>
  5. <!--商品轮播图-->
  6. <app-banner
  7. :videoUrl="goods.video_url"
  8. :share="goods.share"
  9. :picList="goods.pic_url"
  10. :goods_id="goods_id"
  11. :isCart="false"
  12. sign="community"
  13. ></app-banner>
  14. <!-- 商品时间 -->
  15. <app-goods-time
  16. :day="day"
  17. :second="second"
  18. :minute="minute"
  19. :hour="hour"
  20. :theme="getTheme"
  21. :status="activity.status"
  22. :goods="goods"
  23. ></app-goods-time>
  24. <view class="other-info">
  25. <view class="t-omit-two goods-name">{{goods.name}}</view>
  26. <view v-if="goods.subtitle" class="goods-subtitle">
  27. <view class="t-omit-three">{{goods.subtitle}}</view>
  28. </view>
  29. <view class="middleman dir-top-nowrap main-center">
  30. <view v-if="middleman.id > 0" class="middleman-info dir-left-nowrap">
  31. <image class="avatar" :src="middleman.avatar"></image>
  32. <view class="user-info">
  33. <view class="t-omit" style="width: 80%">{{middleman.name}}</view>
  34. <view class="t-omit-two middleman-address">
  35. <image class="icon" src="./../image/add.png"></image>
  36. <text>提货地址:{{middleman.province}}<text v-if="middleman.province != middleman.city">{{middleman.city}}</text>{{middleman.district}}{{middleman.detail}}</text>
  37. </view>
  38. </view>
  39. </view>
  40. <view v-if="activity.status != 2" class="app-share">
  41. <view @click="shareShow = true"
  42. :style="{'background-color': getTheme.background}"
  43. class="app-share-box dir-left-nowrap main-center cross-center">
  44. <image class="app-icon box-grow-0" src="/static/image/icon/icon-share-white.png"></image>
  45. <text class="app-text box-grow-0">分享</text>
  46. </view>
  47. </view>
  48. </view>
  49. <view>
  50. <bd-info-extra :unit="goods.unit" :goods="goods" :theme="getTheme" :min-number="goods.min_number" :limit-buy="goods.limit_buy"></bd-info-extra>
  51. </view>
  52. </view>
  53. <!--商品优惠券-->
  54. <bd-coupon @change="setCoupon" :theme="getTheme" :coupons="goods.goods_coupon_center"></bd-coupon>
  55. <bd-xbc
  56. v-if="goods"
  57. :coAttr="is_open"
  58. :attr-list="checked ? checked.attr_list : []"
  59. :type="goods.type"
  60. :guarantee-title="goods.guarantee_title"
  61. :guarantee-pic="goods.guarantee_pic"
  62. :param_content="goods.param_content"
  63. :param_name="goods.param_name"
  64. :services="goods.services"
  65. :attr-groups="goods.attr_groups"
  66. :goods-stock="goods.goods_stock"
  67. @openAttr="joinCart"
  68. ></bd-xbc>
  69. <bd-hc
  70. :integral="goods.goods_marketing_award.integral"
  71. :coupon="goods.goods_marketing_award.coupon"
  72. :card="goods.goods_marketing_award.card"
  73. :balance="goods.goods_marketing_award.balance"
  74. :theme="getTheme"
  75. ></bd-hc>
  76. <bd-kb
  77. :limit="goods.goods_marketing.limit"
  78. :express="goods.express"
  79. :shipping="goods.goods_marketing.shipping"
  80. :pickup="goods.goods_marketing.pickup"
  81. ></bd-kb>
  82. <bd-comments :goods-id="goods.id"></bd-comments>
  83. <bd-detail :detail="goods.detail"></bd-detail>
  84. <!--空格区域-->
  85. <view class="safe-area-inset-bottom">
  86. <view class="u-bottom-height"></view>
  87. </view>
  88. <!-- 底部按钮 -->
  89. <view v-if="is_open == 1" class="safe-area-inset-bottom u-bottom-fixed">
  90. <view class="bd-bottom dir-left-nowrap">
  91. <view class="bd-back dir-top-nowrap main-center cross-center box-grow-0" @click="back">
  92. <image class="bd-icon" src="./../image/activity.png"></image>
  93. <text class="bd-text">活动</text>
  94. </view>
  95. <view v-if="goods && goods.goods_stock > 0 && activity.status === 1" @click="joinCart"
  96. :style="{'background': goods.buy_goods_auth ? getTheme.background_gradient_btn : '#999999'}"
  97. class="'bd-btn box-grow-1 bd-btn-color">
  98. 加入购物车
  99. </view>
  100. <view class="box-grow-1 bd-btn bd-oversell-btn bd-btn-color" v-else>
  101. 加入购物车
  102. </view>
  103. </view>
  104. </view>
  105. </view>
  106. <app-close v-if="showClose" :modal="false" @update="getMall"></app-close>
  107. <!--商品规格-->
  108. <u-attr
  109. v-if="goods && goods.goods_stock > 0 && activity.status === 1"
  110. v-model="show"
  111. :goods="goods"
  112. :theme="getTheme"
  113. :checked="checked"
  114. :is_show_left="false"
  115. :right-func="true"
  116. right-text="加入购物车"
  117. @rightFunc="rightFunc"
  118. @check="check"
  119. >
  120. </u-attr>
  121. <app-share-qr-code
  122. v-model="shareShow"
  123. :url="url"
  124. :goods="goods"
  125. :poster-config="posterConfig"
  126. :poster-generate="posterGenerate"
  127. :has-poster-nav="hasPosterNav"
  128. @share="hShareAppMessage"
  129. ></app-share-qr-code>
  130. </app-layout>
  131. </template>
  132. <script>
  133. import {mapState, mapGetters} from 'vuex';
  134. import appBanner from '../../../components/page-component/goods/app-goods-banner.vue';
  135. import appGoodsTime from '../components/app-goods-time.vue';
  136. import appShareQrCode from '../../../components/page-component/app-share-qr-code-poster/app-share-qr-code-poster.vue';
  137. import uAttr from '../../../components/page-component/goods/u-attr.vue';
  138. import appClose from '@/components/basic-component/app-close/app-close.vue';
  139. import bdCoupon from '@/components/page-component/goods/bd-coupon.vue';
  140. import bdXbc from '@/components/page-component/goods/bd-xbc.vue';
  141. import bdKb from '@/components/page-component/goods/bd-kb.vue';
  142. import bdHc from '@/components/page-component/goods/bd-hc.vue';
  143. import bdDetail from '@/components/page-component/goods/bd-detail.vue';
  144. import bdComments from '@/components/page-component/goods/bd-comments.vue';
  145. import bdInfoExtra from '@/components/page-component/goods/bd-info-extra.vue';
  146. export default {
  147. name: 'goods',
  148. data() {
  149. return {
  150. showClose: false,
  151. is_open: 0,
  152. goods: {
  153. id: '',
  154. name: '',
  155. cover_pic: '',
  156. price: '',
  157. },
  158. middleman: {},
  159. activity: {},
  160. hasPosterNav: true,
  161. posterConfig: this.$api.community.goods_config,
  162. posterGenerate: this.$api.community.goods_generate,
  163. isShowBuy: false,
  164. shareShow: false,
  165. checked: null,
  166. url: '',
  167. show: false,
  168. list: [],
  169. goods_id: -1,
  170. hour: 0,
  171. minute: 0,
  172. second: 0,
  173. longitude: 0,
  174. latitude: 0,
  175. day: 0,
  176. loading: false,
  177. first: true,
  178. middleman_id: 0,
  179. disable: 'disable'
  180. }
  181. },
  182. onLoad(options) { this.$commonLoad.onload(options);
  183. let that = this;
  184. // #ifdef MP-WEIXIN
  185. wx.showShareMenu({
  186. menus: ['shareAppMessage', 'shareTimeline']
  187. })
  188. // #endif
  189. that.goods_id = options.goods_id;
  190. that.posterConfig = that.posterConfig + '&goods_id=' + that.goods_id;
  191. that.posterGenerate = that.posterGenerate + '&goods_id=' + that.goods_id;
  192. if(options.middleman_id > 0) {
  193. that.middleman_id = options.middleman_id;
  194. that.$showLoading({
  195. type: 'global',
  196. text: '加载中...'
  197. });
  198. that.request({
  199. url: that.$api.community.goods_detail,
  200. data: {
  201. goods_id: that.goods_id,
  202. middleman_id: that.middleman_id,
  203. }
  204. }).then(response => {
  205. that.first = false;
  206. let { goods, activity,middleman } = response;
  207. that.goods = goods;
  208. that.goods.price = that.goods.price.toString();
  209. that.activity = activity;
  210. that.middleman = middleman;
  211. that.loading = true;
  212. that.url = `${that.$api.goods.poster}&goods_id=${that.goods.id}`;
  213. if(activity.time > 0) {
  214. that.getTime(activity.time);
  215. }
  216. that.$hideLoading();
  217. // #ifdef H5
  218. that.hShareAppMessage();
  219. // #endif
  220. });
  221. }else {
  222. // #ifndef H5
  223. uni.getLocation({
  224. success: (e) => {
  225. uni.hideLoading();
  226. that.longitude = e.longitude;
  227. that.latitude = e.latitude;
  228. that.$showLoading({
  229. type: 'global',
  230. text: '加载中...'
  231. });
  232. that.request({
  233. url: that.$api.community.goods_detail,
  234. data: {
  235. goods_id: that.goods_id,
  236. longitude: that.longitude,
  237. latitude: that.latitude
  238. }
  239. }).then(response => {
  240. that.first = false;
  241. let { goods, activity,middleman } = response;
  242. that.goods = goods;
  243. that.activity = activity;
  244. that.middleman = middleman;
  245. that.loading = true;
  246. that.url = `${that.$api.goods.poster}&goods_id=${that.goods.id}`;
  247. if(activity.time > 0) {
  248. that.getTime(activity.time);
  249. }
  250. that.$hideLoading();
  251. });
  252. },
  253. fail: () => {
  254. uni.hideLoading();
  255. uni.showModal({
  256. title: '提示',
  257. content: '获取位置信息失败,需要授权获取您的位置信息',
  258. showCancel: false,
  259. confirmText: '打开授权',
  260. success(e) {
  261. if (e.confirm) {
  262. uni.openSetting({});
  263. }
  264. }
  265. });
  266. },
  267. });
  268. // #endif
  269. // #ifdef H5
  270. that.$jwx.getLocation({
  271. success: (e) => {
  272. uni.hideLoading();
  273. that.longitude = e.longitude;
  274. that.latitude = e.latitude;
  275. that.$showLoading({
  276. type: 'global',
  277. text: '加载中...'
  278. });
  279. that.request({
  280. url: that.$api.community.goods_detail,
  281. data: {
  282. goods_id: that.goods_id,
  283. longitude: that.longitude,
  284. latitude: that.latitude
  285. }
  286. }).then(response => {
  287. that.first = false;
  288. let { goods, activity,middleman } = response;
  289. that.detail = goods;
  290. that.activity = activity;
  291. that.middleman = middleman;
  292. that.loading = true;
  293. that.url = `${that.$api.goods.poster}&goods_id=${that.detail.id}`;
  294. if(activity.time > 0) {
  295. that.getTime(activity.time);
  296. }
  297. that.$hideLoading();
  298. });
  299. },
  300. fail: function () {
  301. uni.showToast({
  302. title: '请开启手机位置权限',
  303. icon: 'none',
  304. duration: 1000
  305. });
  306. },
  307. })
  308. // #endif
  309. }
  310. },
  311. onShow() {
  312. this.showClose = false;
  313. setTimeout(()=>{
  314. this.showClose = true;
  315. })
  316. if(this.first) {
  317. return false
  318. }
  319. this.$showLoading();
  320. this.$nextTick(() => {
  321. this.request({
  322. url: this.$api.community.goods_detail,
  323. data: {
  324. goods_id: this.goods_id,
  325. middleman_id: this.middleman_id,
  326. longitude: this.longitude,
  327. latitude: this.latitude
  328. }
  329. }).then(response => {
  330. let { goods, activity,middleman } = response;
  331. this.goods = goods;
  332. this.activity = activity;
  333. this.middleman = middleman;
  334. this.loading = true;
  335. this.url = `${this.$api.goods.poster}&goods_id=${this.goods.id}`;
  336. if(activity.time > 0) {
  337. this.getTime(activity.time);
  338. }
  339. this.$hideLoading();
  340. });
  341. })
  342. },
  343. onHide() {
  344. clearInterval(this.time);
  345. },
  346. onUnload() {
  347. clearInterval(this.time);
  348. },
  349. computed: {
  350. ...mapGetters('mallConfig', {
  351. getTheme: 'getTheme',
  352. }),
  353. ...mapState({
  354. mall: state => state.mallConfig.mall,
  355. userInfo: state => state.user.info,
  356. })
  357. },
  358. // #ifdef MP-WEIXIN
  359. onShareTimeline() {
  360. // 分享朋友圈beta
  361. return this.$shareTimeline({
  362. title: this.goods.app_share_title ? this.goods.app_share_title : this.goods.name,
  363. imageUrl: this.goods.pic_url[0].pic_url,
  364. query: {
  365. goods_id: this.goods.id,
  366. user_id: this.userInfo.options.user_id
  367. }
  368. });
  369. },
  370. // #endif
  371. // #ifdef MP
  372. onShareAppMessage() {
  373. return this.hShareAppMessage();
  374. },
  375. // #endif
  376. methods: {
  377. hShareAppMessage(s = false){
  378. let { app_share_title, app_share_pic, name, id, pic_url, subtitle} = this.goods;
  379. return this.$shareAppMessage({
  380. path: '/plugins/community/goods/goods',
  381. title: app_share_title ? app_share_title : name,
  382. imageUrl: app_share_pic ? app_share_pic : pic_url[0].pic_url,
  383. desc: subtitle,
  384. params: {
  385. goods_id: id,
  386. user_id: this.userInfo.options.user_id
  387. }
  388. },s);
  389. },
  390. getMall(e) {
  391. this.is_open = e.is_open;
  392. },
  393. async request({url, data}) {
  394. const response = await this.$request({
  395. url: url,
  396. data: data,
  397. });
  398. if (response.code === 0) {
  399. return response.data;
  400. }else {
  401. uni.showToast({
  402. title: response.msg,
  403. icon: 'none',
  404. duration: 1000
  405. });
  406. if(response.msg === '所选活动已下架' || response.msg === '所选活动不存在' ) {
  407. setTimeout(()=>{
  408. uni.navigateBack({});
  409. },1000);
  410. }
  411. if(response.msg == '所选商品不在活动中') {
  412. uni.showToast({
  413. title: response.msg,
  414. icon: 'none',
  415. duration: 1000
  416. });
  417. setTimeout(()=>{
  418. uni.redirectTo({
  419. url: '/plugins/community/list/list'
  420. });
  421. },1000)
  422. return false
  423. }
  424. }
  425. },
  426. check({item}) {
  427. this.checked = item;
  428. },
  429. back() {
  430. uni.redirectTo({
  431. url: '/plugins/community/list/list'
  432. });
  433. },
  434. rightFunc(data) {
  435. let { id, goods_attr_id, num } = data.goods_list[0];
  436. this.$request({
  437. url: this.$api.community.cart_add,
  438. data: {
  439. activity_id: this.activity.id,
  440. goods_id: id,
  441. goods_attr_id: goods_attr_id,
  442. num: num
  443. },
  444. method: 'post'
  445. }).then(response => {
  446. if (response.code === 0) {
  447. this.addResult(response.data.queue_id, response.data.token);
  448. }
  449. });
  450. },
  451. joinCart() {
  452. if (!this.goods.buy_goods_auth) {
  453. this.$tips.showToast({
  454. title: '您暂无权限购买该商品',
  455. icon: 'none'
  456. });
  457. return;
  458. }
  459. this.show = true;
  460. },
  461. addResult(queue_id, token) {
  462. this.$request({
  463. url: this.$api.community.cart_result,
  464. method: 'post',
  465. data: {
  466. queue_id: queue_id,
  467. token: token,
  468. },
  469. }).then(response => {
  470. if (response.code === 0) {
  471. if (response.data && response.data.retry === 1) {
  472. setTimeout(() => {
  473. this.addResult(queue_id, token);
  474. }, 1000);
  475. } else {
  476. this.attrShow = 0;
  477. uni.hideLoading();
  478. uni.showToast({
  479. title: '添加成功',
  480. duration: 1000
  481. });
  482. }
  483. } else {
  484. uni.hideLoading();
  485. uni.showToast({
  486. title: response.msg,
  487. icon: 'none',
  488. duration: 1000
  489. });
  490. }
  491. });
  492. },
  493. getTime(newValue) {
  494. newValue = newValue - 1;
  495. this.day = parseInt(newValue / 3600 / 24);
  496. this.hour = parseInt(newValue / 3600 % 24);
  497. if(this.hour < 10) {
  498. this.hour = '0' + this.hour
  499. }else {
  500. this.hour = this.hour.toString();
  501. }
  502. this.minute = parseInt(newValue / 60 % 60);
  503. if(this.minute < 10) {
  504. this.minute = '0' + this.minute
  505. }else {
  506. this.minute = this.minute.toString();
  507. }
  508. this.second = parseInt(newValue % 60);
  509. if(this.second < 10) {
  510. this.second = '0' + this.second
  511. }else {
  512. this.second = this.second.toString();
  513. }
  514. clearInterval(this.time);
  515. this.time = setInterval(() => {
  516. newValue = newValue - 1;
  517. if (newValue < 0) {
  518. clearInterval(this.time);
  519. }
  520. this.day = parseInt(newValue / 3600 / 24);
  521. this.hour = parseInt(newValue / 3600 % 24);
  522. if(this.hour < 10) {
  523. this.hour = '0' + this.hour
  524. }else {
  525. this.hour = this.hour.toString();
  526. }
  527. this.minute = parseInt(newValue / 60 % 60);
  528. if(this.minute < 10) {
  529. this.minute = '0' + this.minute
  530. }else {
  531. this.minute = this.minute.toString();
  532. }
  533. this.second = parseInt(newValue % 60);
  534. if(this.second < 10) {
  535. this.second = '0' + this.second
  536. }else {
  537. this.second = this.second.toString();
  538. }
  539. }, 1000);
  540. },
  541. setCoupon(index) {
  542. this.$set(this.goods.goods_coupon_center[index], 'is_receive', 1);
  543. }
  544. },
  545. components: {
  546. 'app-banner': appBanner,
  547. 'app-goods-time': appGoodsTime,
  548. 'app-share-qr-code': appShareQrCode,
  549. appClose,
  550. uAttr,
  551. bdCoupon,
  552. bdXbc,
  553. bdKb,
  554. bdHc,
  555. bdDetail,
  556. bdComments,
  557. bdInfoExtra,
  558. }
  559. }
  560. </script>
  561. <style scoped lang="scss">
  562. .other-info {
  563. background-color: #fff;
  564. padding: 20upx;
  565. width: 702upx;
  566. border-radius: 15upx;
  567. margin: 24upx 24upx 0 24upx;
  568. .goods-name {
  569. font-size: #{32rpx};
  570. line-height: 42upx;
  571. color: #353535;
  572. margin-bottom: #{24rpx};
  573. }
  574. .goods-subtitle {
  575. font-size: 24rpx;
  576. line-height: 34upx;
  577. background-color: #ffffff;
  578. color: #999999;
  579. margin-bottom: #{24rpx};
  580. }
  581. .middleman {
  582. height: #{88rpx};
  583. color: #ffffff;
  584. position: relative;
  585. .app-share {
  586. height: #{136rpx};
  587. position: absolute;
  588. right: #{-20rpx};
  589. top: #{12rpx};
  590. .app-share-box {
  591. height: #{48rpx};
  592. border-radius: #{40rpx} 0 0 #{40rpx};
  593. padding: 0 #{14rpx};
  594. width: #{103rpx};
  595. .app-icon {
  596. width: #{22rpx};
  597. height: #{22rpx};
  598. }
  599. .app-text {
  600. font-size: #{22rpx};
  601. color: #ffffff;
  602. margin-left: #{10rpx};
  603. top: #{50rpx};
  604. }
  605. }
  606. }
  607. .middleman-info {
  608. .avatar {
  609. width: #{88rpx};
  610. height: #{88rpx};
  611. border-radius: 50%;
  612. margin-right: #{24rpx};
  613. }
  614. .user-info {
  615. font-size: #{30rpx};
  616. color: #353535;
  617. width: #{520rpx};
  618. .middleman-address {
  619. margin-top: #{16rpx};
  620. font-size: #{24rpx};
  621. .icon {
  622. height: #{25rpx};
  623. width: #{19rpx};
  624. margin-right: #{5rpx};
  625. color: #ff4544;
  626. }
  627. }
  628. }
  629. }
  630. }
  631. }
  632. .app-goods {
  633. background-color: #f7f7f7;
  634. }
  635. .bd-bottom {
  636. width: 750upx;
  637. height: 110upx;
  638. padding: 20upx 24upx;
  639. }
  640. .bd-back {
  641. width: 66upx;
  642. height: 100%;
  643. margin-right: 20upx;
  644. }
  645. .bd-icon {
  646. width: 30upx;
  647. height: 30upx;
  648. }
  649. .bd-text {
  650. font-size: 20upx;
  651. color: #888888;
  652. }
  653. .bd-btn {
  654. text-align: center;
  655. line-height: 70upx;
  656. font-size: 28upx;
  657. border-radius: 35upx;
  658. }
  659. .bd-btn-color {
  660. color: #ffffff;
  661. }
  662. .bd-oversell-btn {
  663. background-color: #CDCDCD;
  664. }
  665. .product-list {
  666. background-color: white;
  667. }
  668. .join-member {
  669. background-color: #ffffff;
  670. padding: 0 #{24rpx};
  671. }
  672. .app-bottom {
  673. background-color: white;
  674. position: fixed;
  675. bottom: 0;
  676. left: 0;
  677. width: 100%;
  678. }
  679. .text {
  680. color: #ffffff;
  681. }
  682. .u-bottom-fixed {
  683. position: fixed;
  684. bottom: 0;
  685. left: 0;
  686. width: 100%;
  687. z-index: 1500;
  688. background-color: #ffffff;
  689. }
  690. .u-bottom-height {
  691. height: 110upx;
  692. }
  693. .u-bottom-height {
  694. height: 110upx;
  695. }
  696. .goods-margin {
  697. margin-top: 20upx;
  698. }
  699. </style>