1 line
16 KiB
Plaintext
1 line
16 KiB
Plaintext
{"version":3,"file":"s-select-sku.js","sources":["../../../../../../src/sheep/components/s-select-sku/s-select-sku.vue","../../../../../../uniComponent:/RDovQXBwL1dvcmsvYWRkci9hY2RyLXVpL3NyYy9zaGVlcC9jb21wb25lbnRzL3Mtc2VsZWN0LXNrdS9zLXNlbGVjdC1za3UudnVl"],"sourcesContent":["<template>\r\n <!-- 规格弹窗 -->\r\n <su-popup :show=\"show\" round=\"10\" @close=\"emits('close')\">\r\n <!-- SKU 信息 -->\r\n <view class=\"ss-modal-box bg-white ss-flex-col\">\r\n <view class=\"modal-header ss-flex ss-col-center\">\r\n <view class=\"header-left ss-m-r-30\">\r\n <image\r\n class=\"sku-image\"\r\n :src=\"state.selectedSku.picUrl || goodsInfo.picUrl\"\r\n mode=\"aspectFill\"\r\n />\r\n </view>\r\n <view class=\"header-right ss-flex-col ss-row-between ss-flex-1\">\r\n <view class=\"goods-title ss-line-2\">{{ goodsInfo.name }}</view>\r\n <view class=\"header-right-bottom ss-flex ss-col-center ss-row-between\">\r\n <view class=\"ss-flex\">\r\n <view class=\"price-text\">\r\n {{ fen2yuan(state.selectedSku.price || goodsInfo.price) }}\r\n </view>\r\n </view>\r\n <view class=\"stock-text ss-m-l-20\">\r\n {{ formatStock('exact', state.selectedSku.stock || goodsInfo.stock) }}\r\n </view>\r\n </view>\r\n </view>\r\n </view>\r\n\r\n <!-- 属性选择 -->\r\n <view class=\"modal-content ss-flex-1\">\r\n <scroll-view scroll-y=\"true\" class=\"modal-content-scroll\" @touchmove.stop>\r\n <view class=\"sku-item ss-m-b-20\" v-for=\"property in propertyList\" :key=\"property.id\">\r\n <view class=\"label-text ss-m-b-20\">{{ property.name }}</view>\r\n <view class=\"ss-flex ss-col-center ss-flex-wrap\">\r\n <button\r\n class=\"ss-reset-button spec-btn\"\r\n v-for=\"value in property.values\"\r\n :class=\"[\r\n {\r\n 'ui-BG-Main-Gradient': state.currentPropertyArray[property.id] === value.id,\r\n },\r\n {\r\n 'disabled-btn': value.disabled === true,\r\n },\r\n ]\"\r\n :key=\"value.id\"\r\n :disabled=\"value.disabled === true\"\r\n @tap=\"onSelectSku(property.id, value.id)\"\r\n >\r\n {{ value.name }}\r\n </button>\r\n </view>\r\n </view>\r\n <view class=\"buy-num-box ss-flex ss-col-center ss-row-between ss-m-b-40\">\r\n <view class=\"label-text\">购买数量</view>\r\n <su-number-box\r\n :min=\"1\"\r\n :max=\"state.selectedSku.stock\"\r\n :step=\"1\"\r\n v-model=\"state.selectedSku.goods_num\"\r\n @change=\"onNumberChange($event)\"\r\n />\r\n </view>\r\n </scroll-view>\r\n </view>\r\n\r\n <!-- 操作区 -->\r\n <view class=\"modal-footer border-top\">\r\n <view class=\"buy-box ss-flex ss-col-center ss-flex ss-col-center ss-row-center\">\r\n <button class=\"ss-reset-button add-btn ui-Shadow-Main\" @tap=\"onAddCart\">\r\n 加入购物车\r\n </button>\r\n <button class=\"ss-reset-button buy-btn ui-Shadow-Main\" @tap=\"onBuy\">立即购买</button>\r\n </view>\r\n </view>\r\n </view>\r\n </su-popup>\r\n</template>\r\n\r\n<script setup>\r\nimport { computed, reactive, watch } from 'vue'\r\nimport sheep from '@/sheep'\r\nimport { formatStock, convertProductPropertyList, fen2yuan } from '@/sheep/hooks/useGoods'\r\n\r\nconst emits = defineEmits(['change', 'addCart', 'buy', 'close'])\r\nconst props = defineProps({\r\n goodsInfo: {\r\n type: Object,\r\n default() {},\r\n },\r\n show: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n})\r\n\r\nconst state = reactive({\r\n selectedSku: {}, // 选中的 SKU\r\n currentPropertyArray: [], // 当前选中的属性,实际是个 Map。key 是 property 编号,value 是 value 编号\r\n})\r\n\r\nconst propertyList = convertProductPropertyList(props.goodsInfo.skus)\r\n\r\n// SKU 列表\r\nconst skuList = computed(() => {\r\n const skuPrices = props.goodsInfo.skus\r\n for (const price of skuPrices) {\r\n price.value_id_array = price.properties.map((item) => item.valueId)\r\n }\r\n return skuPrices\r\n})\r\n\r\nwatch(\r\n () => state.selectedSku,\r\n (newVal) => {\r\n emits('change', newVal)\r\n },\r\n {\r\n immediate: true, // 立即执行\r\n deep: true, // 深度监听\r\n },\r\n)\r\n\r\n// 输入框改变数量\r\nfunction onNumberChange(e) {\r\n if (e === 0) return\r\n if (state.selectedSku.goods_num === e) return\r\n state.selectedSku.goods_num = e\r\n}\r\n\r\n// 加入购物车\r\nfunction onAddCart() {\r\n if (state.selectedSku.id <= 0) {\r\n sheep.$helper.toast('请选择规格')\r\n return\r\n }\r\n if (state.selectedSku.stock <= 0) {\r\n sheep.$helper.toast('库存不足')\r\n return\r\n }\r\n\r\n emits('addCart', state.selectedSku)\r\n}\r\n\r\n// 立即购买\r\nfunction onBuy() {\r\n if (state.selectedSku.id <= 0) {\r\n sheep.$helper.toast('请选择规格')\r\n return\r\n }\r\n if (state.selectedSku.stock <= 0) {\r\n sheep.$helper.toast('库存不足')\r\n return\r\n }\r\n emits('buy', state.selectedSku)\r\n}\r\n\r\n// 改变禁用状态:计算每个 property 属性值的按钮,是否禁用\r\nfunction changeDisabled(isChecked = false, propertyId = 0, valueId = 0) {\r\n let newSkus = [] // 所有可以选择的 sku 数组\r\n if (isChecked) {\r\n // 情况一:选中 property\r\n // 获得当前点击选中 property 的、所有可用 SKU\r\n for (const price of skuList.value) {\r\n if (price.stock <= 0) {\r\n continue\r\n }\r\n if (price.value_id_array.indexOf(valueId) >= 0) {\r\n newSkus.push(price)\r\n }\r\n }\r\n } else {\r\n // 情况二:取消选中 property\r\n // 当前所选 property 下,所有可以选择的 SKU\r\n newSkus = getCanUseSkuList()\r\n }\r\n\r\n // 所有存在并且有库存未选择的 SKU 的 value 属性值 id\r\n let noChooseValueIds = []\r\n for (const price of newSkus) {\r\n noChooseValueIds = noChooseValueIds.concat(price.value_id_array)\r\n }\r\n noChooseValueIds = Array.from(new Set(noChooseValueIds)) // 去重\r\n\r\n if (isChecked) {\r\n // 去除当前选中的 value 属性值 id\r\n const index = noChooseValueIds.indexOf(valueId)\r\n noChooseValueIds.splice(index, 1)\r\n } else {\r\n // 循环去除当前已选择的 value 属性值 id\r\n state.currentPropertyArray.forEach((currentPropertyId) => {\r\n if (currentPropertyId.toString() !== '') {\r\n return\r\n }\r\n // currentPropertyId 为空是反选 填充的\r\n const index = noChooseValueIds.indexOf(currentPropertyId)\r\n if (index >= 0) {\r\n // currentPropertyId 存在于 noChooseValueIds\r\n noChooseValueIds.splice(index, 1)\r\n }\r\n })\r\n }\r\n\r\n // 当前已选择的 property 数组\r\n let choosePropertyIds = []\r\n if (!isChecked) {\r\n // 当前已选择的 property\r\n state.currentPropertyArray.forEach((currentPropertyId, currentValueId) => {\r\n if (currentPropertyId !== '') {\r\n // currentPropertyId 为空是反选 填充的\r\n choosePropertyIds.push(currentValueId)\r\n }\r\n })\r\n } else {\r\n // 当前点击选择的 property\r\n choosePropertyIds = [propertyId]\r\n }\r\n\r\n for (const propertyIndex in propertyList) {\r\n // 当前点击的 property、或者取消选择时候,已选中的 property 不进行处理\r\n if (choosePropertyIds.indexOf(propertyList[propertyIndex].id) >= 0) {\r\n continue\r\n }\r\n // 如果当前 property id 不存在于有库存的 SKU 中,则禁用\r\n for (const valueIndex in propertyList[propertyIndex].values) {\r\n propertyList[propertyIndex].values[valueIndex].disabled =\r\n noChooseValueIds.indexOf(propertyList[propertyIndex].values[valueIndex].id) < 0 // true 禁用 or false 不禁用\r\n }\r\n }\r\n}\r\n\r\n// 当前所选属性下,获取所有有库存的 SKU 们\r\nfunction getCanUseSkuList() {\r\n const newSkus = []\r\n for (const sku of skuList.value) {\r\n if (sku.stock <= 0) {\r\n continue\r\n }\r\n let isOk = true\r\n state.currentPropertyArray.forEach((propertyId) => {\r\n // propertyId 不为空,并且,这个 条 sku 没有被选中,则排除\r\n if (propertyId.toString() !== '' && sku.value_id_array.indexOf(propertyId) < 0) {\r\n isOk = false\r\n }\r\n })\r\n if (isOk) {\r\n newSkus.push(sku)\r\n }\r\n }\r\n return newSkus\r\n}\r\n\r\n// 选择规格\r\nfunction onSelectSku(propertyId, valueId) {\r\n // 清空已选择\r\n let isChecked = true // 选中 or 取消选中\r\n if (\r\n state.currentPropertyArray[propertyId] !== undefined &&\r\n state.currentPropertyArray[propertyId] === valueId\r\n ) {\r\n // 点击已被选中的,删除并填充 ''\r\n isChecked = false\r\n state.currentPropertyArray.splice(propertyId, 1, '')\r\n } else {\r\n // 选中\r\n state.currentPropertyArray[propertyId] = valueId\r\n }\r\n\r\n // 选中的 property 大类\r\n const choosePropertyId = []\r\n state.currentPropertyArray.forEach((currentPropertyId) => {\r\n if (currentPropertyId !== '') {\r\n // currentPropertyId 为空是反选 填充的\r\n choosePropertyId.push(currentPropertyId)\r\n }\r\n })\r\n\r\n // 当前所选 property 下,所有可以选择的 SKU 们\r\n const newSkuList = getCanUseSkuList()\r\n\r\n // 判断所有 property 大类是否选择完成\r\n if (choosePropertyId.length === propertyList.length && newSkuList.length) {\r\n newSkuList[0].goods_num = state.selectedSku.goods_num || 1\r\n state.selectedSku = newSkuList[0]\r\n } else {\r\n state.selectedSku = {}\r\n }\r\n\r\n // 改变 property 禁用状态\r\n changeDisabled(isChecked, propertyId, valueId)\r\n}\r\n\r\nchangeDisabled(false)\r\n// TODO 芋艿:待讨论的优化点:1)单规格,要不要默认选中;2)默认要不要选中第一个规格\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n \r\n// 购买\r\n.buy-box {\r\n padding: 10rpx 0;\r\n\r\n .add-btn {\r\n width: 356rpx;\r\n height: 80rpx;\r\n color: var(--ui-BG-Main);\r\n background-color: var(--ui-BG-Main-light);\r\n border-radius: 40rpx 0 0 40rpx;\r\n }\r\n\r\n .buy-btn {\r\n width: 356rpx;\r\n height: 80rpx;\r\n color: #fff;\r\n background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));\r\n border-radius: 0 40rpx 40rpx 0;\r\n }\r\n\r\n .score-btn {\r\n width: 100%;\r\n height: 80rpx;\r\n margin: 0 20rpx;\r\n color: #fff;\r\n background: linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));\r\n border-radius: 40rpx;\r\n }\r\n}\r\n\r\n.ss-modal-box {\r\n max-height: 1000rpx;\r\n border-radius: 30rpx 30rpx 0 0;\r\n\r\n .modal-header {\r\n position: relative;\r\n padding: 80rpx 20rpx 40rpx;\r\n\r\n .sku-image {\r\n width: 160rpx;\r\n height: 160rpx;\r\n border-radius: 10rpx;\r\n }\r\n\r\n .header-right {\r\n height: 160rpx;\r\n }\r\n\r\n .close-icon {\r\n position: absolute;\r\n top: 10rpx;\r\n right: 20rpx;\r\n font-size: 46rpx;\r\n opacity: 0.2;\r\n }\r\n\r\n .goods-title {\r\n font-size: 28rpx;\r\n font-weight: 500;\r\n line-height: 42rpx;\r\n }\r\n\r\n .score-img {\r\n width: 36rpx;\r\n height: 36rpx;\r\n margin: 0 4rpx;\r\n }\r\n\r\n .score-text {\r\n font-family: OPPOSANS;\r\n font-size: 30rpx;\r\n font-weight: 500;\r\n color: $red;\r\n }\r\n\r\n .price-text {\r\n font-family: OPPOSANS;\r\n font-size: 30rpx;\r\n font-weight: 500;\r\n color: $red;\r\n\r\n &::before {\r\n font-size: 30rpx;\r\n font-weight: 500;\r\n color: $red;\r\n content: '¥';\r\n }\r\n }\r\n\r\n .stock-text {\r\n font-size: 26rpx;\r\n color: #999999;\r\n }\r\n }\r\n\r\n .modal-content {\r\n padding: 0 20rpx;\r\n\r\n .modal-content-scroll {\r\n max-height: 600rpx;\r\n\r\n .label-text {\r\n font-size: 26rpx;\r\n font-weight: 500;\r\n }\r\n\r\n .buy-num-box {\r\n height: 100rpx;\r\n }\r\n\r\n .spec-btn {\r\n min-width: 100rpx;\r\n height: 60rpx;\r\n padding: 0 30rpx;\r\n margin-right: 10rpx;\r\n margin-bottom: 10rpx;\r\n font-size: 26rpx;\r\n color: #434343;\r\n background: #f4f4f4;\r\n border-radius: 30rpx;\r\n }\r\n\r\n .disabled-btn {\r\n font-weight: 400;\r\n color: #c6c6c6;\r\n background: #f8f8f8;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","import Component from 'D:/App/Work/addr/acdr-ui/src/sheep/components/s-select-sku/s-select-sku.vue'\nwx.createComponent(Component)"],"names":["reactive","convertProductPropertyList","computed","watch","sheep"],"mappings":"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"} |