GoodsCon.vue 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293
  1. <template>
  2. <div
  3. :class="[posterImageStatus ? 'noscroll product-con' : 'product-con']"
  4. @scroll.native="onScroll"
  5. >
  6. <div
  7. class="header acea-row row-center-wrapper"
  8. :style="'opacity:' + opacity"
  9. ref="header"
  10. >
  11. <div
  12. @click="$router.back()"
  13. class="iconfont icon-xiangzuo"
  14. style="color: #000000; font-size: 20px; padding-right: 35px;"
  15. ></div>
  16. <div
  17. class="item"
  18. :class="navActive === index ? 'on' : ''"
  19. v-for="(item, index) in navList"
  20. :key="index"
  21. @click="asideTap(index)"
  22. >
  23. {{ item }}
  24. </div>
  25. </div>
  26. <div id="title0">
  27. <product-con-swiper
  28. :img-urls="storeInfo.slider_image"
  29. :videoline="storeInfo.video_link"
  30. ></product-con-swiper>
  31. <div class="wrapper">
  32. <div class="share acea-row row-between row-bottom">
  33. <div class="money font-color-red">
  34. ¥<span class="num">{{ isVip ? storeInfo.vip_price : storeInfo.price }}</span>
  35. <!-- <span
  36. class="vip-money"
  37. v-if="storeInfo.vip_price && storeInfo.vip_price > 0"
  38. >¥{{ storeInfo.vip_price }}</span
  39. ><img
  40. src="@assets/images/vip.png"
  41. class="image"
  42. v-if="storeInfo.vip_price && storeInfo.vip_price > 0"
  43. /> -->
  44. </div>
  45. <div v-if="isVip"
  46. @click="listenerActionSheet"
  47. class="font-color-green"
  48. >分享赚¥{{ (storeInfo.price - storeInfo.vip_price).toFixed(2) }}<span class="iconfont icon-fenxiang"></span></div>
  49. <div v-else
  50. class="iconfont icon-fenxiang"
  51. @click="listenerActionSheet"
  52. ></div>
  53. </div>
  54. <div class="introduce">{{ storeInfo.store_name }}</div>
  55. <div class="label acea-row row-between-wrapper">
  56. <div>原价:¥{{ storeInfo.ot_price }}</div>
  57. <div>库存:{{ storeInfo.stock }}{{ storeInfo.unit_name }}</div>
  58. <div>销量:{{ storeInfo.fsales }}{{ storeInfo.unit_name }}</div>
  59. </div>
  60. <div
  61. class="coupon acea-row row-between-wrapper"
  62. @click="couponTap"
  63. v-if="couponList.length"
  64. >
  65. <div class="hide line1 acea-row">
  66. 优惠券:
  67. <div
  68. class="activity"
  69. v-for="(item, index) in couponList"
  70. :key="index"
  71. >
  72. 满{{ item.use_min_price }}减{{ item.coupon_price }}
  73. </div>
  74. </div>
  75. <div class="iconfont icon-jiantou"></div>
  76. </div>
  77. </div>
  78. <div
  79. class="attribute acea-row row-between-wrapper activitys"
  80. v-if="activity.length"
  81. >
  82. <div class="line1 acea-row">
  83. 活&nbsp;&nbsp;&nbsp;动:
  84. <div
  85. v-for="(item, index) in activity"
  86. :key="index"
  87. @click="goDetail(item)"
  88. >
  89. <div
  90. class="acea-row row-center-wrapper"
  91. v-if="item.type === '1'"
  92. :class="{
  93. activity_pin: index === 0,
  94. activity_miao: index === 1,
  95. activity_kan: index === 2
  96. }"
  97. >
  98. <span class="iconfonts iconfont icon-shenhezhong"></span>
  99. <span class="activity_title">&nbsp;参与秒杀</span>
  100. </div>
  101. <div
  102. class="acea-row row-center-wrapper"
  103. v-if="item.type === '2'"
  104. :class="{
  105. activity_pin: index === 0,
  106. activity_miao: index === 1,
  107. activity_kan: index === 2
  108. }"
  109. >
  110. <span class="iconfonts iconfont icon-kanjia"></span>
  111. <span class="activity_title">&nbsp;参与砍价</span>
  112. </div>
  113. <div
  114. class="acea-row row-center-wrapper"
  115. v-if="item.type === '3'"
  116. :class="{
  117. activity_pin: index === 0,
  118. activity_miao: index === 1,
  119. activity_kan: index === 2
  120. }"
  121. >
  122. <span class="iconfonts iconfont icon-pintuan"></span>
  123. <span class="activity_title">&nbsp;参与拼团</span>
  124. </div>
  125. </div>
  126. </div>
  127. </div>
  128. <div
  129. class="attribute acea-row row-between-wrapper"
  130. @click="selecAttrTap"
  131. v-if="attr.productAttr.length"
  132. >
  133. <div>
  134. {{ attrTxt }}:<span class="atterTxt">{{ attrValue }}</span>
  135. </div>
  136. <div class="iconfont icon-jiantou"></div>
  137. </div>
  138. <!--<div-->
  139. <!--class="store-info"-->
  140. <!--v-if="system_store.id !== undefined && storeSelfMention"-->
  141. <!--&gt;-->
  142. <!--<div-->
  143. <!--class="acea-row row-between-wrapper store-box"-->
  144. <!--@click="showStoreList"-->
  145. <!--&gt;-->
  146. <!--<div class="title">门店信息</div>-->
  147. <!--<div class="iconfont icon-jiantou"></div>-->
  148. <!--</div>-->
  149. <!--<div class="info acea-row row-between-wrapper">-->
  150. <!--<div class="pictrue"><img :src="storeItems.image" /></div>-->
  151. <!--<div class="text">-->
  152. <!--<div class="name line1">-->
  153. <!--{{ storeItems.name }}-->
  154. <!--</div>-->
  155. <!--<div class="address acea-row row-middle" @click="showChang">-->
  156. <!--<span class="addressTxt line1 address_tit">-->
  157. <!--{{ storeItems.address }}{{ ", " + storeItems.detailed_address }}-->
  158. <!--</span>-->
  159. <!--<span class="iconfont icon-youjian"></span>-->
  160. <!--</div>-->
  161. <!--</div>-->
  162. <!--<div class="addressBox">-->
  163. <!--<a-->
  164. <!--class="iconfont icon-dadianhua01 font-color-red phone"-->
  165. <!--:href="'tel:' + storeItems.phone"-->
  166. <!--&gt;</a>-->
  167. <!--<div-->
  168. <!--class="addressTxt line1 corlor-red"-->
  169. <!--@click="showChang"-->
  170. <!--v-if="storeItems.range"-->
  171. <!--&gt;-->
  172. <!--距离{{ storeItems.range }}千米-->
  173. <!--</div>-->
  174. <!--</div>-->
  175. <!--</div>-->
  176. <!--</div>-->
  177. </div>
  178. <div class="userEvaluation" id="title1">
  179. <div class="title acea-row row-between-wrapper">
  180. <div>用户评价({{ replyCount }})</div>
  181. <router-link :to="{ path: '/evaluate_list/' + id }" class="praise"
  182. ><span class="font-color-red">{{ replyChance }}%</span>好评率<span
  183. class="iconfont icon-jiantou"
  184. ></span
  185. ></router-link>
  186. </div>
  187. <user-evaluation :reply="reply" v-if="replyCount"></user-evaluation>
  188. </div>
  189. <div class="product-intro" id="title3">
  190. <div class="title">产品介绍</div>
  191. <div class="conter" v-html="storeInfo.description"></div>
  192. </div>
  193. <div class="superior" v-if="goodList.length > 0" id="title2">
  194. <div class="title acea-row row-center-wrapper">
  195. <img src="@assets/images/ling.png" />
  196. <div class="titleTxt">优品推荐</div>
  197. <img src="@assets/images/ling.png" />
  198. </div>
  199. <template>
  200. <div class="slider-banner banner">
  201. <swiper :options="swiperRecommend">
  202. <swiper-slide v-for="(item, index) in goodList" :key="index">
  203. <div class="list acea-row row-middle">
  204. <div
  205. class="item"
  206. v-for="val in item.list"
  207. :key="val.image"
  208. @click="goGoods(val)"
  209. >
  210. <div class="pictrue">
  211. <img :src="val.image" />
  212. <span
  213. class="pictrue_log pictrue_log_class"
  214. v-if="val.activity && val.activity.type === '1'"
  215. >秒杀</span
  216. >
  217. <span
  218. class="pictrue_log pictrue_log_class"
  219. v-if="val.activity && val.activity.type === '2'"
  220. >砍价</span
  221. >
  222. <span
  223. class="pictrue_log pictrue_log_class"
  224. v-if="val.activity && val.activity.type === '3'"
  225. >拼团</span
  226. >
  227. </div>
  228. <div class="name line1">{{ val.store_name }}}</div>
  229. <div class="money font-color-red">¥{{ val.price }}</div>
  230. </div>
  231. </div>
  232. </swiper-slide>
  233. <div class="swiper-pagination" slot="pagination"></div>
  234. </swiper>
  235. </div>
  236. </template>
  237. </div>
  238. <div style="height:1.2rem;"></div>
  239. <div class="footer acea-row row-between-wrapper">
  240. <div class="item" @click="$router.push({ path: '/customer/list/' + id })">
  241. <div class="iconfont icon-kefu"></div>
  242. <div>客服</div>
  243. </div>
  244. <div class="item" @click="setCollect">
  245. <div
  246. class="iconfont"
  247. :class="storeInfo.userCollect ? 'icon-shoucang1' : 'icon-shoucang'"
  248. ></div>
  249. <div>收藏</div>
  250. </div>
  251. <router-link
  252. :to="'/cart'"
  253. class="item animated"
  254. :class="animated === true ? 'bounceIn' : ''"
  255. >
  256. <div class="iconfont icon-gouwuche1">
  257. <span class="num bg-color-red" v-if="CartCount > 0">{{
  258. CartCount
  259. }}</span>
  260. </div>
  261. <div>购物车</div>
  262. </router-link>
  263. <div class="bnt acea-row">
  264. <div class="joinCart" @click="joinCart">加入购物车</div>
  265. <div class="buy" @click="tapBuy" v-if="attr.productSelect.stock > 0">
  266. 立即购买
  267. </div>
  268. <div class="buy bg-color-hui" v-else>已售罄</div>
  269. </div>
  270. </div>
  271. <Share-red-packets
  272. :priceName="priceName"
  273. v-on:changeFun="changeFun"
  274. v-if="priceName !== 0"
  275. ></Share-red-packets>
  276. <CouponPop v-on:changeFun="changeFun" :coupon="coupon"></CouponPop>
  277. <Product-window
  278. v-on:changeFun="changeFun"
  279. :attr="attr"
  280. :iSplus="iSplus"
  281. ></Product-window>
  282. <StorePoster
  283. v-on:setPosterImageStatus="setPosterImageStatus"
  284. :posterImageStatus="posterImageStatus"
  285. :posterData="posterData"
  286. ></StorePoster>
  287. <ShareInfo
  288. v-on:setShareInfoStatus="setShareInfoStatus"
  289. :shareInfoStatus="shareInfoStatus"
  290. ></ShareInfo>
  291. <div
  292. class="generate-posters acea-row row-middle"
  293. :class="posters ? 'on' : ''"
  294. >
  295. <div class="item" @click="setShareInfoStatus">
  296. <div class="iconfont icon-weixin3"></div>
  297. <div class="">发送给朋友</div>
  298. </div>
  299. <div class="item" @click="setPosterImageStatus">
  300. <div class="iconfont icon-weixin3"></div>
  301. <div class="">发送到朋友圈</div>
  302. </div>
  303. </div>
  304. <div
  305. class="mask"
  306. @touchmove.prevent
  307. @click="listenerActionClose"
  308. v-show="posters"
  309. ></div>
  310. <div class="geoPage" v-if="mapShow">
  311. <iframe
  312. width="100%"
  313. height="100%"
  314. frameborder="0"
  315. scrolling="no"
  316. :src="
  317. 'https://apis.map.qq.com/uri/v1/geocoder?coord=' +
  318. system_store.latitude +
  319. ',' +
  320. system_store.longitude +
  321. '&referer=' +
  322. mapKey
  323. "
  324. >
  325. </iframe>
  326. </div>
  327. </div>
  328. </template>
  329. <style scoped>
  330. .activitys {
  331. border-top: 1px solid #f5f5f5;
  332. margin-top: 0 !important;
  333. }
  334. .address_tit {
  335. width: 88% !important;
  336. }
  337. .activity_pin {
  338. width: auto;
  339. height: 0.44rem;
  340. background: linear-gradient(
  341. 90deg,
  342. rgba(233, 51, 35, 1) 0%,
  343. rgba(250, 101, 20, 1) 100%
  344. );
  345. opacity: 1;
  346. border-radius: 0.22rem;
  347. padding: 0 0.2rem;
  348. margin-left: 0.19rem;
  349. }
  350. .activity_miao {
  351. width: auto;
  352. height: 0.44rem;
  353. padding: 0 0.2rem;
  354. background: linear-gradient(
  355. 90deg,
  356. rgba(250, 102, 24, 1) 0%,
  357. rgba(254, 161, 15, 1) 100%
  358. );
  359. opacity: 1;
  360. border-radius: 0.22rem;
  361. margin-left: 0.19rem;
  362. }
  363. .iconfonts {
  364. color: #fff !important;
  365. font-size: 0.28rem;
  366. display: block;
  367. }
  368. .activity_title {
  369. font-size: 0.24rem;
  370. color: #fff;
  371. }
  372. .activity_kan {
  373. width: auto;
  374. height: 0.44rem;
  375. padding: 0 0.2rem;
  376. background: linear-gradient(
  377. 90deg,
  378. rgba(254, 159, 15, 1) 0%,
  379. rgba(254, 178, 15, 1) 100%
  380. );
  381. opacity: 1;
  382. border-radius: 0.22rem;
  383. margin-left: 0.19rem;
  384. }
  385. .addressBox .phone {
  386. margin-left: 1.1rem;
  387. }
  388. .corlor-red {
  389. color: #ff3366;
  390. }
  391. .store-box {
  392. padding: 0 0.3rem;
  393. border-bottom: 1px solid #f5f5f5;
  394. }
  395. .geoPage {
  396. position: fixed;
  397. width: 100%;
  398. height: 100%;
  399. top: 0;
  400. z-index: 10000;
  401. }
  402. .product-con .header {
  403. position: fixed;
  404. left: 0;
  405. top: 0;
  406. width: 100%;
  407. height: 0.96rem;
  408. font-size: 0.3rem;
  409. color: #050505;
  410. background-color: #fff;
  411. z-index: 11;
  412. border-bottom: 0.01rem solid #eee;
  413. }
  414. .product-con .header .item {
  415. position: relative;
  416. margin: 0 0.35rem;
  417. }
  418. .product-con .header .item.on:before {
  419. position: absolute;
  420. width: 0.6rem;
  421. height: 0.05rem;
  422. background-repeat: no-repeat;
  423. content: "";
  424. background: linear-gradient(to left, #ff3366 0%, #ff6533 100%);
  425. background: -webkit-linear-gradient(to left, #ff3366 0%, #ff6533 100%);
  426. background: -moz-linear-gradient(to left, #ff3366 0%, #ff6533 100%);
  427. bottom: -0.1rem;
  428. }
  429. .product-con .store-info {
  430. margin-top: 0.2rem;
  431. background-color: #fff;
  432. }
  433. .store-info .icon-jiantou {
  434. color: #7a7a7a;
  435. font-size: 0.28rem;
  436. }
  437. .product-con .store-info .title {
  438. font-size: 0.28rem;
  439. color: #282828;
  440. height: 0.8rem;
  441. line-height: 0.8rem;
  442. border-bottom: 0.01rem solid #f5f5f5;
  443. }
  444. .product-con .store-info .info {
  445. padding: 0 0.3rem;
  446. height: 1.26rem;
  447. }
  448. .product-con .store-info .info .pictrue {
  449. width: 0.76rem;
  450. height: 0.76rem;
  451. }
  452. .product-con .store-info .info .pictrue img {
  453. width: 100%;
  454. height: 100%;
  455. border-radius: 0.06rem;
  456. }
  457. .product-con .store-info .info .text {
  458. width: 56%;
  459. }
  460. .product-con .store-info .info .text .name {
  461. font-size: 0.3rem;
  462. color: #282828;
  463. }
  464. .product-con .store-info .info .text .address {
  465. font-size: 0.24rem;
  466. color: #666;
  467. margin-top: 0.03rem;
  468. }
  469. .product-con .store-info .info .text .address .iconfont {
  470. color: #707070;
  471. font-size: 0.18rem;
  472. margin-left: 0.1rem;
  473. }
  474. .addressTxt {
  475. width: auto;
  476. font-size: 0.24rem;
  477. }
  478. .product-con .store-info .info .iconfont {
  479. font-size: 0.4rem;
  480. }
  481. .product-con .superior {
  482. background-color: #fff;
  483. margin-top: 0.2rem;
  484. }
  485. .product-con .superior .title {
  486. height: 0.98rem;
  487. }
  488. .product-con .superior .title img {
  489. width: 0.3rem;
  490. height: 0.3rem;
  491. }
  492. .product-con .superior .title .titleTxt {
  493. margin: 0 0.2rem;
  494. font-size: 0.3rem;
  495. background-image: linear-gradient(to right, #f57a37 0%, #ff3366 100%);
  496. background-image: -webkit-linear-gradient(to right, #f57a37 0%, #ff3366 100%);
  497. background-image: -moz-linear-gradient(to right, #f57a37 0%, #ff3366 100%);
  498. -webkit-background-clip: text;
  499. -webkit-text-fill-color: transparent;
  500. }
  501. .product-con .superior .slider-banner {
  502. width: 6.9rem;
  503. margin: 0 auto;
  504. padding-bottom: 0.2rem;
  505. }
  506. .product-con .superior .slider-banner .list {
  507. width: 100%;
  508. padding-bottom: 0.2rem;
  509. }
  510. .product-con .superior .slider-banner .list .item {
  511. width: 2.15rem;
  512. margin: 0 0.21rem 0.3rem 0;
  513. font-size: 0.26rem;
  514. }
  515. .product-con .superior .slider-banner .list .item:nth-of-type(3n) {
  516. margin-right: 0;
  517. }
  518. .product-con .superior .slider-banner .list .item .pictrue {
  519. width: 100%;
  520. height: 2.15rem;
  521. position: relative;
  522. }
  523. .product-con .superior .slider-banner .list .item .pictrue img {
  524. width: 100%;
  525. height: 100%;
  526. border-radius: 0.06rem;
  527. }
  528. .product-con .superior .slider-banner .list .item .name {
  529. color: #282828;
  530. margin-top: 0.12rem;
  531. }
  532. .product-con .superior .slider-banner .swiper-pagination-bullet {
  533. background-color: #999;
  534. }
  535. .product-con .superior .slider-banner .swiper-pagination-bullet-active {
  536. background-color: #e93323;
  537. }
  538. .mask {
  539. -webkit-filter: blur(2px);
  540. -moz-filter: blur(2px);
  541. -ms-filter: blur(2px);
  542. filter: blur(2px);
  543. }
  544. .footer .icon-shoucang1 {
  545. color: #ff3366;
  546. }
  547. .product-con .product-intro .conter div {
  548. width: 100% !important;
  549. }
  550. .generate-posters {
  551. width: 100%;
  552. height: 1.7rem;
  553. background-color: #fff;
  554. position: fixed;
  555. left: 0;
  556. bottom: 0;
  557. z-index: 99;
  558. transform: translate3d(0, 100%, 0);
  559. -webkit-transform: translate3d(0, 100%, 0);
  560. -ms-transform: translate3d(0, 100%, 0);
  561. -moz-transform: translate3d(0, 100%, 0);
  562. -o-transform: translate3d(0, 100%, 0);
  563. transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
  564. -webkit-transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
  565. -moz-transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
  566. -o-transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9);
  567. }
  568. .generate-posters.on {
  569. transform: translate3d(0, 0, 0);
  570. -webkit-transform: translate3d(0, 0, 0);
  571. -ms-transform: translate3d(0, 0, 0);
  572. -moz-transform: translate3d(0, 0, 0);
  573. -o-transform: translate3d(0, 0, 0);
  574. }
  575. .generate-posters .item {
  576. flex: 50%;
  577. -webkit-flex: 50%;
  578. -ms-flex: 50%;
  579. text-align: center;
  580. }
  581. .generate-posters .item .iconfont {
  582. font-size: 0.8rem;
  583. color: #5eae72;
  584. }
  585. .generate-posters .item .iconfont.icon-haibao {
  586. color: #5391f1;
  587. }
  588. .noscroll {
  589. height: 100%;
  590. overflow: hidden;
  591. }
  592. </style>
  593. <script>
  594. import { swiper, swiperSlide } from "vue-awesome-swiper";
  595. import "@assets/css/swiper.min.css";
  596. import ProductConSwiper from "@components/ProductConSwiper";
  597. import UserEvaluation from "@components/UserEvaluation";
  598. // import ShareRedPackets from "@components/ShareRedPackets";
  599. import CouponPop from "@components/CouponPop";
  600. import ProductWindow from "@components/ProductWindow";
  601. import StorePoster from "@components/StorePoster";
  602. import ShareInfo from "@components/ShareInfo";
  603. import debounce from "lodash.debounce";
  604. import WeChat from "@libs/pay";
  605. import { goShopDetail } from "@libs/order";
  606. import {
  607. getProductDetail,
  608. postCartAdd,
  609. getCartCount,
  610. getProductCode,
  611. storeListApi
  612. } from "@api/store";
  613. import {
  614. getCoupon,
  615. getCollectAdd,
  616. getCollectDel,
  617. getUserInfo
  618. } from "@api/user";
  619. import { isWeixin } from "@utils/index";
  620. import { wechatEvevt } from "@libs/wechat";
  621. import { imageBase64 } from "@api/public";
  622. import { mapGetters } from "vuex";
  623. import cookie from "@utils/store/cookie";
  624. let NAME = "GoodsCon";
  625. const LONGITUDE = "user_longitude";
  626. const LATITUDE = "user_latitude";
  627. export default {
  628. name: NAME,
  629. components: {
  630. swiper,
  631. swiperSlide,
  632. ProductConSwiper,
  633. UserEvaluation,
  634. CouponPop,
  635. ProductWindow,
  636. StorePoster,
  637. ShareInfo
  638. },
  639. data: function() {
  640. return {
  641. iSplus: true,
  642. shareInfoStatus: false,
  643. weixinStatus: false,
  644. mapShow: false,
  645. mapKey: "",
  646. posterData: {
  647. image: "",
  648. title: "",
  649. price: "",
  650. code: ""
  651. },
  652. posterImageStatus: false,
  653. animated: false,
  654. coupon: {
  655. coupon: false,
  656. list: []
  657. },
  658. attr: {
  659. cartAttr: false,
  660. productAttr: [],
  661. productSelect: {}
  662. },
  663. isOpen: false, //是否打开属性组件
  664. productValue: [],
  665. id: 0,
  666. storeInfo: {},
  667. couponList: [],
  668. attrTxt: "请选择",
  669. attrValue: "",
  670. cart_num: 1, //购买数量
  671. replyCount: "",
  672. replyChance: "",
  673. reply: [],
  674. priceName: 0,
  675. CartCount: 0,
  676. posters: false,
  677. banner: [{}, {}],
  678. swiperRecommend: {
  679. pagination: {
  680. el: ".swiper-pagination",
  681. clickable: true
  682. },
  683. autoplay: false,
  684. loop: false,
  685. speed: 1000,
  686. observer: true,
  687. observeParents: true
  688. },
  689. goodList: [],
  690. system_store: {},
  691. qqmapsdk: null,
  692. navList: [],
  693. lock: false,
  694. navActive: 0,
  695. opacity: 0,
  696. storeSelfMention: true,
  697. storeItems: {},
  698. activity: [],
  699. isVip: false
  700. };
  701. },
  702. computed: mapGetters(["isLogin"]),
  703. watch: {
  704. $route(n) {
  705. if (n.name === NAME) {
  706. this.id = n.params.id;
  707. this.storeInfo.slider_image = [];
  708. this.productCon();
  709. }
  710. }
  711. },
  712. updated() {
  713. // window.scroll(0, 0);
  714. },
  715. mounted: function() {
  716. document.addEventListener("scroll", this.onScroll, false);
  717. this.id = this.$route.params.id;
  718. this.storeInfo.slider_image = [];
  719. this.productCon();
  720. this.coupons();
  721. window.addEventListener("scroll", this.handleScroll);
  722. this.getList();
  723. this.updateVIP();
  724. },
  725. methods: {
  726. updateVIP () {
  727. var userinfo = this.$store.state.app.userInfo;
  728. if (this.$store.state.app.token) {
  729. getUserInfo().then(res => {
  730. userinfo = res.data;
  731. this.isVip = userinfo.vip_level > 0;
  732. console.log('Current VIP:', userinfo.vip_level);
  733. });
  734. return;
  735. }
  736. this.isVip = false;
  737. console.log('Current is not Login');
  738. },
  739. // 商品详情跳转
  740. goDetail(item) {
  741. if (item.type === "1") {
  742. this.$router.push({
  743. path: "/activity/seckill_detail/" + item.id + "/" + item.time + "/1"
  744. });
  745. } else if (item.type === "2") {
  746. this.$router.push({
  747. path: "/activity/dargain_detail/" + item.id
  748. });
  749. } else {
  750. this.$router.push({
  751. path: "/activity/group_detail/" + item.id
  752. });
  753. }
  754. },
  755. // 获取门店列表数据
  756. getList() {
  757. let data = {
  758. latitude: cookie.get(LATITUDE) || "", //纬度
  759. longitude: cookie.get(LONGITUDE) || "", //经度
  760. page: 1,
  761. limit: 10
  762. };
  763. storeListApi(data)
  764. .then(res => {
  765. this.storeItems = res.data.list[0];
  766. })
  767. .catch(err => {
  768. console.log(err);
  769. });
  770. },
  771. handleScroll() {
  772. let top = document.body.scrollTop || document.documentElement.scrollTop;
  773. let opacity = top / 350;
  774. opacity = opacity > 1 ? 1 : opacity;
  775. this.opacity = opacity;
  776. },
  777. asideTap(a) {
  778. this.$nextTick(() => {
  779. let index = a;
  780. this.navActive = index;
  781. if (!this.goodList.length && index === 2) {
  782. index = 3;
  783. }
  784. let element = document.querySelector("#title" + index);
  785. const top =
  786. element.offsetTop - this.$refs.header.offsetHeight - window.scrollY;
  787. this.lock = true;
  788. window.scrollBy({ top, left: 0, behavior: "smooth" });
  789. });
  790. },
  791. onScroll: debounce(function() {
  792. if (this.lock) {
  793. this.lock = false;
  794. return;
  795. }
  796. const headerHeight = this.$refs.header.offsetHeight,
  797. { scrollY } = window,
  798. titles = [];
  799. titles.push(document.querySelector("#title0"));
  800. titles.push(document.querySelector("#title1"));
  801. if (this.goodList.length) {
  802. titles.push(document.querySelector("#title2"));
  803. }
  804. titles.push(document.querySelector("#title3"));
  805. titles.reduce((initial, title, index) => {
  806. if (
  807. !document.querySelector("#title0") &&
  808. !document.querySelector("#title1") &&
  809. !document.querySelector("#title2")
  810. ) {
  811. return;
  812. }
  813. if (initial) return initial;
  814. if (scrollY + headerHeight < title.offsetTop + title.offsetHeight) {
  815. initial = true;
  816. this.navActive = index;
  817. }
  818. return initial;
  819. }, false);
  820. }, 500),
  821. showChang: function() {
  822. if (isWeixin()) {
  823. let config = {
  824. latitude: parseFloat(this.storeItems.latitude),
  825. longitude: parseFloat(this.storeItems.longitude),
  826. name: this.storeItems.name,
  827. address: this.storeItems.address + this.system_store.detailed_address
  828. };
  829. wechatEvevt("openLocation", config)
  830. .then(res => {
  831. console.log(res);
  832. })
  833. .catch(res => {
  834. if (res.is_ready) {
  835. res.wx.openLocation(config);
  836. }
  837. });
  838. } else {
  839. if (!this.mapKey)
  840. return this.$dialog.error(
  841. "暂无法使用查看地图,请配置您的腾讯地图key"
  842. );
  843. this.mapShow = true;
  844. }
  845. },
  846. updateTitle() {
  847. document.title = this.storeInfo.store_name || this.$route.meta.title;
  848. },
  849. // 调转到门店列表
  850. showStoreList() {
  851. this.$store.commit("GET_TO", "details");
  852. this.$router.push("/shop/storeList/details");
  853. },
  854. setOpenShare: function() {
  855. var data = this.storeInfo;
  856. var href = location.href;
  857. if (isWeixin()) {
  858. if (this.isLogin) {
  859. getUserInfo().then(res => {
  860. href =
  861. href.indexOf("?") === -1
  862. ? href + "?spread=" + res.data.uid
  863. : href + "&spread=" + res.data.uid;
  864. var configAppMessage = {
  865. desc: data.store_info,
  866. title: data.store_name,
  867. link: href,
  868. imgUrl: data.image
  869. };
  870. wechatEvevt(
  871. ["updateAppMessageShareData", "updateTimelineShareData"],
  872. configAppMessage
  873. )
  874. .then(res => {
  875. console.log(res);
  876. })
  877. .catch(res => {
  878. console.log(res);
  879. if (res.is_ready) {
  880. res.wx.updateAppMessageShareData(configAppMessage);
  881. res.wx.updateTimelineShareData(configAppMessage);
  882. }
  883. });
  884. });
  885. } else {
  886. var configAppMessage = {
  887. desc: data.store_info,
  888. title: data.store_name,
  889. link: href,
  890. imgUrl: data.image
  891. };
  892. wechatEvevt(
  893. ["updateAppMessageShareData", "updateTimelineShareData"],
  894. configAppMessage
  895. )
  896. .then(res => {
  897. console.log(res);
  898. })
  899. .catch(res => {
  900. if (res.is_ready) {
  901. res.wx.updateAppMessageShareData(configAppMessage);
  902. res.wx.updateTimelineShareData(configAppMessage);
  903. }
  904. });
  905. }
  906. }
  907. },
  908. setShareInfoStatus: function() {
  909. if (isWeixin()) {
  910. this.shareInfoStatus = !this.shareInfoStatus;
  911. this.posters = false;
  912. } else {
  913. this.posters = false;
  914. console.log("todo wechat friend");
  915. // todo wechat send to friend
  916. var data = this.storeInfo;
  917. var message = {
  918. title: data.store_name,
  919. description: data.store_info,
  920. thumb: data.image,
  921. media: {
  922. type: Wechat.Type.WEBPAGE,
  923. webpageUrl: "http://www.shotshock.shop/"
  924. }
  925. };
  926. WeChat.shareLink(message, function(success) {
  927. if (success) console.log("share success !");
  928. else console.log("share falied !");
  929. });
  930. }
  931. },
  932. shareCode: function(value) {
  933. var that = this;
  934. getProductCode(that.id).then(res => {
  935. if (res.data.code) that.posterData.code = res.data.code;
  936. value === false && that.listenerActionSheet();
  937. });
  938. },
  939. setPosterImageStatus: function() {
  940. // var sTop = document.body || document.documentElement;
  941. // sTop.scrollTop = 0;
  942. // this.posterImageStatus = !this.posterImageStatus;
  943. this.posters = false;
  944. console.log("todo wechat friends");
  945. var data = this.storeInfo;
  946. var message = {
  947. title: data.store_name,
  948. description: data.store_info,
  949. thumb: data.image,
  950. media: {
  951. type: Wechat.Type.WEBPAGE,
  952. webpageUrl: "http://www.shotshock.shop"
  953. }
  954. };
  955. WeChat.shareLink(
  956. message,
  957. function(success) {
  958. if (success) console.log("share success !");
  959. else console.log("share falied !");
  960. }, false);
  961. },
  962. //产品详情接口;
  963. productCon: function() {
  964. let that = this;
  965. getProductDetail(that.id)
  966. .then(res => {
  967. that.$set(that, "storeInfo", res.data.storeInfo);
  968. that.$set(that.attr, "productAttr", res.data.productAttr);
  969. that.$set(that, "productValue", res.data.productValue);
  970. that.$set(that, "replyCount", res.data.replyCount);
  971. that.$set(that, "replyChance", res.data.replyChance);
  972. that.reply = res.data.reply ? [res.data.reply] : [];
  973. that.$set(that, "reply", that.reply);
  974. that.$set(that, "priceName", res.data.priceName);
  975. that.posterData.image = that.storeInfo.image_base;
  976. that.activity = res.data.activity ? res.data.activity : [];
  977. if (that.storeInfo.store_name.length > 30) {
  978. that.posterData.title =
  979. that.storeInfo.store_name.substring(0, 30) + "...";
  980. } else {
  981. that.posterData.title = that.storeInfo.store_name;
  982. }
  983. that.storeSelfMention = res.data.store_self_mention ? true : false;
  984. that.posterData.price = that.isVip ? that.storeInfo.vip_price : that.storeInfo.price;
  985. that.posterData.code = that.storeInfo.code_base;
  986. that.system_store = res.data.system_store || {};
  987. let good_list = res.data.good_list || [];
  988. let goodArray = [];
  989. let count = Math.ceil(good_list.length / 6);
  990. for (let i = 0; i < count; i++) {
  991. var list = good_list.slice(i * 6, i * 6 + 6);
  992. if (list.length) goodArray.push({ list: list });
  993. }
  994. that.mapKey = res.data.mapKey;
  995. that.$set(that, "goodList", goodArray);
  996. let navList = ["商品", "评价", "详情"];
  997. if (goodArray.length) {
  998. navList.splice(2, 0, "推荐");
  999. }
  1000. that.navList = navList;
  1001. that.updateTitle();
  1002. that.DefaultSelect();
  1003. that.getCartCount();
  1004. that.getImageBase64();
  1005. that.setOpenShare();
  1006. })
  1007. .catch(res => {
  1008. that.$dialog.error(res.msg);
  1009. that.$router.go(-1);
  1010. });
  1011. },
  1012. getImageBase64: function() {
  1013. let that = this;
  1014. imageBase64(this.posterData.image, that.posterData.code)
  1015. .then(res => {
  1016. that.posterData.image = res.data.image;
  1017. that.posterData.code = res.data.code;
  1018. that.isLogin && that.shareCode();
  1019. })
  1020. .catch(() => {
  1021. that.isLogin && that.shareCode();
  1022. });
  1023. },
  1024. //默认选中属性;
  1025. DefaultSelect: function() {
  1026. let productAttr = this.attr.productAttr,
  1027. value = [];
  1028. for (var key in this.productValue) {
  1029. if (this.productValue[key].stock > 0) {
  1030. value = this.attr.productAttr.length ? key.split(",") : [];
  1031. break;
  1032. }
  1033. }
  1034. for (let i = 0; i < productAttr.length; i++) {
  1035. this.$set(productAttr[i], "index", value[i]);
  1036. }
  1037. //sort();排序函数:数字-英文-汉字;
  1038. let productSelect = this.productValue[value.sort().join(",")];
  1039. if (productSelect && productAttr.length) {
  1040. this.$set(
  1041. this.attr.productSelect,
  1042. "store_name",
  1043. this.storeInfo.store_name
  1044. );
  1045. this.$set(this.attr.productSelect, "image", productSelect.image);
  1046. this.$set(this.attr.productSelect, "price", this.isVip ? productSelect.vip_price : productSelect.price);
  1047. this.$set(this.attr.productSelect, "stock", productSelect.stock);
  1048. this.$set(this.attr.productSelect, "unique", productSelect.unique);
  1049. this.$set(this.attr.productSelect, "cart_num", 1);
  1050. this.$set(this, "attrValue", value.sort().join(","));
  1051. this.$set(this, "attrTxt", "已选择");
  1052. } else if (!productSelect && productAttr.length) {
  1053. this.$set(
  1054. this.attr.productSelect,
  1055. "store_name",
  1056. this.storeInfo.store_name
  1057. );
  1058. this.$set(this.attr.productSelect, "image", this.storeInfo.image);
  1059. this.$set(this.attr.productSelect, "price", this.isVip ? this.storeInfo.vip_price : this.storeInfo.price);
  1060. this.$set(this.attr.productSelect, "stock", 0);
  1061. this.$set(this.attr.productSelect, "unique", "");
  1062. this.$set(this.attr.productSelect, "cart_num", 0);
  1063. this.$set(this, "attrValue", "");
  1064. this.$set(this, "attrTxt", "请选择");
  1065. } else if (!productSelect && !productAttr.length) {
  1066. this.$set(
  1067. this.attr.productSelect,
  1068. "store_name",
  1069. this.storeInfo.store_name
  1070. );
  1071. this.$set(this.attr.productSelect, "image", this.storeInfo.image);
  1072. this.$set(this.attr.productSelect, "price", this.isVip ? this.storeInfo.vip_price : this.storeInfo.price);
  1073. this.$set(this.attr.productSelect, "stock", this.storeInfo.stock);
  1074. this.$set(
  1075. this.attr.productSelect,
  1076. "unique",
  1077. this.storeInfo.unique || ""
  1078. );
  1079. this.$set(this.attr.productSelect, "cart_num", 1);
  1080. this.$set(this, "attrValue", "");
  1081. this.$set(this, "attrTxt", "请选择");
  1082. }
  1083. },
  1084. //购物车;
  1085. ChangeCartNum: function(changeValue) {
  1086. //changeValue:是否 加|减
  1087. //获取当前变动属性
  1088. let productSelect = this.productValue[this.attrValue];
  1089. //如果没有属性,赋值给商品默认库存
  1090. if (productSelect === undefined && !this.attr.productAttr.length)
  1091. productSelect = this.attr.productSelect;
  1092. //无属性值即库存为0;不存在加减;
  1093. if (productSelect === undefined) return;
  1094. let stock = productSelect.stock || 0;
  1095. let num = this.attr.productSelect;
  1096. if (changeValue) {
  1097. num.cart_num++;
  1098. if (num.cart_num > stock) {
  1099. this.$set(this.attr.productSelect, "cart_num", stock ? stock : 1);
  1100. this.$set(this, "cart_num", stock ? stock : 1);
  1101. }
  1102. } else {
  1103. num.cart_num--;
  1104. if (num.cart_num < 1) {
  1105. this.$set(this.attr.productSelect, "cart_num", 1);
  1106. this.$set(this, "cart_num", 1);
  1107. }
  1108. }
  1109. },
  1110. //将父级向子集多次传送的函数合二为一;
  1111. changeFun: function(opt) {
  1112. if (typeof opt !== "object") opt = {};
  1113. let action = opt.action || "";
  1114. let value = opt.value === undefined ? "" : opt.value;
  1115. this[action] && this[action](value);
  1116. },
  1117. //打开优惠券插件;
  1118. couponTap: function() {
  1119. let that = this;
  1120. that.coupons();
  1121. that.coupon.coupon = true;
  1122. },
  1123. changecoupon: function(msg) {
  1124. this.coupon.coupon = msg;
  1125. this.coupons();
  1126. },
  1127. currentcoupon: function(res) {
  1128. let that = this;
  1129. that.coupon.coupon = false;
  1130. that.$set(that.coupon.list[res], "is_use", true);
  1131. },
  1132. //可领取优惠券接口;
  1133. coupons: function() {
  1134. let that = this,
  1135. q = { page: 1, limit: 20, type: 1, product_id: that.id };
  1136. getCoupon(q).then(res => {
  1137. that.$set(that, "couponList", res.data || []);
  1138. that.$set(that.coupon, "list", res.data);
  1139. });
  1140. },
  1141. //打开属性插件;
  1142. selecAttrTap: function() {
  1143. this.attr.cartAttr = true;
  1144. this.isOpen = true;
  1145. },
  1146. changeattr: function(msg) {
  1147. this.attr.cartAttr = msg;
  1148. this.isOpen = false;
  1149. },
  1150. //选择属性;
  1151. ChangeAttr: function(res) {
  1152. let productSelect = this.productValue[res];
  1153. if (productSelect) {
  1154. this.$set(this.attr.productSelect, "image", productSelect.image);
  1155. this.$set(this.attr.productSelect, "price", this.isVip ? productSelect.vip_price : productSelect.price);
  1156. this.$set(this.attr.productSelect, "stock", productSelect.stock);
  1157. this.$set(this.attr.productSelect, "unique", productSelect.unique);
  1158. this.$set(this.attr.productSelect, "cart_num", 1);
  1159. this.$set(this, "attrValue", res);
  1160. this.$set(this, "attrTxt", "已选择");
  1161. } else {
  1162. this.$set(this.attr.productSelect, "image", this.storeInfo.image);
  1163. this.$set(this.attr.productSelect, "price", this.isVip ? this.storeInfo.vip_price : this.storeInfo.price);
  1164. this.$set(this.attr.productSelect, "stock", 0);
  1165. this.$set(this.attr.productSelect, "unique", "");
  1166. this.$set(this.attr.productSelect, "cart_num", 0);
  1167. this.$set(this, "attrValue", "");
  1168. this.$set(this, "attrTxt", "请选择");
  1169. }
  1170. },
  1171. //收藏商品
  1172. setCollect: function() {
  1173. let that = this,
  1174. id = that.storeInfo.id,
  1175. category = "product";
  1176. if (that.storeInfo.userCollect) {
  1177. getCollectDel(id, category).then(function() {
  1178. that.storeInfo.userCollect = !that.storeInfo.userCollect;
  1179. });
  1180. } else {
  1181. getCollectAdd(id, category).then(function() {
  1182. that.storeInfo.userCollect = !that.storeInfo.userCollect;
  1183. });
  1184. }
  1185. },
  1186. goGoods(item) {
  1187. goShopDetail(item).then(() => {
  1188. window.scroll(0, 0);
  1189. this.$router.push({ path: "/detail/" + item.id });
  1190. });
  1191. },
  1192. // 点击加入购物车按钮
  1193. joinCart: function() {
  1194. //0=加入购物车
  1195. this.goCat(0);
  1196. },
  1197. // 加入购物车;
  1198. goCat: function(news) {
  1199. let that = this,
  1200. productSelect = that.productValue[this.attrValue];
  1201. //打开属性
  1202. if (that.attrValue) {
  1203. //默认选中了属性,但是没有打开过属性弹窗还是自动打开让用户查看默认选中的属性
  1204. that.attr.cartAttr = !that.isOpen ? true : false;
  1205. } else {
  1206. if (that.isOpen) that.attr.cartAttr = true;
  1207. else that.attr.cartAttr = !that.attr.cartAttr;
  1208. }
  1209. //只有关闭属性弹窗时进行加入购物车
  1210. if (that.attr.cartAttr === true && that.isOpen === false)
  1211. return (that.isOpen = true);
  1212. if (
  1213. !this.attr.productSelect.cart_num ||
  1214. parseInt(this.attr.productSelect.cart_num) <= 0
  1215. )
  1216. return that.$dialog.toast({ mes: "请输入购买数量" });
  1217. //如果有属性,没有选择,提示用户选择
  1218. if (
  1219. that.attr.productAttr.length &&
  1220. productSelect === undefined &&
  1221. that.isOpen === true
  1222. )
  1223. return that.$dialog.toast({ mes: "产品库存不足,请选择其它" });
  1224. let q = {
  1225. productId: that.id,
  1226. cartNum: that.attr.productSelect.cart_num,
  1227. new: news,
  1228. uniqueId:
  1229. that.attr.productSelect !== undefined
  1230. ? that.attr.productSelect.unique
  1231. : ""
  1232. };
  1233. postCartAdd(q)
  1234. .then(function(res) {
  1235. that.isOpen = false;
  1236. that.attr.cartAttr = false;
  1237. if (news) {
  1238. that.$router.push({ path: "/order/submit/" + res.data.cartId });
  1239. } else {
  1240. that.$dialog.toast({
  1241. mes: "添加购物车成功",
  1242. callback: () => {
  1243. that.getCartCount(true);
  1244. }
  1245. });
  1246. }
  1247. })
  1248. .catch(res => {
  1249. that.isOpen = false;
  1250. return that.$dialog.toast({ mes: res.msg });
  1251. });
  1252. },
  1253. //获取购物车数量
  1254. getCartCount: function(isAnima) {
  1255. let that = this;
  1256. const isLogin = that.isLogin;
  1257. if (isLogin) {
  1258. getCartCount({ numType: 0 }).then(res => {
  1259. that.CartCount = res.data.count;
  1260. //加入购物车后重置属性
  1261. if (isAnima) {
  1262. that.animated = true;
  1263. setTimeout(function() {
  1264. that.animated = false;
  1265. }, 500);
  1266. }
  1267. });
  1268. }
  1269. },
  1270. //立即购买;
  1271. tapBuy: function() {
  1272. // 1=直接购买
  1273. this.goCat(1);
  1274. },
  1275. listenerActionSheet: function() {
  1276. if (isWeixin() === true) {
  1277. this.weixinStatus = true;
  1278. }
  1279. this.posters = true;
  1280. },
  1281. listenerActionClose: function() {
  1282. this.posters = false;
  1283. }
  1284. },
  1285. beforeDestroy: function() {
  1286. document.removeEventListener("scroll", this.onScroll, false);
  1287. window.removeEventListener("scroll", this.handleScroll);
  1288. }
  1289. };
  1290. </script>