耀实惠小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
7.0 KiB

  1. <template>
  2. <u-popup mode="bottom" v-model="specShow" closeable border-radius="40" height="70%" @close="hide">
  3. <view class="spec-popup h-100">
  4. <view class="spec-popup-header position-fixed top-0 left-0 vw-100 bg-white p-20 flex align-end">
  5. <view class="m-r-20">
  6. <image class="spec-popup-header-image" :src="image == ''?goodsDetail.pic[0]:image" mode="aspectFit"></image>
  7. </view>
  8. <text class="text-red font-40" v-if="price">{{ price }} {{ goodsType == 'integralStore' ? '兑购' : '' }}</text>
  9. </view>
  10. <view class="spec-popup-container">
  11. <view class="m-b-20">
  12. <view class="spec-popup-item" v-for="(item, index) in specList" :key="index">
  13. <view class="spec-popup-item-title text-grey font-32 m-b-20">{{ item.title }}</view>
  14. <view class="flex flex-wrap">
  15. <view v-for="(attribute, attributeIndex) in item.list" :key="attributeIndex" :class="[
  16. 'spec-popup-item-suk',
  17. selectSpec[item.title] === attribute.name ? 'spec-popup-item-suk--active' : '' ,
  18. attribute.able ? '' : 'spec-popup-item-suk--disabled'
  19. ]" @click="changeSpec(item.title, attribute.name, attribute.able)">
  20. {{ attribute.name }}
  21. </view>
  22. </view>
  23. </view>
  24. </view>
  25. <view class="spec-popup-number flex align-center justify-between">
  26. <text class="font-32 text-black">数量</text>
  27. <u-number-box :min="goodsDetail.sumShop" :max="goodsDetail.stock" v-model="sukNum"></u-number-box>
  28. </view>
  29. </view>
  30. <view class="spec-popup-confirm bg-white position-fixed bottom-0 left-0 vw-100 flex align-center justify-center">
  31. <view class="spec-popup-confirm-btn">
  32. <u-button shape="circle" type="primary" class='btn' @click="$u.debounce(addShopping, 500)">确定</u-button>
  33. </view>
  34. </view>
  35. </view>
  36. </u-popup>
  37. </template>
  38. <script>
  39. import { IMG_URL } from '@/env.js'
  40. export default {
  41. props: {
  42. goodsDetail: {
  43. typeof: Object,
  44. default: () => {}
  45. },
  46. },
  47. data () {
  48. return {
  49. IMG_URL,
  50. specShow: false,
  51. specList: [], // property 列表
  52. skuList: [], // sku 列表
  53. selectSpec: {}, // 选择数据的对象
  54. sukNum: 1,
  55. price: 0,
  56. type: '',
  57. goodsType: '',
  58. image:''
  59. }
  60. },
  61. methods: {
  62. show (bool, type, goodsType) {
  63. this.type = type
  64. this.goodsType = goodsType
  65. this.specShow = bool;
  66. if (bool) {
  67. this.sukNum = this.goodsDetail.sumShop
  68. let specList = JSON.parse(JSON.stringify(this.goodsDetail.attributeListVo))
  69. this.skuList = this.goodsDetail.skuListSku;
  70. // 初始化选择数据的对象
  71. specList.forEach(item => {
  72. this.$set(this.selectSpec, item.title, "");
  73. })
  74. // 将规格数据处理成我们视图所需要的数据类型
  75. this.specList = specList.map(item => {
  76. return {
  77. title: item.title,
  78. list: item.list.map(its => {
  79. return {
  80. name: its,
  81. // 判断是否可以选择
  82. able: this.isAble(item.title, its)
  83. }
  84. })
  85. }
  86. })
  87. }
  88. },
  89. hide () {
  90. this.specShow = false
  91. this.type = ''
  92. this.$emit('close')
  93. },
  94. // 核心判断逻辑
  95. // 判断规格是否可以被选择 核心函数 key当前的规格的title value规格值
  96. isAble(key, value) {
  97. // 深拷贝 避免被影响
  98. let copySelectSpec = JSON.parse(JSON.stringify(this.selectSpec));
  99. // 用对象的好处就在这了 直接赋值当前验证项
  100. copySelectSpec[key] = value;
  101. // console.log(copySelectSpec, key, value)
  102. // 用数组的 some 方法 效率高 符合条件直接退出循环
  103. let flag = this.skuList.some(item => {
  104. // 条件判断 核心逻辑判断
  105. let i = 0;
  106. // 这个for in 循环的逻辑就对底子不深的人来说就看不懂了 原理就是循环已经选中的 和 正在当前对比的数据 和 所有的sku对比 只有当前验证的所有项满足sku中的规格或者其他规格为空时 即满足条件 稍微有点复杂 把注释的调试代码打开就调试下就可以看懂了
  107. for (let k in copySelectSpec) {
  108. // console.log(copySelectSpec[k]) // 注释的调试看逻辑代码
  109. if (copySelectSpec?.[k] && item.list.includes(copySelectSpec[k])) {
  110. // console.log(item)
  111. i++
  112. } else if (copySelectSpec[k] == "") {
  113. i++;
  114. }
  115. }
  116. // 符合下面条件就退出了 不符合会一直循环知道循环结束没有符合的条件就 return false 了
  117. return i == this.goodsDetail.attributeListVo.length
  118. })
  119. return flag
  120. },
  121. // 点击事件
  122. changeSpec(key, value, able) {
  123. if (!able) return
  124. let flag = true
  125. if (this.selectSpec[key] === value) {
  126. this.selectSpec[key] = ''
  127. } else {
  128. this.selectSpec[key] = value
  129. }
  130. for (let key in this.selectSpec) {
  131. if (!this.selectSpec[key]) flag = false
  132. }
  133. if (flag) {
  134. // // debugger
  135. this.skuList.forEach(item => {
  136. let arr = Object.values(this.selectSpec)
  137. if (arr.toString() === item.list.toString()) this.price = item.price
  138. if (arr.toString() === item.list.toString()) this.image = item.image
  139. })
  140. // for (let i = 0; i < this.skuList.length; i++) {
  141. // let item = this.skuList[i]
  142. // let bool = true
  143. // for (var j = 0; j < item.list.length; j++) {
  144. // let subItem = item.list[j]
  145. // bool = true
  146. // console.log('0000000000')
  147. // if (!this.selectSpec.hasOwnProperty(subItem)) {
  148. // bool = false
  149. // break
  150. // }
  151. // }
  152. // console.log(subItemm,this.selectSpec, bool)
  153. // if (bool) {
  154. // this.price = item.price
  155. // break
  156. // }
  157. // }
  158. }
  159. console.log(flag)
  160. // forEach循环改变原数组
  161. this.specList.forEach(item => {
  162. item.list.forEach(its => {
  163. its.able = this.isAble(item.title, its.name);
  164. });
  165. });
  166. },
  167. addShopping () {
  168. this.$emit('addShopping', {num: this.sukNum, price: this.price, spec: this.selectSpec}, this.type)
  169. }
  170. }
  171. }
  172. </script>
  173. <style lang="scss" scoped>
  174. .spec-popup {
  175. &-header {
  176. height: 200rpx;
  177. box-sizing: border-box;
  178. &-image {
  179. width: 160rpx;
  180. height: 160rpx;
  181. }
  182. }
  183. &-container {
  184. padding: 220rpx 40rpx 120rpx;
  185. }
  186. &-item {
  187. &-suk {
  188. height: 60rpx;
  189. border: 2rpx solid transparent;
  190. border-radius: 34rpx;
  191. margin-right: 40rpx;
  192. padding: 0 30px;
  193. margin-bottom: 20rpx;
  194. font-size: 32rpx;
  195. color: #000;
  196. background: #f5f5f5;
  197. display: flex;
  198. align-items: center;
  199. justify-content: center;
  200. &--active {
  201. border-color: $u-type-primary;
  202. color: $u-type-primary;
  203. background: #EEFCFF;
  204. }
  205. &--disabled {
  206. opacity: 0.5;
  207. border-color: #e0e0e0;
  208. color: #999999;
  209. }
  210. }
  211. }
  212. &-confirm {
  213. height: 100rpx;
  214. &-btn {
  215. width: 90%;
  216. height: 80rpx;
  217. /deep/ .btn{
  218. button{
  219. font-size: 36rpx;
  220. }
  221. }
  222. }
  223. }
  224. }
  225. //数量组件样式调整
  226. </style>