Files
jdt-user/src/pages/goods/goods_detail/index.vue
2023-11-28 17:59:45 +08:00

321 lines
6.4 KiB
Vue

<template>
<view class="app">
<view class="head-wrapper" :style="{ top: BarHeight + 'px' }">
<view class="head-menu">
<Left class="iconfont" @click="returns" />
<Home class="iconfont" @click="goHome" />
</view>
</view>
<!-- 幻灯片 -->
<nut-swiper
:init-page="0"
:pagination-visible="true"
pagination-color="#426543"
auto-play="3000"
>
<nut-swiper-item v-for="(itm, idx) in swiperList" :key="idx">
<img :alt="idx.toString()" :src="itm" />
</nut-swiper-item>
</nut-swiper>
<!-- 标题价格 -->
<view class="card">
<view class="header">
<view class="price">
<nut-price
size="normal"
:price="goodInfo.number as number"
position="after"
symbol="元"
/>
<nut-price
size="normal"
:price="goodInfo.exchange as number"
position="after"
symbol="积分"
/>
</view>
<view class="stock"> 库存剩余:{{ goodInfo.stock }}</view>
</view>
<view class="title">{{ goodInfo.name }}</view>
<view class="sub">{{ goodInfo.profile }}</view>
<nut-button size="small" type="primary" @click.stop="add_cart(goodInfo)">
<template #icon>
<Cart2 />
</template>
</nut-button>
</view>
<!-- 产品介绍 -->
<view class="rich-box">
<view class="title">产品介绍</view>
<rich-text
v-if="goodInfo.details"
class="rich"
:nodes="goodInfo.details"
></rich-text>
<nut-empty v-else description="暂无产品介绍"></nut-empty>
</view>
<view style="height: 9vh"></view>
<!-- 底部 -->
<!-- 购物车 -->
<cart ref="cartRef" :mer-info="mer_info" @update-cart="updateCartNum" />
</view>
</template>
<script setup lang="ts">
import { Ref, ref } from "vue";
import Taro from "@tarojs/taro";
import { Home, Left } from "@nutui/icons-vue-taro";
import { getActiveGoodsDetail } from "@/api/goods";
import Cart from "@/components/Cart.vue";
import { Cart2 } from "@nutui/icons-vue-taro";
import { nextTick } from "vue";
const statusBarHeight = Taro.getSystemInfoSync()?.statusBarHeight;
const BarHeight = ref((statusBarHeight as number) + 7);
const swiperList = ref([]);
interface GoodInfo {
gid?: string;
name?: string;
number?: number;
exchange?: number;
cover?: string;
details?: string;
sku?: any[];
stock?: number;
profile?: string;
price?: number;
cartNum?: number;
}
const goodInfo = ref<GoodInfo>({});
Taro.useLoad(async (options) => {
await get_good_detail(options.gid);
mer_info.value = Taro.getStorageSync("mer_info");
await nextTick(async () => {
await cartRef.value.get_cart_list();
});
});
const get_good_detail = async (gid: string) => {
try {
const res = await getActiveGoodsDetail({ gid: gid });
goodInfo.value = {
...res.data.data,
// details: res.data.data.details.,
};
swiperList.value = res.data.data.rotation.split(",");
} catch (e) {
Taro.showToast({
title: e.msg,
icon: "none",
});
}
};
const returns = () => {
Taro.navigateBack({
delta: 1,
});
};
const goHome = () => {
Taro.switchTab({
url: "/pages/index/index",
});
};
interface CartItems {
bid: string;
gid: string;
number: number;
price: number;
cover: string;
name: string;
exchange: number;
}
const mer_info = ref<any>({});
const cartRef = ref(null) as Ref;
const add_cart = async (item: any) => {
const num = item.cartNum ? Number(item.cartNum) + 1 : 1;
await nextTick(async () => {
await cartRef.value.add_cart(item, num);
});
};
const updateCartNum = (cartItems: CartItems[]) => {
if (cartItems.length > 0) {
cartItems.forEach((cartItem: CartItems) => {
if (goodInfo.value.gid === cartItem.gid) {
goodInfo.value.cartNum = cartItem.number;
}
});
} else {
Reflect.deleteProperty(goodInfo.value, "cartNum");
}
};
</script>
<style lang="scss">
page {
--nut-cell-box-shadow: none;
--nut-cell-title-font: 30px;
}
// sku遮罩
.overlay {
background-color: rgba(0, 0, 0, 0.5);
z-index: 1 !important;
}
.head-wrapper {
z-index: 999;
display: flex;
align-items: center;
position: fixed;
left: 30px;
top: 0;
height: 114px;
}
.head-menu {
display: flex;
align-items: center;
height: 54px;
width: 140px;
background: rgba(0, 0, 0, 0.25);
border-radius: 27px;
.iconfont {
flex: 1;
text-align: center;
color: #fff;
box-sizing: border-box;
}
}
.nut-swiper-item img {
width: 100%;
height: 730px;
}
.card {
padding: 30px;
background-color: #fff;
position: relative;
.header {
display: flex;
justify-content: space-between;
align-items: center;
.price {
display: flex;
flex-direction: column;
}
.title {
font-size: 30px;
font-weight: bold;
color: #333;
}
.stock {
color: #8f8f8f;
}
}
.sub {
font-size: 24px;
color: #999;
}
.nut-button {
// margin: 10px;
position: absolute;
right: 40rpx;
bottom: 20rpx;
}
}
.rich-box {
background-color: #fff;
margin-top: 20px;
width: 100vw;
box-sizing: border-box;
text-align: center;
padding: 15px 0;
.title {
font-size: 30px;
font-weight: bold;
color: #333;
}
.rich {
width: 100%;
}
}
.nut-sku {
// 适配ios底部安全区域
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.sku-box {
padding: 100px 50px;
}
.bottom-box {
border-top: 1px solid #e5e5e585;
position: fixed;
box-sizing: border-box;
bottom: 0;
height: 150rpx;
background: #fff;
display: flex;
justify-content: space-between;
align-items: center;
// 适配ios底部安全区域
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
z-index: 999;
width: 100%;
.left {
display: flex;
align-items: center;
justify-content: flex-start;
width: 300px;
padding: 0 20px;
box-sizing: border-box;
.icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #333;
font-size: 25px;
width: 100px;
}
}
.icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #333;
font-size: 25px;
}
}
</style>