shop_app/components/ktt/singleSku.vue

396 lines
9.0 KiB
Vue
Raw Normal View History

2025-05-08 09:16:37 +08:00
<template>
<view>
<up-popup :show="show" :round="10" mode="bottom" @close="handleClose" closeable catchtouchmove="preventD" :z-index="200">
<view class="skuBox">
<view class="oneBox">
<image :src="info.face_img" mode="aspectFill"></image>
<view class="box">
<view class="tit">{{info.title}}</view>
<view class="pricebox">
<view class="text1" v-if="vipOn && info.vip_price > 0 && (is_vip || (!is_vip && vip_price_show))">
<text class="icon1"></text>
<text>{{info.price}}</text>
</view>
<view>
<!-- 显示会员价 -->
<view v-if="vipOn && info.vip_price > 0 && (is_vip || (!is_vip && vip_price_show))" class="vip">
<view class="vip-tag"><text>会员价&nbsp;</text>{{info.vip_price}}</view>
</view>
<!-- 显示普通价格 -->
<view v-else class="vip">
<text class="icon1"></text>
<text>{{info.price}}</text>
</view>
</view>
</view>
<view class="text" v-if="show_stock === 1">剩余{{info.stock <= 0 ? 0 : info.stock}}</view>
</view>
</view>
<scroll-view class="scrollbox" scroll-y="true" enhanced="true">
<view class="twoBox">
<text>数量</text>
<view class="stepper">
<view class="minus flex" @click="minusNum()"><up-icon name="minus" size="12" :color="Color" /></view>
<view class="num">{{num}}</view>
<view class="plus flex" @click="plusNum()"><up-icon name="plus" size="12" color="#fff" /></view>
</view>
</view>
<view class="sku-buy" v-if="sales > 0">
<view class="img" v-for="img in info.avatars" :key="img">
<image :src="img"></image>
</view>
<view class="text">已有<text class="num">{{sales}}</text>个社群好友购买</view>
</view>
<view class="edition">
<view v-for="(item, index) in info.text_modules" :key="item.id">
<view v-if="item.type == 1" class="edition_box" @click="viewImg(item.imgs[0])">
<view v-for="(imgs, index) in item.imgs" :key="index">
<image :src="imgs" mode="widthFix" style="width: 100%;"></image>
</view>
</view>
<view class="edition_box" v-if="item.type == 2">
<view class="small_img">
<view v-for="(list, index) in item.img" :key="index" class="imgs" @click="viewImg(list)">
<image :src="list" mode="aspectFill"></image>
</view>
</view>
</view>
<!-- 文字 -->
<view class="edition_box text1_box" v-if="item.type == 4">
<text user-select="true" class="text">{{item.text}}</text>
</view>
</view>
<view class="imgbox">
<image v-for="(img, idx) in info.gallery" :key="idx" :src="img" class="img" mode="widthFix" @click="viewImg(img)"></image>
</view>
</view>
</scroll-view>
<view class="btn" :class="info.stock <= 0 || !canBuy ? 'dis' : ''" @click="(info.stock > 0 && canBuy) ? addCart():''">加入购物车</view>
</view>
</up-popup>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { get, post } from '@/api/request.js'
import { showToast } from '../common.js'
export default {
props: {
show: {
type: Boolean,
default: true
},
id: {
type: Number,
default: 0
},
show_stock: {
type: Number,
default: 0
},
canBuy: {
type: Boolean,
default: true
},
shortStatus: {
type: Number,
default: 1
},
groupId: {
type: Number,
default: 0
},
sales: {
type: Number,
default: 0
}
},
setup(props, context) {
const data = reactive({
id: 0,
show: false,
info: {},
vipOn: uni.getStorageSync('vip_on') === 1,
is_vip: uni.getStorageSync('is_vip'),
vip_price_show: uni.getStorageSync('vip_price_show') || false,
Color: uni.getStorageSync('theme_color'),
show_stock: 0,
canBuy: true,
num: 1,
groupId: 0,
shortStatus: 1
})
function getSpecInfo(val) {
get(`/api/v1/goods/spec/${data.id}`).then((res) => {
data.info = res.data
data.info.avatars = res.data.avatars || []
data.info.text_modules = res.data.text_modules || []
data.info.gallery = res.data.gallery || []
// 如果商品设置了起购
data.num = 1
if(res.data.limit_type == 1) {
data.num = parseInt(res.data.start_sale_num)
}
if(data.shortStatus == 0) {
data.info.stock = 0
}
})
}
// 数量-减
function minusNum() {
// 如果设置了起购&&起购数量与现有数量相等、现有数量为1 不可减
if((data.info.limit_type == 1 && data.num == parseInt(data.info.start_sale_num)) || data.num == 1) {
} else {
data.num -= 1
}
}
// 数量-加
function plusNum() {
// 如果设置了限购&&起购数量与现有数量相等、现有数量大于等于库存 不可加
if((data.info.limit_type == 2 && data.num == parseInt(data.info.limit)) || (data.num >= data.info.stock)) {
} else {
data.num += 1
}
}
const viewImg = (img) => {
uni.previewImage({
current: 0,
urls: [img]
})
}
function handleClose() {
context.emit('close')
}
const preventD = () => {
return
}
function addCart() {
let params = {
num: data.num,
shop_goods_id: data.id,
shop_goods_sku_id: 0,
shop_group_goods_id: data.groupId,
source_id: 0,
source_type: 'normal'
}
post('/api/v1/carts', params).then((res) => {
context.emit('refresh')
})
}
watch(props, async (newProps) => {
if (newProps.show) {
data.show = true
data.id = newProps.id
data.groupId = newProps.groupId
data.canBuy = newProps.canBuy
data.shortStatus = newProps.shortStatus
data.show_stock = newProps.show_stock
getSpecInfo()
} else {
data.show = false
}
})
return {
...toRefs(data),
getSpecInfo,
handleClose,
viewImg,
preventD,
minusNum,
plusNum,
addCart
}
}
}
</script>
<style lang="scss" scoped>
.skuBox{
background: #fff;
height: 78vh;
overflow: hidden;
.oneBox{
display: flex;
justify-content: space-between;
padding: 24rpx;
box-sizing: border-box;
image{
width: 200rpx;
height: 200rpx;
}
.box{
width: calc(100% - 220rpx);
.tit{
font-size: 30rpx;
}
.pricebox{
display: flex;
align-items: center;
flex-wrap: wrap;
margin: 8rpx 0 20rpx;
.text1{
font-size: 34rpx;
color: #f66d2d;
font-weight: 600;
margin-right: 12rpx;
}
.icon1{
font-size: 24rpx;
}
.vip{
display: flex;
align-items: center;
font-size: 34rpx;
color: #f66d2d;
font-weight: bold;
}
}
.text{
font-size: 24rpx;
color: #999999;
}
.vip-tag {
font-size: 32rpx;
color: #fbe6c3;
background: #353648;
border-radius: 20rpx 0 0 0;
padding: 8rpx 10rpx;
line-height: 1;
text{
font-size: 22rpx;
}
}
}
}
.scrollbox{
width: 100%;
height: calc(78vh - 358rpx);
}
.twoBox{
font-size: 28rpx;
padding: 30rpx 24rpx;
box-sizing: border-box;
border-top: 1rpx solid #eee;
display: flex;
align-items: center;
justify-content: space-between;
.stepper{
display: flex;
align-items: center;
.flex{
width: 40rpx;
height: 40rpx;
box-sizing: border-box;
border-radius: 4rpx;
display: flex;
align-items: center;
justify-content: center;
}
.num{
width: 80rpx;
font-size: 28rpx;
text-align: center;
}
.minus{
border: 1px solid v-bind('Color');
}
.plus{
background-color: v-bind('Color');
}
}
}
.sku-buy{
display: flex;
align-items: center;
padding: 30rpx;
border-top: 1rpx solid #eee;
border-bottom: 1rpx solid #eee;
.img{
width: 50rpx;
height: 50rpx;
margin-left: -10rpx;
border: 4rpx solid #fff;
box-sizing: border-box;
image{
width: 100%;
height: 100%;
border-radius: 10rpx;
}
}
.text {
margin-left: 20rpx;
font-size: 28rpx;
.num{
color: v-bind('Color');
}
}
}
.edition{
padding-bottom: 50rpx;
.edition_box{
margin: 8rpx 0;
position: relative;
padding: 0 20rpx;
.img{
width: 100%;
}
.small_img{
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
.imgs{
width: calc(33% - 11rpx);
height: 220rpx;
margin: 16rpx 16rpx 0 0;
image{
width: 100%;
height: 100%;
object-fit: cover;
}
}
.imgs:nth-child(3n+3){
margin: 16rpx 0 0 0;
}
}
.text{
line-height: 55rpx;
font-size: 30rpx;
color: #222;
}
}
.imgbox{
padding: 20rpx 0;
.img{
width: 100%;
}
}
}
.btn{
height: 110rpx;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
background-color: v-bind('Color');
color: #fff;
font-size: 30rpx;
&.dis{
opacity: 0.65;
}
}
}
</style>