productKlon.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. <template>
  2. <view class="container">
  3. <!-- 轮播图 -->
  4. <top-swiper :imgList="imgList"></top-swiper>
  5. <!-- 标题 -->
  6. <klon-content :goodsObjact="goodsObjact"></klon-content>
  7. <!-- 拼货时间及优惠 -->
  8. <discounts :mark='goodsObjact.mark' :Info="goodsObjact.info" @clickCoupon="Getcoupon" :showCoupon='false'></discounts>
  9. <!-- 猜你喜欢 -->
  10. <!-- <guess-like @Addcar='Addcar' @clickNavTo='navToDetailPage' :goodList = 'good_list||[]'></guess-like> -->
  11. <!-- 评价 -->
  12. <!-- <estimate @navTo="navTo('/pages/product/reply?id=' + goodsid)" v-if="reply" :reply='reply' :list='list'></estimate> -->
  13. <!-- 规格信息 -->
  14. <fresh-detail :goodsObjact="goodsObjact"></fresh-detail>
  15. <!-- 图文详情 -->
  16. <content-text :description="description"></content-text>
  17. <!-- 底部高度撑开 -->
  18. <view class="contentBottomHeight"></view>
  19. <!-- 底部操作菜单 -->
  20. <klon-buttom :goodsObjact="goodsObjact" @buy="toggleSpec()"></klon-buttom>
  21. <view class="popup spec" :class="specClass" @touchmove.stop.prevent="stopPrevent" @click="toggleSpec()">
  22. <!-- 遮罩层 -->
  23. <view class="mask"></view>
  24. <view class="layer attr-content" @click.stop="stopPrevent">
  25. <view class="a-t">
  26. <image :src="actionImage"></image>
  27. <view class="right">
  28. <text class="name">{{ goodsObjact.title }}</text>
  29. <text class="price">¥{{ actionPrice }}</text><!-- * goodsNumber -->
  30. <text class="stock">库存:{{ goodsObjact.stock }}件</text>
  31. <!-- <view class="selected" v-if="specList != ''">
  32. 已选:
  33. <text class="selected-text" v-for="(sItem, sIndex) in specSelected" :key="sIndex">{{ sItem }}</text>
  34. </view> -->
  35. </view>
  36. </view>
  37. <!-- <view v-for="(item, index) in specList" :key="index" class="attr-list">
  38. <text>{{ item.attr_name }}</text>
  39. <view class="item-list">
  40. <text
  41. v-for="(childItem, childIndex) in item.attr_value"
  42. :key="childIndex"
  43. class="tit"
  44. :class="{ selected: childItem.check }"
  45. @click="selectSpec(childItem, item, index)"
  46. >
  47. {{ childItem.attr }}
  48. </text>
  49. </view>
  50. </view> -->
  51. <view class="attr-list">
  52. <text>购买数量</text>
  53. <view class="num-list">
  54. <uni-number-box
  55. class="step"
  56. :isMin="true"
  57. :value="goodsNumber"
  58. :min="1"
  59. :max="goodsNumberMax"
  60. @eventChange="numberChange"></uni-number-box>
  61. </view>
  62. </view>
  63. <button class="btn" @click.stop="buy(1)" v-if="goodsObjact.stock > 0">完成</button>
  64. <button class="btn" style="background-color: #999999;" v-if="goodsObjact.stock < 1">售罄</button>
  65. </view>
  66. </view>
  67. </view>
  68. </template>
  69. <script>
  70. import { cartAdd } from '@/api/product.js';
  71. import { KlonDetail } from '@/api/groupBooking.js';
  72. import { mapState } from 'vuex';
  73. import store from '@/store/index.js';
  74. import { saveUrl } from '@/utils/loginUtils.js';
  75. // #ifdef H5
  76. import { weixindata } from '@/utils/wxAuthorized';
  77. // #endif
  78. // 数量
  79. import uniNumberBox from '@/components/uni-number-box.vue';
  80. // 头部轮播图
  81. import topSwiper from './common/topSwiper.vue';
  82. // 标题
  83. import KlonContent from './common/KlonContent.vue';
  84. // 到货时间及优惠
  85. import discounts from './common/discounts.vue';
  86. // 规格信息
  87. import freshDetail from './common/freshDetail.vue';
  88. // 图文详情
  89. import contentText from './common/contentText.vue';
  90. // 底部按钮
  91. import klonButtom from './common/klonButtom.vue';
  92. // 猜你喜欢
  93. // import guessLike from './common/guessLike.vue';
  94. // 评价
  95. // import estimate from './common/estimate.vue';
  96. export default {
  97. components: {
  98. // guessLike,
  99. topSwiper,
  100. KlonContent,
  101. discounts,
  102. freshDetail,
  103. contentText,
  104. klonButtom,
  105. // estimate,
  106. uniNumberBox
  107. },
  108. data() {
  109. return {
  110. reply: '', //评论
  111. list: '', //商品详情的数据
  112. type: 1, //默认支付方式add为
  113. goodsNumber: 1, //购买数量
  114. goodsid: '', //商品id
  115. description: '', //商品描述
  116. goodsObjact: {
  117. percent:1
  118. }, //保存商品数据
  119. //图片循环
  120. imgList: [],
  121. // 对比对象
  122. actionPrice: 0, //默认选中商品价格
  123. actionImage: '', //默认选中图片
  124. good_list: '', //猜你喜欢列表
  125. goodsNumberMax: 0, //最大可购买数量
  126. // 倒计时数据保存
  127. seckillObj: {
  128. stopTime: 0, //结束时间
  129. stop: false, //是否结束
  130. stopTimeH: 0, //小时
  131. stopTimeM: 0, //分钟
  132. stopTimeS: 0, //秒钟
  133. stopTimeD: 0, //天
  134. upTime: 0 //更新组件内部组件用
  135. },
  136. // 拼团数据保存
  137. pink: {
  138. id: '', //拼团编号
  139. uid: '', //用户编号
  140. people: '', //拼团人数
  141. price: '', //拼团价格
  142. stop_time: '', //拼团结束时间
  143. nickname: '', //团长昵称
  144. avatar: '', //团长头像
  145. count: '', //拼团剩余人数
  146. h: '', //时
  147. i: '', //分
  148. s: '' //秒
  149. },
  150. userInfo: '',
  151. specClass: 'none', //显示隐藏弹窗
  152. };
  153. },
  154. filters: {
  155. parseIntTo(percent) {
  156. percent = +percent * 100;
  157. if (percent % 1 === 0) {
  158. return percent;
  159. } else {
  160. percent = percent.toFixed(1);
  161. return percent;
  162. }
  163. }
  164. },
  165. async onLoad(options) {
  166. let obj = this;
  167. obj.userInfo = uni.getStorageSync('userInfo');
  168. //保存商品id
  169. this.goodsid = options.id;
  170. // 判断有无人邀请
  171. if (options.spread) {
  172. // 存储邀请人
  173. uni.setStorageSync('spread', options.spread);
  174. }
  175. saveUrl();
  176. // 判断是否为秒杀商品
  177. this.goodsDetail();
  178. // 注册邀请信息
  179. // #ifdef H5
  180. let bool = uni.getStorageSync('weichatBrowser') || '';
  181. if (bool) {
  182. weixindata();
  183. }
  184. // #endif
  185. },
  186. computed: {
  187. ...mapState(['weichatObj', 'baseURL', 'urlFile'])
  188. },
  189. // 分享
  190. // onShareAppMessage(options) {
  191. // // 设置菜单中的转发按钮触发转发事件时的转发内容
  192. // let pages = getCurrentPages(); //获取加载的页面
  193. // let currentPage = pages[pages.length - 1]; //获取当前页面的对象
  194. // let url = currentPage.route; //当前页面url
  195. // let item = currentPage.options; //如果要获取url中所带的参数可以查看options
  196. // let shareObj = {
  197. // title: this.goodsObjact.store_name + ' 价格:' + this.goodsObjact.price, // 默认是小程序的名称(可以写slogan等)
  198. // path: url + '?id=' + item.id + '&spread=' + this.userInfo.uid, // 默认是当前页面,必须是以‘/’开头的完整路径
  199. // imageUrl: this.goodsObjact.image,
  200. // success: function(res) {
  201. // // 转发成功之后的回调
  202. // if (res.errMsg == 'shareAppMessage:ok') {
  203. // }
  204. // },
  205. // fail: function() {
  206. // // 转发失败之后的回调
  207. // if (res.errMsg == 'shareAppMessage:fail cancel') {
  208. // // 用户取消转发
  209. // } else if (res.errMsg == 'shareAppMessage:fail') {
  210. // // 转发失败,其中 detail message 为详细失败信息
  211. // }
  212. // }
  213. // };
  214. // return shareObj;
  215. // },
  216. methods: {
  217. //领取优惠券
  218. Getcoupon() {
  219. uni.navigateTo({
  220. url: '/pages/coupon/getcoupon'
  221. });
  222. },
  223. //详情页
  224. navToDetailPage(item) {
  225. let id = item.id;
  226. uni.navigateTo({
  227. url: '/pages/product/product?id=' + id
  228. });
  229. },
  230. // 跳转页面
  231. navTo(url) {
  232. uni.navigateTo({
  233. url
  234. });
  235. },
  236. //加入购物车
  237. Addcar(item) {
  238. let obj = this;
  239. cartAdd({
  240. cartNum: '1', //商品数量
  241. uniqueId: '', //商品标签
  242. new: 0, //商品是否新增加到购物车1为不加入0为加入
  243. mer_id: '',
  244. productId: item.id //商品编号
  245. })
  246. .then(function(e) {
  247. uni.showToast({
  248. title: '成功加入购物车',
  249. type: 'top',
  250. duration: 500,
  251. icon: 'none'
  252. });
  253. obj.goodsDetail();
  254. })
  255. .catch(e => {
  256. console.log(e);
  257. });
  258. },
  259. // 获取普通商品信息
  260. goodsDetail() {
  261. let obj = this;
  262. KlonDetail({}, this.goodsid).then(function({ data }) {
  263. obj.list = data;
  264. obj.good_list = data.good_list; //保存猜你喜欢列表
  265. obj.reply = data.reply; //保存评论列表
  266. let goods = data.storeInfo;
  267. obj.goodsObjact = goods;
  268. if (obj.goodsObjact.description != null) {
  269. obj.description = obj.goodsObjact.description.replace(/\<img/gi, '<img class="rich-img"');
  270. } //小程序商品详情图超出屏幕问题
  271. obj.imgList = goods.images; //保存轮播图
  272. // obj.specList = data.productAttr; //保存分类列表
  273. // obj.productValue = data.productValue; //保存分类查询数据
  274. obj.actionPrice = goods.price; //保存默认选中商品价格
  275. obj.actionImage = goods.image_base; //保存默认选中商品图片
  276. obj.goodsNumberMax = goods.stock; //保存默认选中最大可购买商品数量
  277. // obj.shopId = data.mer_id; //保存商店id
  278. });
  279. },
  280. // 改变数量
  281. numberChange(e) {
  282. //购买数量
  283. this.goodsNumber = e.number;
  284. },
  285. // 规格弹窗开关
  286. toggleSpec(str) {
  287. if (this.specClass === 'show') {
  288. this.specClass = 'hide';
  289. setTimeout(() => {
  290. this.specClass = 'none';
  291. }, 250);
  292. } else if (this.specClass === 'none') {
  293. this.specClass = 'show';
  294. }
  295. // 判断是否为数字
  296. // if (typeof str == 'number') {
  297. // // 保存当前购买类型
  298. // this.type = str;
  299. // }
  300. },
  301. // 立即购买
  302. buy(item) {
  303. let obj = this;
  304. obj.type = item;
  305. // 创建传值对象
  306. let data = {
  307. cartNum: obj.goodsNumber, //商品数量
  308. new: 1,
  309. productId: obj.goodsObjact.product_id,
  310. jlId: obj.goodsid,
  311. };
  312. // if(obj.type == 2) {
  313. // data.new = 0;
  314. // }
  315. cartAdd(data)
  316. .then(function(e) {
  317. let da = e.data;
  318. if (obj.type == 1) {
  319. // 跳转到支付页
  320. uni.navigateTo({
  321. url: '/pages/order/createOrderKlon?id=' + da.cartId
  322. });
  323. }
  324. if (obj.type == 2) {
  325. uni.showToast({
  326. title: '成功加入购物车',
  327. type: 'top',
  328. duration: 2000,
  329. icon: 'none'
  330. });
  331. obj.goodsDetail();
  332. }
  333. })
  334. .catch(e => {
  335. console.log(e);
  336. });
  337. },
  338. // 阻止触发上级事件
  339. stopPrevent() {}
  340. }
  341. };
  342. </script>
  343. <style lang="scss">
  344. //默认商品底部高度
  345. .goodsBottom {
  346. height: 160rpx;
  347. }
  348. page {
  349. background: #f0f0f0;
  350. }
  351. //秒杀、拼团底部高度
  352. .contentBottomHeight {
  353. height: 110rpx;
  354. }
  355. //默认商品底部高度
  356. .goodsBottom {
  357. height: 160rpx;
  358. }
  359. /deep/ .iconenter {
  360. font-size: $font-base + 2rpx;
  361. color: #888;
  362. }
  363. /deep/ .con_image {
  364. width: 130rpx;
  365. height: 130rpx;
  366. display: inline-block;
  367. padding: 15rpx;
  368. image {
  369. width: 100%;
  370. height: 100%;
  371. }
  372. }
  373. /* 商品详情中限制图片大小 */
  374. /deep/ .rich-img {
  375. width: 100% !important;
  376. height: auto;
  377. }
  378. // 弹出层
  379. .popup {
  380. position: fixed;
  381. left: 0;
  382. top: 0;
  383. right: 0;
  384. bottom: 0;
  385. z-index: 99;
  386. &.show {
  387. display: block;
  388. .mask {
  389. animation: showPopup 0.2s linear both;
  390. }
  391. .layer {
  392. animation: showLayer 0.2s linear both;
  393. }
  394. }
  395. &.hide {
  396. .mask {
  397. animation: hidePopup 0.2s linear both;
  398. }
  399. .layer {
  400. animation: hideLayer 0.2s linear both;
  401. }
  402. }
  403. &.none {
  404. display: none;
  405. }
  406. .mask {
  407. position: fixed;
  408. top: 0;
  409. width: 100%;
  410. height: 100%;
  411. z-index: 1;
  412. background-color: rgba(0, 0, 0, 0.4);
  413. }
  414. .layer {
  415. position: fixed;
  416. z-index: 99;
  417. bottom: 0;
  418. width: 100%;
  419. min-height: 35vh;
  420. border-radius: 10rpx 10rpx 0 0;
  421. background-color: #fff;
  422. .btn {
  423. height: 66rpx;
  424. line-height: 66rpx;
  425. border-radius: 100rpx;
  426. background: linear-gradient(270deg, rgba(181,116,242, 1) 0%, rgba(139,86,254, 1) 100%);
  427. font-size: $font-base + 2rpx;
  428. color: #fff;
  429. margin: 50rpx auto 20rpx;
  430. }
  431. }
  432. @keyframes showPopup {
  433. 0% {
  434. opacity: 0;
  435. }
  436. 100% {
  437. opacity: 1;
  438. }
  439. }
  440. @keyframes hidePopup {
  441. 0% {
  442. opacity: 1;
  443. }
  444. 100% {
  445. opacity: 0;
  446. }
  447. }
  448. @keyframes showLayer {
  449. 0% {
  450. transform: translateY(120%);
  451. }
  452. 100% {
  453. transform: translateY(0%);
  454. }
  455. }
  456. @keyframes hideLayer {
  457. 0% {
  458. transform: translateY(0);
  459. }
  460. 100% {
  461. transform: translateY(120%);
  462. }
  463. }
  464. }
  465. // 规格选择弹窗
  466. .attr-content {
  467. padding: 25rpx 30rpx;
  468. .a-t {
  469. display: flex;
  470. image {
  471. width: 170rpx;
  472. height: 170rpx;
  473. flex-shrink: 0;
  474. border-radius: 8rpx;
  475. }
  476. .right {
  477. display: flex;
  478. flex-direction: column;
  479. padding-left: 24rpx;
  480. font-size: $font-sm + 2rpx;
  481. color: $font-color-base;
  482. line-height: 42rpx;
  483. width: 75%;
  484. .price {
  485. font-size: $font-lg;
  486. color: $uni-color-primary;
  487. margin: 10rpx 0rpx;
  488. }
  489. .name {
  490. font-size: 32rpx;
  491. color: $font-color-dark;
  492. height: 50rpx;
  493. overflow: hidden;
  494. text-overflow: ellipsis;
  495. white-space: nowrap;
  496. display: block;
  497. }
  498. .selected-text {
  499. margin-right: 10rpx;
  500. }
  501. }
  502. }
  503. .attr-list {
  504. display: flex;
  505. align-items: center;
  506. justify-content: space-between;
  507. // flex-direction: column;
  508. font-size: $font-base + 2rpx;
  509. color: $font-color-base;
  510. padding-top: 30rpx;
  511. padding-left: 10rpx;
  512. }
  513. .item-list {
  514. padding: 20rpx 0 0;
  515. display: flex;
  516. flex-wrap: wrap;
  517. text {
  518. display: flex;
  519. align-items: center;
  520. justify-content: center;
  521. background: #eee;
  522. margin-right: 20rpx;
  523. margin-bottom: 20rpx;
  524. border-radius: 100rpx;
  525. min-width: 60rpx;
  526. height: 60rpx;
  527. padding: 0 20rpx;
  528. font-size: $font-base;
  529. color: $font-color-dark;
  530. }
  531. .selected {
  532. background: #fbebee;
  533. color: $uni-color-primary;
  534. }
  535. }
  536. .num-list {
  537. // padding: 20rpx 0 0;
  538. display: flex;
  539. flex-wrap: wrap;
  540. text {
  541. display: flex;
  542. align-items: center;
  543. justify-content: center;
  544. border-radius: 100rpx;
  545. min-width: 60rpx;
  546. height: 60rpx;
  547. padding: 0 20rpx;
  548. font-size: $font-base;
  549. color: $font-color-dark;
  550. }
  551. }
  552. }
  553. </style>