goods.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. <template>
  2. <app-layout>
  3. <view v-if="!loading" class="u-goods-detail"></view>
  4. <template v-else>
  5. <!--商品轮播图-->
  6. <app-goods-banner
  7. :picList="picUrl"
  8. :isCart="false"
  9. :share="goods.share"
  10. :goods_id="goodsId"
  11. :video-url="goods.video_url"
  12. sign="booking"
  13. ></app-goods-banner>
  14. <view>
  15. <bd-name
  16. :theme="getTheme"
  17. :name="goods.name"
  18. :is-negotiable="goods.is_negotiable"
  19. :subtitle="goods.subtitle"
  20. :level-show="goods.level_show"
  21. :price="goods.price"
  22. :original-price="goods.original_price"
  23. :price-max="goods.price_max"
  24. :price-min="goods.price_min"
  25. :price-member-max="goods.price_member_max"
  26. :price-member-min="goods.price_member_min"
  27. :discount='discount'
  28. :is-vip-card-user="is_vip_card_user"
  29. :sales="goods.sales"
  30. :unit="goods.unit"
  31. :is-sales="goods.is_sales"
  32. :is-vip="is_vip"
  33. :goods-id="goods.id"
  34. :extra-quick-share="goods.extra_quick_share"
  35. :app-share-pic="goods.app_share_pic"
  36. :app-share-title="goods.app_share_title"
  37. :poster-config="poster_config"
  38. :poster-generate="poster_generate"
  39. :has-poster-nav="true"
  40. v-bind:goods="goods"
  41. @share="hShareAppMessage"
  42. :min-number="goods.min_number"
  43. :limit-buy="goods.limit_buy"
  44. ></bd-name>
  45. </view>
  46. <bd-coupon @change="setCoupon" :theme="getTheme" :coupons="goods.goods_coupon_center"></bd-coupon>
  47. <bd-xbc
  48. :coAttr="is_open"
  49. :attr-list="checked && checked.attr_list"
  50. :type="goods.type"
  51. :guarantee-title="goods.guarantee_title"
  52. :guarantee-pic="goods.guarantee_pic"
  53. :param_content="goods.param_content"
  54. :param_name="goods.param_name"
  55. :services="goods.services"
  56. :attr-groups="goods.attr_groups"
  57. :goods-stock="goods.goods_num"
  58. @openAttr="open"
  59. ></bd-xbc>
  60. <bd-hc
  61. :integral="goods.goods_marketing_award.integral"
  62. :coupon="goods.goods_marketing_award.coupon"
  63. :card="goods.goods_marketing_award.card"
  64. :balance="goods.goods_marketing_award.balance"
  65. :theme="getTheme"
  66. ></bd-hc>
  67. <bd-kb
  68. :limit="goods.goods_marketing && goods.goods_marketing.limit"
  69. :express="goods.express"
  70. :shipping="goods.goods_marketing && goods.goods_marketing.shipping"
  71. :pickup="goods.goods_marketing && goods.goods_marketing.pickup"
  72. ></bd-kb>
  73. <view class="bd-store" v-if="store[0]">
  74. <app-store
  75. :store_id="store[0] && store[0].id"
  76. :address="store[0] && store[0].address"
  77. :name="store[0].name"
  78. :business_hours="store[0].business_hours"
  79. :storeNum="storeNum"
  80. :goods_id="goodsId"
  81. ></app-store>
  82. </view>
  83. <bd-comments :goods-id="goods.id"></bd-comments>
  84. <bd-detail :detail="goods.detail"></bd-detail>
  85. <!--相关推荐-->
  86. <app-related-suggestion-product :theme="getTheme" sign="booking" :list="list" ></app-related-suggestion-product>
  87. <!-- 底部空格 -->
  88. <view class="safe-area-inset-bottom">
  89. <view class="u-bottom-height" :class="full_reduce ? 'u-bottom-height-1' : 'u-bottom-height-0'"></view>
  90. </view>
  91. <!-- 底部按钮 -->
  92. <view v-if="is_open == 1" class="safe-area-inset-bottom u-bottom-fixed">
  93. <view v-if="full_reduce">
  94. <app-goods-full-reduce
  95. :theme="getTheme"
  96. sign="book"
  97. :full_reduce="full_reduce"
  98. >
  99. </app-goods-full-reduce>
  100. </view>
  101. <view class="bd-bottom dir-left-nowrap cross-center">
  102. <view class="u-back dir-top-nowrap main-center cross-center box-grow-0" @click="router('/pages/index/index')">
  103. <image class="u-icon" src="../../../static/image/icon/index.png"></image>
  104. <text class="u-text">首页</text>
  105. </view>
  106. <bd-service :name="goods.name" :url="webUrl"></bd-service>
  107. <view v-if="goods.goods_num > 0" :style="{'background': goods.buy_goods_auth ? getTheme.background_gradient_btn : '#9999999'}" class="u-btn box-grow-1" @click="open">
  108. 立即预约
  109. </view>
  110. <view v-else class="u-btn u-oversell-btn box-grow-1" >已售罄</view>
  111. </view>
  112. </view>
  113. <u-attr
  114. :goods="goods"
  115. v-model="show"
  116. :theme="getTheme"
  117. :checked="checked"
  118. @check="check"
  119. :is_show_left="false"
  120. right-text="立即预约"
  121. :right-func="true"
  122. @rightFunc="rightFunc"
  123. >
  124. </u-attr>
  125. <!-- 快捷导航 -->
  126. <app-quick-navigation></app-quick-navigation>
  127. </template>
  128. <app-close v-if="showClose" :modal="false" @update="getMall"></app-close>
  129. </app-layout>
  130. </template>
  131. <script>
  132. import { mapState,mapGetters } from 'vuex';
  133. import appGoodsBanner from '../../../components/page-component/goods/app-goods-banner.vue';
  134. import appStore from '../components/app-store.vue';
  135. import appRelatedSuggestionProduct from '../../../components/page-component/app-related-suggestion-product/app-related-suggestion-product.vue';
  136. import appQuickNavigation from "../../../components/page-component/app-quick-navigation/app-quick-navigation.vue";
  137. import AppVipCard from '../../../components/page-component/app-vip-card/app-vip-card';
  138. import appGoodsFullReduce from '../../../components/page-component/goods/app-goods-full-reduce.vue';
  139. import uAttr from '../../../components/page-component/goods/u-attr.vue';
  140. import bdName from '@/components/page-component/goods/bd-info.vue';
  141. import bdCoupon from '@/components/page-component/goods/bd-coupon.vue';
  142. import bdXbc from '@/components/page-component/goods/bd-xbc.vue';
  143. import bdKb from '@/components/page-component/goods/bd-kb.vue';
  144. import bdHc from '@/components/page-component/goods/bd-hc.vue';
  145. import bdDetail from '@/components/page-component/goods/bd-detail.vue';
  146. import bdComments from '@/components/page-component/goods/bd-comments.vue';
  147. import appClose from '@/components/basic-component/app-close/app-close.vue';
  148. import bdService from '@/components/page-component/goods/bd-service.vue';
  149. export default {
  150. name: 'goods',
  151. components: {
  152. 'app-goods-banner': appGoodsBanner,
  153. 'app-store': appStore,
  154. 'app-related-suggestion-product': appRelatedSuggestionProduct,
  155. 'app-quick-navigation': appQuickNavigation,
  156. 'app-vip-card': AppVipCard,
  157. uAttr,
  158. appClose,
  159. appGoodsFullReduce,
  160. bdName,
  161. bdCoupon,
  162. bdXbc,
  163. bdKb,
  164. bdHc,
  165. bdDetail,
  166. bdComments,
  167. bdService
  168. },
  169. data() {
  170. return {
  171. showClose: false,
  172. is_open: 0,
  173. goods: {
  174. goods_activity: {
  175. full_reduce: {}
  176. },
  177. goods_marketing: {}
  178. },
  179. goods_marketing: {},
  180. full_reduce: null,
  181. selectAttr: {},
  182. activeIndex: 0,
  183. list: [],
  184. url: '',
  185. webUrl: '',
  186. cartShow: true,
  187. is_vip: false,
  188. is_vip_card_user: 0,
  189. discount: null,
  190. goods_id: 0,
  191. poster_config: this.$api.book.poster_config,
  192. poster_generate: this.$api.book.poster_generate,
  193. // 规格选中
  194. checked: null,
  195. // 规格显示
  196. show: false,
  197. // 详情loading
  198. loading: false,
  199. // 门店列表
  200. store: null,
  201. storeNum: null,
  202. // 商品服务
  203. services: null,
  204. // 商品标题
  205. name: null,
  206. // 商品ID
  207. goodsId: null,
  208. // 商品轮播图
  209. picUrl: null,
  210. disable: 'disable'
  211. }
  212. },
  213. onShow() {
  214. this.showClose = false;
  215. setTimeout(()=>{
  216. this.showClose = true;
  217. })
  218. },
  219. // #ifdef MP-WEIXIN
  220. onShareTimeline() {
  221. let { app_share_title, goods_id, name} = this.goods;
  222. return this.$shareTimeline({
  223. title: app_share_title ? app_share_title : name,
  224. query: {
  225. goods_id: goods_id
  226. }
  227. });
  228. },
  229. // #endif
  230. onLoad(options) { this.$commonLoad.onload(options);
  231. this.webUrl = '/plugins/book/goods/goods?goods_id=' + options.goods_id;
  232. this.goods_id = options.goods_id;
  233. this.request(options.goods_id);
  234. this.newRecommend(options.goods_id);
  235. // #ifdef MP-WEIXIN
  236. wx.showShareMenu({
  237. menus: ['shareAppMessage', 'shareTimeline']
  238. })
  239. // #endif
  240. },
  241. // #ifdef MP
  242. onShareAppMessage() {
  243. this.hShareAppMessage();
  244. },
  245. // #endif
  246. methods: {
  247. hShareAppMessage(s = false){
  248. let { app_share_title, app_share_pic, goods_id, name, subtitle} = this.goods;
  249. return this.$shareAppMessage({
  250. path: '/plugins/book/goods/goods',
  251. title: app_share_title ? app_share_title : name,
  252. imageUrl: app_share_pic ? app_share_pic : this.picUrl[0].pic_url,
  253. desc: subtitle,
  254. params: {
  255. goods_id: goods_id
  256. }
  257. },s);
  258. },
  259. getMall(e) {
  260. this.is_open = e.is_open;
  261. },
  262. check({item}) {
  263. this.checked = item;
  264. },
  265. rightFunc(data) {
  266. uni.navigateTo({
  267. url: `/pages/order-submit/order-submit?mch_list=${JSON.stringify([data])}&preview_url=${encodeURIComponent(this.$api.book.order_preview)}&submit_url=${encodeURIComponent(this.$api.book.order_submit)}&plugin=booking`
  268. });
  269. },
  270. newRecommend(id) {
  271. this.$request({
  272. url: this.$api.goods.new_recommend,
  273. data: {
  274. goods_id: id
  275. }
  276. }).then(response => {
  277. if (response.code === 0) {
  278. this.list = response.data.list;
  279. }
  280. })
  281. },
  282. open() {
  283. if (!this.goods.buy_goods_auth) {
  284. this.$tips.showToast({
  285. title: '您暂无权限购买该商品',
  286. icon: 'none'
  287. });
  288. return;
  289. }
  290. this.show = true;
  291. },
  292. setCoupon(index) {
  293. this.$set(this.goods.goods_coupon_center[index], 'is_receive', 1);
  294. },
  295. router: function(url) {
  296. uni.navigateTo({
  297. url: url
  298. });
  299. },
  300. request(goods_id) {
  301. let _this = this;
  302. // #ifdef MP
  303. uni.getLocation({
  304. type: 'wgs84',
  305. success(s){
  306. _this.$showLoading();
  307. _this.$request({
  308. url: _this.$api.book.detail,
  309. data: {
  310. goods_id: goods_id,
  311. latitude: s.latitude,
  312. longitude: s.longitude,
  313. }
  314. }).then(r => {
  315. if (r.code === 0) {
  316. let list = r.data.list;
  317. let { store, services, name, id, pic_url, goods_marketing } = r.data.list;
  318. _this.item = list;
  319. _this.goods = list;
  320. if (list.goods_activity) {
  321. _this.full_reduce = list.goods_activity.full_reduce;
  322. }
  323. _this.store = store.slice(0, 1);
  324. _this.storeNum = store.length;
  325. _this.services = services;
  326. _this.name = name;
  327. _this.goodsId = id;
  328. _this.picUrl = pic_url;
  329. _this.goods_marketing = goods_marketing;
  330. _this.url = `${_this.$api.book.poster}&goods_id=${id}`;
  331. _this.poster_config = `${_this.poster_config}&goods_id=${id}`;
  332. _this.poster_generate = `${_this.poster_generate}&goods_id=${id}`;
  333. _this.loading = true;
  334. if (list.vip_card_appoint.discount > 0) {
  335. _this.is_vip = true;
  336. _this.discount = list.vip_card_appoint.discount;
  337. }
  338. _this.is_vip_card_user = list.vip_card_appoint.is_vip_card_user;
  339. }
  340. _this.$hideLoading();
  341. });
  342. },
  343. fail() {
  344. uni.showToast({
  345. title: '请开启位置权限',
  346. icon: 'none',
  347. duration: 2000,
  348. success: function() {
  349. setTimeout(() => {
  350. uni.navigateBack();
  351. }, 2000);
  352. }
  353. });
  354. }
  355. });
  356. // #endif
  357. // #ifdef H5
  358. this.$jwx.getLocation({
  359. success(s) {
  360. _this.$showLoading();
  361. _this.$request({
  362. url: _this.$api.book.detail,
  363. data: {
  364. goods_id: goods_id,
  365. latitude: s.latitude,
  366. longitude: s.longitude,
  367. }
  368. }).then(r => {
  369. if (r.code === 0) {
  370. let list = r.data.list;
  371. let { store, services, name, id, pic_url, goods_marketing } = r.data.list;
  372. _this.goods = list;
  373. if (list.goods_activity) {
  374. _this.full_reduce = list.goods_activity.full_reduce;
  375. }
  376. _this.store = store.slice(0, 1);
  377. _this.storeNum = store.length;
  378. _this.services = services;
  379. _this.name = name;
  380. _this.goodsId = id;
  381. _this.picUrl = pic_url;
  382. _this.url = `${_this.$api.book.poster}&goods_id=${id}`;
  383. _this.poster_config = `${_this.poster_config}&goods_id=${id}`;
  384. _this.poster_generate = `${_this.poster_generate}&goods_id=${id}`;
  385. _this.loading = true;
  386. if (list.vip_card_appoint.discount > 0) {
  387. _this.is_vip = true;
  388. _this.discount = list.vip_card_appoint.discount;
  389. }
  390. _this.is_vip_card_user = list.vip_card_appoint.is_vip_card_user;
  391. _this.hShareAppMessage();
  392. }
  393. _this.$hideLoading();
  394. });
  395. },
  396. fail() {
  397. uni.showToast({
  398. title: '请开启位置权限',
  399. icon: 'none',
  400. duration: 2000,
  401. success: function() {
  402. setTimeout(() => {
  403. uni.navigateBack();
  404. }, 2000);
  405. }
  406. });
  407. }
  408. });
  409. // #endif
  410. }
  411. },
  412. computed: {
  413. ...mapGetters('mallConfig', {
  414. getTheme: 'getTheme',
  415. }),
  416. }
  417. }
  418. </script>
  419. <style scoped lang="scss">
  420. .goods-subtitle {
  421. padding: #{24rpx};
  422. padding-top: 0;
  423. font-size: 24rpx;
  424. background-color: #ffffff;
  425. color: #999999;
  426. }
  427. .goods-margin {
  428. margin-top: 20upx;
  429. }
  430. .vip-card {
  431. padding: 20upx 20upx;
  432. background-color: #fff;
  433. }
  434. .u-bottom-height-0 {
  435. height: 110upx;
  436. }
  437. .u-bottom-height-1 {
  438. height: 190upx;
  439. }
  440. .u-bottom-fixed {
  441. position: fixed;
  442. bottom: 0;
  443. left: 0;
  444. width: 100%;
  445. z-index: 1602;
  446. background-color: #ffffff;
  447. box-shadow: 0 -1rpx 20rpx -15rpx #353535;
  448. }
  449. .bd-bottom {
  450. width: 750upx;
  451. height: 110upx;
  452. padding: 20upx 24upx;
  453. }
  454. .u-btn {
  455. line-height: 70upx;
  456. color: #ffffff;
  457. font-size: 28upx;
  458. text-align: center;
  459. border-radius: 35upx;
  460. }
  461. .u-oversell-btn {
  462. background-color: #CDCDCD;
  463. }
  464. .u-back {
  465. width: 66upx;
  466. height: 100%;
  467. margin-right: 20upx;
  468. }
  469. .u-icon {
  470. width: 30upx;
  471. height: 30upx;
  472. margin-bottom: 8upx;
  473. }
  474. .u-text {
  475. font-size: 20upx;
  476. color: #888888;
  477. line-height: 1;
  478. }
  479. .bd-store {
  480. width: 702upx;
  481. border-radius: 15upx;
  482. margin: 24upx 24upx 0 24upx;
  483. overflow: hidden;
  484. }
  485. </style>