detail.vue 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097
  1. <template>
  2. <view class="app-container">
  3. <view class="recommender-container" v-if="isGroupbuyGoods && !isHeadUser">
  4. <view class="content">
  5. <image :src="detail.groupPic"></image>
  6. <view class="name ellipsis">{{ detail.groupUserName }}</view>
  7. <view>向你推荐</view>
  8. </view>
  9. </view>
  10. <!-- <no-data v-if="!isLoaded" :showText="'加载中'"></no-data> -->
  11. <no-data v-if="isLoaded && noData" :showText="'该商品已失效'"></no-data>
  12. <block v-if="isLoaded && !noData">
  13. <view class="swiper-container">
  14. <swiper @change="changeBanner">
  15. <swiper-item v-if="detail.vedio">
  16. <video id="video1" :src="detail.vedio" @play="playVideo" @pause="pauseVideo" controls loop
  17. :enable-progress-gesture="false" :muted="isFixedVideo"></video>
  18. </swiper-item>
  19. <block v-for="(item, index) in bannerList" :key="index" v-if="bannerList.length > 0">
  20. <swiper-item>
  21. <!-- <image :src="item.url" mode="aspectFill" @tap="previewImage(item.url)" ></image> -->
  22. <view class="image" @tap="previewImage(item.url)">
  23. <image :src="item.url" mode="aspectFill" class="img"></image>
  24. <image :src="detail.logo" mode="aspectFill" class="water"
  25. v-if="isShowWater && index == 0"></image>
  26. </view>
  27. </swiper-item>
  28. </block>
  29. </swiper>
  30. <view class="nums" v-show="(detail.vedio && bannerCurrent != 0) || !detail.vedio">
  31. {{ bannerCurrent + 1 }}/{{
  32. bannerList.length + (detail.vedio ? 1 : 0)
  33. }}
  34. </view>
  35. </view>
  36. <view class="video-container" :class="isFixedVideo ? 'isFixed' : ''">
  37. <view class="content">
  38. <view class="close" @tap="closeFixedVideo">
  39. <image src="@/static/icon/close.png"></image>
  40. </view>
  41. <video id="video2" :src="detail.vedio" @error="videoErrorCallback" controls loop
  42. :enable-progress-gesture="false"></video>
  43. </view>
  44. </view>
  45. <!-- goodsTagRelas -->
  46. <view class="seckill-container" v-if="isSeckillGoods">
  47. <view class="price">
  48. <view class="price-1">¥{{ detail.goodsPrice | numToFixed }}</view>
  49. <view class="price-2">¥{{ detail.orgGoodsPrice | numToFixed }}</view>
  50. </view>
  51. <view class="right">
  52. <text>距结束还剩:</text>
  53. <view class="time">
  54. <text>{{ countdownTime[0] }}</text>时<text>{{ countdownTime[1] }}</text>分<text>{{ countdownTime[2] }}</text>秒
  55. </view>
  56. </view>
  57. <view class="clock">
  58. <image src="@/static/icon/clock.png"></image>
  59. </view>
  60. </view>
  61. <view class="main-container">
  62. <view class="title">{{ detail.goodsName }}</view>
  63. <view class="des">{{detail.describeText ? detail.describeText : ''}}</view>
  64. <view class="tags2" v-if="(detail.goodsTagRelas && detail.goodsTagRelas.length > 0)">
  65. <view class="it" v-for="(it, idx) in detail.goodsTagRelas" :key="idx">{{it.goodsTagName}}</view>
  66. </view>
  67. <view class="stock">
  68. <block v-if="!isSeckillGoods">
  69. <view class="left">
  70. <text>剩余{{ detail.stock }}件</text>
  71. </view>
  72. </block>
  73. <block v-if="isSeckillGoods">
  74. <view class="left">
  75. <text>剩余{{ detail.secStockNum }}件</text>
  76. <view class="progress-box">
  77. <progress :percent="(detail.secStockNum / detail.limitBuy) * 100" activeColor="#FF3F42"
  78. active stroke-width="6" />
  79. </view>
  80. </view>
  81. <view class="right" @tap="isOpen = !isOpen" v-if="
  82. (isServiceUser && !isGroupbuyGoods) ||
  83. (isHeadUser && isGroupbuyGoods)
  84. ">
  85. <text>{{ isOpen ? '收起' : '展开' }}</text>
  86. <image :src="
  87. isOpen
  88. ? '../../static/icon/arrow_2.png'
  89. : '../../static/icon/arrow_1.png'
  90. "></image>
  91. </view>
  92. </block>
  93. </view>
  94. <view class="price" v-if="!isSeckillGoods">
  95. <view class="left">
  96. <view class="price-1">¥{{ detail.goodsPrice | numToFixed }}</view>
  97. <view class="price-2">¥{{ detail.orgGoodsPrice | numToFixed }}</view>
  98. </view>
  99. <view class="right" @tap="isOpen = !isOpen" v-if="
  100. (isServiceUser && !isGroupbuyGoods) ||
  101. (isHeadUser && isGroupbuyGoods)
  102. ">
  103. <text>{{ isOpen ? '收起' : '展开' }}</text>
  104. <image :src="
  105. isOpen
  106. ? '../../static/icon/arrow_2.png'
  107. : '../../static/icon/arrow_1.png'
  108. "></image>
  109. </view>
  110. </view>
  111. <view class="bottom" v-if="isOpen">
  112. <view v-if="isHeadUser && isGroupbuyGoods">团长分佣金额</view>
  113. <view v-else>分享可获得收益</view>
  114. <view>¥{{ commission | numToFixed
  115. }}{{ detail.goodsSpecs.length > 1 ? '起' : '' }}</view>
  116. </view>
  117. </view>
  118. <view class="line-container">
  119. <view v-if="
  120. accountInfo.miniProgram &&
  121. accountInfo.miniProgram.appId !== 'wxf89d330c7b0e718d'
  122. ">运费:包邮</view>
  123. <view>销量:<text>{{ detail.soldNum }}</text></view>
  124. </view>
  125. <view class="evaluate-container" v-if="evaluateList.length">
  126. <view class="title">商品评价</view>
  127. <view class="list">
  128. <view class="item" :class="evaluateList.length === 1 ? 'onlyOne' : ''"
  129. v-for="(item, index) in evaluateList">
  130. <view class="top">
  131. <view class="user">
  132. <image :src="item.avatar" mode="aspectFill" v-if="item.avatar.indexOf('http') >= 0">
  133. </image>
  134. <image :src="imageUrl + item.avatar" mode="aspectFill" v-else></image>
  135. <view class="name ellipsis">{{ item.userName }}</view>
  136. </view>
  137. <view class="date">{{ item.createTime }}</view>
  138. </view>
  139. <view class="rate">
  140. <view class="it"><text>商品质量</text><uni-rate :size="14" :margin="4"
  141. :value="item.commentGoods" color="#fff" active-color="#FE781F" :readonly="true" />
  142. </view>
  143. <view class="it"><text>服务质量</text><uni-rate :size="14" :margin="4"
  144. :value="item.commentService" color="#fff" active-color="#FE781F" :readonly="true" />
  145. </view>
  146. <view class="it"><text>配送质量</text><uni-rate :size="14" :margin="4"
  147. :value="item.commentExpress" color="#fff" active-color="#FE781F" :readonly="true" />
  148. </view>
  149. </view>
  150. <view class="tags">
  151. <view class="it" v-for="(it, idx) in item.tags">{{ it }}</view>
  152. </view>
  153. <view class="content">{{ item.content }}</view>
  154. <view class="images" v-if="item.imgs && item.imgs.length > 0">
  155. <image v-for="(it, idx) in item.imgs" :src="it" @tap="previewEvaluateImage(it, item.imgs)">
  156. </image>
  157. </view>
  158. </view>
  159. </view>
  160. <view class="more">
  161. <view class="btn" @tap="toAllEvaluate">查看全部评价</view>
  162. </view>
  163. </view>
  164. <view class="detail-container">
  165. <view class="title">商品详情</view>
  166. <view class="content" v-if="detail.pubCommonTemplate">
  167. <u-parse :content="detail.pubCommonTemplate.content"></u-parse>
  168. </view>
  169. <view class="content" v-if="detail.commonTemplate">
  170. <u-parse :content="detail.commonTemplate.content"></u-parse>
  171. </view>
  172. <view class="content">
  173. <u-parse :content="detail.content"></u-parse>
  174. </view>
  175. </view>
  176. <view class="bottom-container">
  177. <view class="left">
  178. <view class="item" @tap="clickShare">
  179. <image src="@/static/icon/share.png"></image>
  180. <text>分享</text>
  181. </view>
  182. <view class="item" @tap="handleCollect" v-if="!isGroupbuyGoods && !isPackageGoods">
  183. <block v-if="detail.favorite">
  184. <image src="@/static/icon/collect2.png"></image>
  185. <text>已收藏</text>
  186. </block>
  187. <block v-else>
  188. <image src="@/static/icon/collect.png"></image>
  189. <text>收藏</text>
  190. </block>
  191. </view>
  192. <view class="item" @tap="toCart">
  193. <image src="@/static/icon/cart2.png"></image>
  194. <text>购物车</text>
  195. <view class="dot" v-if="cartCount > 0">{{
  196. cartCount <= 99 ? cartCount : '99+'
  197. }}</view>
  198. </view>
  199. </view>
  200. <view class="right" v-if="!isSeckillGoods && !isGroupbuyGoods && !isPackageGoods">
  201. <view class="button cart" @tap="clickCartOrBuy(1)">加入购物车</view>
  202. <view class="button buy" @tap="clickCartOrBuy(2)">立即购买</view>
  203. </view>
  204. <view class="right" v-if="!isSeckillGoods && isGroupbuyGoods">
  205. <view class="button cart" @tap="clickCartOrBuy(1)">加入购物车</view>
  206. <view class="button buy" @tap="clickCartOrBuy(4)">立即拼团</view>
  207. </view>
  208. <view class="right" v-if="isSeckillGoods">
  209. <view class="button cart" @tap="clickCartOrBuy(1)">加入购物车</view>
  210. <view class="button buy" @tap="clickCartOrBuy(3)">马上抢购</view>
  211. </view>
  212. <view class="right" v-if="isPackageGoods">
  213. <view class="button buy" @tap="clickPackageBuy()">立即购买</view>
  214. </view>
  215. </view>
  216. <u-popup :round="10" :closeable="true" :show="isBuyDialog" @close="isBuyDialog = false">
  217. <view class="cart-container">
  218. <view class="main">
  219. <image :src="specList[specCurrent].imgUrl"></image>
  220. <view class="right">
  221. <view class="title ellipsis-2">{{ detail.goodsName }}</view>
  222. <block v-if="isGroupbuyGoods">
  223. <view class="price">
  224. <view class="price-1">¥{{ specList[specCurrent].price }}</view>
  225. <view class="price-2">¥{{ specList[specCurrent].orgPrice }}</view>
  226. </view>
  227. <view class="stock">剩余{{ specList[specCurrent].stockNum }}件</view>
  228. </block>
  229. <block v-else-if="isSeckillGoods">
  230. <view class="price">
  231. <view class="price-1">¥{{ specList[specCurrent].secPrice }}</view>
  232. <view class="price-2">¥{{ specList[specCurrent].price }}</view>
  233. </view>
  234. <view class="stock">剩余{{ detail.secStockNum }}件</view>
  235. </block>
  236. <block v-else>
  237. <view class="price">
  238. <view class="price-1">¥{{ specList[specCurrent].price }}</view>
  239. <view class="price-2">¥{{ detail.orgGoodsPrice }}</view>
  240. </view>
  241. <view class="stock">剩余{{ specList[specCurrent].stockNum }}件</view>
  242. </block>
  243. </view>
  244. </view>
  245. <view class="attr">
  246. <view class="title">已选属性</view>
  247. <view class="list">
  248. <block v-for="(item, index) in specList" :key="index">
  249. <view class="item" @tap="changeSpec(index)"
  250. :class="specCurrent == index ? 'current' : ''">{{ item.name }}-{{ item.specValue }}
  251. </view>
  252. </block>
  253. </view>
  254. </view>
  255. <view class="num">
  256. <view class="title">购买数量</view>
  257. <u-number-box v-model="buyNum" :min="1" :buttonSize="26" iconStyle="font-size: 12px;">
  258. </u-number-box>
  259. </view>
  260. <view class="button" v-if="dialogType == 1" @tap="addToCart">加入购物车</view>
  261. <view class="button" v-if="dialogType == 2" @tap="nowBuy">立即购买</view>
  262. <view class="button" v-if="dialogType == 3" @tap="rushBuy">马上抢购</view>
  263. <view class="button" v-if="dialogType == 4" @tap="nowBuy">马上拼团</view>
  264. </view>
  265. </u-popup>
  266. <u-popup :round="10" :closeable="false" :show="isShareDialog" @close="isShareDialog = false">
  267. <view class="sharelist-container">
  268. <button class="item" open-type="share" @tap="isShareDialog = false">
  269. <image src="@/static/icon/wechat.png"></image>
  270. <text>分享给微信好友</text>
  271. </button>
  272. <view class="item" @tap="markImage">
  273. <image src="@/static/icon/image.png"></image>
  274. <text>生成图片分享</text>
  275. </view>
  276. </view>
  277. </u-popup>
  278. <view class="global-mask" v-show="isShowCanvas" @tap="closeCanvas"></view>
  279. <view class="canvas-container" v-show="isShowCanvas">
  280. <view class="content">
  281. <canvas style="width: 300px; height: 520px" canvas-id="myCanvas" id="myCanvas"></canvas>
  282. </view>
  283. <view class="button"><text @tap="saveImage">保存图片</text></view>
  284. </view>
  285. <u-popup :round="10" :closeable="true" :show="isPackageDialog" @close="isPackageDialog = false">
  286. <view class="package-container">
  287. <view class="main">
  288. <view class="group" v-for="(item, index) in packageList" :key="index">
  289. <view class="title">请选择商品{{ item.num }}件</view>
  290. <view class="goods-list">
  291. <view class="item" v-for="(it, idx) in item.goodsList" :key="idx">
  292. <image :src="it.imgUrl"></image>
  293. <view class="right">
  294. <view class="name ellipsis-2">{{ it.goodsName }}</view>
  295. <view class="des">{{ it.specValue }}</view>
  296. <view class="bottom">
  297. <view class="price">
  298. <view class="price-1">¥{{ it.price | numToFixed }}</view>
  299. <view class="price-2">¥{{ it.orgPrice | numToFixed }}</view>
  300. </view>
  301. <u-number-box v-model="it.num" :min="0" :max="it.limitNum" :buttonSize="26"
  302. iconStyle="font-size: 12px;">
  303. </u-number-box>
  304. </view>
  305. </view>
  306. </view>
  307. </view>
  308. </view>
  309. </view>
  310. <view class="button" @tap="packageBuy()">立即购买</view>
  311. </view>
  312. </u-popup>
  313. <u-popup :round="10" :show="isShowPhoneDialog">
  314. <view class="phone-dialog">
  315. <view class="content">
  316. <view>申请获取以下权限</view>
  317. <text>获得你的公开信息(手机号码)</text>
  318. </view>
  319. <view class="btn">
  320. <button @tap="isShowPhoneDialog = false">取消</button>
  321. <button type="primary" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
  322. 确定授权
  323. </button>
  324. </view>
  325. </view>
  326. </u-popup>
  327. </block>
  328. <canvas style="
  329. width: 800px;
  330. height: 800px;
  331. z-index: -1;
  332. position: fixed;
  333. bottom: -1000px;
  334. right: -1000px;
  335. " canvas-id="myCanvas22" id="myCanvas22"></canvas>
  336. </view>
  337. </template>
  338. <script>
  339. import {
  340. mapState
  341. } from 'vuex';
  342. import {
  343. base64src
  344. } from '@/utils/base.js';
  345. import {
  346. appId
  347. } from '@/utils/config.js';
  348. import {
  349. uploadImg
  350. } from '@/api/axios.js';
  351. export default {
  352. data() {
  353. return {
  354. isShowPhoneDialog: false,
  355. imageUrl: this.$imageUrl,
  356. configInfo: uni.getStorageSync('configInfo'),
  357. isLoaded: false,
  358. noData: true,
  359. goodsId: null, // 商品id
  360. detail: {}, // 商品详情
  361. commission: 0, // 分佣金额
  362. bannerList: [], // 轮播图列表
  363. bannerCurrent: 0, // 轮播图当前值
  364. specList: [], // 规格列表
  365. specCurrent: 0, // 规格当前值
  366. isOpen: false, // 是否展开
  367. isBuyDialog: false, // 是否显示购买/加入购物车弹窗
  368. dialogType: 1, // 弹窗类型: 1加入购物车,2立即购买,3秒杀抢购
  369. isShareDialog: false, // 是否显示分享弹窗
  370. isShowCanvas: false, // 是否显示海报弹窗
  371. buyNum: 1, // 购买/加入购物车 数量
  372. isSeckillGoods: false, // 是否秒杀商品
  373. isGroupbuyGoods: false, // 是否团购商品
  374. isPackageGoods: false, // 是否套购商品
  375. isPackageDialog: false, // 是否显示套购购买弹窗
  376. packageList: [], // 套购选择列表
  377. cartCount: 0, // 购物车内商品数
  378. isFinishCanvas: false, // 是否已完成海报
  379. codeUrl: '', // 商品码
  380. videoContext1: '', // 视频对象
  381. videoContext2: '', // 视频对象
  382. isFixedVideo: false, // 是否显示视频弹窗
  383. isPlayVideo: false, // 视频是否播放中
  384. isCloseMyself: false, // 是否亲自关闭视频弹窗
  385. countdownTime: '', // 倒计时
  386. endHour: 0, // 倒计时结束时间
  387. evaluateList: [],
  388. isShowWater: false,
  389. accountInfo: {},
  390. };
  391. },
  392. computed: {
  393. ...mapState(['userInfo', 'isLogin', 'userId']),
  394. isHeadUser() {
  395. // 是否团长
  396. return this.userInfo.promotionGroupLeader;
  397. },
  398. isServiceUser() {
  399. // 是否业务员
  400. return this.userInfo.type === 'SERVICE';
  401. },
  402. },
  403. watch: {
  404. countdownTime() {
  405. if (
  406. this.countdownTime[0] == 0 &&
  407. this.countdownTime[1] == 0 &&
  408. this.countdownTime[2] == 0
  409. ) {
  410. this.getDetail();
  411. }
  412. },
  413. },
  414. onPageScroll(res) {
  415. if (
  416. res.scrollTop > 300 &&
  417. this.isPlayVideo &&
  418. !this.isCloseMyself &&
  419. this.detail.vedio
  420. ) {
  421. this.isFixedVideo = true;
  422. this.videoContext2.play();
  423. } else {
  424. this.isFixedVideo = false;
  425. this.videoContext2.pause();
  426. }
  427. if (res.scrollTop < 300) {
  428. this.isCloseMyself = false;
  429. }
  430. },
  431. onLoad({
  432. id
  433. }) {
  434. this.accountInfo = uni.getAccountInfoSync();
  435. this.goodsId = id;
  436. this.getDetail();
  437. this.getEvaluateList();
  438. this.getCartCount();
  439. uni.showLoading({
  440. title: '加载中',
  441. });
  442. },
  443. onShow() {
  444. this.isBuyDialog = false;
  445. },
  446. onReady() {
  447. this.videoContext1 = uni.createVideoContext('video1');
  448. this.videoContext2 = uni.createVideoContext('video2');
  449. },
  450. async onShareAppMessage(options) {
  451. if (options && options.from == 'button') {
  452. // 来自页面内的转发按钮
  453. } else {
  454. // 点击微信右上角的分享按钮
  455. }
  456. return {
  457. title: '分享商品「' + this.detail.goodsName + '」',
  458. imageUrl: await this.markImage222(),
  459. path: '/pages/index/index?goodsId=' +
  460. this.goodsId +
  461. '&serviceId=' +
  462. this.userId,
  463. query: {
  464. // id: this.goodsId,
  465. },
  466. success: function(res) {
  467. if (res.errMsg == 'shareAppMessage:ok') {
  468. this.$successToast('分享完成');
  469. }
  470. },
  471. };
  472. },
  473. methods: {
  474. // 获取手机号
  475. getPhoneNumber(e) {
  476. if (e?.detail?.iv && e?.detail?.encryptedData) {
  477. this.$axios({
  478. url: '/user/mobile/grant',
  479. params: {
  480. userId: this.userId,
  481. iv: e.detail.iv,
  482. encryptedData: e.detail.encryptedData,
  483. },
  484. }).then((res) => {
  485. uni.setStorageSync('token', res.data.token);
  486. uni.setStorageSync('isActiveLogout', false);
  487. this.isShowPhoneDialog = false;
  488. this.$getUserInfo();
  489. });
  490. }
  491. },
  492. // 获取详情
  493. getDetail() {
  494. this.$axios({
  495. url: '/goods/detail',
  496. method: 'get',
  497. params: {
  498. goodsId: this.goodsId,
  499. userId: this.userId,
  500. },
  501. })
  502. .then((res) => {
  503. this.detail = res.data;
  504. this.noData = false;
  505. this.isLoaded = true;
  506. // 团购
  507. this.isGroupbuyGoods = res.data.promotionGroup;
  508. // 秒杀
  509. this.isSeckillGoods = res.data.secType;
  510. this.endHour = res.data.endHour;
  511. this.countTime();
  512. // 套购
  513. this.isPackageGoods = res.data.goodsType === 'PACKAGE';
  514. this.bannerList = res.data.images;
  515. this.specList = res.data.goodsSpecs;
  516. this.specCurrent = 0;
  517. if (!this.isPackageGoods) {
  518. let commissionList = [];
  519. this.specList.forEach((item, index) => {
  520. item.price = item.price.toFixed(2);
  521. item.orgPrice = item.orgPrice.toFixed(2);
  522. commissionList.push(item.shareAmount);
  523. });
  524. this.commission = Math.min(...commissionList);
  525. } else {
  526. this.commission = res.data.shareAmount;
  527. }
  528. // 水印
  529. if (res.data.logo && res.data.logoStartTime) {
  530. this.isShowWater = this.$compareTime(
  531. res.data.logoStartTime,
  532. res.data.logoEndTime
  533. );
  534. } else {
  535. this.isShowWater = false;
  536. }
  537. this.markImage222(false);
  538. })
  539. .catch((res) => {
  540. this.noData = true;
  541. this.isLoaded = true;
  542. })
  543. .finally((res) => {
  544. uni.hideLoading();
  545. });
  546. },
  547. // 获取评价列表
  548. getEvaluateList() {
  549. this.$axios({
  550. url: '/order/comment/goods',
  551. method: 'get',
  552. params: {
  553. pageNo: 1,
  554. pageSize: 5,
  555. goodsId: this.goodsId,
  556. },
  557. }).then((res) => {
  558. this.evaluateList = res.data.records;
  559. });
  560. },
  561. // 查询结束时间
  562. checkEndTime(val) {
  563. let yy = new Date().getFullYear();
  564. let mm = new Date().getMonth() + 1;
  565. let dd = new Date().getDate();
  566. // dd = val == 10 ? dd + 1 : dd;
  567. // 每月有多少天
  568. let days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  569. if ((yy % 4 == 0 && yy % 100 != 0) || yy % 400 == 0) {
  570. days[1] = 29;
  571. }
  572. // 如果结束时间=10(表示第二天10点),dd需加一天
  573. if (val == 10) {
  574. if (dd >= days[mm - 1]) {
  575. mm = mm + 1;
  576. } else {
  577. dd = dd + 1;
  578. }
  579. }
  580. let date = yy + '/' + mm + '/' + dd;
  581. let dateTime = date + ' ' + val + ':00:00';
  582. return dateTime;
  583. },
  584. // 计算倒计时
  585. countTime() {
  586. let endDateTime = this.checkEndTime(this.endHour);
  587. var nowtime = new Date(), //获取当前时间
  588. endtime = new Date(endDateTime); //定义结束时间
  589. var lefttime = endtime.getTime() - nowtime.getTime(), //距离结束时间的毫秒数
  590. hh = Math.floor(lefttime / (1000 * 60 * 60)), //计算小时数
  591. mm = Math.floor((lefttime / (1000 * 60)) % 60), //计算分钟数
  592. ss = Math.floor((lefttime / 1000) % 60); //计算秒数
  593. function checkTime(i) {
  594. if (i < 10) {
  595. i = '0' + i;
  596. }
  597. return i;
  598. }
  599. setTimeout(() => {
  600. this.countTime();
  601. }, 1000);
  602. this.countdownTime = [checkTime(hh), checkTime(mm), checkTime(ss)];
  603. },
  604. // 获取商品二维码
  605. getGoodsCode(success) {
  606. const that = this;
  607. this.$axios({
  608. url: '/goods/qrcode',
  609. method: 'get',
  610. params: {
  611. goodsId: this.goodsId,
  612. userId: this.userId,
  613. },
  614. }).then((res) => {
  615. // this.codeUrl = 'data:image/jpeg;base64,' + res.data;
  616. that.codeUrl = res.data;
  617. console.log(this.codeUrl, typeof success);
  618. if (typeof success === 'function') {
  619. success();
  620. }
  621. });
  622. },
  623. // 视频播放
  624. playVideo(e) {
  625. this.isPlayVideo = true;
  626. },
  627. // 视频暂停
  628. pauseVideo(e) {
  629. this.isPlayVideo = false;
  630. },
  631. // 关闭视频弹窗
  632. closeFixedVideo() {
  633. this.isFixedVideo = false;
  634. this.isCloseMyself = true;
  635. this.videoContext2.pause();
  636. },
  637. // 从个人信息获取购物车商品数量
  638. getCartCount() {
  639. this.$axios({
  640. url: '/user/user/detail',
  641. method: 'get',
  642. params: {
  643. userId: this.userId,
  644. },
  645. }).then((res) => {
  646. this.cartCount = res.data.shoppingCartNums;
  647. if (!res.data.openId) {
  648. return uni.navigateTo({
  649. url: '/pages/login/index?isNotOpenid=' + true,
  650. });
  651. }
  652. });
  653. },
  654. // 查看所有评价
  655. toAllEvaluate() {
  656. uni.navigateTo({
  657. url: '/packageGoods/pages/evaluate?goodsId=' + this.goodsId,
  658. });
  659. },
  660. // 收藏/取消收藏
  661. handleCollect() {
  662. if (!this.isLogin) {
  663. return uni.navigateTo({
  664. url: '/pages/login/index',
  665. });
  666. }
  667. if (!this.detail.favorite) {
  668. this.$axios({
  669. url: '/goods/favorite/add',
  670. params: {
  671. goodsId: this.goodsId,
  672. userId: this.userId,
  673. },
  674. }).then((res) => {
  675. this.$successToast('收藏成功');
  676. this.getDetail();
  677. });
  678. } else {
  679. this.$axios({
  680. url: '/goods/favorite/detail/del',
  681. params: {
  682. goodsId: this.goodsId,
  683. userId: this.userId,
  684. },
  685. }).then((res) => {
  686. this.$successToast('取消收藏成功');
  687. this.getDetail();
  688. });
  689. }
  690. },
  691. // 切换图片
  692. changeBanner(e) {
  693. this.bannerCurrent = e.detail.current;
  694. if (this.bannerCurrent > 0 && this.detail.vedio) {
  695. this.videoContext1.pause();
  696. }
  697. },
  698. // 预览图片
  699. previewImage(url) {
  700. let imgs = [];
  701. this.bannerList.forEach((item, index) => {
  702. imgs.push(item.url);
  703. });
  704. uni.previewImage({
  705. urls: imgs,
  706. current: url,
  707. });
  708. },
  709. // 预览评价图片
  710. previewEvaluateImage(url, imgs) {
  711. uni.previewImage({
  712. urls: imgs,
  713. current: url,
  714. });
  715. },
  716. // 点击分享
  717. clickShare() {
  718. if (!this.isLogin) {
  719. return uni.navigateTo({
  720. url: '/pages/login/index',
  721. });
  722. }
  723. // this.getGoodsCode();
  724. this.isShareDialog = true;
  725. },
  726. // 点击加入购物车/立即购买
  727. clickCartOrBuy(type) {
  728. if (!this.isLogin) {
  729. return uni.navigateTo({
  730. url: '/pages/login/index',
  731. });
  732. }
  733. this.dialogType = type;
  734. this.isBuyDialog = true;
  735. },
  736. // 切换规格
  737. changeSpec(index) {
  738. this.specCurrent = index;
  739. },
  740. // 加入购物车
  741. addToCart() {
  742. if (this.specList[this.specCurrent].stockNum == 0) {
  743. return this.$toast('该规格库存不足');
  744. }
  745. this.$axios({
  746. url: '/shpping/cart/add/one',
  747. type: 'application/json',
  748. params: {
  749. userId: this.userId,
  750. buyGoods: [{
  751. goodsId: this.goodsId,
  752. goodsSpecId: this.specList[this.specCurrent].goodsSpecId,
  753. num: this.buyNum,
  754. secKillId: this.detail.secKillId || '',
  755. promotionGroupId: this.detail.promotionGroupId || '',
  756. }, ],
  757. },
  758. isLoading: 1,
  759. }).then((res) => {
  760. this.$successToast('添加成功');
  761. this.getCartCount();
  762. this.isBuyDialog = false;
  763. });
  764. },
  765. // 立即购买
  766. nowBuy() {
  767. if (this.specList[this.specCurrent].stockNum == 0) {
  768. return this.$toast('该规格库存不足');
  769. }
  770. if (!this.userInfo.mobile) {
  771. this.isShowPhoneDialog = true;
  772. return;
  773. }
  774. let buyList = [{
  775. goodsId: this.goodsId,
  776. goodsSpecId: this.specList[this.specCurrent].goodsSpecId,
  777. num: this.buyNum,
  778. secKillId: this.detail.secKillId || '',
  779. promotionGroupId: this.detail.promotionGroupId || '',
  780. }, ];
  781. let url = '/packageGoods/pages/order?buyList=' + JSON.stringify(buyList);
  782. if (this.detail.promotionGroupId) {
  783. url = url + '&groupbuyId=' + this.detail.promotionGroupId;
  784. }
  785. uni.navigateTo({
  786. url,
  787. });
  788. },
  789. // 马上抢购(秒杀)
  790. rushBuy() {
  791. if (this.detail.secStockNum == 0) {
  792. return this.$toast('该规格库存不足');
  793. }
  794. if (!this.userInfo.mobile) {
  795. this.isShowPhoneDialog = true;
  796. return;
  797. }
  798. this.$axios({
  799. url: '/goods/sec/kill/start',
  800. method: 'post',
  801. params: {
  802. secKillId: this.detail.secKillId,
  803. },
  804. }).then((res) => {
  805. if (res.data) {
  806. let buyList = [{
  807. goodsId: this.goodsId,
  808. goodsSpecId: this.specList[this.specCurrent].goodsSpecId,
  809. num: this.buyNum,
  810. secKillId: this.detail.secKillId || '',
  811. promotionGroupId: this.detail.promotionGroupId || '',
  812. }, ];
  813. uni.navigateTo({
  814. url: '/packageGoods/pages/order?buyList=' +
  815. JSON.stringify(buyList) +
  816. '&secKillId=' +
  817. this.detail.secKillId +
  818. '&secKillSpecId=' +
  819. this.detail.secKillSpecId +
  820. '&secToken=' +
  821. res.data,
  822. });
  823. } else {
  824. this.$toast('活动异常');
  825. }
  826. });
  827. },
  828. // 去购物车页面
  829. toCart() {
  830. uni.switchTab({
  831. url: '/pages/cart/index',
  832. });
  833. },
  834. // 打开套购购买弹窗
  835. clickPackageBuy() {
  836. this.packageList = [];
  837. this.$axios({
  838. url: '/goods/package/choice',
  839. method: 'get',
  840. params: {
  841. goodsId: this.goodsId,
  842. },
  843. }).then((res) => {
  844. let goodsList = res.data;
  845. for (let i = 0; i < goodsList.length; i++) {
  846. for (let j = 0; j < goodsList[i].length; j++) {
  847. goodsList[i][j].num = 0;
  848. }
  849. }
  850. let pops = this.detail.packagePop.split(':');
  851. pops.forEach((item, index) => {
  852. this.packageList.push({
  853. num: item,
  854. goodsList: goodsList[index],
  855. });
  856. });
  857. console.log(this.packageList);
  858. this.isPackageDialog = true;
  859. });
  860. },
  861. // 套购购买
  862. packageBuy() {
  863. if (!this.userInfo.mobile) {
  864. this.isShowPhoneDialog = true;
  865. return;
  866. }
  867. let buyList = [];
  868. for (let i = 0; i < this.packageList.length; i++) {
  869. for (let j = 0; j < this.packageList[i].goodsList.length; j++) {
  870. if (this.packageList[i].goodsList[j].num > 0) {
  871. buyList.push({
  872. goodsId: this.packageList[i].goodsList[j].goodsId,
  873. goodsSpecId: this.packageList[i].goodsList[j].goodsSpecId,
  874. popType: this.packageList[i].goodsList[j].type,
  875. num: this.packageList[i].goodsList[j].num,
  876. });
  877. }
  878. }
  879. }
  880. uni.navigateTo({
  881. url: '/packageGoods/pages/order?buyList=' +
  882. JSON.stringify(buyList) +
  883. '&packageId=' +
  884. this.detail.goodsId,
  885. });
  886. },
  887. // 分享
  888. share() {
  889. uni.share({
  890. provider: 'weixin',
  891. scene: 'WXSceneSession',
  892. type: 5,
  893. summary: '我正在使用HBuilderX开发uni-app,赶紧跟我一起来体验!',
  894. success: function(res) {
  895. console.log('success:' + JSON.stringify(res));
  896. },
  897. fail: function(err) {
  898. console.log('fail:' + JSON.stringify(err));
  899. },
  900. });
  901. },
  902. async markImage222(bool = true) {
  903. return new Promise((r) => {
  904. if (
  905. this.detail.logo &&
  906. this.detail.imgUrl &&
  907. this.$compareTime(this.detail.logoStartTime, this.detail.logoEndTime)
  908. ) {
  909. if (!!this.detail.mergeImage) {
  910. r(this.detail.mergeImage);
  911. } else {
  912. if (bool) {
  913. uni.showLoading({
  914. title: '图片生成中',
  915. });
  916. }
  917. this.getGoodsCode(() => {
  918. let img = this.detail.imgUrl;
  919. let logo = this.detail.logo;
  920. var ctx = uni.createCanvasContext('myCanvas22');
  921. ctx.rect(0, 0, 800, 800);
  922. ctx.setFillStyle('#FFFFFF');
  923. ctx.fill();
  924. ctx.stroke();
  925. uni.downloadFile({
  926. url: img,
  927. success: (res) => {
  928. ctx.drawImage(res.tempFilePath, 0, 0, 800, 800);
  929. uni.downloadFile({
  930. url: logo,
  931. success: (res2) => {
  932. ctx.drawImage(res2
  933. .tempFilePath, 0, 0,
  934. 800, 800);
  935. ctx.draw();
  936. uni.canvasToTempFilePath({
  937. x: 0,
  938. y: 0,
  939. width: 800,
  940. height: 800,
  941. canvasId: 'myCanvas22',
  942. success: (
  943. res33) => {
  944. uploadImg({
  945. path: res33
  946. .tempFilePath,
  947. })
  948. .then((
  949. data
  950. ) => {
  951. this.$axios({
  952. url: '/goods/update/mergeImage',
  953. method: 'post',
  954. params: {
  955. goodsId: this
  956. .goodsId,
  957. imgUrl: data
  958. .url,
  959. },
  960. })
  961. .then(
  962. (
  963. res
  964. ) => {
  965. if (
  966. bool
  967. ) {
  968. uni
  969. .hideLoading();
  970. this
  971. .getDetail();
  972. }
  973. r(res
  974. .data
  975. );
  976. }
  977. );
  978. });
  979. },
  980. });
  981. },
  982. });
  983. },
  984. });
  985. });
  986. }
  987. } else {
  988. r(this.detail.imgUrl);
  989. }
  990. });
  991. },
  992. // 生成图片
  993. markImage() {
  994. this.isShareDialog = false;
  995. this.isShowCanvas = true;
  996. if (this.isFinishCanvas) {
  997. return false;
  998. }
  999. uni.showLoading({
  1000. title: '海报生成中',
  1001. });
  1002. // 调用获取二维图接口后执行匿名函数
  1003. this.getGoodsCode(() => {
  1004. let img = this.detail.imgUrl;
  1005. let logo = this.detail.logo;
  1006. let title = this.detail.goodsName;
  1007. let des = this.detail.describeText;
  1008. let price1 = this.detail.goodsPrice;
  1009. let price2 = this.detail.orgGoodsPrice;
  1010. let sales = this.detail.soldNum;
  1011. // let code = this.codeUrl;
  1012. // base64src(this.codeUrl , resCurrent => {
  1013. // code = resCurrent;
  1014. // })
  1015. var ctx = uni.createCanvasContext('myCanvas');
  1016. /**
  1017. * @param {Object} str 要绘制的字符串
  1018. * @param {Number} initX 绘制字符串起始x坐标
  1019. * @param {Number} initY 绘制字符串起始y坐标
  1020. * @param {Number} lineHeight 字行高
  1021. */
  1022. function canvasTextAutoLine(str, initX, initY, lineHeight) {
  1023. var lineWidth = 0;
  1024. var canvasWidth = 260;
  1025. var lastSubStrIndex = 0;
  1026. var lineNum = 0;
  1027. var state = true;
  1028. for (let i = 0; i < str.length; i++) {
  1029. lineWidth += ctx.measureText(str[i]).width;
  1030. if (lineWidth > canvasWidth && lineNum < 1) {
  1031. ctx.fillText(str.substring(lastSubStrIndex, i), initX, initY);
  1032. initY += lineHeight;
  1033. lineWidth = 0;
  1034. lastSubStrIndex = i;
  1035. lineNum++;
  1036. } else if (lineWidth > canvasWidth && lineNum < 2) {
  1037. ctx.fillText(
  1038. str.substring(lastSubStrIndex + 2, i) + '...',
  1039. initX,
  1040. initY
  1041. );
  1042. lineNum++;
  1043. state = false;
  1044. }
  1045. if (i == str.length - 1 && state) {
  1046. ctx.fillText(str.substring(lastSubStrIndex, i + 1), initX, initY);
  1047. }
  1048. }
  1049. }
  1050. // 白色背景
  1051. ctx.rect(0, 0, 300, 520);
  1052. ctx.setFillStyle('#FFFFFF');
  1053. ctx.fill();
  1054. ctx.stroke();
  1055. // 商品名称
  1056. ctx.setFontSize(14);
  1057. ctx.setFillStyle('#333333');
  1058. canvasTextAutoLine(title, 20, 300, 18);
  1059. // 商品描述
  1060. if (des) {
  1061. ctx.setFontSize(12);
  1062. ctx.setFillStyle('#999999');
  1063. canvasTextAutoLine(des, 20, 336, 16);
  1064. }
  1065. // 现价
  1066. ctx.setFontSize(16);
  1067. ctx.setFillStyle('#FF3F42');
  1068. ctx.fillText('¥' + price1, 20, 380);
  1069. // 原价
  1070. ctx.setFontSize(13);
  1071. ctx.setFillStyle('#666666');
  1072. ctx.fillText('¥' + price2, 20, 396);
  1073. ctx.setStrokeStyle('#666666');
  1074. ctx.moveTo(20, 392);
  1075. ctx.lineTo(ctx.measureText('¥' + price2).width + 20, 392);
  1076. ctx.stroke();
  1077. // 销量
  1078. ctx.setFontSize(12);
  1079. ctx.setFillStyle('#666666');
  1080. ctx.fillText(
  1081. '销量:' + sales,
  1082. 260 - ctx.measureText('销量:' + sales).width + 20,
  1083. 380
  1084. );
  1085. // 二维码
  1086. // ctx.drawImage(code, 110, 404, 80, 80)
  1087. // 提示
  1088. ctx.setFontSize(12);
  1089. ctx.setFillStyle('#FE781F');
  1090. ctx.fillText('打开微信扫描识别查看商品', 78, 500);
  1091. // 图片
  1092. uni.downloadFile({
  1093. url: img,
  1094. success: (res) => {
  1095. ctx.drawImage(res.tempFilePath, 20, 20, 260, 260);
  1096. // 二维码
  1097. uni.downloadFile({
  1098. url: this.codeUrl,
  1099. success: (res) => {
  1100. ctx.drawImage(res.tempFilePath, 110, 404, 80, 80);
  1101. if (this.isShowWater) {
  1102. uni.downloadFile({
  1103. url: logo,
  1104. success: (res2) => {
  1105. ctx.drawImage(res2
  1106. .tempFilePath, 20, 20,
  1107. 260, 260);
  1108. ctx.draw();
  1109. uni.hideLoading();
  1110. this.isFinishCanvas = true;
  1111. },
  1112. });
  1113. } else {
  1114. console.log('生成画布成功');
  1115. ctx.draw();
  1116. uni.hideLoading();
  1117. this.isFinishCanvas = true;
  1118. }
  1119. },
  1120. });
  1121. },
  1122. });
  1123. });
  1124. },
  1125. // 保存图片
  1126. saveImage() {
  1127. let that = this;
  1128. uni.canvasToTempFilePath({
  1129. x: 0,
  1130. y: 0,
  1131. width: 300,
  1132. height: 520,
  1133. canvasId: 'myCanvas',
  1134. success: function(res) {
  1135. uni.saveImageToPhotosAlbum({
  1136. filePath: res.tempFilePath,
  1137. success: function() {
  1138. that.$successToast('保存成功');
  1139. },
  1140. });
  1141. },
  1142. });
  1143. },
  1144. // 关闭canvas
  1145. closeCanvas() {
  1146. this.isShowCanvas = false;
  1147. uni.hideLoading();
  1148. },
  1149. },
  1150. };
  1151. </script>
  1152. <style lang="scss">
  1153. .app-container {
  1154. background: #f4f2f2;
  1155. box-sizing: border-box;
  1156. padding-bottom: 100rpx;
  1157. }
  1158. .recommender-container {
  1159. position: fixed;
  1160. top: 20rpx;
  1161. left: 0;
  1162. z-index: 99;
  1163. display: flex;
  1164. justify-content: center;
  1165. width: 100%;
  1166. .content {
  1167. font-size: 28rpx;
  1168. color: #ffffff;
  1169. background: rgba($color: #000000, $alpha: 0.8);
  1170. display: flex;
  1171. padding: 0 15rpx;
  1172. height: 60rpx;
  1173. border-radius: 60rpx;
  1174. justify-content: center;
  1175. align-items: center;
  1176. image {
  1177. width: 40rpx;
  1178. height: 40rpx;
  1179. display: block;
  1180. border-radius: 50%;
  1181. margin-right: 10rpx;
  1182. }
  1183. .name {
  1184. max-width: 160rpx;
  1185. margin-right: 6rpx;
  1186. }
  1187. }
  1188. }
  1189. .swiper-container {
  1190. position: relative;
  1191. swiper {
  1192. height: 750rpx;
  1193. }
  1194. .image {
  1195. width: 750rpx;
  1196. height: 750rpx;
  1197. display: block;
  1198. margin: 0 auto;
  1199. overflow: hidden;
  1200. position: relative;
  1201. .img {
  1202. width: 750rpx;
  1203. height: 750rpx;
  1204. display: block;
  1205. }
  1206. .water {
  1207. width: 750rpx;
  1208. height: 750rpx;
  1209. display: block;
  1210. position: absolute;
  1211. left: 0;
  1212. top: 0;
  1213. z-index: 1;
  1214. }
  1215. }
  1216. // image {
  1217. // height: 750rpx;
  1218. // width: 750rpx;
  1219. // display: block;
  1220. // margin: 0 auto;
  1221. // overflow: hidden;
  1222. // }
  1223. video {
  1224. height: 750rpx;
  1225. width: 750rpx;
  1226. display: block;
  1227. margin: 0 auto;
  1228. overflow: hidden;
  1229. }
  1230. .nums {
  1231. position: absolute;
  1232. right: 20rpx;
  1233. bottom: 20rpx;
  1234. background: rgba($color: #000000, $alpha: 0.2);
  1235. border-radius: 8rpx;
  1236. line-height: 48rpx;
  1237. padding: 0 12rpx;
  1238. font-size: 28rpx;
  1239. color: #ffffff;
  1240. }
  1241. }
  1242. .video-container {
  1243. position: fixed;
  1244. right: 20rpx;
  1245. bottom: 300rpx;
  1246. z-index: -99;
  1247. &.isFixed {
  1248. z-index: 99;
  1249. }
  1250. .content {
  1251. position: relative;
  1252. }
  1253. video {
  1254. height: 200rpx;
  1255. width: 375rpx;
  1256. }
  1257. .close {
  1258. position: absolute;
  1259. right: 0;
  1260. top: 0;
  1261. z-index: 100;
  1262. background: rgba($color: #000000, $alpha: 0.4);
  1263. padding: 10rpx;
  1264. image {
  1265. width: 28rpx;
  1266. height: 28rpx;
  1267. display: block;
  1268. }
  1269. }
  1270. }
  1271. .seckill-container {
  1272. height: 120rpx;
  1273. background: linear-gradient(-90deg, rgba(255, 37, 118, 1) 0%, #ff5648 100%);
  1274. display: flex;
  1275. justify-content: space-between;
  1276. align-items: center;
  1277. padding: 0 20rpx;
  1278. position: relative;
  1279. .clock {
  1280. position: absolute;
  1281. right: 220rpx;
  1282. top: 20rpx;
  1283. image {
  1284. width: 74rpx;
  1285. height: 72rpx;
  1286. display: block;
  1287. }
  1288. }
  1289. .price-1 {
  1290. font-size: 40rpx;
  1291. color: #ffffff;
  1292. line-height: 44rpx;
  1293. }
  1294. .price-2 {
  1295. font-size: 28rpx;
  1296. line-height: 32rpx;
  1297. color: #dddddd;
  1298. text-decoration: line-through;
  1299. }
  1300. .right {
  1301. display: flex;
  1302. flex-direction: column;
  1303. align-items: center;
  1304. text {
  1305. font-size: 24rpx;
  1306. color: #ffffff;
  1307. }
  1308. .time {
  1309. font-size: 24rpx;
  1310. color: #ffffff;
  1311. display: flex;
  1312. align-items: center;
  1313. margin-top: 6rpx;
  1314. text {
  1315. width: 40rpx;
  1316. height: 40rpx;
  1317. background: #ffffff;
  1318. border-radius: 4rpx;
  1319. color: #ff2775;
  1320. font-size: 24rpx;
  1321. line-height: 40rpx;
  1322. text-align: center;
  1323. margin: 0 4rpx;
  1324. }
  1325. }
  1326. }
  1327. }
  1328. .tags2 {
  1329. display: flex;
  1330. flex-wrap: wrap;
  1331. .it {
  1332. font-size: 20rpx;
  1333. height: 30rpx;
  1334. line-height: 30rpx;
  1335. padding: 0 6rpx;
  1336. margin-right: 10rpx;
  1337. border: 1px solid #FE781F;
  1338. color: #FE781F;
  1339. box-sizing: border-box;
  1340. margin-top: 10rpx;
  1341. display: flex;
  1342. align-items: center;
  1343. flex-direction: row;
  1344. border-radius: 10rpx;
  1345. }
  1346. }
  1347. .main-container {
  1348. background: #ffffff;
  1349. padding: 20rpx 20rpx 0;
  1350. .title {
  1351. font-size: 32rpx;
  1352. color: #333333;
  1353. line-height: 40rpx;
  1354. font-weight: 600;
  1355. }
  1356. .des {
  1357. font-size: 24rpx;
  1358. color: #999999;
  1359. line-height: 28rpx;
  1360. margin-top: 8rpx;
  1361. }
  1362. .stock {
  1363. display: flex;
  1364. justify-content: space-between;
  1365. align-items: flex-end;
  1366. margin-top: 20rpx;
  1367. padding-bottom: 20rpx;
  1368. .left {
  1369. display: flex;
  1370. align-items: center;
  1371. text {
  1372. font-size: 24rpx;
  1373. color: #666666;
  1374. }
  1375. .progress-box {
  1376. width: 140rpx;
  1377. border-radius: 6px;
  1378. overflow: hidden;
  1379. margin-left: 10rpx;
  1380. }
  1381. }
  1382. .right {
  1383. font-size: 28rpx;
  1384. color: #999999;
  1385. display: flex;
  1386. align-items: center;
  1387. image {
  1388. width: 20rpx;
  1389. height: 20rpx;
  1390. display: block;
  1391. margin-left: 10rpx;
  1392. }
  1393. }
  1394. }
  1395. .price {
  1396. display: flex;
  1397. justify-content: space-between;
  1398. align-items: flex-end;
  1399. // margin-top: 10rpx;
  1400. padding-bottom: 20rpx;
  1401. .left {
  1402. display: flex;
  1403. flex-direction: column;
  1404. }
  1405. .price-1 {
  1406. font-size: 32rpx;
  1407. color: #ff3f42;
  1408. line-height: 36rpx;
  1409. }
  1410. .price-2 {
  1411. font-size: 26rpx;
  1412. color: #666666;
  1413. line-height: 30rpx;
  1414. text-decoration: line-through;
  1415. }
  1416. .right {
  1417. font-size: 28rpx;
  1418. color: #999999;
  1419. display: flex;
  1420. align-items: center;
  1421. image {
  1422. width: 20rpx;
  1423. height: 20rpx;
  1424. display: block;
  1425. margin-left: 10rpx;
  1426. }
  1427. }
  1428. }
  1429. .bottom {
  1430. display: flex;
  1431. align-items: center;
  1432. justify-content: space-between;
  1433. height: 76rpx;
  1434. border-top: 1px solid #eaeaea;
  1435. font-size: 28rpx;
  1436. color: #666666;
  1437. }
  1438. }
  1439. .line-container {
  1440. background: #ffffff;
  1441. margin-top: 20rpx;
  1442. display: flex;
  1443. justify-content: space-between;
  1444. align-items: center;
  1445. height: 88rpx;
  1446. font-size: 28rpx;
  1447. color: #333333;
  1448. padding: 0 20rpx;
  1449. text {
  1450. color: #fe781f;
  1451. }
  1452. }
  1453. .detail-container {
  1454. background: #ffffff;
  1455. margin-top: 20rpx;
  1456. .title {
  1457. font-size: 32rpx;
  1458. color: #333333;
  1459. line-height: 88rpx;
  1460. text-align: center;
  1461. font-weight: 600;
  1462. }
  1463. .content {
  1464. image {
  1465. width: 100%;
  1466. }
  1467. }
  1468. }
  1469. .evaluate-container {
  1470. background: #ffffff;
  1471. margin-top: 20rpx;
  1472. .title {
  1473. font-size: 32rpx;
  1474. color: #333333;
  1475. line-height: 88rpx;
  1476. text-align: center;
  1477. font-weight: 600;
  1478. }
  1479. .list {
  1480. display: flex;
  1481. overflow-x: scroll;
  1482. padding: 0 20rpx;
  1483. .item {
  1484. width: 650rpx;
  1485. padding-right: 30rpx;
  1486. flex-shrink: 0;
  1487. &:last-child {
  1488. padding-right: 20rpx;
  1489. }
  1490. &.onlyOne {
  1491. width: 710rpx;
  1492. }
  1493. .top {
  1494. display: flex;
  1495. justify-content: space-between;
  1496. align-items: center;
  1497. .user {
  1498. display: flex;
  1499. align-items: center;
  1500. image {
  1501. width: 80rpx;
  1502. height: 80rpx;
  1503. display: block;
  1504. border-radius: 50%;
  1505. margin-right: 20rpx;
  1506. }
  1507. .name {
  1508. font-size: 28rpx;
  1509. color: #333333;
  1510. width: 250rpx;
  1511. }
  1512. }
  1513. .date {
  1514. font-size: 28rpx;
  1515. color: #999999;
  1516. }
  1517. }
  1518. .rate {
  1519. margin-top: 14rpx;
  1520. .it {
  1521. display: flex;
  1522. align-items: center;
  1523. font-size: 24rpx;
  1524. color: #666666;
  1525. margin-top: 5rpx;
  1526. &>text {
  1527. margin-right: 10rpx;
  1528. }
  1529. }
  1530. }
  1531. .tags {
  1532. display: flex;
  1533. flex-wrap: wrap;
  1534. .it {
  1535. line-height: 44rpx;
  1536. padding: 0 15rpx;
  1537. border: 1px solid #eaeaea;
  1538. border-radius: 44rpx;
  1539. font-size: 24rpx;
  1540. margin-right: 14rpx;
  1541. margin-top: 14rpx;
  1542. color: #666666;
  1543. }
  1544. }
  1545. .content {
  1546. font-size: 28rpx;
  1547. color: #333333;
  1548. margin-top: 14rpx;
  1549. }
  1550. .images {
  1551. display: flex;
  1552. flex-wrap: wrap;
  1553. margin-top: 14rpx;
  1554. image {
  1555. width: 140rpx;
  1556. height: 140rpx;
  1557. margin-right: 20rpx;
  1558. margin-bottom: 20rpx;
  1559. }
  1560. }
  1561. }
  1562. }
  1563. .more {
  1564. display: flex;
  1565. justify-content: center;
  1566. padding: 10rpx 0 30rpx;
  1567. .btn {
  1568. width: 220rpx;
  1569. height: 68rpx;
  1570. line-height: 68rpx;
  1571. text-align: center;
  1572. border-radius: 68rpx;
  1573. border: 1px solid #eaeaea;
  1574. font-size: 28rpx;
  1575. color: #666666;
  1576. }
  1577. }
  1578. }
  1579. .bottom-container {
  1580. position: fixed;
  1581. bottom: 0;
  1582. left: 0;
  1583. width: 100%;
  1584. box-sizing: border-box;
  1585. padding: 0 20rpx;
  1586. background: #ffffff;
  1587. display: flex;
  1588. justify-content: space-between;
  1589. align-items: center;
  1590. height: 100rpx;
  1591. border-top: 1px solid #eaeaea;
  1592. .left {
  1593. display: flex;
  1594. width: 280rpx;
  1595. .item {
  1596. display: flex;
  1597. flex-direction: column;
  1598. align-items: center;
  1599. justify-content: center;
  1600. margin-right: 40rpx;
  1601. position: relative;
  1602. width: 66rpx;
  1603. &:last-child {
  1604. margin-right: 0;
  1605. }
  1606. image {
  1607. width: 40rpx;
  1608. height: 40rpx;
  1609. display: block;
  1610. }
  1611. text {
  1612. font-size: 22rpx;
  1613. color: #333333;
  1614. margin-top: 4rpx;
  1615. }
  1616. .dot {
  1617. position: absolute;
  1618. right: -4rpx;
  1619. top: -8rpx;
  1620. background: #ff3f42;
  1621. width: 32rpx;
  1622. height: 32rpx;
  1623. line-height: 32rpx;
  1624. text-align: center;
  1625. border-radius: 32rpx;
  1626. font-size: 20rpx;
  1627. color: #ffffff;
  1628. }
  1629. }
  1630. }
  1631. .right {
  1632. display: flex;
  1633. .button {
  1634. width: 190rpx;
  1635. height: 80rpx;
  1636. line-height: 80rpx;
  1637. text-align: center;
  1638. border-radius: 80rpx;
  1639. font-size: 28rpx;
  1640. color: #ffffff;
  1641. &.cart {
  1642. background: #fe781f;
  1643. }
  1644. &.buy {
  1645. background: #ff3f42;
  1646. margin-left: 10rpx;
  1647. }
  1648. &.sec {
  1649. background: linear-gradient(-90deg, #ff3f42 0%, #fe781f 100%);
  1650. }
  1651. }
  1652. }
  1653. }
  1654. .cart-container {
  1655. padding: 50rpx 20rpx 30rpx;
  1656. .main {
  1657. display: flex;
  1658. padding: 20rpx 0;
  1659. border-bottom: 1px solid #eaeaea;
  1660. image {
  1661. width: 200rpx;
  1662. height: 200rpx;
  1663. display: block;
  1664. flex-shrink: 0;
  1665. }
  1666. .right {
  1667. margin-left: 26rpx;
  1668. display: flex;
  1669. flex-direction: column;
  1670. justify-content: space-between;
  1671. .title {
  1672. font-size: 28rpx;
  1673. color: #333333;
  1674. line-height: 36rpx;
  1675. }
  1676. .price {
  1677. display: flex;
  1678. flex-direction: column;
  1679. }
  1680. .price-1 {
  1681. font-size: 32rpx;
  1682. color: #ff3f42;
  1683. line-height: 36rpx;
  1684. }
  1685. .price-2 {
  1686. font-size: 26rpx;
  1687. color: #666666;
  1688. line-height: 30rpx;
  1689. text-decoration: line-through;
  1690. }
  1691. .stock {
  1692. font-size: 24rpx;
  1693. color: #999999;
  1694. }
  1695. }
  1696. }
  1697. .attr {
  1698. padding: 20rpx 0;
  1699. border-bottom: 1px solid #eaeaea;
  1700. .title {
  1701. font-size: 28rpx;
  1702. color: #333333;
  1703. }
  1704. .list {
  1705. display: flex;
  1706. flex-wrap: wrap;
  1707. .item {
  1708. margin-top: 16rpx;
  1709. padding: 10rpx 16rpx;
  1710. font-size: 24rpx;
  1711. color: #666666;
  1712. background: #f5f5f5;
  1713. border-radius: 5rpx;
  1714. margin-right: 16rpx;
  1715. &.current {
  1716. color: #ff3f42;
  1717. background: rgba($color: #ff3f42, $alpha: 0.2);
  1718. }
  1719. }
  1720. }
  1721. }
  1722. .num {
  1723. padding: 20rpx 0;
  1724. display: flex;
  1725. justify-content: space-between;
  1726. align-items: center;
  1727. .title {
  1728. font-size: 28rpx;
  1729. color: #333333;
  1730. }
  1731. }
  1732. .button {
  1733. text-align: center;
  1734. line-height: 74rpx;
  1735. border-radius: 74rpx;
  1736. background: linear-gradient(-90deg, #ff3f42 0%, #fe781f 100%);
  1737. font-size: 28rpx;
  1738. color: #ffffff;
  1739. margin-top: 20rpx;
  1740. }
  1741. }
  1742. .package-container {
  1743. padding: 30rpx 20rpx;
  1744. .main {
  1745. max-height: 75vh;
  1746. overflow-y: scroll;
  1747. .group {
  1748. border-bottom: 1px solid #eaeaea;
  1749. &:last-child {
  1750. border: none;
  1751. }
  1752. .title {
  1753. font-size: 28rpx;
  1754. color: #ff3f42;
  1755. line-height: 28rpx;
  1756. margin: 20rpx 0;
  1757. }
  1758. .goods-list {
  1759. .item {
  1760. display: flex;
  1761. align-items: center;
  1762. background: #ffffff;
  1763. margin-bottom: 20rpx;
  1764. image {
  1765. width: 180rpx;
  1766. height: 180rpx;
  1767. display: block;
  1768. margin-right: 20rpx;
  1769. flex-shrink: 0;
  1770. }
  1771. .right {
  1772. flex: 1;
  1773. height: 190rpx;
  1774. display: flex;
  1775. justify-content: space-between;
  1776. flex-direction: column;
  1777. .name {
  1778. font-size: 28rpx;
  1779. color: #333333;
  1780. line-height: 36rpx;
  1781. height: 72rpx;
  1782. }
  1783. .des {
  1784. font-size: 24rpx;
  1785. color: #999999;
  1786. line-height: 36rpx;
  1787. }
  1788. .bottom {
  1789. display: flex;
  1790. justify-content: space-between;
  1791. align-items: center;
  1792. .price {
  1793. display: flex;
  1794. flex-direction: column;
  1795. }
  1796. .price-1 {
  1797. font-size: 32rpx;
  1798. color: #ff3f42;
  1799. line-height: 36rpx;
  1800. }
  1801. .price-2 {
  1802. font-size: 26rpx;
  1803. color: #666666;
  1804. line-height: 30rpx;
  1805. text-decoration: line-through;
  1806. }
  1807. }
  1808. }
  1809. }
  1810. }
  1811. }
  1812. }
  1813. .button {
  1814. text-align: center;
  1815. line-height: 74rpx;
  1816. border-radius: 74rpx;
  1817. background: linear-gradient(-90deg, #ff3f42 0%, #fe781f 100%);
  1818. font-size: 28rpx;
  1819. color: #ffffff;
  1820. margin-top: 20rpx;
  1821. }
  1822. }
  1823. .sharelist-container {
  1824. padding: 30rpx 0;
  1825. display: flex;
  1826. button {
  1827. background: none;
  1828. border-radius: 0;
  1829. &::after {
  1830. border: none;
  1831. }
  1832. }
  1833. .item {
  1834. display: flex;
  1835. width: 50%;
  1836. flex-direction: column;
  1837. align-items: center;
  1838. image {
  1839. width: 100rpx;
  1840. height: 100rpx;
  1841. display: block;
  1842. margin-bottom: 20rpx;
  1843. }
  1844. text {
  1845. font-size: 28rpx;
  1846. line-height: 32rpx;
  1847. color: #333333;
  1848. }
  1849. }
  1850. }
  1851. .canvas-container {
  1852. position: fixed;
  1853. left: 50%;
  1854. top: 50%;
  1855. z-index: 999;
  1856. margin-left: -150px;
  1857. margin-top: -280px;
  1858. .button {
  1859. display: flex;
  1860. justify-content: center;
  1861. text {
  1862. display: block;
  1863. width: 280rpx;
  1864. height: 70rpx;
  1865. border-radius: 70rpx;
  1866. background: linear-gradient(-90deg, #ff3f42 0%, #fe781f 100%);
  1867. font-size: 28rpx;
  1868. color: #ffffff;
  1869. text-align: center;
  1870. line-height: 70rpx;
  1871. margin-top: 20rpx;
  1872. }
  1873. }
  1874. }
  1875. .phone-dialog {
  1876. padding: 40rpx;
  1877. box-sizing: border-box;
  1878. .content {
  1879. margin-top: 30rpx;
  1880. margin-bottom: 30rpx;
  1881. line-height: 50rpx;
  1882. text {
  1883. color: #9d9d9d;
  1884. }
  1885. }
  1886. .btn {
  1887. display: flex;
  1888. justify-content: center;
  1889. margin-top: 60rpx;
  1890. button::after {
  1891. border: none;
  1892. }
  1893. button {
  1894. width: 180rpx;
  1895. height: 70rpx;
  1896. line-height: 70rpx;
  1897. margin: 0;
  1898. font-size: 28rpx;
  1899. margin: 0 30rpx;
  1900. &:first-child {
  1901. background: #f5f5f5;
  1902. color: #00ba5c;
  1903. }
  1904. }
  1905. }
  1906. }
  1907. </style>