index.vue 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389
  1. <template>
  2. <view class="goods-sku-popup" catchtouchmove="true" :class="valueCom && complete ? 'show' : 'none'" @touchmove.stop.prevent="moveHandle"
  3. @click.stop="stop">
  4. <!-- 页面内容开始 -->
  5. <view class="mask" @click="close('mask')"></view>
  6. <view class="layer attr-content" :class="{'safe-area-inset-bottom':safeAreaInsetBottom }"
  7. :style="{ borderRadius: borderRadius + 'rpx ' + borderRadius + 'rpx 0 0' }">
  8. <view class="specification-wrapper">
  9. <scroll-view class="specification-wrapper-content" scroll-y="true">
  10. <view class="specification-header">
  11. <view class="specification-left">
  12. <image class="product-img" :src="selectShop.image ? selectShop.image : goodsInfo[goodsThumbName]"
  13. :style="{ backgroundColor: goodsThumbBackgroundColor }" mode="aspectFill" @click="previewImage"></image>
  14. </view>
  15. <view class="specification-right">
  16. <view class="price-content" :style="{ color: themeColorFn('priceColor') }">
  17. <text class="sign">¥</text>
  18. <text class="price" :class="priceCom.length > 16 ? 'price2' : ''">{{ priceCom }}</text>
  19. </view>
  20. <view class="inventory" v-if="!hideStock">{{ stockText }}:{{ stockCom }}</view>
  21. <view class="inventory" v-else></view>
  22. <view class="choose" v-show="isManyCom">
  23. <text v-if="!selectArr.every(val => val == '')">已选:{{ selectArr.join(' ') }}</text>
  24. </view>
  25. </view>
  26. </view>
  27. <view class="specification-content">
  28. <view v-show="isManyCom" class="specification-item" v-for="(item, index1) in goodsInfo[specListName]" :key="index1">
  29. <view class="item-title">{{ item.name }}</view>
  30. <view class="item-wrapper">
  31. <view class="item-content" v-for="(item_value, index2) in item.list" :key="index2"
  32. :class="[item_value.ishow ? '' : 'noactived', subIndex[index1] == index2 ? 'actived' : '']" :style="[
  33. item_value.ishow ? '' : themeColorFn('disableStyle'),
  34. item_value.ishow ? themeColorFn('btnStyle') : '',
  35. subIndex[index1] == index2 ? themeColorFn('activedStyle') : ''
  36. ]" @click="skuClick(item_value, index1, index2)">
  37. {{ item_value.name }}
  38. </view>
  39. </view>
  40. </view>
  41. <!-- 显示限购 -->
  42. <view class="number-box-view">
  43. <view style="flex: 1; display: flex; align-items: center;">数量</view>
  44. <view style="flex: 4; display: flex; align-items: center; justify-content: flex-end;">
  45. <text v-if="maxBuyNum > 0" style="margin-right: 18rpx; font-size: 26rpx; color: #e74800;">限购{{ maxBuyNum }}件</text>
  46. <number-box v-model="selectNum" :min="minBuyNum || 1" :max="maxBuyNumCom" :step="stepBuyNum || 1"
  47. :step-strictly="stepStrictly" :positive-integer="true">
  48. </number-box>
  49. </view>
  50. </view>
  51. </view>
  52. </scroll-view>
  53. <view class="close" @click="close('close')" v-if="showClose != false">
  54. <image class="close-item" :src="closeImage"></image>
  55. </view>
  56. </view>
  57. <view class="btn-wrapper" v-if="outFoStock || mode == 4">
  58. <view class="sure" style="color:#ffffff;background-color:#cccccc">{{ noStockText }}</view>
  59. </view>
  60. <view class="btn-wrapper" v-else-if="mode == 5">
  61. <view class="sure" style="color:#ffffff;background-color:#cccccc">{{ disableText }}</view>
  62. </view>
  63. <view class="btn-wrapper" v-else-if="mode == 1">
  64. <view class="sure add-cart" style="border-radius:38rpx 0rpx 0rpx 38rpx;" :style="{
  65. color: themeColorFn('addCartColor'),
  66. backgroundColor: themeColorFn('addCartBackgroundColor')
  67. }" @click="addCart">
  68. {{ addCartText }}
  69. </view>
  70. <view class="sure" style="border-radius:0rpx 38rpx 38rpx 0rpx;" :style="{
  71. color: themeColorFn('buyNowColor'),
  72. backgroundColor: themeColorFn('buyNowBackgroundColor')
  73. }" @click="buyNow">
  74. {{ buyNowText }}
  75. </view>
  76. </view>
  77. <view class="btn-wrapper" v-else-if="mode == 2">
  78. <view class="sure add-cart" :style="{
  79. color: themeColorFn('addCartColor'),
  80. backgroundColor: themeColorFn('addCartBackgroundColor')
  81. }" @click="addCart">
  82. {{ addCartText }}
  83. </view>
  84. </view>
  85. <view class="btn-wrapper" v-else-if="mode == 3">
  86. <view class="sure" :style="{
  87. color: themeColorFn('buyNowColor'),
  88. backgroundColor: themeColorFn('buyNowBackgroundColor')
  89. }" @click="buyNow">
  90. {{ buyNowText }}
  91. </view>
  92. </view>
  93. </view>
  94. <!-- 页面内容结束 -->
  95. </view>
  96. </template>
  97. <script>
  98. import NumberBox from './number-box'
  99. var vk; // vk依赖
  100. var goodsCache = {}; // 本地商品缓存
  101. export default {
  102. name: 'GoodsSkuPopup',
  103. components: { NumberBox },
  104. emits: ['update:modelValue', 'input', 'update-goods', 'open', 'close', 'add-cart', 'buy-now', 'cart', 'buy', 'num-change'],
  105. props: {
  106. // true 组件显示 false 组件隐藏
  107. value: {
  108. Type: Boolean,
  109. default: false
  110. },
  111. modelValue: {
  112. Type: Boolean,
  113. default: false
  114. },
  115. // vk云函数路由模式参数开始-----------------------------------------------------------
  116. // 商品id
  117. goodsId: {
  118. Type: String,
  119. default: ''
  120. },
  121. // vk路由模式框架下的云函数地址
  122. action: {
  123. Type: String,
  124. default: ''
  125. },
  126. // vk云函数路由模式参数结束-----------------------------------------------------------
  127. // 该商品已抢完时的按钮文字
  128. noStockText: {
  129. Type: String,
  130. default: '该商品已抢完'
  131. },
  132. // 库存文字
  133. stockText: {
  134. Type: String,
  135. default: '库存'
  136. },
  137. // 商品表id的字段名
  138. goodsIdName: {
  139. Type: String,
  140. default: '_id'
  141. },
  142. // sku表id的字段名
  143. skuIdName: {
  144. Type: String,
  145. default: '_id'
  146. },
  147. // sku_list的字段名
  148. skuListName: {
  149. Type: String,
  150. default: 'sku_list'
  151. },
  152. // spec_list的字段名
  153. specListName: {
  154. Type: String,
  155. default: 'spec_list'
  156. },
  157. // 库存的字段名 默认 stock
  158. stockName: {
  159. Type: String,
  160. default: 'stock'
  161. },
  162. // sku组合路径的字段名
  163. skuArrName: {
  164. Type: String,
  165. default: 'sku_name_arr'
  166. },
  167. // 默认单规格时的规格组名称
  168. defaultSingleSkuName: {
  169. Type: String,
  170. default: '默认'
  171. },
  172. // 模式 1:都显示 2:只显示购物车 3:只显示立即购买 4:显示缺货按钮 5:禁用 默认 1
  173. mode: {
  174. Type: Number,
  175. default: 1
  176. },
  177. // 点击遮罩是否关闭组件 true 关闭 false 不关闭 默认true
  178. maskCloseAble: {
  179. Type: Boolean,
  180. default: true
  181. },
  182. // 顶部圆角值
  183. borderRadius: {
  184. Type: [String, Number],
  185. default: 0
  186. },
  187. // 商品缩略图字段名(未选择sku时)
  188. goodsThumbName: {
  189. Type: [String],
  190. default: 'goods_thumb'
  191. },
  192. // 商品缩略图背景颜色,如#999999
  193. goodsThumbBackgroundColor: {
  194. Type: String,
  195. default: '#999999'
  196. },
  197. // 最小购买数量 默认 1
  198. minBuyNum: {
  199. Type: [Number, String],
  200. default: 1
  201. },
  202. // 最大购买数量 默认 100000
  203. maxBuyNum: {
  204. Type: [Number, String],
  205. default: 100000
  206. },
  207. // 步进器步长 默认 1
  208. stepBuyNum: {
  209. Type: [Number, String],
  210. default: 1
  211. },
  212. // 是否只能输入 step 的倍数
  213. stepStrictly: {
  214. Type: Boolean,
  215. default: false
  216. },
  217. // 自定义获取商品信息的函数,支付宝小程序不支持该属性,请使用localdata属性
  218. customAction: {
  219. Type: [Function],
  220. default: null
  221. },
  222. // 本地数据源
  223. localdata: {
  224. type: Object
  225. },
  226. // 价格的字体颜色
  227. priceColor: {
  228. Type: String
  229. },
  230. // 立即购买按钮的文字
  231. buyNowText: {
  232. Type: String,
  233. default: '立即购买'
  234. },
  235. // 立即购买按钮的字体颜色
  236. buyNowColor: {
  237. Type: String
  238. },
  239. // 立即购买按钮的背景颜色
  240. buyNowBackgroundColor: {
  241. Type: String
  242. },
  243. // 加入购物车按钮的文字
  244. addCartText: {
  245. Type: String,
  246. default: '加入购物车'
  247. },
  248. // 加入购物车按钮的字体颜色
  249. addCartColor: {
  250. Type: String
  251. },
  252. // 加入购物车按钮的背景颜色
  253. addCartBackgroundColor: {
  254. Type: String
  255. },
  256. // 不可点击时,按钮的样式
  257. disableStyle: {
  258. Type: Object,
  259. default: null
  260. },
  261. // 按钮点击时的样式
  262. activedStyle: {
  263. Type: Object,
  264. default: null
  265. },
  266. // 按钮常态的样式
  267. btnStyle: {
  268. Type: Object,
  269. default: null
  270. },
  271. // 是否显示右上角关闭按钮
  272. showClose: {
  273. Type: Boolean,
  274. default: true
  275. },
  276. // 关闭按钮的图片地址 https://img.alicdn.com/imgextra/i1/121022687/O1CN01ImN0O11VigqwzpLiK_!!121022687.png
  277. closeImage: {
  278. Type: String,
  279. default: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAqCAYAAADFw8lbAAAEyUlEQVR42sSZeWwNURTGp4OqtBo7sSXELragdkpQsRRJ1Zr4hyJiJ9YgxNIg1qANiT+E1i5IY0kVVWtQEbuEKLFGUSH27/ANN5PXmTvzupzkl/tm8t6b7517lnvvC0lKSjJ8WmnQAUSDFqABqALKgl8gD7wE90E2SAeXwFf1SxISErQeVtKHwCgwFsSDSIf3hYFKoCkYDBaDdyAViHdueHmoF6FtwDLQ23b/E7gM7oIcejIERIDaoBFoC8qA8mA8SQNz6W1XC9GY+nCQCCYAk/c+gF0gBZwH312+IxR0BCPBUIaH2A+wHsxHCHxx+gLT5QGN6a2JfG8uvVCDws9oiDQYlxkMGfHyQvARlADTwcXk5OT6foV2kS8ATXidymlcyen1a/Jjl9IJh3hPkjELYqO8Cu0KjjNZvtETw5jFBWXPmGSTGQKSeOn5iQ0kVLL0CINfPNcPbDMKyRCbGzEMBJ+ZD8cChYFdqGTqfsWT8otPGoVsEHsMwxDFs3shNsxJ6BrQ0Po8OGUUkVHsNCVml+cntB1jUWwn2GEUsTEMrASbDK+2CCQ0kYX6nfLLisMmKqUr0S60M+jG10vAm+JSCa8+x7CKlzHwaktV6DiObzUzPJIxFO1BQ12wGtTReO9GetVgY/kjNJzZbcWmTjHfxw51AsRqvL8eOAtmsJuFu3g1l+1ZLB5eDTVZ3K0P7tL0TkWOpSg61kVkBtuuNRthGs+wtJST5aQI7cEbkkRXNYVKgX6kIdYuUhYzMQwxN8tiExCLFqHNeSF9/aem0BzGp5PYQCJ7c/Gsk1RfuSD6U1dNpcDf9ZigTmKbMRZ9iVTsHscGJluW2FMf1SSQWGnBmaB6kCJVTVVNJZE++Cx9drEllS1KMCINpURFmEbBWA63Fz9s95cGIdJgp/zXmT4pZcOvSUzuZttTbblmnc3PIjjmidDXvKgdhMh0JdbzuCjWrbNOVovjS5P7bkPJ/mBESkz2BO0166ybNeJ431S2q+01NntuIq3E0amzjiZtk9tssWyTDzO4525bACK9NAUn68TtkNhpEXpOSagRml+S6iLSSeweHv242Qhl13rRyvoDvDlKyTQny/ZQJ+1iH7vVbEx7OR5UiKVIO7VicgvHCtwrudloMIV7/0uadVYW57O4Wvvi8v4pymlKkrpwvsDeLLZAY2pkwbAB3PSQfC+4cH7l4k1ZH8zkZRq8ecO+Z5rN40JJqnXFuGfaxPCTLjcn0OZOpnArXw8HY4paIbw5CcMgXq6HN2/mt6+XGLrN15tBryIUGavMpCTrfKcDCKkAceA9S8nhAOehhSUyhXpkBxxnP4YM1InugP7cBkjBPcqVUWFYCEROxXiQz5JlXV+IfKh7mpfJac+lZ6V87QXVClBkTc7YWsWTPSDyitfzUTlJlj8TbvE6jluDOdwZ+jX57GLO3ADeuyZrDYi86vV81FD2UVGsmT+5Zl0BnkhoseOEaogL46pqO4v/IqUEyalIR4h85BgjHv6+aUWRMbb7EstX6O0cpT1Gco0ry8fWygLDMjmDnQeBt3Qe7uVfkeugDwVLcsVzGsuwLXbV+I63XNAkG5r/hvgRqgqWs6pJPKrsbvz/Q6yyun0w/h6lP+BnzrCpfPMT2L8FGAA7k1GZ/vnaqAAAAABJRU5ErkJggg=='
  280. },
  281. // 是否隐藏库存显示
  282. hideStock: {
  283. Type: Boolean,
  284. default: false
  285. },
  286. // 颜色主题
  287. theme: {
  288. Type: String,
  289. default: 'default'
  290. },
  291. // 请求中的提示
  292. actionTips: {
  293. Type: String,
  294. default: '请求中...'
  295. },
  296. // 默认选中的SKU
  297. defaultSelect: {
  298. Type: Object
  299. },
  300. // 是否使用缓存
  301. useCache: {
  302. Type: Boolean,
  303. default: true
  304. },
  305. /**
  306. * 默认商品,设置该值可快速展示商品
  307. * 逻辑: 先展示 defaultGoods 信息,再取数据库,再更新页面(通常为更新库存)
  308. */
  309. defaultGoods: {
  310. Type: Object
  311. },
  312. /**
  313. * 金额是否需要除以100
  314. * 1:金额会除以100
  315. * 0:金额不会除以100
  316. */
  317. amountType: {
  318. Type: Number,
  319. default: 1
  320. },
  321. // 每次选择完SKU后,购买数量归1,如果有最小购买数量,则设置为最小购买数量
  322. selectedInit: {
  323. Type: Boolean,
  324. default: false
  325. },
  326. // 是否开启底部安全区适配,默认true
  327. safeAreaInsetBottom: {
  328. Type: Boolean,
  329. default: true
  330. },
  331. // 按钮禁用提示的文字
  332. disableText: {
  333. Type: String,
  334. default: "暂不支持购买"
  335. }
  336. },
  337. data() {
  338. return {
  339. complete: false, // 组件是否加载完成
  340. goodsInfo: {}, // 商品信息
  341. isShow: false, // true 显示 false 隐藏
  342. initKey: true, // 是否需要初始化 true 是 false 否
  343. // #ifndef MP-BAIDU
  344. shopItemInfo: {}, // 存放要和选中的值进行匹配的数据(因百度小程序setData不支持中文字段,故不编译shopItemInfo变量)
  345. // #endif
  346. selectArr: [], // 存放被选中的值
  347. subIndex: [], // 是否选中 因为不确定是多规格还是单规格,所以这里定义数组来判断
  348. selectShop: {}, // 存放最后选中的商品
  349. selectNum: this.minBuyNum || 1, // 选中数量
  350. outFoStock: false, // 是否全部sku都缺货
  351. openTime: 0,
  352. themeColor: {
  353. // 默认主题
  354. default: {
  355. priceColor: 'rgb(254, 86, 10)',
  356. buyNowColor: '#ffffff',
  357. buyNowBackgroundColor: 'rgb(254, 86, 10)',
  358. addCartColor: '#ffffff',
  359. addCartBackgroundColor: 'rgb(255, 148, 2)',
  360. btnStyle: {
  361. color: '#333333',
  362. borderColor: '#f4f4f4',
  363. backgroundColor: '#ffffff'
  364. },
  365. activedStyle: {
  366. color: 'rgb(254, 86, 10)',
  367. borderColor: 'rgb(254, 86, 10)',
  368. backgroundColor: 'rgba(254,86,10,0.1)'
  369. },
  370. disableStyle: {
  371. color: '#c3c3c3',
  372. borderColor: '#f6f6f6',
  373. backgroundColor: '#f6f6f6'
  374. }
  375. },
  376. // 红黑主题
  377. 'red-black': {
  378. priceColor: 'rgb(255, 68, 68)',
  379. buyNowColor: '#ffffff',
  380. buyNowBackgroundColor: 'rgb(255, 68, 68)',
  381. addCartColor: '#ffffff',
  382. addCartBackgroundColor: 'rgb(85, 85, 85)',
  383. activedStyle: {
  384. color: 'rgb(255, 68, 68)',
  385. borderColor: 'rgb(255, 68, 68)',
  386. backgroundColor: 'rgba(255,68,68,0.1)'
  387. }
  388. },
  389. // 黑白主题
  390. 'black-white': {
  391. priceColor: 'rgb(47, 47, 52)',
  392. buyNowColor: '#ffffff',
  393. buyNowBackgroundColor: 'rgb(47, 47, 52)',
  394. addCartColor: 'rgb(47, 47, 52)',
  395. addCartBackgroundColor: 'rgb(235, 236, 242)',
  396. // btnStyle:{
  397. // color:"rgb(47, 47, 52)",
  398. // borderColor:"rgba(235,236,242,0.5)",
  399. // backgroundColor:"rgba(235,236,242,0.5)",
  400. // },
  401. activedStyle: {
  402. color: 'rgb(47, 47, 52)',
  403. borderColor: 'rgba(47,47,52,0.12)',
  404. backgroundColor: 'rgba(47,47,52,0.12)'
  405. }
  406. },
  407. // 咖啡色主题
  408. coffee: {
  409. priceColor: 'rgb(195, 167, 105)',
  410. buyNowColor: '#ffffff',
  411. buyNowBackgroundColor: 'rgb(195, 167, 105)',
  412. addCartColor: 'rgb(195, 167, 105)',
  413. addCartBackgroundColor: 'rgb(243, 238, 225)',
  414. activedStyle: {
  415. color: 'rgb(195, 167, 105)',
  416. borderColor: 'rgb(195, 167, 105)',
  417. backgroundColor: 'rgba(195, 167, 105,0.1)'
  418. }
  419. },
  420. // 浅绿色主题
  421. green: {
  422. priceColor: 'rgb(99, 190, 114)',
  423. buyNowColor: '#ffffff',
  424. buyNowBackgroundColor: 'rgb(99, 190, 114)',
  425. addCartColor: 'rgb(99, 190, 114)',
  426. addCartBackgroundColor: 'rgb(225, 244, 227)',
  427. activedStyle: {
  428. color: 'rgb(99, 190, 114)',
  429. borderColor: 'rgb(99, 190, 114)',
  430. backgroundColor: 'rgba(99, 190, 114,0.1)'
  431. }
  432. }
  433. }
  434. };
  435. },
  436. created() {
  437. let that = this;
  438. vk = that.vk;
  439. if (that.valueCom) {
  440. that.open();
  441. }
  442. },
  443. mounted() {},
  444. methods: {
  445. // 初始化
  446. init(notAutoClick) {
  447. let that = this;
  448. // 清空之前的数据
  449. that.selectArr = [];
  450. that.subIndex = [];
  451. that.selectShop = {};
  452. that.selectNum = that.minBuyNum || 1;
  453. that.outFoStock = false;
  454. that.shopItemInfo = {};
  455. let specListName = that.specListName;
  456. that.goodsInfo[specListName].map(item => {
  457. that.selectArr.push('');
  458. that.subIndex.push(-1);
  459. });
  460. that.checkItem(); // 计算sku里面规格形成路径
  461. that.checkInpath(-1); // 传-1是为了不跳过循环
  462. if (!notAutoClick) that.autoClickSku(); // 自动选择sku策略
  463. },
  464. // 使用vk路由模式框架获取商品信息
  465. findGoodsInfo(obj = {}) {
  466. let that = this;
  467. let { useCache } = obj;
  468. if (typeof vk == 'undefined') {
  469. that.toast('custom-action必须是function', 'none');
  470. return false;
  471. }
  472. let { actionTips } = that;
  473. let actionTitle = '';
  474. let actionAoading = false;
  475. if (actionTips !== 'custom') {
  476. actionTitle = useCache ? '' : '请求中...';
  477. } else {
  478. actionAoading = useCache ? false : true;
  479. }
  480. vk.callFunction({
  481. url: that.action,
  482. title: actionTitle,
  483. loading: actionAoading,
  484. data: {
  485. goods_id: that.goodsId
  486. },
  487. success(data) {
  488. that.updateGoodsInfo(data.goodsInfo);
  489. // 更新缓存
  490. goodsCache[that.goodsId] = data.goodsInfo;
  491. that.$emit('update-goods', data.goodsInfo);
  492. },
  493. fail() {
  494. that.updateValue(false);
  495. }
  496. });
  497. },
  498. updateValue(value) {
  499. let that = this;
  500. if (value) {
  501. that.$emit('open', true);
  502. that.$emit('input', true);
  503. that.$emit('update:modelValue', true);
  504. } else {
  505. that.$emit('input', false);
  506. that.$emit('close', 'close');
  507. that.$emit('update:modelValue', false);
  508. }
  509. },
  510. // 更新商品信息(库存、名称、图片)
  511. updateGoodsInfo(goodsInfo) {
  512. let that = this;
  513. // goodsInfo.sku_list.map((item, index) => {
  514. // item.sku_name_arr = ["20ml/瓶"];
  515. // });
  516. let { skuListName } = that;
  517. if (JSON.stringify(that.goodsInfo) === '{}' || that.goodsInfo[that.goodsIdName] !== goodsInfo[that.goodsIdName]) {
  518. that.goodsInfo = goodsInfo;
  519. that.initKey = true;
  520. } else {
  521. that.goodsInfo[skuListName] = goodsInfo[skuListName];
  522. }
  523. if (that.initKey) {
  524. that.initKey = false;
  525. // 是否默认选中第一个SKU
  526. // 条件是 单规格商品或者多规格单SKU商品
  527. const skuList = that.goodsInfo[that.skuListName]
  528. const autoClickSku = !that.isManyCom ? true : skuList.length === 1
  529. that.init(!autoClickSku)
  530. }
  531. // 更新选中sku的库存信息
  532. let select_sku_info = that.getListItem(that.goodsInfo[skuListName], that.skuIdName, that.selectShop[that.skuIdName]);
  533. Object.assign(that.selectShop, select_sku_info);
  534. that.defaultSelectSku();
  535. that.complete = true;
  536. },
  537. async open() {
  538. let that = this;
  539. that.openTime = new Date().getTime();
  540. let findGoodsInfoRun = true;
  541. let skuListName = that.skuListName;
  542. // 先获取缓存中的商品信息
  543. let useCache = false;
  544. let goodsInfo = goodsCache[that.goodsId];
  545. if (goodsInfo && that.useCache) {
  546. useCache = true;
  547. that.updateGoodsInfo(goodsInfo);
  548. } else {
  549. that.complete = false;
  550. }
  551. if (that.customAction && typeof that.customAction === 'function') {
  552. try {
  553. goodsInfo = await that
  554. .customAction({
  555. useCache,
  556. goodsId: that.goodsId,
  557. goodsInfo,
  558. close: function() {
  559. setTimeout(function() {
  560. that.close();
  561. }, 500);
  562. }
  563. })
  564. .catch(err => {
  565. setTimeout(function() {
  566. that.close();
  567. }, 500);
  568. });
  569. } catch (err) {
  570. let { message = '' } = err;
  571. if (message.indexOf('.catch is not a function') > -1) {
  572. that.toast('custom-action必须返回一个Promise', 'none');
  573. setTimeout(function() {
  574. that.close();
  575. }, 500);
  576. return false;
  577. }
  578. }
  579. // 更新缓存
  580. goodsCache[that.goodsId] = goodsInfo;
  581. if (goodsInfo && typeof goodsInfo == 'object' && JSON.stringify(goodsInfo) != '{}') {
  582. findGoodsInfoRun = false;
  583. that.updateGoodsInfo(goodsInfo);
  584. that.updateValue(true);
  585. } else {
  586. that.toast('未获取到商品信息', 'none');
  587. that.$emit('input', false);
  588. return false;
  589. }
  590. } else if (typeof that.localdata !== 'undefined' && that.localdata !== null) {
  591. goodsInfo = that.localdata;
  592. if (goodsInfo && typeof goodsInfo == 'object' && JSON.stringify(goodsInfo) != '{}') {
  593. findGoodsInfoRun = false;
  594. that.updateGoodsInfo(goodsInfo);
  595. that.updateValue(true);
  596. } else {
  597. that.toast('未获取到商品信息', 'none');
  598. that.$emit('input', false);
  599. return false;
  600. }
  601. } else {
  602. if (findGoodsInfoRun) that.findGoodsInfo({ useCache });
  603. }
  604. },
  605. // 监听 - 弹出层收起
  606. close(s) {
  607. let that = this;
  608. if (new Date().getTime() - that.openTime < 400) {
  609. return false;
  610. }
  611. if (s == 'mask') {
  612. if (that.maskCloseAble !== false) {
  613. that.$emit('input', false);
  614. that.$emit('close', 'mask');
  615. that.$emit('update:modelValue', false);
  616. }
  617. } else {
  618. that.$emit('input', false);
  619. that.$emit('close', 'close');
  620. that.$emit('update:modelValue', false);
  621. }
  622. },
  623. moveHandle() {
  624. //禁止父元素滑动
  625. },
  626. // sku按钮的点击事件
  627. skuClick(value, index1, index2) {
  628. let that = this;
  629. if (value.ishow) {
  630. if (that.selectArr[index1] != value.name) {
  631. that.$set(that.selectArr, index1, value.name);
  632. that.$set(that.subIndex, index1, index2);
  633. } else {
  634. that.$set(that.selectArr, index1, '');
  635. that.$set(that.subIndex, index1, -1);
  636. }
  637. that.checkInpath(index1);
  638. // 如果全部选完
  639. that.checkSelectShop();
  640. }
  641. },
  642. // 检测是否已经选完sku
  643. checkSelectShop() {
  644. let that = this;
  645. // 如果全部选完
  646. if (that.selectArr.every(item => item != '')) {
  647. that.selectShop = that.shopItemInfo[that.getArrayToSting(that.selectArr)];
  648. let stock = that.selectShop[that.stockName];
  649. if (typeof stock !== 'undefined' && that.selectNum > stock) {
  650. that.selectNum = stock;
  651. }
  652. if (that.selectNum > that.maxBuyNum) {
  653. that.selectNum = that.maxBuyNum;
  654. }
  655. if (that.selectNum < that.minBuyNum) {
  656. that.selectNum = that.minBuyNum;
  657. }
  658. if (that.selectedInit) {
  659. that.selectNum = that.minBuyNum || 1;
  660. }
  661. } else {
  662. that.selectShop = {};
  663. }
  664. },
  665. // 检查路径
  666. checkInpath(clickIndex) {
  667. let that = this;
  668. let specListName = that.specListName;
  669. //console.time('筛选可选路径需要的时间是');
  670. //循环所有属性判断哪些属性可选
  671. //当前选中的兄弟节点和已选中属性不需要循环
  672. let specList = that.goodsInfo[specListName];
  673. for (let i = 0, len = specList.length; i < len; i++) {
  674. if (i == clickIndex) {
  675. continue;
  676. }
  677. let len2 = specList[i].list.length;
  678. for (let j = 0; j < len2; j++) {
  679. if (that.subIndex[i] != -1 && j == that.subIndex[i]) {
  680. continue;
  681. }
  682. let choosed_copy = [...that.selectArr];
  683. that.$set(choosed_copy, i, specList[i].list[j].name);
  684. let choosed_copy2 = choosed_copy.filter(item => item !== '' && typeof item !== 'undefined');
  685. if (that.shopItemInfo.hasOwnProperty(that.getArrayToSting(choosed_copy2))) {
  686. specList[i].list[j].ishow = true;
  687. } else {
  688. specList[i].list[j].ishow = false;
  689. }
  690. }
  691. }
  692. that.$set(that.goodsInfo, specListName, specList);
  693. // console.timeEnd('筛选可选路径需要的时间是');
  694. },
  695. // 计算sku里面规格形成路径
  696. checkItem() {
  697. let that = this;
  698. // console.time('计算有多小种可选路径需要的时间是');
  699. let { stockName } = that;
  700. let skuListName = that.skuListName;
  701. // 去除库存小于等于0的商品sku
  702. let originalSkuList = that.goodsInfo[skuListName];
  703. let skuList = [];
  704. let stockNum = 0;
  705. originalSkuList.map((skuItem, index) => {
  706. if (skuItem[stockName] > 0) {
  707. skuList.push(skuItem);
  708. stockNum += skuItem[stockName];
  709. }
  710. });
  711. if (stockNum <= 0) {
  712. that.outFoStock = true;
  713. }
  714. // 计算有多小种可选路径
  715. let result = skuList.reduce(
  716. (arrs, items) => {
  717. return arrs.concat(
  718. items[that.skuArrName].reduce(
  719. (arr, item) => {
  720. return arr.concat(
  721. arr.map(item2 => {
  722. // 利用对象属性的唯一性实现二维数组去重
  723. //console.log(1,that.shopItemInfo,that.getArrayToSting([...item2, item]),item2,item,items);
  724. if (!that.shopItemInfo.hasOwnProperty(that.getArrayToSting([...item2, item]))) {
  725. that.shopItemInfo[that.getArrayToSting([...item2, item])] = items;
  726. }
  727. return [...item2, item];
  728. })
  729. );
  730. },
  731. [
  732. []
  733. ]
  734. )
  735. );
  736. },
  737. [
  738. []
  739. ]
  740. );
  741. // console.timeEnd('计算有多小种可选路径需要的时间是');
  742. },
  743. getArrayToSting(arr) {
  744. let str = '';
  745. arr.map((item, index) => {
  746. item = item.replace(/\./g, '。');
  747. if (index == 0) {
  748. str += item;
  749. } else {
  750. str += ',' + item;
  751. }
  752. });
  753. return str;
  754. },
  755. // 检测sku选项是否已全部选完,且有库存
  756. checkSelectComplete(obj = {}) {
  757. let that = this;
  758. let clickTime = new Date().getTime();
  759. if (that.clickTime && clickTime - that.clickTime < 400) {
  760. return false;
  761. }
  762. that.clickTime = clickTime;
  763. let { selectShop, selectNum, stockText, stockName } = that;
  764. if (!selectShop || !selectShop[that.skuIdName]) {
  765. that.toast('请先选择对应规格', 'none');
  766. return false;
  767. }
  768. if (selectNum <= 0) {
  769. that.toast('购买数量必须>0', 'none');
  770. return false;
  771. }
  772. // 判断库存
  773. if (selectNum > selectShop[stockName]) {
  774. that.toast(stockText + '不足', 'none');
  775. return false;
  776. }
  777. if (typeof obj.success == 'function') obj.success(selectShop);
  778. },
  779. // 加入购物车
  780. addCart() {
  781. let that = this;
  782. that.checkSelectComplete({
  783. success: function(selectShop) {
  784. selectShop.buy_num = that.selectNum;
  785. that.$emit('add-cart', selectShop);
  786. that.$emit('cart', selectShop);
  787. // setTimeout(function() {
  788. // that.init();
  789. // }, 300);
  790. }
  791. });
  792. },
  793. // 立即购买
  794. buyNow() {
  795. let that = this;
  796. that.checkSelectComplete({
  797. success: function(selectShop) {
  798. selectShop.buy_num = that.selectNum;
  799. that.$emit('buy-now', selectShop);
  800. that.$emit('buy', selectShop);
  801. }
  802. });
  803. },
  804. // 弹窗
  805. toast(title, icon) {
  806. uni.showToast({
  807. title: title,
  808. icon: icon
  809. });
  810. },
  811. // 获取对象数组中的某一个item,根据指定的键值
  812. getListItem(list, key, value) {
  813. let that = this;
  814. let item;
  815. for (let i in list) {
  816. if (typeof value == 'object') {
  817. if (JSON.stringify(list[i][key]) === JSON.stringify(value)) {
  818. item = list[i];
  819. break;
  820. }
  821. } else {
  822. if (list[i][key] === value) {
  823. item = list[i];
  824. break;
  825. }
  826. }
  827. }
  828. return item;
  829. },
  830. getListIndex(list, key, value) {
  831. let that = this;
  832. let index = -1;
  833. for (let i = 0; i < list.length; i++) {
  834. if (list[i][key] === value) {
  835. index = i;
  836. break;
  837. }
  838. }
  839. return index;
  840. },
  841. // 自动选择sku前提是只有一组sku,默认自动选择最前面的有库存的sku
  842. autoClickSku() {
  843. let that = this;
  844. let { stockName } = that;
  845. let skuList = that.goodsInfo[that.skuListName];
  846. let specListArr = that.goodsInfo[that.specListName];
  847. if (specListArr.length == 1) {
  848. let specList = specListArr[0].list;
  849. for (let i = 0; i < specList.length; i++) {
  850. let sku = that.getListItem(skuList, that.skuArrName, [specList[i].name]);
  851. if (sku && sku[stockName] > 0) {
  852. that.skuClick(specList[i], 0, i);
  853. break;
  854. }
  855. }
  856. }
  857. },
  858. // 主题颜色
  859. themeColorFn(name) {
  860. let that = this;
  861. let { theme, themeColor } = that;
  862. let color = that[name] ? that[name] : themeColor[theme][name];
  863. return color;
  864. },
  865. defaultSelectSku() {
  866. let that = this;
  867. let { defaultSelect } = that;
  868. if (defaultSelect && defaultSelect.sku && defaultSelect.sku.length > 0) {
  869. that.selectSku(defaultSelect);
  870. }
  871. },
  872. /**
  873. * 主动方法 - 设置sku
  874. that.$refs.skuPopup.selectSku({
  875. sku:["红色","256G","公开版"],
  876. num:5
  877. });
  878. */
  879. selectSku(obj = {}) {
  880. let that = this;
  881. let { sku: skuArr, num: selectNum } = obj;
  882. let specListArr = that.goodsInfo[that.specListName];
  883. if (skuArr && specListArr.length === skuArr.length) {
  884. // 先清空
  885. let skuClickArr = [];
  886. let clickKey = true;
  887. for (let index = 0; index < skuArr.length; index++) {
  888. let skuName = skuArr[index];
  889. let specList = specListArr[index].list;
  890. let index1 = index;
  891. let index2 = that.getListIndex(specList, 'name', skuName);
  892. if (index2 == -1) {
  893. clickKey = false;
  894. break;
  895. }
  896. skuClickArr.push({
  897. spec: specList[index2],
  898. index1: index1,
  899. index2: index2
  900. });
  901. }
  902. if (clickKey) {
  903. that.init(true);
  904. skuClickArr.map(item => {
  905. that.skuClick(item.spec, item.index1, item.index2);
  906. });
  907. }
  908. }
  909. if (selectNum > 0) that.selectNum = selectNum;
  910. },
  911. priceFilter(n = 0) {
  912. let that = this;
  913. if (typeof n == 'string') {
  914. n = parseFloat(n);
  915. }
  916. if (that.amountType === 0) {
  917. return n.toFixed(2);
  918. } else {
  919. return (n / 100).toFixed(2);
  920. }
  921. },
  922. pushGoodsCache(goodsInfo) {
  923. let that = this;
  924. let { goodsIdName } = that;
  925. goodsCache[goodsInfo[goodsIdName]] = goodsInfo;
  926. },
  927. // 用于阻止冒泡
  928. stop() {},
  929. // 图片预览
  930. previewImage() {
  931. let that = this;
  932. let { selectShop, goodsInfo, goodsThumbName } = that;
  933. let src = selectShop.image ? selectShop.image : goodsInfo[goodsThumbName];
  934. if (src) {
  935. uni.previewImage({
  936. urls: [src]
  937. });
  938. }
  939. },
  940. getMaxStock() {
  941. let maxStock = 0;
  942. let that = this;
  943. let { selectShop = {}, goodsInfo = {}, skuListName, stockName } = that;
  944. if (selectShop[stockName]) {
  945. maxStock = selectShop[stockName];
  946. } else {
  947. let skuList = goodsInfo[skuListName];
  948. if (skuList && skuList.length > 0) {
  949. let valueArr = [];
  950. skuList.map((skuItem, index) => {
  951. valueArr.push(skuItem[stockName]);
  952. });
  953. let max = Math.max(...valueArr);
  954. maxStock = max;
  955. }
  956. }
  957. return maxStock;
  958. },
  959. numChange(e) {
  960. this.$emit("num-change", e.value);
  961. }
  962. },
  963. // 计算属性
  964. computed: {
  965. valueCom() {
  966. // #ifndef VUE3
  967. return this.value;
  968. // #endif
  969. // #ifdef VUE3
  970. return this.modelValue;
  971. // #endif
  972. },
  973. // 最大购买数量
  974. maxBuyNumCom() {
  975. let that = this;
  976. let maxStock = that.getMaxStock();
  977. let max = that.maxBuyNum || 100000;
  978. // 最大购买量不能超过当前商品的库存
  979. if (max > maxStock) {
  980. max = maxStock;
  981. }
  982. return max;
  983. },
  984. // 是否是多规格
  985. isManyCom() {
  986. let that = this;
  987. let { goodsInfo, defaultSingleSkuName, specListName } = that;
  988. let isMany = true;
  989. if (
  990. goodsInfo[specListName] &&
  991. goodsInfo[specListName].length === 1 &&
  992. goodsInfo[specListName][0].list.length === 1 &&
  993. goodsInfo[specListName][0].name === defaultSingleSkuName
  994. ) {
  995. isMany = false;
  996. }
  997. return isMany;
  998. },
  999. // 默认价格区间计算
  1000. priceCom() {
  1001. let str = '';
  1002. let that = this;
  1003. let { selectShop = {}, goodsInfo = {}, skuListName, skuIdName } = that;
  1004. if (selectShop[skuIdName]) {
  1005. str = that.priceFilter(selectShop.price);
  1006. } else {
  1007. let skuList = goodsInfo[skuListName];
  1008. if (skuList && skuList.length > 0) {
  1009. let valueArr = [];
  1010. skuList.map((skuItem, index) => {
  1011. valueArr.push(skuItem.price);
  1012. });
  1013. let min = that.priceFilter(Math.min(...valueArr));
  1014. let max = that.priceFilter(Math.max(...valueArr));
  1015. if (min === max) {
  1016. str = min + '';
  1017. } else {
  1018. str = `${min} - ${max}`;
  1019. }
  1020. }
  1021. }
  1022. return str;
  1023. },
  1024. // 库存显示
  1025. stockCom() {
  1026. let str = '';
  1027. let that = this;
  1028. let { selectShop = {}, goodsInfo = {}, skuListName, stockName } = that;
  1029. if (selectShop[stockName]) {
  1030. str = selectShop[stockName];
  1031. } else {
  1032. let skuList = goodsInfo[skuListName];
  1033. if (skuList && skuList.length > 0) {
  1034. let valueArr = [];
  1035. skuList.map((skuItem, index) => {
  1036. valueArr.push(skuItem[stockName]);
  1037. });
  1038. let min = Math.min(...valueArr);
  1039. let max = Math.max(...valueArr);
  1040. if (min === max) {
  1041. str = min;
  1042. } else {
  1043. str = `${min} - ${max}`;
  1044. }
  1045. }
  1046. }
  1047. return str;
  1048. }
  1049. },
  1050. watch: {
  1051. valueCom(newVal, oldValue) {
  1052. let that = this;
  1053. if (newVal) {
  1054. that.open();
  1055. }
  1056. },
  1057. defaultGoods: {
  1058. immediate: true,
  1059. handler: function(newVal, oldValue) {
  1060. let that = this;
  1061. let { goodsIdName } = that;
  1062. if (typeof newVal === 'object' && newVal && newVal[goodsIdName] && !goodsCache[newVal[goodsIdName]]) {
  1063. that.pushGoodsCache(newVal);
  1064. }
  1065. }
  1066. }
  1067. }
  1068. };
  1069. </script>
  1070. <style lang="scss" scoped>
  1071. /* sku弹出层 */
  1072. .goods-sku-popup {
  1073. position: fixed;
  1074. left: var(--window-left);
  1075. right: var(--window-right);
  1076. bottom: var(--window-bottom);
  1077. top: var(--window-top);
  1078. z-index: 21;
  1079. overflow: hidden;
  1080. &.show {
  1081. display: block;
  1082. .mask {
  1083. animation: showPopup 0.2s linear both;
  1084. }
  1085. .layer {
  1086. animation: showLayer 0.2s linear both;
  1087. bottom: var(--window-bottom);
  1088. }
  1089. }
  1090. &.hide {
  1091. .mask {
  1092. animation: hidePopup 0.2s linear both;
  1093. }
  1094. .layer {
  1095. animation: hideLayer 0.2s linear both;
  1096. }
  1097. }
  1098. &.none {
  1099. display: none;
  1100. }
  1101. .mask {
  1102. position: fixed;
  1103. left: var(--window-left);
  1104. right: var(--window-right);
  1105. top: var(--window-top);
  1106. // width: 100%;
  1107. height: 100%;
  1108. z-index: 1;
  1109. background-color: rgba(0, 0, 0, 0.65);
  1110. }
  1111. .layer {
  1112. display: flex;
  1113. flex-direction: column;
  1114. position: fixed;
  1115. left: var(--window-left);
  1116. right: var(--window-right);
  1117. bottom: var(--window-bottom);
  1118. z-index: 99;
  1119. border-radius: 10rpx 10rpx 0 0;
  1120. background-color: #fff;
  1121. // 设置ios刘海屏底部横线安全区域
  1122. padding-bottom: constant(safe-area-inset-bottom);
  1123. padding-bottom: env(safe-area-inset-bottom);
  1124. .specification-wrapper {
  1125. width: 100%;
  1126. padding: 30rpx 25rpx;
  1127. box-sizing: border-box;
  1128. .specification-wrapper-content {
  1129. width: 100%;
  1130. max-height: 900rpx;
  1131. min-height: 300rpx;
  1132. &::-webkit-scrollbar {
  1133. /*隐藏滚轮*/
  1134. display: none;
  1135. }
  1136. .specification-header {
  1137. width: 100%;
  1138. display: flex;
  1139. flex-direction: row;
  1140. position: relative;
  1141. margin-bottom: 40rpx;
  1142. .specification-left {
  1143. width: 180rpx;
  1144. height: 180rpx;
  1145. flex: 0 0 180rpx;
  1146. .product-img {
  1147. width: 180rpx;
  1148. height: 180rpx;
  1149. }
  1150. }
  1151. .specification-right {
  1152. flex: 1;
  1153. padding: 0 50rpx 10rpx 28rpx;
  1154. box-sizing: border-box;
  1155. display: flex;
  1156. flex-direction: column;
  1157. justify-content: center;
  1158. font-weight: 500;
  1159. .price-content {
  1160. color: #fe560a;
  1161. margin-bottom: 10rpx;
  1162. .sign {
  1163. font-size: 28rpx;
  1164. margin-right: 4rpx;
  1165. }
  1166. .price {
  1167. margin-left: 4rpx;
  1168. font-size: 48rpx;
  1169. }
  1170. .price2 {
  1171. margin-left: 4rpx;
  1172. font-size: 36rpx;
  1173. }
  1174. }
  1175. .inventory {
  1176. font-size: 24rpx;
  1177. color: #525252;
  1178. margin-bottom: 14rpx;
  1179. }
  1180. .choose {
  1181. font-size: 24rpx;
  1182. color: #525252;
  1183. min-height: 32rpx;
  1184. }
  1185. }
  1186. }
  1187. .specification-content {
  1188. font-weight: 500;
  1189. .specification-item {
  1190. margin-bottom: 40rpx;
  1191. &:last-child {
  1192. margin-bottom: 0;
  1193. }
  1194. .item-title {
  1195. margin-bottom: 20rpx;
  1196. font-size: 28rpx;
  1197. color: #999999;
  1198. }
  1199. .item-wrapper {
  1200. display: flex;
  1201. flex-direction: row;
  1202. flex-flow: wrap;
  1203. margin-bottom: -20rpx;
  1204. .item-content {
  1205. display: inline-block;
  1206. padding: 10rpx 35rpx;
  1207. font-size: 24rpx;
  1208. border-radius: 10rpx;
  1209. background-color: #ffffff;
  1210. color: #333333;
  1211. margin-right: 20rpx;
  1212. margin-bottom: 20rpx;
  1213. border: 2rpx solid #f4f4f4;
  1214. box-sizing: border-box;
  1215. &.actived {
  1216. border-color: #fe560a;
  1217. color: #fe560a;
  1218. }
  1219. &.noactived {
  1220. // background-color: #f6f6f6;
  1221. // border-color: #f6f6f6;
  1222. // color: #c3c3c3;
  1223. color: #c8c9cc;
  1224. background: #f2f3f5;
  1225. border-color: #f2f3f5;
  1226. }
  1227. }
  1228. }
  1229. }
  1230. .number-box-view {
  1231. display: flex;
  1232. padding-top: 20rpx;
  1233. }
  1234. }
  1235. }
  1236. .close {
  1237. position: absolute;
  1238. top: 30rpx;
  1239. right: 25rpx;
  1240. width: 50rpx;
  1241. height: 50rpx;
  1242. display: flex;
  1243. justify-content: center;
  1244. align-items: center;
  1245. .close-item {
  1246. width: 40rpx;
  1247. height: 40rpx;
  1248. }
  1249. }
  1250. }
  1251. .btn-wrapper {
  1252. display: flex;
  1253. width: 100%;
  1254. height: 120rpx;
  1255. flex: 0 0 120rpx;
  1256. align-items: center;
  1257. justify-content: space-between;
  1258. padding: 0 26rpx;
  1259. box-sizing: border-box;
  1260. .layer-btn {
  1261. width: 335rpx;
  1262. height: 76rpx;
  1263. border-radius: 38rpx;
  1264. color: #fff;
  1265. font-weight: 500;
  1266. font-size: 28rpx;
  1267. display: flex;
  1268. justify-content: center;
  1269. align-items: center;
  1270. &.add-cart {
  1271. background: #ffbe46;
  1272. }
  1273. &.buy {
  1274. background: #fe560a;
  1275. }
  1276. }
  1277. .sure {
  1278. margin: 0 auto;
  1279. width: 95%;
  1280. max-width: 1200rpx;
  1281. height: 80rpx;
  1282. border-radius: 38rpx;
  1283. color: #fff;
  1284. font-weight: 500;
  1285. font-size: 28rpx;
  1286. background: #fe560a;
  1287. display: flex;
  1288. justify-content: center;
  1289. align-items: center;
  1290. }
  1291. .sure.add-cart {
  1292. background: #ff9402;
  1293. }
  1294. }
  1295. .btn-wrapper.safe-area-inset-bottom {
  1296. padding-bottom: 0;
  1297. padding-bottom: constant(safe-area-inset-bottom);
  1298. padding-bottom: env(safe-area-inset-bottom);
  1299. }
  1300. }
  1301. @keyframes showPopup {
  1302. 0% {
  1303. opacity: 0;
  1304. }
  1305. 100% {
  1306. opacity: 1;
  1307. }
  1308. }
  1309. @keyframes hidePopup {
  1310. 0% {
  1311. opacity: 1;
  1312. }
  1313. 100% {
  1314. opacity: 0;
  1315. }
  1316. }
  1317. @keyframes showLayer {
  1318. 0% {
  1319. transform: translateY(120%);
  1320. }
  1321. 100% {
  1322. transform: translateY(0%);
  1323. }
  1324. }
  1325. @keyframes hideLayer {
  1326. 0% {
  1327. transform: translateY(0);
  1328. }
  1329. 100% {
  1330. transform: translateY(120%);
  1331. }
  1332. }
  1333. }
  1334. </style>