| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- <template>
- <popup
- @close="close"
- ref="popupRef"
- isClose
- iconSize="16px"
- zIndex="998"
- iconColor="var(--text)"
- >
- <template #title>
- <view class="product_info">
- <image
- :src="cur_img || pic_url"
- class="cur_img"
- @click="previewImage(1, cur_img || pic_url)"
- ></image>
- <view class="product_price">
- <rich-text
- class="texts"
- :nodes="MoneyAbouthtml((skuItem && skuItem.price) || price, true)"
- ></rich-text>
- </view>
- </view>
- </template>
- <template #content>
- <scroll-view class="sku_info" scroll-y>
- <view class="prop_wrapper" v-for="(val, num) in listArr" :key="val">
- <view class="spec_title">{{ val.name }}</view>
- <view class="spec_items">
- <view
- class="spec_item"
- :class="(listActive[num] || 0) == index ? 'active' : ''"
- v-for="(item, index) in val.spec"
- :key="index"
- @click="listClick(num, item, index)"
- >
- <image
- :src="item.specUrl"
- v-if="item.specUrl"
- class="img"
- ></image>
- <view class="text" v-else>{{ item.specName }}</view>
- </view>
- </view>
- </view>
- <view class="prop_wrapper">
- <view class="spec_title">
- <trans _t="数量" />
- </view>
- <view class="spec_items decrease">
- <up-number-box
- v-model="total"
- :min="1"
- :max="skuItem.quantity"
- @change="totalChange"
- ></up-number-box>
- <view class="inventory">
- <trans _t="库存" />:{{ skuItem.quantity }}
- </view>
- </view>
- <view class="least_purchase">
- <trans _t="最小购买数量" />
- </view>
- </view>
- </scroll-view>
- </template>
- <template #footer>
- <view
- class="footer_btn"
- @click="btnClick"
- :style="{
- opacity: canBuyNow ? 1 : 0.5,
- 'pointer-events': canBuyNow ? 'auto' : 'none',
- }"
- >
- <trans :_t="btnText == 'add' ? '加入购物车' : '立即购买'" />
- </view>
- </template>
- </popup>
- </template>
- <script setup>
- import popup from "@/components/popup";
- import { ref, computed } from "vue";
- import { useSystemStore } from "@/store";
- import { Moneyhtml, Toast, MoneyAbouthtml } from "@/utils";
- import { SHOP_ADD_CART, SHOP_CART_CONFIRM } from "@/api";
- import { useShopStore } from "@/store";
- const useShop = useShopStore();
- const props = defineProps({
- pic_url: String,
- props_spec: {
- type: Object,
- default: () => ({}),
- },
- price: {
- type: [String, Number],
- default: 0,
- },
- sku: {
- type: Object,
- default: () => [],
- },
- channel: {
- type: [String, Number],
- default: 0,
- },
- goods_id: {
- type: [String, Number],
- default: 0,
- },
- isFree: {
- type: [String, Number],
- default: 0,
- },
- });
- const emit = defineEmits(["open", "close"]);
- const total = ref(1);
- const cur_img = ref(props.pic_url);
- const listActive = ref([]);
- const btnText = ref("add");
- const listArr = computed(() => {
- const arr = Object.values(props.props_spec);
- listActive.value = new Array(arr.length).fill(0);
- return arr;
- });
- const shopIds = computed(() => {
- let arr = [];
- listActive.value.forEach((ele, num) => {
- let item = listArr.value[num].spec[ele];
- let str = `${item.pid}:${item.specId}`;
- arr.push(str);
- });
- arr.join(";");
- return arr.join(";");
- });
- const skuItem = computed(() => {
- let findItem = props.sku.find((item) => item.properties == shopIds.value);
- return findItem;
- });
- const useSystem = useSystemStore();
- const popupRef = ref(null);
- const symbol = computed(() => useSystem.getSymbol);
- // 是否可以立即购买(isFree==1 时需满199)
- const canBuyNow = computed(() => {
- if (btnText.value !== "buy") return true;
- if (Number(props.isFree) !== 1) return true;
- const unitPrice = parseFloat(
- (skuItem.value && skuItem.value.price) || props.price || 0
- );
- const totalPrice = unitPrice * (total.value || 1);
- return totalPrice >= 199;
- });
- const totalChange = (e) => {};
- const listClick = (num, item, index) => {
- let new_listActive = listActive.value;
- new_listActive[num] = index;
- listActive.value = new_listActive;
- if (item.specUrl) {
- cur_img.value = item.specUrl;
- }
- };
- const btnClick = () => {
- if (!canBuyNow.value) {
- Toast("包邮通道需满199才可立即购买");
- return;
- }
- addCart();
- };
- const close = () => {
- popupRef.value && popupRef.value.close();
- emit("close");
- };
- const open = (value = "add") => {
- btnText.value = value;
- popupRef.value && popupRef.value.open();
- };
- const addCart = async () => {
- try {
- const res = await SHOP_ADD_CART({
- channel: props.channel,
- goods_id: props.goods_id,
- sku_id: skuItem.value.sku_id,
- total: total.value,
- });
- useShop.setCartNum(res.data.cartCount);
- if (btnText.value == "buy") {
- uni.navigateTo({
- url: `/pages/shop/shopConfirm?comfirmId=${res.data.cartId}&isFree=${props.isFree}`,
- });
- } else {
- close();
- }
- } catch (error) {
- Toast(error.msg);
- }
- };
- function previewImage(index, urls) {
- uni.previewImage({
- current: index,
- urls: [urls],
- success() {},
- });
- }
- defineExpose({
- open,
- close,
- });
- </script>
- <style lang="less" scoped>
- @import url("@/style.less");
- /deep/ .pop {
- .top {
- align-items: unset;
- padding-bottom: 24rpx;
- }
- .conts {
- padding-top: 0;
- }
- }
- .uni-preview-container {
- z-index: 99999 !important;
- /* 确保高于其他元素 */
- }
- .product_info {
- .flex();
- .cur_img {
- width: 144rpx;
- height: 144rpx;
- border-radius: 8rpx;
- margin-right: 24rpx;
- }
- .product_price {
- color: var(--red);
- .size(40rpx);
- font-weight: 700;
- .flex();
- .texts {
- margin-left: 8rpx;
- /deep/ div {
- .ver(baseline);
- .decimal {
- .size(24rpx);
- }
- }
- }
- }
- }
- .sku_info {
- .prop_wrapper {
- margin-top: 8rpx;
- .spec_title {
- .ver();
- color: var(--text);
- .size(28rpx);
- font-weight: 700;
- line-height: 40rpx;
- min-height: 60rpx;
- }
- .spec_items {
- .flex();
- flex-wrap: wrap;
- gap: 16rpx;
- margin-top: 24rpx;
- .spec_item {
- border: var(--bor);
- color: var(--text);
- border-radius: 8rpx;
- overflow: hidden;
- .img {
- width: 88rpx;
- height: 88rpx;
- display: block;
- }
- .text {
- .size(28rpx);
- line-height: 60rpx;
- padding: 0 24rpx;
- }
- }
- .active {
- border-color: var(--black);
- color: var(--light);
- background-color: var(--black);
- }
- }
- .decrease {
- .ver();
- /deep/ .u-number-box {
- border: 1px solid #dcdfe6;
- border-radius: 16rpx;
- .u-number-box__minus,
- .u-number-box__plus {
- width: 76rpx !important;
- height: 76rpx !important;
- background-color: transparent !important;
- .u-icon__icon {
- .size(26rpx) !important;
- color: var(--text) !important;
- }
- &--hover {
- .u-icon__icon {
- color: var(--primary) !important;
- }
- }
- }
- .u-number-box__input {
- margin: 0;
- border-left: 1px solid #dcdfe6;
- border-right: 1px solid #dcdfe6;
- height: 76rpx !important;
- width: 160rpx !important;
- background-color: transparent !important;
- }
- }
- .inventory {
- color: var(--text);
- margin-left: 8rpx;
- .size(28rpx);
- line-height: 60rpx;
- }
- }
- .least_purchase {
- color: var(--text-01);
- margin-top: 8rpx;
- .size(28rpx);
- line-height: 60rpx;
- }
- }
- }
- .footer_btn {
- background-color: var(--black);
- color: var(--light);
- border-radius: 20rpx;
- padding: 16rpx 30rpx;
- .flex_center();
- .size();
- font-weight: bold;
- height: 100rpx;
- }
- </style>
|