_seckillId.vue 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555
  1. <template>
  2. <div class="detail">
  3. <!-- 面包屑导航 -->
  4. <div class="crumbs-shop">
  5. <div class="content">
  6. <div class="crumbs"></div>
  7. <div class="shop-box">
  8. <nuxt-link :to="'/shopIndex?sid=' + prodInfo.shopId" class="shop">
  9. <i class="self" v-if="shopInfo && shopInfo.shopId === 1">{{$t('prodDetail.selfEmployed')}}</i>
  10. <i class="shop-icon" v-if="shopInfo && shopInfo.shopId != 1"></i>
  11. {{ shopInfo ? shopInfo.shopName : '' }}
  12. </nuxt-link>
  13. <a href="javascript:void(0)" @click="toChatIm(shopInfo)" class="im-chat"><span class="btn-im"></span>{{$t('prodDetail.contactCustomerService')}}</a>
  14. <span
  15. class="favourite"
  16. v-if="!isShopCollection"
  17. @click="toggleShopCollect"
  18. >
  19. <i class="favourite-icon"></i>{{$t('prodDetail.collectionStores')}}
  20. </span>
  21. <span class="favourite active" @click="toggleShopCollect" v-else>
  22. <i class="favourite-icon"></i>{{$t('prodDetail.collectedStores')}}
  23. </span>
  24. </div>
  25. </div>
  26. </div>
  27. <!-- /面包屑导航 -->
  28. <div class="content">
  29. <div class="detail-up">
  30. <!-- 商品图片 -->
  31. <div class="img">
  32. <div class="big-img">
  33. <img v-if="(!prodInfo.video || !showVideo) && prodInfo.pic" :src="prodInfo.pic" alt />
  34. <img v-if="(!prodInfo.video || !showVideo) && !prodInfo.pic" src="~/assets/img/def.png" alt />
  35. <!-- 商品视频 -->
  36. <video
  37. v-show="showVideo"
  38. id="prodVideo"
  39. class="big-img prod-video"
  40. :src="prodInfo.video"
  41. controls
  42. ></video>
  43. <!-- 商品视频end -->
  44. <div class="oper-btn" v-if="showPlayBtn && prodInfo.video">
  45. <img
  46. src="~/assets/images/play.png"
  47. @click="playVideo"
  48. alt="播放"
  49. />
  50. </div>
  51. <div class="close-btn" v-if="!showPlayBtn && showVideo">
  52. <img
  53. src="~/assets/images/close.png"
  54. alt="关闭"
  55. @click="stopVideo"
  56. />
  57. </div>
  58. </div>
  59. <div class="small-img">
  60. <i
  61. class="left-arrow"
  62. @click="prevImg"
  63. :class="{
  64. limit: prodImgs.length - 5 <= 0 || this.offsetCount < 1
  65. }"
  66. >&lt;</i
  67. >
  68. <i
  69. class="right-arrow"
  70. @click="nextImg"
  71. :class="{
  72. limit:
  73. prodImgs.length - 5 <= 0 ||
  74. this.offsetCount >= prodImgs.length - 5
  75. }"
  76. >&gt;</i
  77. >
  78. <div class="img-box">
  79. <div class="offset-box" ref="carouser">
  80. <div
  81. class="item"
  82. v-for="(item, index) in prodImgs"
  83. :key="index"
  84. :class="{ active: item.isActive }"
  85. @mouseover="changeProdImg(index)"
  86. >
  87. <img :src="item.img" />
  88. </div>
  89. </div>
  90. </div>
  91. </div>
  92. </div>
  93. <!-- /商品图片 -->
  94. <!-- 商品详情 -->
  95. <div class="info" v-if="prodInfo">
  96. <div class="name-box">
  97. <div class="name">{{ prodInfo.prodName }}</div>
  98. <div class="des">
  99. <div :title="prodInfo.brief" class="brief">
  100. {{ prodInfo.brief }}
  101. </div>
  102. </div>
  103. </div>
  104. <!-- 拼团和秒杀商品 -->
  105. <div class="activity">
  106. <div class="name flash-sale">
  107. {{
  108. prodInfo.seckill.seckillName
  109. ? prodInfo.seckill.seckillName
  110. : $t('spike.secondsOfActivity')
  111. }}
  112. </div>
  113. <div class="limit" v-if="countdown.obj.signs != -1">
  114. {{$t('prodDetail.distanceActivity')}} <span>{{ countdown.obj.signs ? $t('end') : $t('start') }}</span
  115. > {{$t('onlyLeft')}}:
  116. <span class="time" v-if="countdown && countdown.obj.day">{{
  117. countdown.obj.day +
  118. $t('day1') +
  119. countdown.obj.hou +
  120. $t('time1') +
  121. countdown.obj.min +
  122. $t('minutes') +
  123. countdown.obj.sec +
  124. $t('seconds')
  125. }}</span>
  126. <span class="time" v-else>{{
  127. countdown.obj.day +
  128. ':' +
  129. countdown.obj.hou +
  130. ':' +
  131. countdown.obj.min +
  132. ':' +
  133. countdown.obj.sec
  134. }}</span>
  135. </div>
  136. <div class="limit" v-else>{{$t('spike.secondsOfActivity')}}</div>
  137. </div>
  138. <div class="price-box">
  139. <div class="item goods-price">
  140. <span class="tit">{{$t('price')}}</span>
  141. <div class="con">
  142. <div class="price">
  143. <span class="big">{{
  144. parsePrice(defaultSku.seckillPrice)[0]
  145. }}</span>
  146. .{{ parsePrice(defaultSku.seckillPrice)[1] }}
  147. </div>
  148. <div class="old-price" v-if="defaultSku.price">
  149. ¥{{ defaultSku.price.toFixed(2) }}
  150. </div>
  151. </div>
  152. <span v-if="findSku" class="tit">{{$t('prodDetail.remainingInventory')}}</span>
  153. <div v-if="findSku" class="con">
  154. {{defaultSku.seckillStocks}}
  155. </div>
  156. </div>
  157. <!-- 说明(虚拟商品) -->
  158. <div
  159. v-if="prodInfo.mold === 1 && (prodInfo.writeOffNum !== 0 || (prodInfo.writeOffNum === 0 && prodInfo.isRefund === 0))"
  160. class="item goods-price">
  161. <span class="tit">{{$t('prodDetail.instructions')}}</span>
  162. <div class="con">
  163. <!-- writeOffNum 0无需核销 1单次核销 -1多次核销 -->
  164. <span v-if="prodInfo.writeOffNum !== 0">
  165. <!-- writeOffTime核销有效期 -1.长期有效 0.自定义 1.当天24点前 x.x天内有效 -->
  166. <span v-if="prodInfo.writeOffTime === -1">{{$t('prodDetail.longTermValidity')}}</span>
  167. <span v-else-if="prodInfo.writeOffTime === 0">{{$t('prodDetail.afterPurchase')}} {{prodInfo.writeOffStart}} {{$t('prodDetail.to')}} {{prodInfo.writeOffEnd}} <i v-if="$t('language')=='zh'">{{$t('prodDetail.effective')}}</i></span>
  168. <span v-else-if="prodInfo.writeOffTime === 1">{{$t('prodDetail.validOnTheSameDay')}}</span>
  169. <span v-else>{{$t('prodDetail.purchase')}}{{prodInfo.writeOffTime}}{{$t('prodDetail.validDay')}}</span>
  170. </span>
  171. <!-- isRefund 0不支持退款 1支持退款 -->
  172. <span v-if="prodInfo.isRefund === 0"><span v-if="prodInfo.writeOffNum !== 0">,</span>{{$t('prodDetail.refundsAreNotAllowed')}}</span>
  173. </div>
  174. </div>
  175. </div>
  176. <div class="sku-box" v-if="prodInfo.skuList.length">
  177. <div
  178. class="items sku-text"
  179. v-for="(skuLine, key) in skuGroup"
  180. :key="key"
  181. >
  182. <span class="tit">{{ key }}</span>
  183. <div class="con">
  184. <span
  185. class="item"
  186. @click="toChooseItem(skuLineItem, key, $event)"
  187. :class="[
  188. selectedProp.find(el => el.key === key && el.value === skuLineItem) ? 'active' : '',
  189. isSkuLineItemNotOptional(
  190. allProperties,
  191. selectedPropObj,
  192. key,
  193. skuLineItem,
  194. propKeys
  195. )
  196. ? 'not-optional'
  197. : ''
  198. ]"
  199. v-for="skuLineItem in skuLine"
  200. :key="skuLineItem"
  201. >{{ skuLineItem }}</span
  202. >
  203. </div>
  204. </div>
  205. </div>
  206. <!-- 计数器 -->
  207. <div class="sku-box">
  208. <div class="items">
  209. <span class="tit">{{$t('quantity')}}</span>
  210. <div class="con">
  211. <div class="goods-number" onselectstart="return false">
  212. <span
  213. :class="['reduce', this.prohibit1 ? 'limit' : '']"
  214. @click="reduce"
  215. >-</span
  216. >
  217. <input
  218. type="number"
  219. class="number"
  220. v-model="prodNum"
  221. oninput="value=value.replace(/[^\d]/g,'')"
  222. @blur="resetProdNum"
  223. />
  224. <span
  225. :class="['increase', this.prohibit2 ? 'limit' : '']"
  226. @click="increase"
  227. >+</span
  228. >
  229. </div>
  230. </div>
  231. </div>
  232. </div>
  233. <div class="btns">
  234. <a
  235. href="javascript:void(0)"
  236. class="buy-now"
  237. :class="[countdown.obj.signs?'':'disabled-gray']"
  238. @click="buyNow"
  239. v-if="findSku && defaultSku.seckillStocks && countdown.obj.signs == 1"
  240. >{{$t('prodDetail.grabYourCopyNow')}}</a
  241. >
  242. <a
  243. href="javascript:void(0)"
  244. class="shortage"
  245. v-else-if="findSku && defaultSku.seckillStocks && countdown.obj.signs == 0"
  246. >{{$t('prodDetail.eventNotStarted')}}</a
  247. >
  248. <a
  249. href="javascript:void(0)"
  250. class="shortage"
  251. v-else-if="findSku && defaultSku.seckillStocks && countdown.obj.signs == -1"
  252. >{{$t('prodDetail.theEventHasEnded')}}</a
  253. >
  254. <a href="javascript:void(0)" class="shortage" v-else-if="!findSku"
  255. >{{$t('prodDetail.productNotInStock')}}</a
  256. >
  257. <a
  258. href="javascript:void(0)"
  259. class="shortage"
  260. v-else-if="!defaultSku.seckillStocks"
  261. >{{$t('prodDetail.productOutOfStock')}}</a
  262. >
  263. <a
  264. href="javascript:void(0)"
  265. class="collect"
  266. v-if="!isCollection"
  267. @click="toggleCollect()"
  268. >
  269. <i class="icon"></i>{{$t('prodDetail.collectionOfProducts')}}
  270. </a>
  271. <a
  272. href="javascript:void(0)"
  273. class="collected"
  274. v-if="isCollection"
  275. @click="toggleCollect()"
  276. >
  277. <i class="icon"></i>{{$t('prodDetail.bookmarked')}}
  278. </a>
  279. </div>
  280. </div>
  281. <!-- 商品详情 -->
  282. </div>
  283. <div class="detail-down">
  284. <div class="introduce-box">
  285. <div class="tab">
  286. <div
  287. :class="['item', introduceOrCommentInt ? 'active' : '']"
  288. @click="toggleIntroduceInt"
  289. >
  290. {{$t('prodDetail.productIntroduction')}}
  291. </div>
  292. <div
  293. :class="['item', introduceOrCommentCom ? 'active' : '']"
  294. @click="toggleIntroduceCom"
  295. >
  296. {{$t('prodDetail.productReviews')}}
  297. <i class="number">({{ prodCommData.number }})</i>
  298. </div>
  299. </div>
  300. <!-- 商品介绍 -->
  301. <div class="introduce" v-show="introduceOrCommentInt">
  302. <div>
  303. <div class="params" v-for="(params, index) in prodParameterList" :key="index">
  304. <div
  305. class="params-box"
  306. v-for="item in params"
  307. :key="item.prodParameterId"
  308. >
  309. <div class="key">{{ item.parameterKey }}</div>
  310. <div :title="item.parameterValue" class="value">{{ item.parameterValue }}</div>
  311. </div>
  312. </div>
  313. </div>
  314. <div v-rich="prodInfo.content" v-if="prodInfo.content"></div>
  315. </div>
  316. <!-- /商品介绍 -->
  317. <!-- 商品评论 -->
  318. <div class="comment" v-if="introduceOrCommentCom">
  319. <!-- 好评率 -->
  320. <div class="good-rates">
  321. <div class="score">
  322. <div class="tit">{{$t('prodDetail.favorableRatingRate')}}:</div>
  323. <div class="con">{{ prodCommData.positiveRating }}%</div>
  324. </div>
  325. <div class="average">
  326. <div class="item">
  327. <div class="text">5.0</div>
  328. <div class="stars">
  329. <i class="star"></i>
  330. <i class="star"></i>
  331. <i class="star"></i>
  332. <i class="star"></i>
  333. <i class="star"></i>
  334. </div>
  335. <div class="number">({{ prodCommData.scoreNumber5 }})</div>
  336. </div>
  337. <div class="item">
  338. <div class="text">4.0</div>
  339. <div class="stars">
  340. <i class="star"></i>
  341. <i class="star"></i>
  342. <i class="star"></i>
  343. <i class="star"></i>
  344. <i class="star-gray"></i>
  345. </div>
  346. <div class="number">({{ prodCommData.scoreNumber4 }})</div>
  347. </div>
  348. <div class="item">
  349. <div class="text">3.0</div>
  350. <div class="stars">
  351. <i class="star"></i>
  352. <i class="star"></i>
  353. <i class="star"></i>
  354. <i class="star-gray"></i>
  355. <i class="star-gray"></i>
  356. </div>
  357. <div class="number">({{ prodCommData.scoreNumber3 }})</div>
  358. </div>
  359. <div class="item">
  360. <div class="text">2.0</div>
  361. <div class="stars">
  362. <i class="star"></i>
  363. <i class="star"></i>
  364. <i class="star-gray"></i>
  365. <i class="star-gray"></i>
  366. <i class="star-gray"></i>
  367. </div>
  368. <div class="number">({{ prodCommData.scoreNumber2 }})</div>
  369. </div>
  370. <div class="item">
  371. <div class="text">1.0</div>
  372. <div class="stars">
  373. <i class="star"></i>
  374. <i class="star-gray"></i>
  375. <i class="star-gray"></i>
  376. <i class="star-gray"></i>
  377. <i class="star-gray"></i>
  378. </div>
  379. <div class="number">({{ prodCommData.scoreNumber1 }})</div>
  380. </div>
  381. </div>
  382. </div>
  383. <!-- /好评率 -->
  384. <!-- 评论列表 -->
  385. <div class="comment-tab">
  386. <div
  387. class="item"
  388. :class="evaluate === -1 ? 'active' : ''"
  389. @click="getProdCommPageByProd(-1)"
  390. >
  391. {{$t('all')}}
  392. <span class="number">({{ prodCommData.number }})</span>
  393. </div>
  394. <div
  395. class="item"
  396. :class="evaluate === 0 ? 'active' : ''"
  397. @click="getProdCommPageByProd(0)"
  398. >
  399. {{$t('prodDetail.goodReview')}}
  400. <span class="number">({{ prodCommData.praiseNumber }})</span>
  401. </div>
  402. <div
  403. class="item"
  404. :class="evaluate === 1 ? 'active' : ''"
  405. @click="getProdCommPageByProd(1)"
  406. >
  407. {{$t('prodDetail.mediumRating')}}
  408. <span class="number"
  409. >({{ prodCommData.secondaryNumber }})</span
  410. >
  411. </div>
  412. <div
  413. class="item"
  414. :class="evaluate === 2 ? 'active' : ''"
  415. @click="getProdCommPageByProd(2)"
  416. >
  417. {{$t('prodDetail.poorReviews')}}
  418. <span class="number"
  419. >({{ prodCommData.negativeNumber }})</span
  420. >
  421. </div>
  422. <div
  423. class="item"
  424. :class="evaluate === 3 ? 'active' : ''"
  425. @click="getProdCommPageByProd(3)"
  426. >
  427. {{$t('prodDetail.withPictures')}}
  428. <span class="number">({{ prodCommData.picNumber }})</span>
  429. </div>
  430. </div>
  431. <div class="comment-con" v-if="prodCommList.records.length">
  432. <div
  433. class="item"
  434. v-for="(item, comIndex) in prodCommList.records"
  435. :key="item.prodCommId"
  436. >
  437. <div class="buyer-msg">
  438. <div class="img">
  439. <img :src="item.pic" alt v-if="item.pic" />
  440. <img src="~/assets/images/buyer-img.png" alt v-else />
  441. </div>
  442. <div class="name">
  443. {{ item.nickName ? item.nickName : $t('prodDetail.anonymousUser') }}
  444. </div>
  445. </div>
  446. <div class="buyer-comment">
  447. <div class="stars">
  448. <i
  449. class="star"
  450. v-for="index in item.score"
  451. :key="index"
  452. ></i>
  453. </div>
  454. <div class="text">{{ item.content }}</div>
  455. <div class="img-box" v-if="item.pics && item.prodImgs">
  456. <span
  457. class="img"
  458. v-for="(img, imgIndex) in item.prodImgs"
  459. @click="imgShow(comIndex, imgIndex)"
  460. :key="imgIndex"
  461. >
  462. <img :src="img" @click="imgShow(comIndex, imgIndex)" />
  463. </span>
  464. </div>
  465. <div class="big-img-show" v-if="showBigImg">
  466. <div class="mask" @click="closeShowBigImg"></div>
  467. <img :src="imgPath" />
  468. </div>
  469. <div class="time-sku">
  470. <span class="time">{{ item.recTime }}</span>
  471. </div>
  472. <div class="seller-reply" v-if="item.replyContent">
  473. <div class="tit">{{$t('prodDetail.merchantResponse')}}:</div>
  474. <div class="con">{{ item.replyContent }}</div>
  475. <div class="time">{{ item.replyTime }}</div>
  476. </div>
  477. </div>
  478. </div>
  479. </div>
  480. <div class="comment-con" v-if="!prodCommList.records.length">
  481. <div class="comment-empty">{{$t('prodDetail.noComments')}}</div>
  482. </div>
  483. <!-- /评论列表 -->
  484. <!-- 页码 -->
  485. <div class="pagination">
  486. <div class="pages" v-if="page.pages >= 1">
  487. <a
  488. href="javascript:void(0);"
  489. class="item prev"
  490. :class="{ default: page.current <= 1 }"
  491. @click="getSearchProdPage(page.current - 1)"
  492. >{{$t('pagination.previousPage')}}</a
  493. >
  494. <div v-for="item in page.rainbow" :key="item.prodId">
  495. <a
  496. href="javascript:void(0);"
  497. @click="getSearchProdPage(item)"
  498. class="item"
  499. :class="{ cur: page.current == item }"
  500. v-if="item !== '...'"
  501. >{{ item }}</a
  502. >
  503. <span class="ellipsis" v-else>...</span>
  504. </div>
  505. <a
  506. href="javascript:void(0);"
  507. class="item next"
  508. :class="{ default: page.current > page.pages - 1 }"
  509. @click="getSearchProdPage(page.current + 1)"
  510. >{{$t('pagination.nextPage')}}</a
  511. >
  512. <div class="total-num">
  513. {{$t('pagination.total')}}
  514. <span class="num">{{ page.pages }}</span
  515. >{{$t('pagination.page')}}
  516. </div>
  517. </div>
  518. <!-- /页码 -->
  519. </div>
  520. </div>
  521. <!-- /商品评论 -->
  522. </div>
  523. <div class="side">
  524. <!-- 店内搜索 -->
  525. <div class="shop-search">
  526. <div class="tit">{{$t('prodDetail.inStoreSearch')}}</div>
  527. <div class="con">
  528. <input type="text" class="text" v-model="prodName" />
  529. <a href="javascript:void(0)" class="btn" @click="toShopIndex"></a>
  530. </div>
  531. </div>
  532. <!-- /店内搜索 -->
  533. <!-- 店内分类 -->
  534. <div class="shop-category">
  535. <div class="tit">{{$t('prodDetail.inStoreCategories')}}</div>
  536. <div class="con">
  537. <div
  538. class="items active"
  539. v-for="(item, index) in shopCategorys"
  540. :key="index"
  541. >
  542. <nuxt-link
  543. :to="
  544. '/shopIndex?sid=' +
  545. prodInfo.shopId +
  546. '&cid=' +
  547. item.categoryId
  548. "
  549. >
  550. <div class="item-main">{{ item.categoryName }}</div>
  551. </nuxt-link>
  552. </div>
  553. </div>
  554. </div>
  555. <!-- 店内分类 -->
  556. <!-- 热销产品 -->
  557. <div class="sale-well">
  558. <div class="tit">{{$t('prodDetail.hotProducts')}}</div>
  559. <div class="con">
  560. <div
  561. class="item"
  562. v-for="item in hotSales.records"
  563. :key="item.prodId"
  564. >
  565. <nuxt-link :to="'/detail/' + item.prodId">
  566. <div class="goods-img">
  567. <img v-if="item.pic" :src="item.pic" alt />
  568. <img v-else src="~/assets/img/def.png" alt />
  569. </div>
  570. <div class="goods-msg">
  571. <div class="goods-name">{{ item.prodName }}</div>
  572. <div class="goods-price">
  573. <div class="price">
  574. <span class="big">{{ parsePrice(item.price)[0] }}</span>
  575. .{{ parsePrice(item.price)[1] }}
  576. </div>
  577. </div>
  578. </div>
  579. </nuxt-link>
  580. </div>
  581. </div>
  582. </div>
  583. <!-- 热销产品 -->
  584. </div>
  585. </div>
  586. </div>
  587. <!-- 滑动导航 -->
  588. <transition name="fade">
  589. <div class="scroll-tab" v-if="showScrollTab">
  590. <div class="content">
  591. <div class="shop-search">
  592. <input type="text" class="text" :placeholder="$t('prodDetail.inStoreSearch')" />
  593. <a href="javascript:void(0)" class="btn"></a>
  594. </div>
  595. <div class="tab">
  596. <div
  597. :class="['item', introduceOrCommentInt ? 'active' : '']"
  598. @click="toggleIntroduceInt"
  599. >
  600. {{$t('prodDetail.productIntroduction')}}
  601. </div>
  602. <div
  603. :class="['item', introduceOrCommentCom ? 'active' : '']"
  604. @click="toggleIntroduceCom"
  605. >
  606. {{$t('prodDetail.productReviews')}}
  607. <i class="number">({{ prodCommData.number }})</i>
  608. </div>
  609. </div>
  610. </div>
  611. </div>
  612. </transition>
  613. <!-- /滑动导航 -->
  614. <el-dialog
  615. :title="$t('tips')"
  616. :visible="Boolean(countdown.obj.signs == -1)"
  617. width="15%"
  618. center
  619. :close-on-press-escape="false"
  620. :close-on-click-modal="false"
  621. :showClose="false"
  622. top="25vh"
  623. >
  624. <span class="seckill-end-tips">{{$t('spike.currentSecondsAreOver')}}</span>
  625. <span slot="footer" class="dialog-footer">
  626. <el-button type="primary" @click="toIndex">{{$t('determine')}}</el-button>
  627. </span>
  628. </el-dialog>
  629. <!-- 登录弹窗组件 -->
  630. <LoginPopup v-if="showLogin" v-on:hideLoginPop="hideLoginPop" />
  631. <!-- /登录弹窗组件 -->
  632. </div>
  633. </template>
  634. <script>
  635. import util from '~/plugins/util'
  636. import { _toPage } from "~/plugins/util";
  637. import { picDomain } from '~/plugins/config';
  638. import LoginPopup from '~/components/login-popup'
  639. import PageUtil from '~/plugins/pageUtil'
  640. import Cookie from 'js-cookie'
  641. import bus from '~/plugins/bus'
  642. export default {
  643. components: {
  644. LoginPopup
  645. },
  646. data () {
  647. return {
  648. showLogin:false,
  649. prodName: '',
  650. prodInfo: {},
  651. prodImgs: [],
  652. offsetCount: 0, //图片偏移数
  653. showScrollTab: false,
  654. introduceOrCommentInt: true, // true商品介绍 false商品评论
  655. introduceOrCommentCom: false,
  656. prodCommData: {},
  657. prodCommType: true, // 商品评论类型
  658. prodCommList: {},
  659. shopInfo: {},
  660. evaluate: -1,
  661. hotSales: {},
  662. defaultSku: {}, // 选中的sku
  663. skuGroup: [], //
  664. selectedProp: [],
  665. findSku: true, // 能不能找得到sku
  666. prodNum: 1, //计数器数量
  667. prohibit1: true, //计数器-是否禁用
  668. prohibit2: false, //计数器+是否禁用
  669. isCollection: false, //商品是否已收藏
  670. isShopCollection: false,//店铺是否已收藏
  671. totalCartNum: 0, //购物车数量
  672. shopCategorys: [],
  673. page: {
  674. pages: 0, // 总页数
  675. rainbow: [], // 分页条
  676. current: 1
  677. },
  678. timer: {},
  679. imgPath: '', // 当前点击的评论图片
  680. showBigImg: false, // 评论大图显隐
  681. scrollTop: 0,
  682. toPrePage: 0, // 0不用跳转 1跳转
  683. prodParameterList: [],
  684. showVideo: false, // 是否展示视频
  685. showPlayBtn: true, // 视频播放按钮
  686. }
  687. },
  688. head () {
  689. return {
  690. title: this.$t('spike.spikeTitle'),
  691. }
  692. },
  693. //在页面加载之前先加载数据
  694. async asyncData ({ app, params, redirect }) {
  695. const data = await app.$axios.get('/seckill/prod', {
  696. params: {
  697. seckillId: params.seckillId
  698. }
  699. }).then(({ data }) => {
  700. if (data) {
  701. return data
  702. } else {
  703. return redirect('/error')
  704. }
  705. }).catch(()=> {
  706. return redirect('/error')
  707. })
  708. var prodImgs = []
  709. if (data) {
  710. if (data.imgs) {
  711. data.imgs.split(',').forEach(imgStr => {
  712. prodImgs.push({
  713. img: imgStr,
  714. isActive: false
  715. })
  716. })
  717. prodImgs[0].isActive = true
  718. }
  719. for (let i = 0; i < data.skuList.length; i++) {
  720. const element = data.skuList[i];
  721. element.pic = element.pic ? picDomain + element.pic : ''
  722. }
  723. // data.content = util.formatHtml(data.content) // 去除商品详情富文本样式
  724. // 倒计时处理
  725. let betweenTimestamp = util.betweenTimestamp(util.dateToTimestamp(data.seckill.startTime), util.dateToTimestamp(data.seckill.endTime))
  726. var countdown = {
  727. obj: util.betweenTime(betweenTimestamp),
  728. stamp: betweenTimestamp
  729. }
  730. return {
  731. prodInfo: data,
  732. prodImgs: prodImgs,
  733. shopId: data.shopId,
  734. countdown: countdown,
  735. }
  736. }
  737. },
  738. watch: {
  739. prodNum(nv) {
  740. if (nv <= 1) {
  741. this.prohibit1 = true
  742. if(this.defaultSku.seckillStocks == 0 || nv == this.defaultSku.seckillStocks){
  743. this.prohibit2 = true
  744. }
  745. }else if(nv == this.defaultSku.seckillStocks){
  746. this.prohibit2 = true
  747. }else {
  748. this.prohibit1 = false
  749. this.prohibit2 = false
  750. }
  751. }
  752. },
  753. mounted () {
  754. this.startCountdown()
  755. //查询商品是否已经收藏
  756. this.isProdCollected()
  757. this.isShopCollected()
  758. //获取店铺分类
  759. this.getShopCategory()
  760. this.groupSkuProp(this.prodInfo.skuList, this.prodInfo.seckill.seckillPrice)
  761. this.getShopHead(this.prodInfo.shopId)
  762. if (this.prodInfo.video) {
  763. // 获取商品视频
  764. this.prodVideo = document.getElementById('prodVideo')
  765. this.showPlayBtn = true
  766. }
  767. //获取热销商品
  768. this.getHotSales();
  769. let flag = 0
  770. this.prodParameterList[flag] = []
  771. const prodParameterList = this.prodInfo.prodParameterList || []
  772. for (let i = 0; i < prodParameterList.length; i++) {
  773. let params = prodParameterList[i]
  774. if (i % 3 === 0 && i !== 0) {
  775. flag++
  776. this.prodParameterList[flag] = []
  777. }
  778. this.prodParameterList[flag].push(params)
  779. }
  780. // 获取商品评论数
  781. this.$axios.get('/prod/prodCommData', {
  782. params: {
  783. prodId: this.prodInfo.prodId
  784. }
  785. }).then(({ data }) => {
  786. this.prodCommData = data
  787. })
  788. this.getProdCommPageByProd(-1);
  789. // 监听页面滚动
  790. window.addEventListener('scroll', this.scrollToTop);
  791. if(Cookie.get('token')) {
  792. this.$axios.post('/p/prodBrowseLog', {
  793. prodId: this.prodInfo.prodId
  794. })
  795. }
  796. },
  797. methods: {
  798. /**
  799. * 回到首页
  800. */
  801. toIndex () {
  802. this.$router.push({ path: '/' })
  803. },
  804. /**
  805. * 页面滚动事件
  806. */
  807. scrollToTop () {
  808. var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
  809. this.showScrollTab = scrollTop > 750 ? true : false
  810. },
  811. /**
  812. * 评论点击图片显示大图
  813. */
  814. imgShow (comIndex, imgIndex) {
  815. let imgPath = this.prodCommList.records[comIndex].prodImgs[imgIndex]
  816. this.imgPath = imgPath
  817. if (this.imgPath) {
  818. this.showBigImg = true
  819. }
  820. let dom = document.getElementsByTagName("body").className = "hid";
  821. },
  822. /**
  823. * 关闭评论大图显隐
  824. */
  825. closeShowBigImg () {
  826. this.showBigImg = false
  827. },
  828. /**
  829. * 倒计时
  830. */
  831. startCountdown () {
  832. this.countdown = {
  833. stamp: this.countdown.stamp>0? this.countdown.stamp -= 1000 : this.countdown.stamp += 1000,
  834. obj: util.betweenTime(this.countdown.stamp)
  835. }
  836. if (Math.abs(this.countdown.stamp) < 1000) {
  837. clearTimeout(this.timer)
  838. setTimeout(() => {
  839. this.$router.push({
  840. path:'/flash-sale'
  841. })
  842. }, 1000);
  843. // if (new Date().getTime() > util.dateToTimestamp(this.prodInfo.seckill.endTime)) {
  844. // this.$router.push({
  845. // path:'/flash-sale'
  846. // })
  847. // } else {
  848. // // location.reload()
  849. // }
  850. return
  851. }
  852. this.timer = setTimeout(() => {
  853. this.startCountdown()
  854. }, 1000);
  855. },
  856. /**
  857. * 小图点击事件
  858. */
  859. changeProdImg(index) {
  860. if (this.prodImgs[index].isActive === true) {
  861. return
  862. }
  863. this.prodImgs.forEach(prodImg => {
  864. prodImg.isActive = false
  865. })
  866. this.prodImgs[index].isActive = true
  867. this.prodInfo.pic = this.prodImgs[index].img
  868. this.stopVideo()
  869. },
  870. /**
  871. * 关闭视频
  872. */
  873. stopVideo() {
  874. this.showVideo = false
  875. if (this.prodVideo !== undefined) {
  876. this.prodVideo.pause()
  877. }
  878. this.showPlayBtn = true
  879. },
  880. /**
  881. * 播放视频
  882. */
  883. playVideo() {
  884. this.showVideo = true
  885. this.prodVideo.play(0)
  886. this.showPlayBtn = false
  887. },
  888. // 切换图片
  889. prevImg() {
  890. if (this.prodImgs.length - 5 > 0) {
  891. if (this.offsetCount > 0) {
  892. this.offsetCount--
  893. this.$refs.carouser.style.left = '-' + 78 * this.offsetCount + 'px'
  894. } else {
  895. return false
  896. }
  897. } else if (this.prodImgs.length - 5 <= 0) {
  898. return false
  899. } else {
  900. return false
  901. }
  902. },
  903. nextImg() {
  904. if (this.prodImgs.length - 5 > 0) {
  905. if (this.offsetCount < this.prodImgs.length - 5) {
  906. this.offsetCount++
  907. this.$refs.carouser.style.left = '-' + 78 * this.offsetCount + 'px'
  908. } else if (this.prodImgs.length - 5 <= 0) {
  909. return false
  910. } else {
  911. return false
  912. }
  913. } else {
  914. return false
  915. }
  916. },
  917. /**
  918. * 获取店铺信息
  919. */
  920. getShopHead (shopId) {
  921. this.$axios.get('/shop/headInfo', {
  922. params: {
  923. shopId: shopId
  924. }
  925. }).then(({ data }) => {
  926. this.shopInfo = data
  927. })
  928. },
  929. /**
  930. * 获取店铺分类
  931. */
  932. getShopCategory () {
  933. this.$axios.get('/category/categoryInfo', {
  934. params: {
  935. shopId: this.shopId
  936. }
  937. }).then(({ data }) => {
  938. this.shopCategorys = data
  939. })
  940. },
  941. /**
  942. * 价格过滤
  943. */
  944. parsePrice (value) {
  945. var val = Number(value)
  946. if (!val) {
  947. val = 0;
  948. }
  949. // 截取小数点后两位,并以小数点为切割点将val转化为数组
  950. return val.toFixed(2).split(".");
  951. },
  952. /**
  953. * 切换商品介绍/商品评论
  954. */
  955. toggleIntroduceInt () {
  956. this.introduceOrCommentInt = true
  957. this.introduceOrCommentCom = false
  958. },
  959. toggleIntroduceCom () {
  960. this.introduceOrCommentInt = false
  961. this.introduceOrCommentCom = true
  962. },
  963. /**
  964. * 获取评论分页数据
  965. */
  966. getSearchProdPage (current) {
  967. if (current == 0 || current == this.page.current || current > this.page.pages) {
  968. return
  969. } else {
  970. this.getProdCommPageByProd(this.evaluate, current);
  971. }
  972. },
  973. /**
  974. * 获取商品评论列表
  975. */
  976. getProdCommPageByProd (evaluate, curPage) {
  977. this.evaluate = evaluate
  978. this.$axios.get('/prod/prodCommPageByProd', {
  979. params: {
  980. prodId: this.prodInfo.prodId,
  981. current: curPage || 1,
  982. size: 10,
  983. evaluate: this.evaluate
  984. }
  985. }).then(({ data }) => {
  986. this.prodCommList = data
  987. if (this.prodCommList.records.length > 0) {
  988. this.prodCommList.records.forEach(prodComm => {
  989. var prodImgs = []
  990. if (prodComm.pics) {
  991. prodComm.pics.split(',').forEach(imgStr => {
  992. prodImgs.push(imgStr)
  993. })
  994. }
  995. prodComm.prodImgs = prodImgs
  996. })
  997. }
  998. data.rainbow = PageUtil.rainbowWithDot(data.current, data.pages, 5)
  999. this.page = data
  1000. })
  1001. },
  1002. /**
  1003. * 获取热销商品
  1004. */
  1005. getHotSales () {
  1006. // this.$axios.get('/search/searchProdPage', {
  1007. this.$axios.get('/search/page', {
  1008. params: {
  1009. shopId: this.prodInfo.shopId,
  1010. size: 5,
  1011. sort: 1,
  1012. orderBy: 1,
  1013. isAllProdType: true,
  1014. current: 1,
  1015. isActive: 1 // 过滤掉活动商品
  1016. }
  1017. }).then(({ data }) => {
  1018. this.hotSales.records = data.records[0].products
  1019. })
  1020. },
  1021. /**
  1022. * 收藏商品
  1023. */
  1024. toggleCollect () {
  1025. var prodId = this.prodInfo.prodId
  1026. var isCollection = this.isCollection
  1027. this.$axios.post('/p/user/collection/addOrCancel', prodId).then(({ data }) => {
  1028. this.isCollection = !isCollection
  1029. if (this.isCollection) {
  1030. this.$message({
  1031. message: this.$t('prodDetail.collectionSuccess'),
  1032. type: 'success',
  1033. duration: 1000
  1034. });
  1035. } else {
  1036. this.$message({
  1037. message: this.$t('prodDetail.uncollected'),
  1038. type: 'warning',
  1039. duration: 1000
  1040. });
  1041. }
  1042. })
  1043. },
  1044. /**
  1045. * 查询商品是否已收藏
  1046. */
  1047. isProdCollected () {
  1048. if (!Cookie.get('token')) {
  1049. return
  1050. }
  1051. this.$axios.get('/p/user/collection/isCollection', {
  1052. params: {
  1053. prodId: this.prodInfo.prodId
  1054. }
  1055. }).then(({ data }) => {
  1056. this.isCollection = data
  1057. })
  1058. },
  1059. /**
  1060. * 收藏店铺
  1061. */
  1062. toggleShopCollect () {
  1063. var shopId = this.prodInfo.shopId
  1064. var isShopCollection = this.isShopCollection
  1065. this.$axios.post('/p/shop/collection/addOrCancel', shopId).then(({ data }) => {
  1066. this.isShopCollection = !isShopCollection
  1067. if (this.isShopCollection) {
  1068. this.$message({
  1069. message: this.$t('prodDetail.collectionSuccess'),
  1070. type: 'success',
  1071. duration: 1000
  1072. });
  1073. } else {
  1074. this.$message({
  1075. message: this.$t('prodDetail.uncollected'),
  1076. type: 'warning',
  1077. duration: 1000
  1078. });
  1079. }
  1080. })
  1081. },
  1082. /**
  1083. * 查询店铺是否已收藏
  1084. */
  1085. isShopCollected () {
  1086. if (!Cookie.get('token')) {
  1087. return
  1088. }
  1089. this.$axios.get('/p/shop/collection/isCollection', {
  1090. params: {
  1091. shopId: this.prodInfo.shopId
  1092. }
  1093. }).then(({ data }) => {
  1094. this.isShopCollection = data
  1095. })
  1096. },
  1097. /**
  1098. * 减少商品数量
  1099. */
  1100. reduce () {
  1101. var prodNum = parseInt(this.prodNum)
  1102. if(prodNum<=1){
  1103. return
  1104. }
  1105. if(this.defaultSku.seckillStocks || this.defaultSku.seckillStocks == 0) {
  1106. if (!prodNum || prodNum <= 1) {
  1107. this.prodNum = prodNum
  1108. this.prohibit1 = true //禁用
  1109. this.prohibit2 = false
  1110. if(this.defaultSku.seckillStocks == 0){
  1111. this.prohibit2 = true
  1112. }
  1113. }else {
  1114. this.prodNum = prodNum - 1
  1115. this.prohibit1 = false
  1116. this.prohibit2 = false
  1117. }
  1118. } else {
  1119. this.prodNum = 0
  1120. this.prohibit1 = true
  1121. this.prohibit2 = true
  1122. }
  1123. },
  1124. /**
  1125. * 增加商品数量
  1126. */
  1127. increase () {
  1128. var prodNum = parseInt(this.prodNum)
  1129. if(this.defaultSku.seckillStocks) { // 有库存
  1130. if(!this.prodNum) {
  1131. this.prodNum = 1
  1132. return
  1133. }
  1134. // 判断秒杀是否限购 maxNum: -1不限购
  1135. if (this.prodInfo.seckill.maxNum != -1) { // 限购
  1136. if (prodNum < this.defaultSku.seckillStocks && prodNum < this.prodInfo.seckill.maxNum) {
  1137. this.prodNum = prodNum + 1
  1138. } else if(prodNum <= this.prodInfo.seckill.maxNum && this.prodInfo.seckill.maxNum < this.defaultSku.seckillStocks) {
  1139. this.$message({
  1140. message: this.$t('purchaseRestrictions') + this.prodInfo.seckill.maxNum + this.$t('items'),
  1141. type: 'warning',
  1142. duration: 1000
  1143. });
  1144. this.prohibit1 = false
  1145. this.prohibit2 = true //禁用
  1146. } else {
  1147. this.$message({
  1148. message: this.$t('prodDetail.insufficientInventory'),
  1149. type: 'warning',
  1150. duration: 1000
  1151. });
  1152. this.prohibit1 = false
  1153. this.prohibit2 = true //禁用
  1154. }
  1155. } else { // 不限购
  1156. if (prodNum < this.defaultSku.seckillStocks) {
  1157. this.prodNum = prodNum + 1
  1158. this.prohibit1 = false
  1159. this.prohibit2 = false
  1160. } else {
  1161. this.$message({
  1162. message: this.$t('prodDetail.insufficientInventory'),
  1163. type: 'warning',
  1164. duration: 1000
  1165. });
  1166. this.prohibit1 = false
  1167. this.prohibit2 = true //禁用
  1168. }
  1169. }
  1170. }else {
  1171. this.prodNum = 0
  1172. this.prohibit1 = true
  1173. this.prohibit2 = true //禁用
  1174. }
  1175. },
  1176. /**
  1177. * 手动输入数量过滤
  1178. */
  1179. resetProdNum () {
  1180. //失去焦点时
  1181. var prodNum = parseInt(this.prodNum)
  1182. if(this.defaultSku.seckillStocks) { // 有库存
  1183. if (!prodNum || prodNum <= 1) {
  1184. this.prohibit1 = true //禁用
  1185. this.prohibit2 = false //禁用
  1186. }else {
  1187. this.prohibit1 = false
  1188. this.prohibit2 = false
  1189. }
  1190. if (this.prodInfo.seckill.maxNum != -1 ) { // 限购
  1191. if (prodNum > this.prodInfo.seckill.maxNum && this.prodInfo.seckill.maxNum < this.defaultSku.seckillStocks) {
  1192. // 输入数量 > 限购数量 && 限购数量 < 库存
  1193. this.$message({
  1194. message: this.$t('purchaseRestrictions') + this.prodInfo.seckill.maxNum + this.$t('items'),
  1195. type: 'warning',
  1196. duration: 1000
  1197. });
  1198. this.prohibit1 = false
  1199. this.prohibit2 = true //禁用
  1200. }else if (prodNum > this.defaultSku.seckillStocks && this.defaultSku.seckillStocks < this.prodInfo.seckill.maxNum) {
  1201. this.$message({
  1202. message: this.$t('prodDetail.insufficientInventory'),
  1203. type: 'warning',
  1204. duration: 1000
  1205. });
  1206. this.prohibit1 = false
  1207. this.prohibit2 = true //禁用
  1208. }
  1209. } else {
  1210. if (prodNum > this.defaultSku.seckillStocks) {
  1211. this.$message({
  1212. message: this.$t('prodDetail.insufficientInventory'),
  1213. type: 'warning',
  1214. duration: 1000
  1215. });
  1216. this.prohibit2 = true //禁用
  1217. this.prohibit1 = false
  1218. }
  1219. }
  1220. }else { // 无库存
  1221. this.prodNum = 0
  1222. this.prohibit1 = true //禁用
  1223. this.prohibit2 = true //禁用
  1224. }
  1225. },
  1226. /**
  1227. * 组装SKU
  1228. */
  1229. groupSkuProp: function (skuList, defaultPrice) {
  1230. if (skuList.length == 1 && !skuList[0].properties) {
  1231. this.defaultSku = skuList[0]
  1232. return;
  1233. }
  1234. var skuGroup = {};
  1235. var allProperties = [];
  1236. var propKeys = [];
  1237. var selectedPropObj = {}
  1238. var defaultSku = null;
  1239. for (var i = 0; i < skuList.length; i++) {
  1240. var isDefault = false;
  1241. if (!defaultSku && skuList[i].seckillPrice == defaultPrice) { //找到和商品价格一样的那个SKU,作为默认选中的SKU
  1242. defaultSku = skuList[i];
  1243. isDefault = true;
  1244. }
  1245. var properties = skuList[i].properties; //版本:公开版;颜色:金色;内存:64GB
  1246. allProperties.push(properties);
  1247. var propList = properties.split(";"); // ["版本:公开版","颜色:金色","内存:64GB"]
  1248. for (var j = 0; j < propList.length; j++) {
  1249. var propval = propList[j].split(":"); //["版本","公开版"]
  1250. var props = skuGroup[propval[0]]; //先取出 版本对应的值数组
  1251. //如果当前是默认选中的sku,把对应的属性值 组装到selectedProp
  1252. if (isDefault) {
  1253. propKeys.push(propval[0]);
  1254. selectedPropObj[propval[0]] = propval[1];
  1255. }
  1256. if (props == undefined) {
  1257. props = []; //假设还没有版本,新建个新的空数组
  1258. props.push(propval[1]); //把 "公开版" 放进空数组
  1259. } else {
  1260. if (props.indexOf(propval[1]) === -1) { //如果数组里面没有"公开版"
  1261. props.push(propval[1]); //把 "公开版" 放进数组
  1262. }
  1263. }
  1264. skuGroup[propval[0]] = props; //最后把数据 放回版本对应的值
  1265. }
  1266. }
  1267. this.defaultSku = defaultSku
  1268. this.propKeys = propKeys
  1269. this.selectedPropObj = selectedPropObj
  1270. this.parseSelectedObjToVals(skuList);
  1271. this.skuGroup = skuGroup
  1272. this.allProperties = allProperties
  1273. },
  1274. /**
  1275. * 将已选的 {key:val,key2:val2}转换成 [val,val2]
  1276. */
  1277. parseSelectedObjToVals: function (skuList) {
  1278. var selectedPropObj = this.selectedPropObj
  1279. var selectedProperties = "";
  1280. var selectedProp = [];
  1281. for (var key in selectedPropObj) {
  1282. // selectedProp.push(selectedPropObj[key]);
  1283. selectedProp.push({key: key, value: selectedPropObj[key] });
  1284. selectedProperties += key + ":" + selectedPropObj[key] + ";";
  1285. }
  1286. selectedProperties = selectedProperties.substring(0, selectedProperties.length - 1);
  1287. this.selectedProp = selectedProp
  1288. this.selectedProperties = selectedProperties
  1289. this.selectedPropObj = selectedPropObj
  1290. var findSku = false;
  1291. for (var i = 0; i < skuList.length; i++) {
  1292. // 解决排序问题导致无法匹配
  1293. // if (skuList[i].properties == selectedProperties) {
  1294. if (
  1295. this.compareArray(selectedProperties.split(';').sort(),
  1296. skuList[i].properties.split(';').sort())
  1297. ) {
  1298. findSku = true;
  1299. this.defaultSku = skuList[i]
  1300. // if(this.defaultSku.pic!=null){
  1301. // this.defaultSku.pic = picDomain+this.defaultSku.pic
  1302. // }
  1303. this.changeSkuImg(this.defaultSku.pic);
  1304. break;
  1305. }
  1306. }
  1307. this.findSku = findSku
  1308. },
  1309. /**
  1310. * 比较两个数组中的元素是否相等
  1311. * @param a1 第一个数组
  1312. * @param a2 第二个数组
  1313. * @return boolean 两个数组中的元素都相等则返回 true,反之返回 false
  1314. */
  1315. compareArray(a1, a2) {
  1316. if (!a1 || !a2) {
  1317. return false;
  1318. }
  1319. if (a1.length !== a2.length) {
  1320. return false;
  1321. }
  1322. for (var i = 0, n = a1.length; i < n; i++) {
  1323. if (a1[i] !== a2[i]) {
  1324. return false;
  1325. }
  1326. }
  1327. return true;
  1328. },
  1329. /**
  1330. * 切换SKU图片
  1331. */
  1332. changeSkuImg (skuPic) {
  1333. if (skuPic) {
  1334. // if (this.prodImgs[0].sku) {
  1335. // this.prodImgs.splice(0, 1)
  1336. // }
  1337. this.prodImgs.forEach(prodImg => {
  1338. prodImg.isActive = false
  1339. })
  1340. // this.prodImgs.splice(0, 0, {
  1341. // img: skuPic,
  1342. // isActive: true,
  1343. // sku: true
  1344. // });
  1345. this.prodInfo.pic = skuPic
  1346. } else {
  1347. this.prodInfo.pic = this.prodImgs[0].img
  1348. }
  1349. },
  1350. /**
  1351. * 判断当前的规格值 是否可以选
  1352. */
  1353. isSkuLineItemNotOptional (allProperties, selectedPropObj, key, item, propKeys) {
  1354. var selectedPropObj = Object.assign({}, selectedPropObj)
  1355. var properties = "";
  1356. selectedPropObj[key] = item;
  1357. for (var j = 0; j < propKeys.length; j++) {
  1358. properties += propKeys[j] + ":" + selectedPropObj[propKeys[j]] + ";";
  1359. }
  1360. properties = properties.substring(0, properties.length - 1);
  1361. for (var i = 0; i < allProperties.length; i++) {
  1362. if (properties == allProperties[i]) {
  1363. return false;
  1364. }
  1365. }
  1366. for (var i = 0; i < allProperties.length; i++) {
  1367. if (allProperties[i].indexOf(item) >= 0) {
  1368. return true;
  1369. }
  1370. }
  1371. return false;
  1372. },
  1373. /**
  1374. * 规格点击事件
  1375. */
  1376. toChooseItem (skuLineItem, key, event) {
  1377. this.selectedPropObj[key] = skuLineItem;
  1378. this.parseSelectedObjToVals(this.prodInfo.skuList);
  1379. if(this.defaultSku.seckillStocks) {
  1380. this.prodNum = 1
  1381. this.prohibit1 = true
  1382. this.prohibit2 = false
  1383. }else {
  1384. this.prodNum = 0
  1385. this.prohibit1 = true
  1386. this.prohibit2 = true
  1387. }
  1388. },
  1389. /**
  1390. * 立即抢购
  1391. */
  1392. buyNow () {
  1393. if (!this.findSku) {
  1394. return;
  1395. }
  1396. if (!this.prodNum || this.prodNum < 1) {
  1397. this.$message({
  1398. message: this.$t('prodDetail.pleaseEnterTheCorrectNumberOfItems'),
  1399. type: 'warning',
  1400. duration: 1000
  1401. })
  1402. return;
  1403. }
  1404. if (this.prodInfo.seckill.maxNum != -1 ) { // 限购
  1405. if (this.prodNum > this.prodInfo.seckill.maxNum) {
  1406. this.$message({
  1407. message: this.$t('purchaseRestrictions') + this.prodInfo.seckill.maxNum + this.$t('items'),
  1408. type: 'warning',
  1409. duration: 1000
  1410. });
  1411. this.prohibit1 = false
  1412. this.prohibit2 = true //禁用
  1413. return
  1414. }
  1415. } else {
  1416. if (this.prodNum > this.defaultSku.seckillStocks) {
  1417. this.$message.warning(this.$t('prodDetail.insufficientInventory'))
  1418. this.prohibit2 = true //禁用
  1419. return
  1420. }
  1421. }
  1422. if (!this.countdown.obj.signs) {
  1423. this.$message({
  1424. message: this.$t('prodDetail.theSpikeActivityHasNotStarted'),
  1425. type: 'warning',
  1426. duration: 1000
  1427. })
  1428. return;
  1429. }
  1430. if (!Cookie.get('token')) {
  1431. bus.$emit("showLogin", true)
  1432. } else {
  1433. const secKillObj = {
  1434. addrId: 0,
  1435. prodCount: this.prodNum,
  1436. seckillSkuId: this.defaultSku.seckillSkuId,
  1437. }
  1438. sessionStorage.setItem("secKillObj", JSON.stringify(secKillObj));
  1439. this.$router.push({
  1440. path: '/secdetail/confirm-order?seckillId=' + this.defaultSku.seckillId,
  1441. })
  1442. }
  1443. },
  1444. /**
  1445. * 搜索
  1446. */
  1447. toShopIndex () {
  1448. var searchTerms = this.prodName.trim() //去除字符串的头尾空格
  1449. if (!searchTerms) {
  1450. this.$message({
  1451. message: this.$t('prodDetail.searchContentCannotBeEmpty'),
  1452. type: 'error',
  1453. duration: 1000
  1454. })
  1455. return
  1456. }
  1457. // 跳转到商品列表页
  1458. let url = '/shopIndex?sid=' + this.shopId + '&pn=' + searchTerms
  1459. this.$router.push({ path: url })
  1460. },
  1461. // 跳转商家客服
  1462. toChatIm (prodInfo) {
  1463. if (Cookie.get('token')) {
  1464. let routeUrl = this.$router.resolve({
  1465. path: `/chat?shopId=${prodInfo.shopId}`
  1466. });
  1467. window.open(routeUrl.href, 'view_window');
  1468. } else {
  1469. this.showLogin = true
  1470. }
  1471. },
  1472. /**
  1473. * 隐藏登录弹窗
  1474. */
  1475. hideLoginPop () {
  1476. this.showLogin = false
  1477. },
  1478. },
  1479. destroyed () {
  1480. // 页面销毁时移除监听
  1481. window.removeEventListener('scroll', this.scrollToTop)
  1482. clearTimeout(this.timer)
  1483. },
  1484. }
  1485. </script>
  1486. <style scoped src='~/assets/css/detail.css'></style>
  1487. <style scoped>
  1488. .seckill-end-tips {
  1489. width: 100%;
  1490. text-align: center;
  1491. display: inline-block;
  1492. }
  1493. </style>