_prodId.vue 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361
  1. <template>
  2. <div class="detail">
  3. <!-- 面包屑导航 -->
  4. <div class="crumbs-shop">
  5. <div class="content">
  6. <div class="crumbs">
  7. <!-- <a href="javascript:void(0)"
  8. class="item-a">首页</a>
  9. <span class="arrow">></span>
  10. <a href="javascript:void(0)"
  11. class="item-a">数码科技</a>
  12. <span class="arrow">></span>
  13. <a href="javascript:void(0)"
  14. class="item-a">手机</a>
  15. <span class="arrow">></span>
  16. <span class="item-span">iPhone 11 Pro Max</span>-->
  17. </div>
  18. <div class="shop-box">
  19. <nuxt-link :to="'/shopIndex?sid=' + prodInfo.shopId" class="shop">
  20. <i class="self" v-if="shopInfo && shopInfo.shopId === 1">{{
  21. $t('prodDetail.selfEmployed')
  22. }}</i>
  23. <i class="shop-icon" v-if="shopInfo && shopInfo.shopId != 1"></i>
  24. {{ shopInfo ? shopInfo.shopName : '' }}
  25. </nuxt-link>
  26. <a
  27. href="javascript:void(0)"
  28. @click="toChatIm(prodInfo)"
  29. class="im-chat"
  30. ><span class="btn-im"></span
  31. >{{ $t('prodDetail.contactCustomerService') }}</a
  32. >
  33. <span
  34. class="favourite"
  35. v-if="!isShopCollection"
  36. @click="toggleShopCollect"
  37. >
  38. <i class="favourite-icon"></i
  39. >{{ $t('prodDetail.collectionStores') }}
  40. </span>
  41. <span class="favourite active" @click="toggleShopCollect" v-else>
  42. <i class="favourite-icon"></i>{{ $t('prodDetail.collectedStores') }}
  43. </span>
  44. </div>
  45. </div>
  46. </div>
  47. <!-- /面包屑导航 -->
  48. <div class="content">
  49. <div class="detail-up">
  50. <!-- 商品图片 -->
  51. <div class="img">
  52. <div class="big-img">
  53. <img v-if="(!prodInfo.video || !showVideo) && prodInfo.pic" :src="prodInfo.pic" alt @error="changePicUrl" />
  54. <img v-if="(!prodInfo.video || !showVideo) && !prodInfo.pic" src="~/assets/img/def.png" alt />
  55. <!-- 商品视频 -->
  56. <video
  57. v-show="showVideo"
  58. id="prodVideo"
  59. class="big-img prod-video"
  60. :src="prodInfo.video"
  61. controls
  62. ></video>
  63. <!-- 商品视频end -->
  64. <div class="oper-btn" v-if="showPlayBtn && prodInfo.video">
  65. <img
  66. src="~/assets/images/play.png"
  67. @click="playVideo"
  68. alt="播放"
  69. />
  70. </div>
  71. <div class="close-btn" v-if="!showPlayBtn && showVideo">
  72. <img
  73. src="~/assets/images/close.png"
  74. alt="关闭"
  75. @click="stopVideo"
  76. />
  77. </div>
  78. </div>
  79. <div class="small-img">
  80. <i
  81. class="left-arrow"
  82. @click="prevImg"
  83. :class="{
  84. limit: prodImgs.length - 5 <= 0 || this.offsetCount < 1
  85. }"
  86. >&lt;</i
  87. >
  88. <i
  89. class="right-arrow"
  90. @click="nextImg"
  91. :class="{
  92. limit:
  93. prodImgs.length - 5 <= 0 ||
  94. this.offsetCount >= prodImgs.length - 5
  95. }"
  96. >&gt;</i
  97. >
  98. <div class="img-box">
  99. <div class="offset-box" ref="carouser">
  100. <div
  101. class="item"
  102. v-for="(item, index) in prodImgs"
  103. :key="index"
  104. :class="{ active: item.isActive }"
  105. @mouseover="changeProdImg(index)"
  106. >
  107. <img :src="item.img"/>
  108. </div>
  109. </div>
  110. </div>
  111. </div>
  112. </div>
  113. <!-- /商品图片 -->
  114. <!-- 商品详情 -->
  115. <div class="info">
  116. <div class="name-box">
  117. <div class="name">{{ prodInfo.prodName }}</div>
  118. <div class="des">
  119. <div :title="prodInfo.brief" class="brief">
  120. {{ prodInfo.brief }}
  121. </div>
  122. <!-- <span
  123. v-if="
  124. prodInfo.brief &&
  125. prodInfo.brief !== null &&
  126. discountDet.length > 0 &&
  127. prodInfo.prodType != 5
  128. "
  129. >,</span
  130. > -->
  131. <span class="discount-info" v-if="discountDet.length && prodInfo.prodType != 5">
  132. <a
  133. href="javascript:void(0)"
  134. class="go-discount"
  135. @click="toDiscountDetail(discountDet[0].discountId)"
  136. >
  137. {{ discountDet[0].discountName
  138. }}{{ $t('prodDetail.specialZone') }},{{
  139. discountDet[0].endTime.substring(0, 10)
  140. }}{{ $t('prodDetail.deadline') }},{{
  141. $t('prodDetail.grabYourCopyNow')
  142. }}
  143. <span class="arr">&gt;&gt;</span>
  144. </a>
  145. </span>
  146. </div>
  147. </div>
  148. <!-- 预售商品 -->
  149. <div
  150. class="activity"
  151. v-if="prodInfo.preSellStatus == 1 && prodInfo.prodType != 1"
  152. >
  153. <div class="name group-buy">{{ $t('prodDetail.preSale') }}</div>
  154. <div class="limit">
  155. {{ $t('prodDetail.expected') }}&nbsp;&nbsp;{{
  156. prodInfo.preSellTime
  157. }}&nbsp;&nbsp;{{ $t('prodDetail.startShipping') }}
  158. </div>
  159. </div>
  160. <!-- /预售商品 -->
  161. <!-- 拼团商品 -->
  162. <div
  163. class="activity"
  164. v-if="prodInfo.prodType == 1 && prodInfo.code !== -1"
  165. >
  166. <div class="name group-buy">
  167. {{ $t('prodDetail.groupingTogetherForMoreBenefits') }}
  168. </div>
  169. <div class="limit">
  170. {{ $t('prodDetail.distanceActivity') }}
  171. {{ countdown.obj.signs ? $t('end') : $t('start') }}
  172. {{ $t('onlyLeft') }}:
  173. <span class="time" v-if="countdown.obj.day"
  174. >{{ countdown.obj.day }}{{ $t('day')
  175. }}{{ countdown.obj.hou }}:{{ countdown.obj.min }}:{{
  176. countdown.obj.sec
  177. }}</span
  178. >
  179. <span class="time" v-else
  180. >{{ countdown.obj.hou }}:{{ countdown.obj.min }}:{{
  181. countdown.obj.sec
  182. }}</span
  183. >
  184. </div>
  185. </div>
  186. <!-- /拼团商品 -->
  187. <div class="price-box">
  188. <div class="item goods-price">
  189. <span class="tit">{{ $t('price') }}</span>
  190. <div class="con">
  191. <div class="price">
  192. <span class="big">{{ parsePrice(defaultSku.price)[0] }}</span>
  193. .{{ parsePrice(defaultSku.price)[1] }}
  194. </div>
  195. <!-- 商品销售价大于市场价时 不展示市场价 -->
  196. <div
  197. class="old-price"
  198. v-if="
  199. defaultSku.oriPrice &&
  200. defaultSku.oriPrice > defaultSku.price
  201. "
  202. >
  203. ¥{{ defaultSku.oriPrice }}
  204. </div>
  205. </div>
  206. <span v-if="findSku" class="tit">{{
  207. $t('prodDetail.remainingInventory')
  208. }}</span>
  209. <div v-if="findSku" class="con">
  210. {{ defaultSku.stocks }}
  211. </div>
  212. </div>
  213. <!-- 预售 -->
  214. <div
  215. class="item coupons"
  216. v-if="
  217. prodInfo.prodType == 1 &&
  218. prodInfo.code !== -1 &&
  219. prodInfo.preSellStatus == 1
  220. "
  221. >
  222. <span class="tit">{{ $t('prodDetail.preSale') }}</span>
  223. <div class="con pre-sale-red">
  224. {{ $t('prodDetail.thisItemIsAPreSaleItem') }},{{
  225. $t('prodDetail.expected')
  226. }}&nbsp;&nbsp;{{ prodInfo.preSellTime | cutDate }}&nbsp;&nbsp;{{
  227. $t('prodDetail.startShipping')
  228. }}
  229. </div>
  230. </div>
  231. <!-- /预售 -->
  232. <!-- 领券 -->
  233. <div class="item coupons" v-if="couponList.length > 0 && prodInfo.prodType != 5">
  234. <span class="tit">{{ $t('vouchers') }}</span>
  235. <div class="con">
  236. <div
  237. class="coupon-block"
  238. v-for="coupon in couponList"
  239. :key="coupon.couponId"
  240. @click="receiveCoupon(coupon)"
  241. >
  242. <span
  243. class="conpon"
  244. v-if="coupon.couponType == 1 && $t('full') == '满'"
  245. >{{ $t('full') }}{{ $t('yuan') + coupon.cashCondition }}{{ $t('less')
  246. }}{{ $t('yuan') }}{{ coupon.reduceAmount }}</span
  247. >
  248. <span
  249. class="conpon"
  250. v-if="coupon.couponType == 2 && $t('full') == '满'"
  251. >{{ $t('full') }}{{$t('yuan') + coupon.cashCondition }}{{ $t('enjoy')
  252. }}{{ coupon.couponDiscount }}{{ $t('fold') }}</span
  253. >
  254. <!-- 英文版优惠卷样式 -->
  255. <span
  256. class="conpon"
  257. v-if="coupon.couponType == 1 && $t('full') != '满'"
  258. >{{$t('yuan') + coupon.reduceAmount + ' off over '
  259. }}{{$t('yuan') + coupon.cashCondition }}</span
  260. >
  261. <span
  262. class="conpon"
  263. v-if="coupon.couponType == 2 && $t('full') != '满'"
  264. >{{ coupon.couponDiscount + '%' + ' off over' }}
  265. {{$t('yuan') + coupon.cashCondition }}</span
  266. >
  267. </div>
  268. <nuxt-link to="/coupons" class="more">
  269. {{ $t('more') }}
  270. <i class="arrow">>></i>
  271. </nuxt-link>
  272. </div>
  273. </div>
  274. <!-- /领券 -->
  275. <!-- 限时特惠 -->
  276. <div class="item discount" v-if="(discountDet.length && prodInfo.prodType != 5) || prodInfo.giveaway && prodInfo.giveaway.giveawayProds.length">
  277. <span class="tit">{{ $t('promotion') }}</span>
  278. <div class="con">
  279. <div class="discount-con">
  280. <div
  281. class="discount-item"
  282. v-if="prodInfo.giveaway && prodInfo.giveaway.giveawayProds.length"
  283. >
  284. <div class="type">
  285. {{ $t('prodDetail.gift') }}
  286. </div>
  287. <nuxt-link :to="'/detail/' + item.prodId" class="packge-item" v-for="(item, giveawayProdsIndex) in prodInfo.giveaway.giveawayProds" :key="giveawayProdsIndex">
  288. <img class="img" :src="item.pic" alt="">
  289. <div class="count">×{{ item.giveawayNum }}</div>
  290. </nuxt-link>
  291. </div>
  292. <div
  293. class="discount-item"
  294. :class="index > 0 ? 'item-box' : ''"
  295. v-for="(item, index) in discountDet"
  296. :key="item.discountId"
  297. >
  298. <div class="type">
  299. {{
  300. [
  301. $t('prodDetail.fullAmountReduction'),
  302. $t('prodDetail.fullPieceDiscount'),
  303. $t('prodDetail.fullDiscount'),
  304. $t('prodDetail.discountOnFullItems')
  305. ][item.discountRule]
  306. }}
  307. </div>
  308. <div class="text">{{ item.discountName }}</div>
  309. <a
  310. href="javascript:void(0)"
  311. class="det"
  312. @click="toDiscountDetail(item.discountId)"
  313. >
  314. {{ $t('more') }}
  315. <span class="arr">&gt;&gt;</span>
  316. </a>
  317. </div>
  318. </div>
  319. </div>
  320. </div>
  321. <!-- /限时特惠 -->
  322. <!-- 虚拟商品-说明 -->
  323. <div
  324. v-if="
  325. prodInfo.mold === 1 &&
  326. (prodInfo.writeOffNum !== 0 ||
  327. (prodInfo.writeOffNum === 0 && prodInfo.isRefund === 0))
  328. "
  329. class="item"
  330. >
  331. <span class="tit">{{ $t('prodDetail.instructions') }}</span>
  332. <!-- writeOffNum 0无需核销 1单次核销 -1多次核销 -->
  333. <span v-if="prodInfo.writeOffNum !== 0">
  334. <!-- writeOffTime核销有效期 -1.长期有效 0.自定义 1.当天24点前 x.x天内有效 -->
  335. <span v-if="prodInfo.writeOffTime === -1">{{
  336. $t('prodDetail.longTermValidity')
  337. }}</span>
  338. <span v-else-if="prodInfo.writeOffTime === 0"
  339. >{{ $t('prodDetail.afterPurchase') }}
  340. {{ prodInfo.writeOffStart }} {{ $t('prodDetail.to') }}
  341. {{ prodInfo.writeOffEnd }}
  342. <i v-if="$t('language') == 'zh'">{{
  343. $t('prodDetail.effective')
  344. }}</i></span
  345. >
  346. <span v-else-if="prodInfo.writeOffTime === 1">{{
  347. $t('prodDetail.validOnTheSameDay')
  348. }}</span>
  349. <span v-else
  350. >{{ $t('prodDetail.purchase') }}{{ prodInfo.writeOffTime
  351. }}{{ $t('prodDetail.validDay') }}</span
  352. >
  353. </span>
  354. <!-- isRefund 0不支持退款 1支持退款 -->
  355. <span v-if="prodInfo.isRefund === 0"
  356. ><span v-if="prodInfo.writeOffNum !== 0">,</span
  357. >{{ $t('prodDetail.refundsAreNotAllowed') }}</span
  358. >
  359. </div>
  360. <!-- <div class="item distribution">
  361. <span class="tit">配送</span>
  362. <div class="con">限时免邮(新疆、内蒙等地区除外)</div>
  363. </div>-->
  364. </div>
  365. <div class="sku-box" v-if="prodInfo.skuList.length">
  366. <div
  367. class="items sku-text"
  368. v-for="(skuLine, key) in skuGroup"
  369. :key="key"
  370. >
  371. <span class="tit">{{ key }}</span>
  372. <div class="con">
  373. <span
  374. class="item"
  375. @click="toChooseItem(skuLineItem, key, $event)"
  376. :class="[
  377. selectedProp.find(
  378. el => el.key === key && el.value === skuLineItem
  379. )
  380. ? 'active'
  381. : '',
  382. isSkuLineItemNotOptional(
  383. allProperties,
  384. selectedPropObj,
  385. key,
  386. skuLineItem,
  387. propKeys
  388. )
  389. ? 'not-optional'
  390. : ''
  391. ]"
  392. v-for="(skuLineItem, index) in skuLine"
  393. :key="index"
  394. >{{ skuLineItem }}</span
  395. >
  396. </div>
  397. </div>
  398. </div>
  399. <!-- 计数器 -->
  400. <div class="sku-box">
  401. <div class="items">
  402. <span class="tit">{{ $t('quantity') }}</span>
  403. <div class="con">
  404. <div class="goods-number" onselectstart="return false">
  405. <span
  406. :class="['reduce', this.prohibit1 ? 'limit' : '']"
  407. @click="reduce"
  408. >-</span
  409. >
  410. <!-- <input type="number" class="number" v-model="prodNum" /> -->
  411. <input
  412. type="number"
  413. class="number"
  414. v-model="prodNum"
  415. oninput="value=value.replace(/[^\d]/g,'')"
  416. @blur="judgeInput"
  417. />
  418. <span
  419. :class="['increase', this.prohibit2 ? 'limit' : '']"
  420. @click="increase"
  421. >+</span
  422. >
  423. </div>
  424. </div>
  425. </div>
  426. </div>
  427. <div
  428. class="btns"
  429. v-if="
  430. (prodInfo.prodType != 1 || (prodInfo.prodType === 1 && !activityId)) && prodInfo.prodType != 5
  431. "
  432. >
  433. <a
  434. href="javascript:void(0)"
  435. class="buy-now"
  436. @click="buyNow"
  437. v-if="
  438. prodInfo.prodType != 1 ||
  439. (prodInfo.prodType === 1 &&
  440. !activityId &&
  441. findSku &&
  442. defaultSku.stocks)
  443. "
  444. >{{ $t('buyNow') }}</a
  445. >
  446. <a
  447. href="javascript:void(0)"
  448. class="shortage"
  449. v-else-if="!findSku"
  450. >{{ $t('prodDetail.productNotInStock') }}</a
  451. >
  452. <a
  453. href="javascript:void(0)"
  454. class="shortage"
  455. v-else-if="!defaultSku.stocks"
  456. >{{ $t('prodDetail.productOutOfStock') }}</a
  457. >
  458. <a
  459. href="javascript:void(0)"
  460. class="add-cart"
  461. v-if="findSku && defaultSku.stocks && prodInfo.mold !== 1"
  462. @click="addToCart"
  463. >{{ $t('prodDetail.addToCart') }}</a
  464. >
  465. <a
  466. href="javascript:void(0)"
  467. class="collect"
  468. v-if="!isCollection"
  469. @click="toggleCollect()"
  470. >
  471. <i class="icon"></i>{{ $t('prodDetail.collectionOfProducts') }}
  472. </a>
  473. <a
  474. href="javascript:void(0)"
  475. class="collected"
  476. v-if="isCollection"
  477. @click="toggleCollect()"
  478. >
  479. <i class="icon"></i>{{ $t('prodDetail.bookmarked') }}
  480. </a>
  481. </div>
  482. <!-- 活动商品按钮 -->
  483. <div v-if="prodInfo.prodType == 5" class="btns">
  484. <a
  485. href="javascript:void(0)"
  486. class="shortage"
  487. >{{ $t('prodDetail.notAvailableForPurchase') }}</a
  488. >
  489. </div>
  490. <!-- 拼团按钮 -->
  491. <div
  492. class="btns group-btn"
  493. v-if="prodInfo.prodType === 1 && activityId"
  494. >
  495. <a
  496. href="javascript:void(0)"
  497. :class="[
  498. 'build-group',
  499. countdown.obj.signs ? '' : 'disabled-gray',
  500. this.$store.state.locale == 'en' ? 'en' : ''
  501. ]"
  502. v-if="findSku"
  503. >
  504. <span class="group-price"
  505. >¥{{
  506. groupSku.actPrice ? groupSku.actPrice.toFixed(2) : ''
  507. }}</span
  508. >
  509. <span class="group-text">{{
  510. $t('prodDetail.iWantToOpenAGroup')
  511. }}</span>
  512. <!-- <span class="group-code">
  513. <span class="text">手机扫码开团</span>
  514. <span class="code-img">
  515. <img :src="miniQrCodeImg" alt />
  516. </span>
  517. </span>-->
  518. <div class="group-code">
  519. <span class="text">{{
  520. countdown.obj.signs
  521. ? $t('prodDetail.cellPhoneScanCodeOpenGroup')
  522. : $t('prodDetail.groupingActivitiesHaveNotStarted')
  523. }}</span>
  524. <div
  525. :class="[
  526. 'code-img',
  527. countdown.obj.signs ? '' : 'display-none'
  528. ]"
  529. id="spellQrcode"
  530. ></div>
  531. </div>
  532. </a>
  533. <a
  534. href="javascript:void(0)"
  535. :class="[
  536. 'alone-group',
  537. !findSku ? 'cannotbuy' : '',
  538. this.$store.state.locale == 'en' ? 'en' : ''
  539. ]"
  540. @click="buyNow"
  541. >
  542. <span class="group-price"
  543. >¥{{ Number(defaultSku.price).toFixed(2) }}</span
  544. >
  545. <span class="group-text">{{
  546. $t('prodDetail.separatePurchase')
  547. }}</span>
  548. </a>
  549. <a
  550. href="javascript:void(0)"
  551. class="add-cart add-cart-group"
  552. v-if="findSku"
  553. @click="addToCart"
  554. >
  555. <!-- && defaultSku.stocks -->
  556. <span>{{ $t('prodDetail.addToCart') }}</span>
  557. </a>
  558. <a
  559. href="javascript:void(0)"
  560. class="collect"
  561. v-if="!isCollection"
  562. @click="toggleCollect()"
  563. >
  564. <i class="icon"></i>{{ $t('prodDetail.collectionOfProducts') }}
  565. </a>
  566. <a
  567. href="javascript:void(0)"
  568. class="collected"
  569. v-if="isCollection"
  570. @click="toggleCollect()"
  571. >
  572. <i class="icon"></i>{{ $t('prodDetail.bookmarked') }}
  573. </a>
  574. </div>
  575. <!-- /拼团按钮 -->
  576. </div>
  577. <!-- 商品详情 -->
  578. </div>
  579. <div class="detail-down" v-if="comboList && comboList.length">
  580. <div class="introduce-box packages">
  581. <div class="tab">
  582. <div
  583. class="item"
  584. :class="{active: selectComboId === combo.comboId }"
  585. v-for="(combo,index) in comboList"
  586. @click="selectCombo(combo.comboId)"
  587. :key="index"
  588. >
  589. {{ combo.name }}
  590. </div>
  591. </div>
  592. <!-- defaultCombo -->
  593. <div class="packages-content" v-if="defaultCombo">
  594. <div class="left">
  595. <div class="prod-box">
  596. <img class="img" :src="defaultCombo.mainProd.pic" alt="">
  597. <div class="prod-name">{{ defaultCombo.mainProd.prodName }}</div>
  598. <div class="price">
  599. ¥{{ defaultCombo.mainProd.comboPrice | price }}
  600. <span class="combo-count">x {{defaultCombo.mainProd.leastNum}}</span>
  601. </div>
  602. </div>
  603. <div class="add-icon" v-if="defaultCombo.matchingProds.length"></div>
  604. <div class="prod-box necessary" v-for="(item, index) in defaultCombo.matchingProds" :key="index">
  605. <img class="img" :src="item.pic" alt="">
  606. <div class="prod-name">{{ item.prodName }}</div>
  607. <div class="price">
  608. <div class="price-count-con">
  609. <input
  610. type="checkbox"
  611. class="checkbox default"
  612. @click="selectComboItem(item)"
  613. :class="{ checked: isChecked(item), default: 1 }"
  614. />
  615. <span>¥{{ item.comboPrice | price }}</span>
  616. </div>
  617. <span class="combo-count">x {{item.leastNum}}</span>
  618. </div>
  619. </div>
  620. </div>
  621. <div class="right">
  622. <div class="mean-icon"></div>
  623. <div class="settlement-box">
  624. <div class="text">{{ $t("package.selected") }}{{ choiceCombNum }}{{ $t("package.packageItem") }}</div>
  625. <div class="text item">
  626. {{ $t("package.packagePrice") }}
  627. <span class="price-text item">¥{{ comboAmount }}</span>
  628. </div>
  629. <div class="btn item" @click="handleSelectPackage">{{ $t("buyNow") }}</div>
  630. <div class="btn-add-cart item" @click="handleSelectPackage">{{ $t("prodDetail.addToCart") }}</div>
  631. </div>
  632. </div>
  633. </div>
  634. </div>
  635. </div>
  636. <div class="detail-down detail-comment">
  637. <div class="introduce-box">
  638. <div class="tab">
  639. <div
  640. :class="['item', introduceOrCommentInt ? 'active' : '']"
  641. @click="toggleIntroduceInt"
  642. >
  643. {{ $t('prodDetail.productIntroduction') }}
  644. </div>
  645. <div
  646. :class="['item', introduceOrCommentCom ? 'active' : '']"
  647. @click="toggleIntroduceCom"
  648. >
  649. {{ $t('prodDetail.productReviews') }}
  650. <i class="number">({{ prodCommData.number }})</i>
  651. </div>
  652. </div>
  653. <!-- <transition name="fade"> -->
  654. <!-- 商品介绍 -->
  655. <div class="introduce" v-show="introduceOrCommentInt">
  656. <div>
  657. <div class="params" v-for="(params, index) in prodParameterList" :key="index">
  658. <div
  659. class="params-box"
  660. v-for="item in params"
  661. :key="item.prodParameterId"
  662. >
  663. <div class="key">{{ item.parameterKey }}</div>
  664. <div :title="item.parameterValue" class="value">{{ item.parameterValue }}</div>
  665. </div>
  666. </div>
  667. </div>
  668. <div v-if="prodInfo.content" v-rich="prodInfo.content"></div>
  669. </div>
  670. <!-- /商品介绍 -->
  671. <!-- </transition> -->
  672. <!-- <transition name="fade"> -->
  673. <!-- 商品评论 -->
  674. <div class="comment" v-if="introduceOrCommentCom">
  675. <!-- 好评率 -->
  676. <div class="good-rates">
  677. <div class="score">
  678. <div class="tit">
  679. {{ $t('prodDetail.favorableRatingRate') }}:
  680. </div>
  681. <div class="con">{{ prodCommData.positiveRating }}%</div>
  682. </div>
  683. <div class="average">
  684. <div class="item">
  685. <div class="text">5.0</div>
  686. <div class="stars">
  687. <i class="star"></i>
  688. <i class="star"></i>
  689. <i class="star"></i>
  690. <i class="star"></i>
  691. <i class="star"></i>
  692. </div>
  693. <div class="number">({{ prodCommData.scoreNumber5 }})</div>
  694. </div>
  695. <div class="item">
  696. <div class="text">4.0</div>
  697. <div class="stars">
  698. <i class="star"></i>
  699. <i class="star"></i>
  700. <i class="star"></i>
  701. <i class="star"></i>
  702. <i class="star-gray"></i>
  703. </div>
  704. <div class="number">({{ prodCommData.scoreNumber4 }})</div>
  705. </div>
  706. <div class="item">
  707. <div class="text">3.0</div>
  708. <div class="stars">
  709. <i class="star"></i>
  710. <i class="star"></i>
  711. <i class="star"></i>
  712. <i class="star-gray"></i>
  713. <i class="star-gray"></i>
  714. </div>
  715. <div class="number">({{ prodCommData.scoreNumber3 }})</div>
  716. </div>
  717. <div class="item">
  718. <div class="text">2.0</div>
  719. <div class="stars">
  720. <i class="star"></i>
  721. <i class="star"></i>
  722. <i class="star-gray"></i>
  723. <i class="star-gray"></i>
  724. <i class="star-gray"></i>
  725. </div>
  726. <div class="number">({{ prodCommData.scoreNumber2 }})</div>
  727. </div>
  728. <div class="item">
  729. <div class="text">1.0</div>
  730. <div class="stars">
  731. <i class="star"></i>
  732. <i class="star-gray"></i>
  733. <i class="star-gray"></i>
  734. <i class="star-gray"></i>
  735. <i class="star-gray"></i>
  736. </div>
  737. <div class="number">({{ prodCommData.scoreNumber1 }})</div>
  738. </div>
  739. </div>
  740. </div>
  741. <!-- /好评率 -->
  742. <!-- 评论列表 -->
  743. <div class="comment-tab">
  744. <div
  745. class="item"
  746. :class="evaluate === -1 ? 'active' : ''"
  747. @click="getProdCommPageByProd(-1)"
  748. >
  749. {{ $t('all') }}
  750. <span class="number">({{ prodCommData.number }})</span>
  751. </div>
  752. <div
  753. class="item"
  754. :class="evaluate === 0 ? 'active' : ''"
  755. @click="getProdCommPageByProd(0)"
  756. >
  757. {{ $t('prodDetail.goodReview') }}
  758. <span class="number">({{ prodCommData.praiseNumber }})</span>
  759. </div>
  760. <div
  761. class="item"
  762. :class="evaluate === 1 ? 'active' : ''"
  763. @click="getProdCommPageByProd(1)"
  764. >
  765. {{ $t('prodDetail.mediumRating') }}
  766. <span class="number"
  767. >({{ prodCommData.secondaryNumber }})</span
  768. >
  769. </div>
  770. <div
  771. class="item"
  772. :class="evaluate === 2 ? 'active' : ''"
  773. @click="getProdCommPageByProd(2)"
  774. >
  775. {{ $t('prodDetail.poorReviews') }}
  776. <span class="number"
  777. >({{ prodCommData.negativeNumber }})</span
  778. >
  779. </div>
  780. <div
  781. class="item"
  782. :class="evaluate === 3 ? 'active' : ''"
  783. @click="getProdCommPageByProd(3)"
  784. >
  785. {{ $t('prodDetail.withPictures') }}
  786. <span class="number">({{ prodCommData.picNumber }})</span>
  787. </div>
  788. </div>
  789. <div class="comment-con" v-if="prodCommList.records.length">
  790. <div
  791. class="item"
  792. v-for="(item, comIndex) in prodCommList.records"
  793. :key="item.prodCommId"
  794. >
  795. <div class="buyer-msg">
  796. <div class="img">
  797. <img :src="item.pic" alt v-if="item.pic" />
  798. <img src="~/assets/images/buyer-img.png" alt v-else />
  799. </div>
  800. <div class="name">
  801. {{
  802. item.nickName
  803. ? item.nickName
  804. : $t('prodDetail.anonymousUser')
  805. }}
  806. </div>
  807. </div>
  808. <div class="buyer-comment">
  809. <div style="display: flex">
  810. <div class="stars" style="width:95px">
  811. <i
  812. class="star"
  813. v-for="index in item.score"
  814. :key="index"
  815. ></i>
  816. </div>
  817. <div style="color: #999">{{ item.skuName || '' }}</div>
  818. </div>
  819. <div class="text">
  820. <span style="white-space:pre-wrap;">{{
  821. item.content
  822. }}</span>
  823. </div>
  824. <div class="img-box" v-if="item.pics">
  825. <span
  826. class="img"
  827. v-for="(img, imgIndex) in item.prodImgs"
  828. :key="imgIndex"
  829. >
  830. <img
  831. :src="img"
  832. @click="imgShow(comIndex, imgIndex)"
  833. alt
  834. />
  835. <div class="big-img-show" v-if="showBigImg">
  836. <!-- <div v-for="imgIndex in item.prodImgs" :key="imgIndex"> -->
  837. <i class="left-arrow" @click="prevImgCom()">&lt;</i>
  838. <i class="right-arrow" @click="nextImgCom()">&gt;</i>
  839. <div class="mask" @click="closeShowBigImg"></div>
  840. <img :src="imgPath" />
  841. <!-- </div> -->
  842. </div>
  843. </span>
  844. </div>
  845. <div class="time-sku">
  846. <span class="time">{{ item.recTime }}</span>
  847. <!-- <span class="sku">银色 256GB</span> -->
  848. </div>
  849. <!-- <div class="append-comment">
  850. <div class="append-time">购买5天后追评</div>
  851. <div class="append-con">刚买完没几天就降价了,心痛啊啊啊啊啊啊啊啊啊啊啊啊</div>
  852. </div>-->
  853. <div class="seller-reply" v-if="item.replyContent">
  854. <div class="tit">
  855. {{ $t('prodDetail.merchantResponse') }}:
  856. </div>
  857. <div class="con">{{ item.replyContent }}</div>
  858. <div class="time">{{ item.replyTime }}</div>
  859. </div>
  860. </div>
  861. </div>
  862. </div>
  863. <div class="comment-con" v-if="!prodCommList.records.length">
  864. <div class="comment-empty">{{ $t('prodDetail.noComments') }}</div>
  865. </div>
  866. <!-- /评论列表 -->
  867. <!-- 页码 -->
  868. <div class="pagination">
  869. <div class="pages" v-if="page.pages >= 1">
  870. <a
  871. href="javascript:void(0);"
  872. class="item prev"
  873. :class="{ default: page.current <= 1 }"
  874. @click="getSearchProdPage(page.current - 1)"
  875. >{{ $t('pagination.previousPage') }}</a
  876. >
  877. <div v-for="item in page.rainbow" :key="item.prodId">
  878. <a
  879. href="javascript:void(0);"
  880. @click="getSearchProdPage(item)"
  881. class="item"
  882. :class="{ cur: page.current == item }"
  883. v-if="item !== '...'"
  884. >{{ item }}</a
  885. >
  886. <span class="ellipsis" v-else>...</span>
  887. </div>
  888. <a
  889. href="javascript:void(0);"
  890. class="item next"
  891. :class="{ default: page.current > page.pages - 1 }"
  892. @click="getSearchProdPage(page.current + 1)"
  893. >{{ $t('pagination.nextPage') }}</a
  894. >
  895. <!-- <div class="go-page">
  896. 到第
  897. <input type="text"
  898. class="page-input" />页
  899. <a href
  900. class="page-btn">GO</a>
  901. </div>-->
  902. <div class="total-num">
  903. {{ $t('pagination.total') }}
  904. <span class="num">{{ page.pages }}</span
  905. >{{ $t('pagination.page') }}
  906. </div>
  907. </div>
  908. <!-- /页码 -->
  909. </div>
  910. </div>
  911. <!-- /商品评论 -->
  912. <!-- </transition> -->
  913. </div>
  914. <div class="side">
  915. <!-- 店内搜索 -->
  916. <div class="shop-search">
  917. <div class="tit">{{ $t('prodDetail.inStoreSearch') }}</div>
  918. <div class="con">
  919. <input type="text" class="text" v-model="prodName" />
  920. <a href="javascript:void(0)" class="btn" @click="toShopIndex"></a>
  921. </div>
  922. </div>
  923. <!-- /店内搜索 -->
  924. <!-- 店内分类 -->
  925. <div class="shop-category">
  926. <div class="tit">{{ $t('prodDetail.inStoreCategories') }}</div>
  927. <div class="con">
  928. <div
  929. class="items active"
  930. v-for="(item, index) in shopCategorys"
  931. :key="index"
  932. >
  933. <nuxt-link
  934. :to="
  935. '/shopIndex?sid=' +
  936. prodInfo.shopId +
  937. '&cid=' +
  938. item.categoryId
  939. "
  940. >
  941. <div class="item-main">{{ item.categoryName }}</div>
  942. </nuxt-link>
  943. </div>
  944. </div>
  945. </div>
  946. <!-- 店内分类 -->
  947. <!-- 热销产品 -->
  948. <div class="sale-well">
  949. <div class="tit">{{ $t('prodDetail.hotProducts') }}</div>
  950. <div class="con">
  951. <div class="item" v-for="item in hotSales" :key="item.prodId">
  952. <nuxt-link :to="'/detail/' + item.prodId">
  953. <div class="goods-img">
  954. <img v-if="item.pic" :src="item.pic" alt />
  955. <img v-else src="~/assets/img/def.png" alt />
  956. </div>
  957. <div class="goods-msg">
  958. <div class="goods-name">{{ item.prodName }}</div>
  959. <div class="goods-price">
  960. <div class="price">
  961. <span class="big">{{ parsePrice(item.price)[0] }}</span>
  962. .{{ parsePrice(item.price)[1] }}
  963. </div>
  964. </div>
  965. </div>
  966. </nuxt-link>
  967. </div>
  968. </div>
  969. </div>
  970. <!-- 热销产品 -->
  971. </div>
  972. </div>
  973. </div>
  974. <!-- 滑动导航 -->
  975. <transition name="fade">
  976. <div class="scroll-tab" v-if="showScrollTab">
  977. <div class="content">
  978. <div class="shop-search">
  979. <input
  980. type="text"
  981. class="text"
  982. v-model="prodName"
  983. :placeholder="$t('prodDetail.inStoreSearch')"
  984. />
  985. <a href="javascript:void(0)" class="btn" @click="toShopIndex"></a>
  986. </div>
  987. <div class="tab">
  988. <div
  989. :class="['item', introduceOrCommentInt ? 'active' : '']"
  990. @click="toggleIntroduceInt"
  991. >
  992. {{ $t('prodDetail.productIntroduction') }}
  993. </div>
  994. <div
  995. :class="['item', introduceOrCommentCom ? 'active' : '']"
  996. @click="toggleIntroduceCom"
  997. >
  998. {{ $t('prodDetail.productReviews') }}
  999. <i class="number">({{ prodCommData.number }})</i>
  1000. </div>
  1001. </div>
  1002. <div class="add-cart-btn" @click="addToCart">
  1003. {{ $t('prodDetail.addToCart') }}
  1004. </div>
  1005. </div>
  1006. </div>
  1007. </transition>
  1008. <!-- /滑动导航 -->
  1009. <!-- 弹窗 -->
  1010. <div class="popup-mask" v-if="false"></div>
  1011. <div class="popup-box" v-if="false">
  1012. <div class="tit">
  1013. <div class="text">{{ $t('tips') }}</div>
  1014. <div class="close"></div>
  1015. </div>
  1016. <div class="con">
  1017. <div class="tip">
  1018. <div
  1019. class="tip-
  1020. success"
  1021. ></div>
  1022. <div class="tip-info">
  1023. <div class="result">
  1024. {{ $t('prodDetail.congratulationsYouHaveSuccessfullyReceived') }}
  1025. <span class="number"> <i class="small">¥</i>500 </span
  1026. >{{ $t('discountCoupon') }}!
  1027. </div>
  1028. <div class="date">
  1029. {{ $t('prodDetail.timeOfUse') }}:2019.12.12-2019.12.12
  1030. </div>
  1031. <div class="btns">
  1032. <a href="javascript:void(0)" class="btn">
  1033. {{ $t('prodDetail.viewCouponsCollected') }}
  1034. <span class="arrow">>></span>
  1035. </a>
  1036. </div>
  1037. </div>
  1038. </div>
  1039. </div>
  1040. </div>
  1041. <!-- /弹窗 -->
  1042. <!-- 登录弹窗组件 -->
  1043. <LoginPopup v-if="showLogin" v-on:hideLoginPop="hideLoginPop" />
  1044. <!-- /登录弹窗组件 -->
  1045. <!-- 选择套餐 -->
  1046. <SelectPackage
  1047. :shop-info="shopInfo"
  1048. :combo-id="selectComboId"
  1049. :select-match-ids="selectMatchIds"
  1050. v-if="showSelectPackage"
  1051. ref="selectPackageRef"
  1052. @hideSelectPackage="hideSelectPackage" />
  1053. </div>
  1054. </template>
  1055. <script>
  1056. import util from '~/plugins/util'
  1057. import CategroySidebar from '~/components/categroy-sidebar'
  1058. import LoginPopup from '~/components/login-popup'
  1059. import SelectPackage from '~/components/select-package'
  1060. import PageUtil from '~/plugins/pageUtil'
  1061. import Cookie from 'js-cookie'
  1062. import bus from '~/plugins/bus'
  1063. import { h5Path } from '~/plugins/config'
  1064. import Big from 'big.js'
  1065. // import DOMPurify from 'dompurify'
  1066. export default {
  1067. components: {
  1068. CategroySidebar,
  1069. LoginPopup,
  1070. SelectPackage
  1071. },
  1072. data() {
  1073. return {
  1074. // groupActivityId: this.$route.params.groupActivityId,
  1075. showLogin: false,
  1076. prodId: this.$route.params.prodId,
  1077. prodName: '',
  1078. prodInfo: {},
  1079. prodImgs: [],
  1080. offsetCount: 0, //图片偏移数
  1081. imgCounts: 0, //缩略图数量
  1082. showScrollTab: false,
  1083. introduceOrCommentInt: true, // true商品介绍 false商品评论
  1084. introduceOrCommentCom: false,
  1085. prodCommData: {},
  1086. prodCommType: true, // 商品评论类型
  1087. prodCommList: {},
  1088. shopInfo: {},
  1089. evaluate: -1,
  1090. hotSales: [],
  1091. defaultSku: {}, // 选中的sku
  1092. choiceCombNum: 0, //选中的套餐商品数量
  1093. skuGroup: [], //
  1094. selectedProp: [],
  1095. findSku: true, // 能不能找得到sku
  1096. prodNum: 1, //计数器数量
  1097. // prohibit: false, //计数器是否禁用
  1098. prohibit1: true, //计数器-是否禁用
  1099. prohibit2: false, //计数器+是否禁用
  1100. isCollection: false, //商品是否已收藏
  1101. isShopCollection: false, //店铺是否已收藏
  1102. couponList: [], //优惠券
  1103. totalCartNum: 0, //购物车数量
  1104. shopCategorys: [],
  1105. page: {
  1106. pages: 0, // 总页数
  1107. rainbow: [], // 分页条
  1108. current: 1
  1109. },
  1110. groupProdInfo: {}, //团购
  1111. countdown: { obj: { day: '', hou: '', min: '', sec: '', signs: '' } }, //倒计时
  1112. countdownFlag: null, //判断团购活动开始结束
  1113. groupSkuList: [], //团购sku列表
  1114. groupSku: {}, //团购sku信息
  1115. miniQrCodeImg: '', //团购跳转二维码
  1116. discountDet: [], //限时特惠专区详情
  1117. showVideo: false, // 是否展示视频
  1118. showPlayBtn: true, // 视频播放按钮
  1119. imgPath: '', // 当前点击的评论图片
  1120. showBigImg: false, // 评论大图显隐
  1121. scrollTop: 0,
  1122. oriPrice: 0, // 市场价
  1123. bigComIndex: -1, // 评论大图切换
  1124. bigImgIndex: -1, // 评论大图切换
  1125. hasMaxNum: 0, // 是否限购 1限购
  1126. maxNum: 0, // 限购数量
  1127. language: this.$store.state.locale,
  1128. prodParameterList: [],
  1129. showSelectPackage: false,
  1130. comboList: [],
  1131. selectComboId: 0,
  1132. defaultCombo: null,
  1133. selectMatchIds: [],
  1134. detailCommentOffsetTop: 0
  1135. }
  1136. },
  1137. head() {
  1138. return {
  1139. title: this.$t('prodDetail.productDetails')
  1140. }
  1141. },
  1142. //在页面加载之前先加载数据
  1143. async asyncData({ app, params, redirect }) {
  1144. const data = await app.$axios
  1145. .get('/prod/prodInfo', {
  1146. params: {
  1147. prodId: params.prodId
  1148. }
  1149. })
  1150. .then(({ data }) => {
  1151. console.log(data);
  1152. return data
  1153. })
  1154. .catch(err => {
  1155. return redirect('/error')
  1156. })
  1157. const prodImgs = []
  1158. if (data.imgs && data.imgs[0]) {
  1159. data.imgs.split(',').forEach(imgStr => {
  1160. prodImgs.push({
  1161. img: imgStr,
  1162. isActive: false
  1163. })
  1164. })
  1165. prodImgs[0].isActive = true
  1166. }
  1167. // data.content = DOMPurify.sanitize(data.content)
  1168. return {
  1169. prodInfo: data,
  1170. prodImgs: prodImgs,
  1171. shopId: data.shopId,
  1172. activityId: data.activityId,
  1173. oriPrice: data.oriPrice,
  1174. comboList: data.comboList || []
  1175. }
  1176. },
  1177. created() {
  1178. // this.prodInfo.content = this.DOMPurify.sanitize(this.prodInfo.content)
  1179. },
  1180. watch: {
  1181. // prodNum(nv) {
  1182. // if (nv <= 1) {
  1183. // this.prohibit1 = true
  1184. // } else {
  1185. // this.prohibit1 = false
  1186. // }
  1187. // }
  1188. prodNum(nv) {
  1189. if (nv <= 1) {
  1190. this.prohibit1 = true
  1191. if (this.defaultSku.stocks == 0 || nv == this.defaultSku.stocks) {
  1192. this.prohibit2 = true
  1193. }
  1194. } else if (nv == this.defaultSku.stocks) {
  1195. this.prohibit2 = true
  1196. } else {
  1197. this.prohibit1 = false
  1198. this.prohibit2 = false
  1199. }
  1200. }
  1201. },
  1202. filters: {
  1203. // 截取日期: 2020-11-25 00:00:00 -> 2020-11-25
  1204. cutDate(dateStr) {
  1205. if (!dateStr) return ''
  1206. return (dateStr = dateStr.split(' ')[0])
  1207. },
  1208. price(value) {
  1209. if(value) {
  1210. return value.toFixed(2)
  1211. }
  1212. return 0.00
  1213. }
  1214. },
  1215. mounted() {
  1216. if(this.comboList && this.comboList.length > 0) {
  1217. this.selectCombo(this.comboList[0].comboId)
  1218. }
  1219. // console.log(this.prodInfo)
  1220. // 设置网页标题
  1221. document.title = this.$t('prodDetail.productDetails')
  1222. if (this.prodInfo.video) {
  1223. // 获取商品视频
  1224. this.prodVideo = document.getElementById('prodVideo')
  1225. this.showPlayBtn = true
  1226. }
  1227. let flag = 0
  1228. this.prodParameterList[flag] = []
  1229. const prodParameterList = this.prodInfo.prodParameterList || []
  1230. for (let i = 0; i < prodParameterList.length; i++) {
  1231. let params = prodParameterList[i]
  1232. if (i % 3 === 0 && i !== 0) {
  1233. flag++
  1234. this.prodParameterList[flag] = []
  1235. }
  1236. this.prodParameterList[flag].push(params)
  1237. }
  1238. // 提前加载拼团时间
  1239. this.groupBuyInfo()
  1240. //查询商品是否已经收藏
  1241. this.isProdCollected()
  1242. this.isShopCollected()
  1243. //获取店铺分类
  1244. this.getShopCategory()
  1245. this.getShopHead(this.prodInfo.shopId)
  1246. //获取热销商品
  1247. this.getHotSales()
  1248. // 获取商品评论数
  1249. this.$axios
  1250. .get('/prod/prodCommData', {
  1251. params: {
  1252. prodId: this.$route.params.prodId
  1253. }
  1254. })
  1255. .then(({ data }) => {
  1256. this.prodCommData = data
  1257. })
  1258. this.getProdCommPageByProd(-1)
  1259. // 监听页面滚动
  1260. window.addEventListener('scroll', this.scrollToTop)
  1261. //优惠券
  1262. this.getCouponList()
  1263. //通过商品id获取商品所有促销活动
  1264. this.$axios
  1265. .get('/marking/discount/getDiscountByProdId', {
  1266. params: {
  1267. prodId: this.$route.params.prodId
  1268. }
  1269. })
  1270. .then(({ data }) => {
  1271. this.discountDet = data
  1272. })
  1273. // 组装sku
  1274. this.groupSkuProp(this.prodInfo.skuList, this.prodInfo.price)
  1275. // 保存足迹
  1276. if(Cookie.get('token')) {
  1277. this.$axios.post('/p/prodBrowseLog', {
  1278. prodId: this.$route.params.prodId
  1279. })
  1280. }
  1281. // 获取到评价框的垂直位置
  1282. this.getCommentScrollTop()
  1283. },
  1284. computed: {
  1285. comboAmount() {
  1286. if(!this.defaultCombo) {
  1287. return 0
  1288. }
  1289. let price = new Big(this.defaultCombo.mainProd.comboPrice).times(this.defaultCombo.mainProd.leastNum)
  1290. this.defaultCombo.matchingProds.forEach(item => {
  1291. if(this.selectMatchIds.findIndex(id => id === item.prodId) >=0) {
  1292. price = price.plus(new Big(item.comboPrice).times(item.leastNum))
  1293. }
  1294. })
  1295. price = price.toFixed(2)
  1296. return price
  1297. }
  1298. },
  1299. methods: {
  1300. /**
  1301. *
  1302. */
  1303. getCommentScrollTop() {
  1304. this.$nextTick(()=> {
  1305. this.detailCommentOffsetTop = document.querySelector('.detail-comment').offsetTop
  1306. })
  1307. },
  1308. /**
  1309. * 页面滚动事件
  1310. */
  1311. scrollToTop() {
  1312. var scrollTop =
  1313. window.pageYOffset ||
  1314. document.documentElement.scrollTop ||
  1315. document.body.scrollTop
  1316. this.showScrollTab = scrollTop > this.detailCommentOffsetTop
  1317. },
  1318. /**
  1319. * 生成二维码- 拼团跳转到h5
  1320. */
  1321. loadQRCode() {
  1322. let qrcode = new QRCode('spellQrcode', {
  1323. text:
  1324. h5Path +
  1325. `/pages/prod/prod?prodid=${this.prodId}&groupActivityId=${this.activityId}`,
  1326. width: 110,
  1327. height: 110,
  1328. colorDark: '#000000',
  1329. colorLight: '#ffffff',
  1330. correctLevel: 3
  1331. })
  1332. },
  1333. /**
  1334. * 评论点击图片显示大图
  1335. */
  1336. imgShow(comIndex, imgIndex) {
  1337. this.bigComIndex = comIndex
  1338. document.documentElement.style.overflowY = 'hidden'
  1339. var bigProdImgs = this.prodCommList.records[comIndex].prodImgs.length
  1340. if (imgIndex == -1) {
  1341. this.closeShowBigImg()
  1342. this.bigImgIndex = -1
  1343. this.bigComIndex = -1
  1344. return
  1345. }
  1346. if (imgIndex == bigProdImgs) {
  1347. this.closeShowBigImg()
  1348. this.bigImgIndex = -1
  1349. this.bigComIndex = -1
  1350. return
  1351. }
  1352. let imgPath = this.prodCommList.records[comIndex].prodImgs[imgIndex]
  1353. this.imgPath = imgPath
  1354. if (this.imgPath) {
  1355. this.showBigImg = true
  1356. }
  1357. let dom = (document.getElementsByTagName('body').className = 'hid')
  1358. this.bigImgIndex = imgIndex
  1359. },
  1360. prevImgCom() {
  1361. var comIndex = this.bigComIndex
  1362. var imgIndex = this.bigImgIndex - 1
  1363. this.imgShow(comIndex, imgIndex)
  1364. },
  1365. nextImgCom() {
  1366. var comIndex = this.bigComIndex
  1367. var imgIndex = this.bigImgIndex + 1
  1368. this.imgShow(comIndex, imgIndex)
  1369. },
  1370. // 获取选中套餐数量
  1371. selectMatchNum() {
  1372. if ( this.defaultCombo.mainProd) {
  1373. let mainProdNum = this.defaultCombo.mainProd.leastNum
  1374. if ( this.defaultCombo.matchingProds.length ) {
  1375. this.defaultCombo.matchingProds.forEach(item =>{
  1376. if ( item.isChecked ) {
  1377. mainProdNum += item.leastNum
  1378. }
  1379. })
  1380. }
  1381. return mainProdNum
  1382. }
  1383. },
  1384. /**
  1385. * 关闭评论大图显隐
  1386. */
  1387. closeShowBigImg() {
  1388. this.showBigImg = false
  1389. document.documentElement.style.overflowY = 'scroll'
  1390. },
  1391. /**
  1392. * 关闭视频
  1393. */
  1394. stopVideo() {
  1395. this.showVideo = false
  1396. if (this.prodVideo !== undefined) {
  1397. this.prodVideo.pause()
  1398. }
  1399. this.showPlayBtn = true
  1400. },
  1401. /**
  1402. * 播放视频
  1403. */
  1404. playVideo() {
  1405. this.showVideo = true
  1406. this.prodVideo.play(0)
  1407. this.showPlayBtn = false
  1408. },
  1409. // 切换图片
  1410. prevImg() {
  1411. if (this.prodImgs.length - 5 > 0) {
  1412. if (this.offsetCount > 0) {
  1413. this.offsetCount--
  1414. this.$refs.carouser.style.left = '-' + 78 * this.offsetCount + 'px'
  1415. } else {
  1416. return false
  1417. }
  1418. } else if (this.prodImgs.length - 5 <= 0) {
  1419. return false
  1420. } else {
  1421. return false
  1422. }
  1423. },
  1424. nextImg() {
  1425. if (this.prodImgs.length - 5 > 0) {
  1426. if (this.offsetCount < this.prodImgs.length - 5) {
  1427. this.offsetCount++
  1428. this.$refs.carouser.style.left = '-' + 78 * this.offsetCount + 'px'
  1429. } else if (this.prodImgs.length - 5 <= 0) {
  1430. return false
  1431. } else {
  1432. return false
  1433. }
  1434. } else {
  1435. return false
  1436. }
  1437. },
  1438. /**
  1439. * 商品已下架
  1440. */
  1441. handleClose() {
  1442. this.tipsDialogVisible = false
  1443. this.$router.go(-1)
  1444. },
  1445. /**
  1446. * 团购信息
  1447. */
  1448. groupBuyInfo() {
  1449. if (this.prodInfo.prodType != 1) {
  1450. return
  1451. }
  1452. this.$axios
  1453. .get('/groupProd/info', {
  1454. params: {
  1455. prodId: this.prodId,
  1456. groupActivityId: this.activityId
  1457. }
  1458. })
  1459. .then(({ data }) => {
  1460. // 判断活动是否失效
  1461. if (data.code === "A00001") {
  1462. this.prodInfo.code = -1
  1463. this.activityId = ''
  1464. return
  1465. }
  1466. this.groupProdInfo = data.data //团购
  1467. this.groupSkuList = data.data.groupSkuList
  1468. this.groupSku = data.data.groupSkuList[0]
  1469. // console.log(this.groupSkuList,data.data,'groupSkuList这是第一次赋值');
  1470. // this.prodInfo.skuList = data.obj.groupSkuList
  1471. this.hasMaxNum = data.data.hasMaxNum // 是否限购 1限购
  1472. this.maxNum = data.data.maxNum // 限购数量
  1473. let betweenTimestamp = util.betweenTimestamp(
  1474. util.dateToTimestamp(this.groupProdInfo.startTime),
  1475. util.dateToTimestamp(this.groupProdInfo.endTime)
  1476. )
  1477. var countdown = {
  1478. obj: util.betweenTime(betweenTimestamp),
  1479. stamp: betweenTimestamp
  1480. }
  1481. this.countdown = countdown
  1482. this.countdownFlag = this.countdown.obj.signs
  1483. this.startCountdown() //请求倒计时
  1484. // this.getMiniQrCode() //请求二维码
  1485. this.$nextTick(() => {
  1486. this.loadQRCode() //请求二维码
  1487. })
  1488. // 组装团购sku
  1489. this.setDefaultGroupSku()
  1490. })
  1491. },
  1492. /**
  1493. * 倒计时
  1494. */
  1495. startCountdown() {
  1496. this.countdown = {
  1497. stamp:
  1498. this.countdown.stamp < 0
  1499. ? this.countdown.stamp + 1000
  1500. : this.countdown.stamp - 1000,
  1501. obj: util.betweenTime(this.countdown.stamp)
  1502. }
  1503. if (this.countdown.obj.signs != this.countdownFlag) {
  1504. clearTimeout(this.timer)
  1505. location.reload()
  1506. return
  1507. }
  1508. this.timer = setTimeout(() => {
  1509. this.startCountdown()
  1510. }, 1000)
  1511. },
  1512. /**
  1513. * 请求团购小程序二维码
  1514. */
  1515. getMiniQrCode() {
  1516. var contents = {
  1517. groupActivityId: this.activityId,
  1518. prodId: this.prodId
  1519. }
  1520. var content = JSON.stringify(contents)
  1521. this.$axios
  1522. .get('/qrcodeTicket/miniQrCode', {
  1523. params: {
  1524. content: content,
  1525. type: 1
  1526. },
  1527. responseType: 'blob' // 设置接收格式为blob格式
  1528. })
  1529. .then(({ data }) => {
  1530. //接受二进制文件流
  1531. this.miniQrCodeImg = window.URL.createObjectURL(data)
  1532. })
  1533. },
  1534. /**
  1535. * 小图点击事件
  1536. */
  1537. changeProdImg(index) {
  1538. if (this.prodImgs[index].isActive === true) {
  1539. return
  1540. }
  1541. this.prodImgs.forEach(prodImg => {
  1542. prodImg.isActive = false
  1543. })
  1544. this.prodImgs[index].isActive = true
  1545. this.prodInfo.pic = this.prodImgs[index].img
  1546. this.stopVideo()
  1547. },
  1548. /**
  1549. * 大图加载失败时往下一张图加载
  1550. */
  1551. changePicUrl(){
  1552. let defaultUrl=require("~/assets/img/def.png")
  1553. let currentIndex=this.prodImgs.findIndex(prodImg =>
  1554. prodImg.isActive == true
  1555. )
  1556. this.prodImgs[currentIndex].img=defaultUrl
  1557. let nextIndex=currentIndex+1
  1558. if(nextIndex>=this.prodImgs.length){
  1559. this.prodInfo.pic=this.prodImgs[0].img
  1560. return
  1561. }
  1562. this.changeProdImg(nextIndex)
  1563. },
  1564. /**
  1565. * 获取店铺信息
  1566. */
  1567. getShopHead(shopId) {
  1568. this.$axios
  1569. .get('/shop/headInfo', {
  1570. params: {
  1571. shopId: shopId
  1572. }
  1573. })
  1574. .then(({ data }) => {
  1575. this.shopInfo = data
  1576. })
  1577. },
  1578. /**
  1579. * 获取店铺分类
  1580. */
  1581. getShopCategory() {
  1582. this.$axios
  1583. .get('/category/categoryInfo', {
  1584. params: {
  1585. shopId: this.shopId
  1586. }
  1587. })
  1588. .then(({ data }) => {
  1589. this.shopCategorys = data
  1590. })
  1591. },
  1592. /**
  1593. * 价格过滤
  1594. */
  1595. parsePrice(value) {
  1596. var val = Number(value)
  1597. if (!val) {
  1598. val = 0
  1599. }
  1600. // 截取小数点后两位,并以小数点为切割点将val转化为数组
  1601. return val.toFixed(2).split('.')
  1602. },
  1603. /**
  1604. * 切换商品介绍/商品评论
  1605. */
  1606. toggleIntroduceInt() {
  1607. this.introduceOrCommentInt = true
  1608. this.introduceOrCommentCom = false
  1609. },
  1610. toggleIntroduceCom() {
  1611. this.introduceOrCommentInt = false
  1612. this.introduceOrCommentCom = true
  1613. },
  1614. /**
  1615. * 获取评论分页数据
  1616. */
  1617. getSearchProdPage(current) {
  1618. if (
  1619. current == 0 ||
  1620. current == this.page.current ||
  1621. current > this.page.pages
  1622. ) {
  1623. return
  1624. } else {
  1625. this.getProdCommPageByProd(this.evaluate, current)
  1626. }
  1627. },
  1628. /**
  1629. * 获取商品评论列表
  1630. */
  1631. getProdCommPageByProd(evaluate, curPage) {
  1632. this.evaluate = evaluate
  1633. this.$axios
  1634. .get('/prod/prodCommPageByProd', {
  1635. params: {
  1636. prodId: this.$route.params.prodId,
  1637. current: curPage || 1,
  1638. size: 10,
  1639. evaluate: this.evaluate
  1640. }
  1641. })
  1642. .then(({ data }) => {
  1643. this.prodCommList = data
  1644. this.prodCommList.records.forEach(prodComm => {
  1645. var prodImgs = []
  1646. if (prodComm.pics) {
  1647. prodComm.pics.split(',').forEach(imgStr => {
  1648. prodImgs.push(imgStr)
  1649. })
  1650. }
  1651. prodComm.prodImgs = prodImgs
  1652. })
  1653. data.rainbow = PageUtil.rainbowWithDot(data.current, data.pages, 5)
  1654. this.page = data
  1655. })
  1656. },
  1657. /**
  1658. * 获取热销商品
  1659. */
  1660. getHotSales() {
  1661. // this.$axios.get('/search/searchProdPage', {
  1662. this.$axios
  1663. .get('/search/page', {
  1664. params: {
  1665. shopId: this.prodInfo.shopId,
  1666. size: 5,
  1667. sort: 1,
  1668. orderBy: 1,
  1669. isAllProdType: true,
  1670. current: 1,
  1671. isActive: 1 // 过滤掉活动商品
  1672. }
  1673. })
  1674. .then(({ data }) => {
  1675. this.hotSales = data.records[0].products
  1676. })
  1677. },
  1678. /**
  1679. * 收藏商品
  1680. */
  1681. toggleCollect() {
  1682. var prodId = this.prodInfo.prodId
  1683. var isCollection = this.isCollection
  1684. this.$axios
  1685. .post('/p/user/collection/addOrCancel', prodId)
  1686. .then(({ data }) => {
  1687. this.isCollection = !isCollection
  1688. if (this.isCollection) {
  1689. this.$message({
  1690. message: this.$t('prodDetail.collectionSuccess'),
  1691. type: 'success',
  1692. duration: 1000
  1693. })
  1694. } else {
  1695. this.$message({
  1696. message: this.$t('prodDetail.uncollected'),
  1697. type: 'warning',
  1698. duration: 1000
  1699. })
  1700. }
  1701. })
  1702. },
  1703. /**
  1704. * 查询商品是否已收藏
  1705. */
  1706. isProdCollected() {
  1707. if (!Cookie.get('token')) {
  1708. return
  1709. }
  1710. this.$axios
  1711. .get('/p/user/collection/isCollection', {
  1712. params: {
  1713. prodId: this.prodInfo.prodId
  1714. }
  1715. })
  1716. .then(({ data }) => {
  1717. this.isCollection = data
  1718. })
  1719. },
  1720. /**
  1721. * 收藏店铺
  1722. */
  1723. toggleShopCollect() {
  1724. var shopId = this.prodInfo.shopId
  1725. var isShopCollection = this.isShopCollection
  1726. this.$axios
  1727. .post('/p/shop/collection/addOrCancel', shopId)
  1728. .then(({ data }) => {
  1729. this.isShopCollection = !isShopCollection
  1730. if (this.isShopCollection) {
  1731. this.$message({
  1732. message: this.$t('prodDetail.collectionSuccess'),
  1733. type: 'success',
  1734. duration: 1000
  1735. })
  1736. } else {
  1737. this.$message({
  1738. message: this.$t('prodDetail.uncollected'),
  1739. type: 'warning',
  1740. duration: 1000
  1741. })
  1742. }
  1743. })
  1744. },
  1745. /**
  1746. * 查询店铺是否已收藏
  1747. */
  1748. isShopCollected() {
  1749. if (!Cookie.get('token')) {
  1750. return
  1751. }
  1752. this.$axios
  1753. .get('/p/shop/collection/isCollection', {
  1754. params: {
  1755. shopId: this.prodInfo.shopId
  1756. }
  1757. })
  1758. .then(({ data }) => {
  1759. this.isShopCollection = data
  1760. })
  1761. },
  1762. /**
  1763. * 减少商品数量
  1764. */
  1765. reduce() {
  1766. var prodNum = parseInt(this.prodNum)
  1767. if (this.defaultSku.stocks) {
  1768. if (!prodNum || prodNum <= 1) {
  1769. this.prodNum = prodNum
  1770. this.prohibit1 = true //禁用
  1771. this.prohibit2 = false
  1772. } else {
  1773. this.prodNum = prodNum - 1
  1774. this.prohibit1 = false
  1775. this.prohibit2 = false
  1776. }
  1777. } else {
  1778. this.prodNum = 0
  1779. this.prohibit1 = true
  1780. this.prohibit2 = true
  1781. }
  1782. },
  1783. /*
  1784. * 失去焦点时对输入框的判断
  1785. */
  1786. judgeInput(e) {
  1787. var prodNum = parseInt(this.prodNum)
  1788. if (this.defaultSku.stocks) {
  1789. if (!prodNum || prodNum <= 0) {
  1790. this.prohibit1 = true
  1791. this.prohibit2 = false
  1792. } else {
  1793. this.prohibit1 = false
  1794. this.prohibit2 = false
  1795. }
  1796. if (prodNum > this.defaultSku.stocks) {
  1797. this.$message({
  1798. message: this.$t('prodDetail.insufficientInventory'),
  1799. type: 'warning',
  1800. duration: 1000
  1801. })
  1802. this.prohibit1 = false
  1803. this.prohibit2 = true
  1804. this.prodNum = 1
  1805. }
  1806. } else {
  1807. this.prodNum = 0
  1808. this.prohibit1 = true
  1809. this.prohibit2 = true
  1810. }
  1811. },
  1812. /**
  1813. * 增加商品数量
  1814. */
  1815. increase() {
  1816. var prodNum = parseInt(this.prodNum)
  1817. if (this.defaultSku.stocks) {
  1818. if (!this.prodNum) {
  1819. this.prodNum = 1
  1820. return
  1821. }
  1822. if (prodNum < this.defaultSku.stocks) {
  1823. this.prodNum = prodNum + 1
  1824. } else {
  1825. this.$message({
  1826. message: this.$t('prodDetail.insufficientInventory'),
  1827. type: 'warning',
  1828. duration: 1000
  1829. })
  1830. this.prohibit1 = false // -是否禁用
  1831. this.prohibit2 = true // +是否禁用
  1832. }
  1833. } else {
  1834. this.prodNum = 0
  1835. this.prohibit1 = true // -是否禁用
  1836. this.prohibit2 = true // +是否禁用
  1837. }
  1838. },
  1839. /**
  1840. * 请求优惠券列表
  1841. */
  1842. getCouponList() {
  1843. this.$axios
  1844. .get('/coupon/listByProdId', {
  1845. params: {
  1846. prodId: this.$route.params.prodId,
  1847. shopId: this.prodInfo.shopId
  1848. }
  1849. })
  1850. .then(({ data }) => {
  1851. this.couponList = data
  1852. })
  1853. },
  1854. /**
  1855. * 组装SKU
  1856. */
  1857. groupSkuProp: function(skuList, defaultPrice) {
  1858. if (skuList.length == 1 && !skuList[0].properties) {
  1859. this.defaultSku = skuList[0]
  1860. this.imgCounts = this.prodImgs.length
  1861. this.$refs.carouser.style.width = this.imgCounts * 78 + 'px' // 设置图片盒子的初始宽度
  1862. return
  1863. }
  1864. var skuGroup = {}
  1865. var allProperties = []
  1866. var propKeys = []
  1867. var selectedPropObj = {}
  1868. var defaultSku = null
  1869. for (var i = 0; i < skuList.length; i++) {
  1870. var isDefault = false
  1871. if (!defaultSku && skuList[i].price == defaultPrice) {
  1872. //找到和商品价格一样的那个SKU,作为默认选中的SKU
  1873. defaultSku = skuList[i]
  1874. isDefault = true
  1875. }
  1876. var properties = skuList[i].properties //版本:公开版;颜色:金色;内存:64GB
  1877. allProperties.push(properties)
  1878. var propList = properties.split(';') // ["版本:公开版","颜色:金色","内存:64GB"]
  1879. for (var j = 0; j < propList.length; j++) {
  1880. var propval = propList[j].split(':') //["版本","公开版"]
  1881. var props = skuGroup[propval[0]] //先取出 版本对应的值数组
  1882. //如果当前是默认选中的sku,把对应的属性值 组装到selectedProp
  1883. if (isDefault) {
  1884. propKeys.push(propval[0])
  1885. selectedPropObj[propval[0]] = propval[1]
  1886. }
  1887. if (props == undefined) {
  1888. props = [] //假设还没有版本,新建个新的空数组
  1889. props.push(propval[1]) //把 "公开版" 放进空数组
  1890. } else {
  1891. if (props.indexOf(propval[1]) === -1) {
  1892. //如果数组里面没有"公开版"
  1893. props.push(propval[1]) //把 "公开版" 放进数组
  1894. }
  1895. }
  1896. skuGroup[propval[0]] = props //最后把数据 放回版本对应的值
  1897. }
  1898. }
  1899. this.imgCounts = defaultSku.pic
  1900. ? this.prodImgs.length + 1
  1901. : this.prodImgs.length
  1902. this.$refs.carouser.style.width = this.imgCounts * 78 + 'px' // 设置图片盒子的初始宽度
  1903. this.defaultSku = defaultSku
  1904. this.propKeys = propKeys
  1905. this.selectedPropObj = selectedPropObj
  1906. // 商品图片多出来
  1907. this.parseSelectedObjToVals(skuList)
  1908. this.skuGroup = skuGroup
  1909. this.allProperties = allProperties
  1910. },
  1911. /**
  1912. * 将已选的 {key:val,key2:val2}转换成 [val,val2]
  1913. */
  1914. parseSelectedObjToVals: function(skuList) {
  1915. var selectedPropObj = this.selectedPropObj
  1916. var selectedProperties = ''
  1917. var selectedProp = []
  1918. for (var key in selectedPropObj) {
  1919. // selectedProp.push(selectedPropObj[key]);
  1920. selectedProp.push({ key: key, value: selectedPropObj[key] })
  1921. selectedProperties += key + ':' + selectedPropObj[key] + ';'
  1922. }
  1923. selectedProperties = selectedProperties.substring(
  1924. 0,
  1925. selectedProperties.length - 1
  1926. )
  1927. this.selectedProp = selectedProp
  1928. this.selectedProperties = selectedProperties
  1929. this.selectedPropObj = selectedPropObj
  1930. var findSku = false
  1931. for (var i = 0; i < skuList.length; i++) {
  1932. // 解决排序问题导致无法匹配
  1933. if (
  1934. this.compareArray(
  1935. selectedProperties.split(';').sort(),
  1936. skuList[i].properties.split(';').sort()
  1937. )
  1938. ) {
  1939. findSku = true
  1940. this.defaultSku = skuList[i]
  1941. this.changeSkuImg(this.defaultSku.pic)
  1942. break
  1943. }
  1944. // if (skuList[i].properties == selectedProperties) {
  1945. // findSku = true;
  1946. // this.defaultSku = skuList[i]
  1947. // this.changeSkuImg(this.defaultSku.pic);
  1948. // break;
  1949. // }
  1950. }
  1951. this.findSku = findSku
  1952. // 组装团购sku
  1953. this.setDefaultGroupSku()
  1954. },
  1955. /**
  1956. * 比较两个数组中的元素是否相等
  1957. * @param a1 第一个数组
  1958. * @param a2 第二个数组
  1959. * @return boolean 两个数组中的元素都相等则返回 true,反之返回 false
  1960. */
  1961. compareArray(a1, a2) {
  1962. if (!a1 || !a2) {
  1963. return false
  1964. }
  1965. if (a1.length !== a2.length) {
  1966. return false
  1967. }
  1968. for (var i = 0, n = a1.length; i < n; i++) {
  1969. if (a1[i] !== a2[i]) {
  1970. return false
  1971. }
  1972. }
  1973. return true
  1974. },
  1975. /**
  1976. * 切换SKU图片
  1977. */
  1978. changeSkuImg(skuPic) {
  1979. if (skuPic) {
  1980. // if (this.prodImgs[0].sku) {
  1981. // this.prodImgs.splice(0, 1)
  1982. // }
  1983. this.prodImgs.forEach(prodImg => {
  1984. prodImg.isActive = false
  1985. })
  1986. // this.prodImgs.splice(0, 0, {
  1987. // img: skuPic,
  1988. // isActive: true,
  1989. // sku: true
  1990. // });
  1991. this.prodInfo.pic = skuPic
  1992. } else {
  1993. this.prodInfo.pic = this.prodImgs[0].img
  1994. }
  1995. },
  1996. /**
  1997. * 判断当前的规格值 是否可以选
  1998. */
  1999. isSkuLineItemNotOptional(
  2000. allProperties,
  2001. selectedPropObj,
  2002. key,
  2003. item,
  2004. propKeys
  2005. ) {
  2006. var selectedPropObj = Object.assign({}, selectedPropObj)
  2007. var properties = ''
  2008. selectedPropObj[key] = item
  2009. for (var j = 0; j < propKeys.length; j++) {
  2010. properties += propKeys[j] + ':' + selectedPropObj[propKeys[j]] + ';'
  2011. }
  2012. properties = properties.substring(0, properties.length - 1)
  2013. for (var i = 0; i < allProperties.length; i++) {
  2014. if (properties == allProperties[i]) {
  2015. return false
  2016. }
  2017. }
  2018. for (var i = 0; i < allProperties.length; i++) {
  2019. if (allProperties[i].indexOf(item) >= 0) {
  2020. return true
  2021. }
  2022. }
  2023. return false
  2024. },
  2025. /**
  2026. * 规格点击事件
  2027. */
  2028. toChooseItem(skuLineItem, key, event) {
  2029. this.selectedPropObj[key] = skuLineItem
  2030. this.parseSelectedObjToVals(this.prodInfo.skuList)
  2031. if (this.defaultSku.stocks) {
  2032. // 有库存
  2033. this.prodNum = 1
  2034. this.prohibit1 = true
  2035. this.prohibit2 = false
  2036. } else {
  2037. this.prodNum = 0
  2038. this.prohibit1 = true //禁用
  2039. this.prohibit2 = true //禁用
  2040. }
  2041. },
  2042. /**
  2043. * 组装团购sku
  2044. */
  2045. setDefaultGroupSku() {
  2046. var groupSkuList = JSON.parse(JSON.stringify(this.groupSkuList))
  2047. var selectedP = this.selectedProperties.split(';')
  2048. if (groupSkuList.length) {
  2049. for (var i = 0; i < groupSkuList.length; i++) {
  2050. // 进行规格名称对应判断
  2051. let skuNames = groupSkuList[i].properties.split(';')
  2052. let haveSku = selectedP.every(item=>{
  2053. let flag = skuNames.some(itemC=>{
  2054. return item === itemC
  2055. })
  2056. return flag
  2057. })
  2058. // 规格名一一对应则进行赋值
  2059. if (haveSku) {
  2060. this.groupSku = groupSkuList[i]
  2061. break
  2062. }
  2063. }
  2064. }
  2065. },
  2066. /**
  2067. * 加入购物车
  2068. */
  2069. addToCart() {
  2070. if (!this.findSku) {
  2071. return
  2072. }
  2073. if (!this.prodNum || this.prodNum <= 0) {
  2074. this.$message({
  2075. message: this.$t('prodDetail.pleaseEnterTheCorrectNumberOfItems'),
  2076. type: 'warning',
  2077. duration: 1000
  2078. })
  2079. return
  2080. }
  2081. this.$axios
  2082. .post('/p/shopCart/changeItem', {
  2083. basketId: 0,
  2084. count: this.prodNum,
  2085. prodId: this.$route.params.prodId,
  2086. shopId: this.prodInfo.shopId,
  2087. shopName: this.shopInfo.shopName,
  2088. skuId: this.defaultSku.skuId
  2089. // distributionCardNo: this.distributionCardNo
  2090. })
  2091. .then(({ data }) => {
  2092. util.tapLog(4, null, null, this.prodNum)
  2093. this.getCartCount()
  2094. this.$message.success(this.$t('prodDetail.successfullyAddedCart'))
  2095. })
  2096. },
  2097. /**
  2098. * 获取购物车商品总数
  2099. */
  2100. getCartCount() {
  2101. this.$axios.get('/p/shopCart/prodCount').then(({ data }) => {
  2102. this.$store.commit('cartNumber/changeCartNumber', data)
  2103. })
  2104. },
  2105. /**
  2106. * 立即购买
  2107. */
  2108. buyNow() {
  2109. if (!this.findSku) {
  2110. this.$message.error(this.$t('prodDetail.productNotInStock') + '~')
  2111. return
  2112. }
  2113. if (!this.defaultSku.stocks || this.prodNum > this.defaultSku.stocks) {
  2114. this.$message({
  2115. message: this.$t('prodDetail.insufficientInventory'),
  2116. type: 'warning',
  2117. duration: 1000
  2118. })
  2119. return
  2120. }
  2121. if (!this.prodNum || this.prodNum <= 0) {
  2122. this.$message({
  2123. message: this.$t('prodDetail.pleaseEnterTheCorrectNumberOfItems'),
  2124. type: 'warning',
  2125. duration: 1000
  2126. })
  2127. return
  2128. }
  2129. if (!Cookie.get('token')) {
  2130. bus.$emit('showLogin', true)
  2131. } else {
  2132. sessionStorage.setItem(
  2133. 'orderItem',
  2134. JSON.stringify({
  2135. prodId: this.prodInfo.prodId,
  2136. skuId: this.defaultSku.skuId,
  2137. prodCount: this.prodNum,
  2138. shopId: this.prodInfo.shopId
  2139. })
  2140. )
  2141. this.$router.push({
  2142. path: '/submit-order?orderEntry=1'
  2143. })
  2144. }
  2145. },
  2146. /**
  2147. * 领取优惠券
  2148. */
  2149. receiveCoupon(coupon) {
  2150. this.$axios
  2151. .post('/p/myCoupon/receive', coupon.couponId)
  2152. .then(({ data }) => {
  2153. if (data) {
  2154. this.$message({
  2155. message: data,
  2156. type: 'success',
  2157. duration: 1000
  2158. })
  2159. }
  2160. })
  2161. },
  2162. toShopIndex() {
  2163. var searchTerms = this.prodName.trim() //去除字符串的头尾空格
  2164. if (!searchTerms) {
  2165. this.$message({
  2166. message: this.$t('prodDetail.searchContentCannotBeEmpty'),
  2167. type: 'error',
  2168. duration: 1000
  2169. })
  2170. return
  2171. }
  2172. // 跳转到商品列表页
  2173. let url = '/shopIndex?sid=' + this.shopId + '&pn=' + searchTerms
  2174. this.$router.push({ path: url })
  2175. },
  2176. //跳转活动详情
  2177. toDiscountDetail(discountId) {
  2178. this.$router.push({
  2179. path: '/discount-detail',
  2180. query: {
  2181. discountId: discountId
  2182. }
  2183. })
  2184. },
  2185. // 跳转商家客服
  2186. toChatIm(prodInfo) {
  2187. if (Cookie.get('token')) {
  2188. let routeUrl = this.$router.resolve({
  2189. path: '/chat?shopId=' + prodInfo.shopId + '&prodId=' + prodInfo.prodId
  2190. })
  2191. window.open(routeUrl.href, 'view_window')
  2192. } else {
  2193. this.showLogin = true
  2194. }
  2195. },
  2196. /**
  2197. * 隐藏登录弹窗
  2198. */
  2199. hideLoginPop() {
  2200. this.showLogin = false
  2201. },
  2202. handleSelectPackage() {
  2203. if (!Cookie.get('token')) {
  2204. bus.$emit('showLogin', true)
  2205. return
  2206. }
  2207. this.$axios
  2208. .post(`/combo/getCombo`, {
  2209. comboId: this.selectComboId,
  2210. matchingProdIds: this.selectMatchIds
  2211. })
  2212. .then(({ data }) => {
  2213. this.showSelectPackage = true
  2214. this.$nextTick(()=>{
  2215. this.$refs.selectPackageRef.getComboData(data)
  2216. })
  2217. })
  2218. },
  2219. hideSelectPackage() {
  2220. this.showSelectPackage = false
  2221. },
  2222. isChecked(combo) {
  2223. if(combo.required) {
  2224. return true
  2225. }
  2226. if(combo.isChecked) {
  2227. return true
  2228. }
  2229. return false
  2230. },
  2231. selectComboItem(comboItem) {
  2232. if(comboItem.required) {
  2233. return
  2234. }
  2235. if(this.isChecked(comboItem)) {
  2236. comboItem.isChecked = false
  2237. let index = this.findProdIndex(comboItem.prodId)
  2238. if(index >= 0) {
  2239. this.selectMatchIds.splice(index,1)
  2240. }
  2241. }else {
  2242. this.$set(comboItem,'isChecked',true)
  2243. if(this.findProdIndex(comboItem.prodId) < 0) {
  2244. this.selectMatchIds.push(comboItem.prodId)
  2245. }
  2246. }
  2247. this.choiceCombNum = this.selectMatchNum()
  2248. },
  2249. findProdIndex(prodId) {
  2250. let index = this.selectMatchIds.findIndex(item => item === prodId)
  2251. return index
  2252. },
  2253. // 选择套餐
  2254. selectCombo(comboId) {
  2255. this.selectComboId = comboId
  2256. this.selectMatchIds = []
  2257. // defaultCombo
  2258. for(let i = 0; i <this.comboList.length; i++) {
  2259. if(this.comboList[i].comboId === comboId) {
  2260. this.defaultCombo = this.comboList[i]
  2261. break
  2262. }
  2263. }
  2264. this.defaultCombo.matchingProds.forEach(item => {
  2265. if(item.required) {
  2266. this.$set(item,'isChecked',true)
  2267. this.selectMatchIds.push(item.prodId)
  2268. }else {
  2269. this.$set(item,'isChecked',false)
  2270. }
  2271. })
  2272. this.choiceCombNum = this.selectMatchNum()
  2273. }
  2274. },
  2275. destroyed() {
  2276. // 页面销毁时移除监听
  2277. window.removeEventListener('scroll', this.scrollToTop)
  2278. clearTimeout(this.timer)
  2279. }
  2280. }
  2281. </script>
  2282. <style src="~/assets/css/detail.css"></style>