uni-app——规格选择判断库存(类似电商商品加购)
<template>
<view class="detail_page" v-cloak :class="isShowPopup? 'popup-show': ''">
<navBar :title="topInfo.title" :url="topInfo.url" :icon_title="topInfo.icon_title" :type="topInfo.type">
</navBar>
<view class="pages" v-cloak>
<view class="info scroll_item" id="scroll0">
<view class="banner_top">
<swiper :swiperConfig="swiperConfig"></swiper>
</view>
<view class="page_info page_item">
<view class="price">
<text class="large">{{listData.price}}</text>
元起
</view>
<view class="title">{{listData.name}}</view>
<view class="sub_title">强效清洗,全面爱家,重新焕发地毯新生</view>
</view>
<view class="form_box page_item">
<uni-forms ref="signUpform" :value="signUpformData" :rules="rules">
<uni-forms-item label="小区" name="housing_id" style="display: none;"></uni-forms-item>
<uni-forms-item label="地址" name="user_address_id" @tap="goAddress">
<text class="picker_lable">{{address}}</text>
</uni-forms-item>
<uni-forms-item label="规格" name="flag" @tap="chorceSpecs">
<text class="picker_lable">{{specs}}</text>
</uni-forms-item>
<uni-forms-item label="时间" name="start_time" @tap="openDatetimePicker">
<text class="picker_lable">{{signUpformData.start_time}}</text>
</uni-forms-item>
</uni-forms>
</view>
</view>
<view class="details scroll_item " id="scroll1" style="padding-bottom:80px;">
<view style="color: #a29696;margin-bottom: 20rpx; text-align: center;">——详情——</view>
<view class="page_detail page_item" v-html="detail_content" style="margin-bottom:70px;">
{{detail_content}}
</view>
</view>
<view class="footer">
<view>
<image class="service" mode="aspectFit" @tap="callPhone" src="../../static/images/service.png">
</image>
<view class="byButton" form-type="submit" @tap="handleBuy">立即购买</view>
</view>
</view>
</view>
<!-- 页面滚动到详情时再显示锚点 -->
<view class="fixedtop" v-show="scrollDistance > 100">
<view class="fixedtop_box">
<view v-for="(item,index) in fixedList" :key="index" :class="{'active':currentIndex == index}"
@tap="changeactive(index)">{{item.name}}
</view>
</view>
</view>
<!-- 规格 -->
<uni-popup ref="popup" type="bottom" :mask-click="false">
<view class="specs_box spec-shade">
<view class="specs_box_box">
<view class="title">
<text></text>
<text class="title">请选择服务规格</text>
<!-- <text @click="closeProp"
class="iconfont icon-close"></text> -->
<text></text>
</view>
<view class="spec-cont">
<view class="goods-choose-show flex-star">
<view class="goods-choose-show-right" v-if="currentItem">
<p>¥{{currentItem.price || 0}}</p>
<view>库存{{currentItem.all_count || 0}}件</view>
<!-- <view>{{specShowString}}</view> -->
</view>
</view>
<view class="spec-linebox" style="max-height: 550rpx;overflow-y: scroll;">
<view class="spec-item" v-for="(skuItem,skuIndex) in skuInfo">
<p>{{skuItem.title}}</p>
<view class="item-cont flex-star">
<span v-for="(item,index) in skuItem.option"
:class="[item.isShow ? '' : 'noProduct',subIndex[skuIndex] == item.id ? 'act' : '']"
@click="item.isShow ? specificationBtn(item.info,skuIndex,item.id) : disabled">{{item.info}}</span>
</view>
</view>
</view>
</view>
<button class="confirm" @click="confirmSpec">确定</button>
</view>
</view>
</uni-popup>
<!-- 时间 -->
<SimpleDateTimePicker ref="myPicker" @submit="handleSubmit" :start-year="year" :end-year="year+20" />
</view>
</template>
<script>
import navBar from "@/components/navBar/navBar.vue"
import swiper from "@/components/swiper/swiper.vue"
import forms from "@/components/uni-forms/uni-forms.vue"
import formItems from "@/components/uni-forms-item/uni-forms-item.vue"
import SimpleDateTimePicker
from "uni_modules/buuug7-simple-datetime-picker/components/buuug7-simple-datetime-picker/buuug7-simple-datetime-picker.vue";
import popup from "@/components/uni-popup/uni-popup.vue"
import {
mapMutations
} from 'vuex';
export default {
components: {
navBar,
swiper,
formItems,
forms,
SimpleDateTimePicker,
popup
},
data() {
return {
isShowPopup: false,
payParams: 0,
goods_id: 0,
isInit: 0, // 默认只显示第一组规格
allCount_id: 0, // 库存为0的id
stockIndex: 0, //库存为0的id组
stock_flag: [],
getSpecs: [],
topInfo: {
url: "../../pages/index/index",
title: "预约详情",
icon_title: "返回",
type: 'tab'
},
token: "",
year: "",
listData: {},
swiperConfig: {
indicatorDots: true,
vertical: false,
autoplay: true,
interval: 2000,
duration: 600,
bannerList: [],
swiperH_height: "400rpx"
},
detail_content: "", //详情内容
specs: "请选择规格",
address: "请选择服务地址",
signUpformData: {
user_address_id: "",
housing_id: "",
flag: "",
start_time: "请选择服务时间"
},
currentIndex: 0,
fixedList: [{
name: "商品",
targetDom: ".info"
},
{
name: "详情",
targetDom: ".details"
}
], // 固定顶部锚点链接
rules: {
address: {
rules: [{
required: true,
errorMessage: "请选择服务地址"
}]
},
type: {
rules: [{
required: true,
errorMessage: "请选择服务规格"
}]
},
serviceTime: {
rules: [{
required: true,
errorMessage: "请选择服务时间"
}]
}
},
elHeight: "",
scrollDistance: 0,
doms: "",
topList: [],
multiIndex: 0,
specsList: [],
isShow: false,
selectArr: [],
subIndex: [],
currentItem: {
flag: '',
price: 0,
all_count: 0,
title: ""
},
skuInfo: [],
specShowString: '选择规格',
goodsData: {
priceInfo: [],
SKUInfo: [],
},
category_type: 0,// 分类id(只针对垃圾回收)
}
},
onLoad(option) {
console.log('下单确定地址', option);
/* 获取当前年份 */
let date = new Date();
this.year = date.getFullYear();
/* 设置页面滚动高度 */
let screenH = uni.getSystemInfoSync().screenHeight;
this.elHeight = screenH;
let loginRes = this.checkLogin();
if (!loginRes) {
return false;
} else {
/* 初始化页面 */
if (option.id) {
uni.setStorageSync("goods_id", option.id);
}
if(option.category_type){
uni.setStorageSync("category_type", option.category_type);
}
this.token = uni.getStorageSync("token");
this.goods_id = uni.getStorageSync("goods_id");
this.category_type = uni.getStorageSync("category_type");
}
// this.firstStock();
this.getStock();
this.getInfo();
/* 选择地址 */
if (option.address_id) {
this.signUpformData.user_address_id = option.address_id;
this.address = option.address;
}
/* 小区id */
if (option.housing_id) {
this.signUpformData.housing_id = option.housing_id;
}
},
methods: {
getStock() {
let _param = {};
_param.operate = "order.get_price",
_param.goods_id = this.goods_id;
_param.token = this.token;
_param.flag = [0];
this.$myRequset({
url: "/api?operate=goods.get_price",
method: "POST",
data: _param,
}).then((res) => {
this.goodsData.priceInfo = res.data.data;
// console.log('获取价格', this.goodsData.priceInfo);
});
},
getInfo() {
this.$myRequset({
url: "/api?operate=goods.info",
method: "POST",
data: {
token: this.token,
goods_id: this.goods_id
},
}).then((res) => {
this.swiperConfig.bannerList = res.data.data.album_images;
this.listData.name = this.topInfo.title = res.data.data.name;
this.listData.price = res.data.data.price;
this.detail_content = res.data.data.content;
this.goodsData.SKUInfo = res.data.data.spec_config;
this.skuInfo = this.goodsData.SKUInfo;
if(this.skuInfo){
this.skuInfo.forEach(item => {
item.option.forEach(specItem => {
specItem.isShow = true;
})
})
}
// console.log('规格列表', this.goodsData.SKUInfo);
// console.log('规格列表_skuInfo', this.skuInfo);
});
},
disabled() {
uni.showToast({
title: "不可点击"
})
},
/* 规格 */
chorceSpecs() {
setInterval(function() {
uni.hideKeyboard(); //隐藏软键盘
}, 10);
if (!this.signUpformData.user_address_id) {
uni.showToast({
title: "请先选择地址",
icon: "none"
})
} else if (this.specsList) {
this.$refs.popup.open();
this.isShowPopup = true;
} else {
uni.showToast({
title: "暂无规格可选",
icon: "none"
})
}
},
closeProp() {
if (this.subIndex.length == 0) {
uni.showToast({
icon: "error",
title: "请选择服务规格"
});
} else {
this.$refs.popup.close();
}
},
/* 确定规格 */
confirmSpec() {
console.log('当前选择', this.subIndex);
console.log('当前选择', this.selectArr);
// this.signUpformData.type = this.subIndex.toString(",");
this.signUpformData.flag = this.subIndex;
this.specs = this.specShowString;
if (this.currentItem.price == 0) {
uni.showToast({
icon: "none",
title: "请选择完整规格"
})
} else {
this.$refs.popup.close();
}
},
/**
* @param {String} specName 当前点击规格按钮的值(黑色,35)
* @param {Number} specIndex 选择的规格下标(例子中颜色是0,尺码是1)
* @param {Number} specItemIndex 选择规格值id(例子中35下标是0)
*/
specificationBtn(specName, specIndex, specItemIndex) {
if (this.selectArr[specIndex] != specName) { //判断所选规格数组中是否包含当前点击规格
this.selectArr[specIndex] = specName; //如果没有则把当前规格添加
this.subIndex[specIndex] = Number(specItemIndex); //添加选中样式
} else {
this.selectArr[specIndex] = '';
this.subIndex[specIndex] = -1; //去除样式
}
this.specShowString = this.spaceRemoveArr(this.selectArr).join(',') || '选择规格'; //所选规格页面中展示,数组为空则变为选择规格
this.inventoryLookup(); //当规格选完后,去匹配
this.clickPitch(); //库存判断,实现不可点击
},
spaceRemoveArr(arr) { //数组去除空字符串
let tempArr = []
arr.forEach(item => {
if (item) {
tempArr.push(item)
}
})
return tempArr;
},
/* 规格选完后,去匹配 */
inventoryLookup() {
try {
this.goodsData.priceInfo.forEach((item, index) => {
if (item.title == this.specShowString) {
this.currentItem = item;
this.listData.price = this.currentItem.price;
throw new Error();
} else {
this.currentItem = {
flag: '',
price: 0,
all_count: 0,
title: ""
};
}
})
} catch (e) {}
},
/* 库存判断,实现不可点击 */
clickPitch() {
let result = [];
// console.log('库存判断:',this.goodsData.SKUInfo);
for (let i in this.goodsData.SKUInfo) {
result[i] = this.selectArr[i] ? this.selectArr[i] : '';
}
//最难理解的大概就是这里了,这里跟着循环里打印结果,多走几遍就大致明白了 假象.jpg
for (let i in this.goodsData.SKUInfo) {
let last = result[i];
// console.log("最后点击======",last);
for (let k in this.goodsData.SKUInfo[i].option) {
result[i] = this.goodsData.SKUInfo[i].option[k].info;
// console.log('result--------', result, "last:", last);
this.skuInfo[i].option[k].isShow = this.isMay(result)
}
result[i] = last;
}
// console.log('库存结果111:',result);
},
isMay(result) {
for (let i in result) {
if (result[i] == '') {
return true;
}
}
for (let i in this.goodsData.priceInfo) {
if (this.goodsData.priceInfo[i].title == result.join(",") && this.goodsData.priceInfo[i].all_count >
0) {
return true;
}
}
},
goAddress() {
console.log('goAddress');
uni.redirectTo({
url: "../addressList/addressList"
});
},
/* 时间 */
openDatetimePicker() {
if (!this.signUpformData.user_address_id) {
uni.showToast({
icon: "none",
title: "请选择服务地址"
})
} else if (!this.signUpformData.flag) {
uni.showToast({
icon: "none",
title: "请选择服务规格"
})
} else {
this.$refs.myPicker.show();
}
},
/* 选择时间 */
handleSubmit(e) {
console.log('times', e);
this.signUpformData.start_time = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}`;
},
// 锚点链接滚动监听
onPageScroll(res){
this.scrollDistance = res.scrollTop;
// console.log('滚动距离',res.scrollTop);//距离页面顶部距离
if(res.scrollTop >=600){
this.currentIndex = 1;
}else{
this.currentIndex = 0;
}
},
/* 锚点点击*/
changeactive(index) {
console.log('sdsd',index);
if(index==1){
uni.pageScrollTo({
duration:300, // 毫秒
scrollTop:600 // 位置
});
}else{
uni.pageScrollTo({
duration:300, // 毫秒
scrollTop:0 // 位置
});
}
},
/* 表单提交 */
handleBuy() {
this.$refs.signUpform.validate().then(res => {
console.log('表单数据信息:', res);
let _param = res;
_param.operate = "wechat.miniapp";
_param.token = this.token;
_param.goods_id = this.goods_id;
// 垃圾回收
if(this.category_type == 21){
_param.category_type = this.category_type;
}
console.log('(_param.flag', typeof _param.flag);
let _res = this.$myRequset({
url: "/api/pay/index",
method: "POST",
data: _param,
}).then((res) => {
console.log('_res', res);
if (res.data.code == 1) {
let signType = res.data.data.signType
let nonceStr = res.data.data.nonceStr;
let _package = res.data.data.package;
let paySign = res.data.data.paySign;
let timeStamp = res.data.data.timeStamp;
uni.requestPayment({
provider: 'wxpay',
timeStamp: timeStamp,
nonceStr: nonceStr,
package: _package,
signType: signType,
paySign: paySign,
success: function(res) {
console.log('pay_success:' + JSON.stringify(res));
uni.reLaunch({
url: "../../pages/order/order"
});
},
fail: function(err) {
console.log('pay_fail:' + JSON.stringify(err));
uni.reLaunch({
url: "../../pages/order/order",
});
}
});
} else {
uni.showToast({
icon: "none",
title: "请选择规格"
})
return false;
}
});
}).catch(err => {
uni.showToast({
title: err[0].errorMessage,
icon: "none"
});
})
},
/* 拨打电话 */
callPhone() {
uni.makePhoneCall({
phoneNumber: "15902341080"
});
},
}
}
</script>
https://www.cnblogs.com/LindaBlog/p/15570833.html