shop_h5/pages/vip/wheel/good.vue

510 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="whole">
<view class="swiperBox">
<swiper class="box" :autoplay="true" :interval="5000" :duration="500" :indicator-dots="false" :circular="true">
<swiper-item>
<image class="img" :src="goodsInfo.face_img + '?x-oss-process=image/format,webp'" :webp="true" mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
<view class="oneBox">
<view class="price">
<view class="font">{{((goodsInfo.max_price * 100 - pageInfo.amount * 100) / 100).toFixed(2)}}</view>
<view class="huaxian">{{goodsInfo.max_price}}</view>
</view>
<view class="desc">已享有抵扣优惠可直接下单</view>
<view class="title">{{goodsInfo.title}}</view>
</view>
<!-- 商品规格sku -->
<view class="sku-list" v-if="goodsInfo.specs_type === 1">
<view class="title">商品规格</view>
<view class="sku-list-item" v-for="(item, index) in specsList" :key="item.spec_id">
<view class="sku-list-item-name">{{item.spec_name }}</view>
<view class="sku-list-item-tag">
<view class="tag"
v-for="(it, i) in item.value"
:key="it.id"
@click="!it.show ? chooseSku(it, index, i) : ''"
:class="choose['v'+ (index + 1) +'_id'] == it.id ? 'choose' : it.show ? 'dis' : '' ">
<image v-if="it.img" :src="it.img"></image>
<text>{{it.value}}</text>
</view>
</view>
</view>
</view>
<view class="twoBox">
<view class="title">商品详情</view>
<!-- <view class="desc"><text>{{goodsInfo.description}}</text></view> -->
<!-- 商品详情 -->
<view class="edition">
<div v-for="(item, index) in goodsInfo.text_modules" :key="item.id">
<div class="edition_box big" v-if="item.type == 1" @click="preViewImg(item.imgs[0])">
<div v-for="(imgs, index) in item.imgs" :key="index">
<image :src="imgs + '?x-oss-process=image/format,webp'" :webp="true" mode="widthFix" style="height:100%;width:100%" class="image"></image>
</div>
</div>
<div class="edition_box" v-if="item.type == 2">
<div class="small_img">
<div v-for="(list, index1) in item.img" :key="index1" class="imgs" @click="preViewImg(item.img)">
<image :src="list + '?x-oss-process=image/format,webp'" mode="aspectFill" :webp="true"></image>
</div>
</div>
</div>
<div class="edition_box" v-if="item.type == 3" @click="openVideo(item.video[0])">
<div class="background">
<up-icon name="play-right-fill" size="42" color="#fff" />
</div>
<image :src="item.video_img" mode="widthFix" style="height:100%;width:100%"></image>
</div>
<div class="edition_box text1_box" v-if="item.type == 4">
<text selectable="true" user-select="true" class="text">{{item.text}}</text>
</div>
</div>
</view>
</view>
<view class="btmbox">
<view class="addbtn" @click="confirmPay()">立即下单</view>
</view>
<video-dialog :url="videoUrl" :show="showVideo" @close="showVideo = false"></video-dialog>
</view>
</template>
<script>
import { ref, reactive, toRefs, watch } from 'vue'
import { get, post } from '@/api/request.js'
import { showToast } from '@/components/common.js'
import videoDialog from '@/components/videoDialog/index.vue'
import { Style } from '@/utils/list.js'
export default {
components: {
videoDialog
},
setup() {
const data = reactive({
pageInfo: {
amount: 0
},
id: 0,
videoUrl: '',
showVideo: false,
specsList: [],
chooseItem: {
price: 0
},
skuName: [], // 规格名
choose: {},
chooseIndex: [],
images: [],
sku_skuInfo: [],
goodsInfo: {
max_price: 0
},
Color: '',
bgColor: '',
priceColor: '',
shop_goods_id: 0
})
async function getPageInfo() {
uni.showLoading({
title: '加载中...',
mask: true
})
await get('/api/v1/UserCoupon/' + data.id).then((res) => {
data.pageInfo = res.data
data.shop_goods_id = res.data.extend && res.data.extend.id || 0
uni.hideLoading()
})
}
const getGoodsInfo = async () => {
await get(`/api/v1/goods/detail/${data.shop_goods_id}`).then((res) => {
data.goodsInfo = res.data
})
}
const getGoodSpec = async () => {
await get(`/api/v1/goods/spec/${data.shop_goods_id}`).then((res) => {
data.specsList = res.data.specs || []
data.sku_skuInfo = res.data.skus
if(res.data.specs_type === 1) {
data.chooseItem = res.data.skus[0]
}
// 在仅有一个规格的时候设置状态
if(data.specsList.length == 1) {
data.specsList[0].value.forEach((req, i) => {
data.sku_skuInfo.forEach((res, j) => {
if(req.id == res.v1_id && (res.price == 0 || res.stock <= 0)){
req.show = true
}
})
})
}
data.images = []
data.specsList[0] && data.specsList[0].value.forEach((it) => {
if(it.img_800){
data.images.push(it.img_800)
}
})
})
}
// 规格选择-主要逻辑
function chooseSku(curObj, index, i_index) {
data.choose['v' + (index + 1) + '_id'] = data.specsList[index].value[i_index].id
data.skuName[index] = data.specsList[index].value[i_index].value
data.chooseIndex.push(index)
data.chooseIndex = Array.from(new Set(data.chooseIndex))
if(data.specsList.length - Object.keys(data.choose).length == 1) {
// 如果只有一个规格类未选中,则去判断未选中的这一项是否可选
data.specsList.forEach((req, i) => {
if(data.chooseIndex.indexOf(i) == -1) {
req.value.forEach((rej, j) => {
data.sku_skuInfo.forEach((ress, m) => {
let flag = [rej.id === ress['v'+(i+1)+'_id']]
for (const key in data.choose) {
flag.push(ress[key] == data.choose[key])
}
if(flag.findIndex(target=>target===false)==-1){
if(ress.stock <= 0 || ress.price == 0){
rej.show = true
} else {
rej.show = false
}
}
})
})
}
})
} else if(data.specsList.length == Object.keys(data.choose).length) {
for (const key in data.choose) {
let i = parseInt(key.substr(1, 1))
data.specsList[i-1].value.forEach((req) => {
data.sku_skuInfo.forEach((ress, m) => {
let flag = [req.id == ress['v'+i+'_id']]
for (const k in data.choose) {
let j = parseInt(k.substr(1, 1))
if(i != j) {
flag.push(ress[k] == data.choose[k])
}
}
if(flag.findIndex(target => target === false) ==-1){
if((ress.stock <= 0 || ress.price == 0)){
req.show = true
} else {
req.show = false
}
}
})
})
}
}
}
function preViewImg(img) {
uni.previewImage({
urls: [img],
current: 1
})
}
const openVideo = (e) => {
data.showVideo = true
data.videoUrl = e
}
function confirmPay() {
if (data.chooseIndex.length != data.specsList.length && data.goodsInfo.specs_type === 1) {
showToast('请选择完整规格')
return false
}
toBuyGoods()
}
function toBuyGoods() {
let goods = [{
num: 1,
shop_goods_id: data.chooseItem.shop_goods_id,
shop_goods_sku_id: data.chooseItem.id,
shop_group_goods_id: 0
}]
uni.setStorageSync('shopGoods', goods)
wx.showToast({
title: '加载中...',
icon: 'loading',
duration: 1200,
mask: true,
success() {
setTimeout(() => {
uni.navigateTo({
url: '/pages/pay/index?type=0&from=1&coupon_id=' + data.id
})
}, 1000)
}
})
}
watch(() => data.choose, (newChoose) => {
// 判断选择规格值是否完整
if (Object.keys(newChoose).length != data.specsList.length) {
return
}
// 对比选中项
data.sku_skuInfo.forEach((sku, s_index) => {
let num = data.chooseItem.num
if (
sku.v1_id == newChoose.v1_id &&
sku.v2_id == newChoose.v2_id &&
sku.v3_id == newChoose.v3_id &&
sku.v4_id == newChoose.v4_id
) {
data.chooseItem = { ...sku }
if (num > 0) {
data.chooseItem.num = num < sku.stock ? num : sku.stock
} else if (sku.stock > 0) {
data.chooseItem.num = 1
} else {
data.chooseItem.num = 0
}
if (sku.pic_url === 'undefined') {
data.chooseItem.pic_url = props.skuInfo.face_img
}
}
})
},
{ deep: true }
)
return {
...toRefs(data),
preViewImg,
confirmPay,
getPageInfo,
openVideo,
toBuyGoods,
getGoodsInfo,
getGoodSpec,
chooseSku
}
},
async onLoad(options) {
this.id = options.id
await this.getPageInfo()
await this.getGoodsInfo()
await this.getGoodSpec()
this.Color = uni.getStorageSync('theme_color')
this.bgColor = Style[uni.getStorageSync('theme_index') * 1].bgColor
this.priceColor = Style[uni.getStorageSync('theme_index') * 1].priceColor
}
}
</script>
<style lang="scss" scoped>
.whole{
padding-bottom: 1px;
.swiperBox{
.box{
width: 100%;
height: 600rpx;
.img{
width: 100%;
height: 100%;
}
}
}
.oneBox{
padding: 30rpx;
box-sizing: border-box;
background-color: #fff;
margin-bottom: 20rpx;
.price{
display: flex;
align-items: center;
.font{
font-size: 32rpx;
font-weight: bold;
color: v-bind('priceColor');
}
.huaxian{
margin-left: 20rpx;
color: #676767;
text-decoration: line-through;
font-size: 28rpx;
}
}
.desc{
margin-top: 10rpx;
font-size: 24rpx;
color: #9C9C9C;
}
.title{
font-size: 30rpx;
line-height: 44rpx;
color: #000;
font-weight: bold;
margin-top: 20rpx;
}
}
.twoBox{
margin: 20rpx 0 100rpx;
padding: 30rpx 0;
box-sizing: border-box;
background-color: #fff;
.title{
font-size: 30rpx;
color: #333;
font-weight: 600;
margin-bottom: 30rpx;
padding: 0 30rpx;
}
.desc{
padding: 24rpx 30rpx;
font-size: 28rpx;
color: #333;
line-height: 50rpx;
border-top: 1px solid #e5e5e5;
}
}
.btmbox{
position: fixed;
bottom: 0;
padding: 20rpx 30rpx;
box-sizing: border-box;
width: 100%;
z-index: 90;
background: #fff;
.addbtn{
width: 100%;
height: 80rpx;
color: #fff;
background: v-bind('Color');
border-radius: 10rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
}
}
}
.edition{
background-color: #fff;
}
.edition_box {
margin: 8rpx 0;
position: relative;
&.big{
margin: 0;
}
.image{
vertical-align: bottom;
}
.background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
image {
width: 30px;
height: 30px;
}
}
.img {
width: 100%;
}
.small_img {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
.imgs {
width: 32.3%;
height: 200rpx;
margin: 20rpx 0;
image {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.imgs:nth-child(2) {
margin: 20rpx 10rpx;
}
.imgs:nth-child(5) {
margin: 20rpx 10rpx;
}
.imgs:nth-child(8) {
margin: 20rpx 10rpx;
}
}
.text {
line-height: 55rpx;
font-size: 30rpx;
color: #222;
}
}
.text1_box{
padding: 20rpx 30rpx;
}
.sku-list {
padding: 30rpx;
box-sizing: border-box;
margin-top: 20rpx;
background-color: #fff;
.title{
font-size: 30rpx;
color: #333;
font-weight: bold;
margin-bottom: 30rpx;
}
.sku-list-item {
margin-bottom: 20rpx;
.sku-list-item-name {
font-size: 28rpx;
font-weight: 600;
}
.sku-list-item-tag {
display: flex;
flex-wrap: wrap;
font-size: 26rpx;
}
.tag {
display: flex;
align-items: center;
justify-content: center;
color: #000;
background-color: #f4f4f4;
margin-right: 22rpx;
margin-top: 20rpx;
padding: 12rpx 20rpx;
box-sizing: border-box;
border-radius: 6rpx;
image {
width: 35rpx;
height: 35rpx;
margin-right: 15rpx;
}
&.dis{
opacity: 0.35;
}
}
.choose {
background-color: v-bind('Color');
color: #fff;
}
}
}
</style>