|
|
|
<template>
|
|
|
|
<view class="bg">
|
|
|
|
<!-- 日期选择区域 -->
|
|
|
|
<view class="date-all-box">
|
|
|
|
<!-- 月份选择 -->
|
|
|
|
<view class="month-box">
|
|
|
|
<view @tap="changeMonth(index)" :class="'month-item' + (monthIndex === index ? ' active' : '')"
|
|
|
|
v-for="(item, index) in month" :key="index">
|
|
|
|
{{ item }}月
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 星期表头 -->
|
|
|
|
<view class="day-header">
|
|
|
|
<view class="day-header-item">日</view>
|
|
|
|
<view class="day-header-item">一</view>
|
|
|
|
<view class="day-header-item">二</view>
|
|
|
|
<view class="day-header-item">三</view>
|
|
|
|
<view class="day-header-item">四</view>
|
|
|
|
<view class="day-header-item">五</view>
|
|
|
|
<view class="day-header-item">六</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 日期展示 -->
|
|
|
|
<view class="day-box" v-if="selectDate">
|
|
|
|
<!-- 填充空白 -->
|
|
|
|
<view class="day-item" v-for="(item, index) in currentMonthDays[1]" :key="index">
|
|
|
|
<view class="date-item-in">
|
|
|
|
<view class="date-num"></view>
|
|
|
|
<view class="date-price-place"></view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<!-- 显示日期 -->
|
|
|
|
<view
|
|
|
|
:class="'day-item' + (selectDate.selectMonth === month[monthIndex] && selectDate.selectDate === index + 1 ? ' active' : '')"
|
|
|
|
v-for="(item, index) in currentMonthDays[0]" :key="index">
|
|
|
|
<view class="date-item-in" @tap="selectDateFun(index + 1)">
|
|
|
|
<view :class="
|
|
|
|
'date-num' + (getPriceInfo(month[monthIndex], index + 1) && getPriceInfo(month[monthIndex], index + 1).product_price !== null ? ' active' : '')
|
|
|
|
">
|
|
|
|
{{ formatDay(index + 1) }}
|
|
|
|
</view>
|
|
|
|
<view class="price" v-if="
|
|
|
|
getPriceInfo(month[monthIndex], index + 1) &&
|
|
|
|
getPriceInfo(month[monthIndex], index + 1).product_price !== null &&
|
|
|
|
getPriceInfo(month[monthIndex], index + 1).stock !== null
|
|
|
|
">
|
|
|
|
¥{{ getPriceInfo(month[monthIndex], index + 1).m_price / 100 }}
|
|
|
|
</view>
|
|
|
|
<view class="date-price-place"
|
|
|
|
v-else-if="getPriceInfo(month[monthIndex], index + 1) && getPriceInfo(month[monthIndex], index + 1).stock === 0">
|
|
|
|
售罄
|
|
|
|
</view>
|
|
|
|
<view class="date-price-place" v-else></view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 规格选择区域 -->
|
|
|
|
<view class="box" v-for="(item, index) in sku" :key="index">
|
|
|
|
<view class="box-top">
|
|
|
|
<view class="box-title">{{ item.sku_name }}</view>
|
|
|
|
<view class="box-tip text-overflow">{{ item.sku_type_info }}</view>
|
|
|
|
<view :class="'iconfont' + (nums[index] === 0 ? ' disable' : '')" @tap="minus(index)">-</view>
|
|
|
|
<view class="number">{{ nums[index] }}</view>
|
|
|
|
<view :class="'iconfont' + (nums[index] === selectDate.info[index].stock ? ' disable' : '')"
|
|
|
|
@tap="add(index)">+</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="single-price" v-if="selectDate">{{ selectDate.info[index].price / 100 }}</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 底部固定栏 -->
|
|
|
|
<view class="fixed-bottom">
|
|
|
|
<text class="fixed-text">合计:</text>
|
|
|
|
<view class="price">{{ totalPrice() / 100 }}</view>
|
|
|
|
<view class="btn" @tap="order">下一步</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
id: '',
|
|
|
|
monthCount: 2, // 显示的月份数量
|
|
|
|
month: [],
|
|
|
|
monthDays: [],
|
|
|
|
monthIndex: 0,
|
|
|
|
productInfo: null,
|
|
|
|
sku: [],
|
|
|
|
nums: [],
|
|
|
|
selectDate: null,
|
|
|
|
price: 0,
|
|
|
|
prices: {}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
onLoad(option) {
|
|
|
|
if (option && option.id) this.id = option.id;
|
|
|
|
},
|
|
|
|
onShow() {
|
|
|
|
this.getSku();
|
|
|
|
this.initDate();
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
// 计算当前月份的天数信息
|
|
|
|
currentMonthDays() {
|
|
|
|
return this.monthDays[this.monthIndex];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
// 获取产品下的规格
|
|
|
|
getSku() {
|
|
|
|
this.Post({
|
|
|
|
id: this.id
|
|
|
|
}, '/api/product/get_product_detail').then(res => {
|
|
|
|
const nums = res.data.sku.map(() => 1);
|
|
|
|
// 排序
|
|
|
|
this.sortSku(res.data.sku);
|
|
|
|
this.productInfo = res.data;
|
|
|
|
this.sku = res.data.sku;
|
|
|
|
this.nums = nums;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 初始化日期信息
|
|
|
|
initDate() {
|
|
|
|
const today = new Date();
|
|
|
|
const monthInfoList = [];
|
|
|
|
|
|
|
|
// 生成monthCount个月份的数据
|
|
|
|
for (let i = 0; i < this.monthCount; i++) {
|
|
|
|
const month = today.getMonth() + 1 + i;
|
|
|
|
const year = today.getFullYear() + Math.floor((month - 1) / 12);
|
|
|
|
const currentMonth = (month - 1) % 12 + 1;
|
|
|
|
monthInfoList.push({
|
|
|
|
month: currentMonth,
|
|
|
|
year
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
this.month = monthInfoList.map(item => item.month);
|
|
|
|
this.monthDays = monthInfoList.map(item => this.getMonthDays(item.month, item.year));
|
|
|
|
|
|
|
|
// 计算日期范围,获取更多月份的价格信息
|
|
|
|
const startDate = this.formatDate(today);
|
|
|
|
const endYear = monthInfoList[this.monthCount - 1].year;
|
|
|
|
const endMonth = monthInfoList[this.monthCount - 1].month;
|
|
|
|
const endDay = this.monthDays[this.monthCount - 1][0];
|
|
|
|
const endDate = `${endYear}/${endMonth}/${endDay}`;
|
|
|
|
|
|
|
|
this.Post({
|
|
|
|
product_id: this.id,
|
|
|
|
start_date: startDate,
|
|
|
|
end_date: endDate
|
|
|
|
}, '/api/product/get_product_sku_price_by_date').then(res => {
|
|
|
|
const prices = this.processPriceData(res.data);
|
|
|
|
this.prices = prices;
|
|
|
|
const {
|
|
|
|
selectDate,
|
|
|
|
selectMonth
|
|
|
|
} = this.findFirstAvailableDate(prices);
|
|
|
|
if (!selectDate) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const info = prices[`${selectMonth}-${selectDate}`];
|
|
|
|
info.selectMonth = selectMonth;
|
|
|
|
info.selectDate = selectDate;
|
|
|
|
this.selectDate = info;
|
|
|
|
this.monthIndex = this.month.indexOf(selectMonth);
|
|
|
|
console.log(111, this.selectDate);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 获取月份信息
|
|
|
|
getMonthInfo(today) {
|
|
|
|
const month1 = today.getMonth() + 1;
|
|
|
|
const month2 = (month1 + 1) % 12;
|
|
|
|
const year = today.getFullYear();
|
|
|
|
const year2 = month1 < month2 ? year : year + 1;
|
|
|
|
return {
|
|
|
|
month1,
|
|
|
|
month2,
|
|
|
|
year,
|
|
|
|
year2
|
|
|
|
};
|
|
|
|
},
|
|
|
|
// 获取这个月有几天
|
|
|
|
getMonthDays(month, year) {
|
|
|
|
const date = new Date(`${year}/${month}/01`).getDay();
|
|
|
|
if (month === 2) {
|
|
|
|
if ((year % 100 !== 0 && year % 4 === 0) || year % 400 === 0) {
|
|
|
|
return [29, date];
|
|
|
|
} else {
|
|
|
|
return [28, date];
|
|
|
|
}
|
|
|
|
} else if ((month < 8 && month % 2 === 1) || (month >= 8 && month % 2 === 0)) {
|
|
|
|
return [31, date];
|
|
|
|
} else {
|
|
|
|
return [30, date];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// 格式化日期
|
|
|
|
formatDate(date) {
|
|
|
|
const year = date.getFullYear();
|
|
|
|
const month = date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : date.getMonth() + 1;
|
|
|
|
const day = date.getDate();
|
|
|
|
return [year, month, day].join('-');
|
|
|
|
},
|
|
|
|
// 切换月份
|
|
|
|
changeMonth(index) {
|
|
|
|
this.monthIndex = index;
|
|
|
|
},
|
|
|
|
// 选择日期
|
|
|
|
selectDateFun(day) {
|
|
|
|
const selectMonth = this.month[this.monthIndex];
|
|
|
|
if (!selectMonth) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const info = this.getPriceInfo(selectMonth, day);
|
|
|
|
console.log(info)
|
|
|
|
if (info && info.stock !== 0) {
|
|
|
|
info.selectMonth = selectMonth;
|
|
|
|
info.selectDate = day;
|
|
|
|
this.selectDate = info;
|
|
|
|
}
|
|
|
|
this.$forceUpdate()
|
|
|
|
},
|
|
|
|
// 减少数量
|
|
|
|
minus(index) {
|
|
|
|
if (!this.selectDate) {
|
|
|
|
uni.showToast({
|
|
|
|
title: '请先选择出行日期',
|
|
|
|
icon: 'none'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this.nums[index] === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.nums[index]--;
|
|
|
|
this.$forceUpdate();
|
|
|
|
},
|
|
|
|
// 添加数量
|
|
|
|
add(index) {
|
|
|
|
if (!this.selectDate) {
|
|
|
|
uni.showToast({
|
|
|
|
title: '请先选择出行日期',
|
|
|
|
icon: 'none'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this.selectDate.info[index].stock === this.nums[index]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.nums[index]++;
|
|
|
|
this.$forceUpdate();
|
|
|
|
},
|
|
|
|
// 总价
|
|
|
|
totalPrice() {
|
|
|
|
if (!this.selectDate) return 0;
|
|
|
|
return this.nums.reduce((total, num, index) => {
|
|
|
|
return total + num * this.selectDate.info[index].price;
|
|
|
|
}, 0);
|
|
|
|
},
|
|
|
|
// 下一步
|
|
|
|
order() {
|
|
|
|
if (!this.selectDate) {
|
|
|
|
uni.showToast({
|
|
|
|
title: '请先选择日期',
|
|
|
|
icon: 'none'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const allNum = this.nums.reduce((total, num) => total + num, 0);
|
|
|
|
if (allNum === 0) {
|
|
|
|
uni.showToast({
|
|
|
|
title: '至少选择一个规格',
|
|
|
|
icon: 'none'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.sku.forEach((item, index) => {
|
|
|
|
item.num = this.nums[index];
|
|
|
|
item.price = this.selectDate.info[index].price;
|
|
|
|
});
|
|
|
|
const data = {
|
|
|
|
product: this.productInfo,
|
|
|
|
sku: this.sku,
|
|
|
|
selectDate: this.selectDate,
|
|
|
|
price: this.totalPrice()
|
|
|
|
};
|
|
|
|
this.$store.commit('changeLineInfo', data);
|
|
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
url: '/subPackages/line/orders'
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 规格排序
|
|
|
|
sortSku(sku) {
|
|
|
|
sku.sort((a, b) => a.id - b.id);
|
|
|
|
},
|
|
|
|
// 处理价格数据
|
|
|
|
processPriceData(data) {
|
|
|
|
const prices = {};
|
|
|
|
data.forEach(item => {
|
|
|
|
this.sortSku(item.info);
|
|
|
|
const stock = item.info.reduce((total, i) => total + i.stock, 0);
|
|
|
|
item.stock = stock;
|
|
|
|
if (item.stock > 0) {
|
|
|
|
const [, ...dateParts] = item.date.split('-');
|
|
|
|
const newDate = dateParts.map(d => parseInt(d));
|
|
|
|
const key = newDate.join('-');
|
|
|
|
prices[key] = item;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return prices;
|
|
|
|
},
|
|
|
|
// 查找第一个可用日期
|
|
|
|
findFirstAvailableDate(prices) {
|
|
|
|
let selectDate;
|
|
|
|
let selectMonth;
|
|
|
|
for (const key in prices) {
|
|
|
|
const [month, day] = key.split('-');
|
|
|
|
if (!selectDate) {
|
|
|
|
selectDate = parseInt(day);
|
|
|
|
selectMonth = parseInt(month);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
selectDate,
|
|
|
|
selectMonth
|
|
|
|
};
|
|
|
|
},
|
|
|
|
// 获取价格信息
|
|
|
|
getPriceInfo(month, day) {
|
|
|
|
return this.prices[`${month}-${day}`];
|
|
|
|
},
|
|
|
|
// 格式化日期显示
|
|
|
|
formatDay(day) {
|
|
|
|
return day >= 10 ? day : `0${day}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
/* 样式部分保持不变 */
|
|
|
|
.bg {
|
|
|
|
background: #f6f6f6;
|
|
|
|
padding-bottom: 200rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.date-all-box {
|
|
|
|
margin: 25rpx;
|
|
|
|
|
|
|
|
.month-box {
|
|
|
|
padding: 0 20rpx;
|
|
|
|
height: 116rpx;
|
|
|
|
display: flex;
|
|
|
|
border-bottom: 1rpx solid #ccc;
|
|
|
|
align-items: center;
|
|
|
|
overflow-x: auto;
|
|
|
|
|
|
|
|
::-webkit-scrollbar {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.month-item {
|
|
|
|
margin-right: 70rpx;
|
|
|
|
font-size: 33rpx;
|
|
|
|
color: #000;
|
|
|
|
font-weight: 500;
|
|
|
|
line-height: 116rpx;
|
|
|
|
position: relative;
|
|
|
|
}
|
|
|
|
|
|
|
|
.month-item.active::after {
|
|
|
|
content: '1';
|
|
|
|
display: block;
|
|
|
|
font-size: 0;
|
|
|
|
position: absolute;
|
|
|
|
left: 0;
|
|
|
|
right: 0;
|
|
|
|
height: 8rpx;
|
|
|
|
background: #6A8A27;
|
|
|
|
border-radius: 4rpx;
|
|
|
|
bottom: 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.day-header {
|
|
|
|
padding-top: 40rpx;
|
|
|
|
line-height: 45rpx;
|
|
|
|
font-size: 29rpx;
|
|
|
|
color: #000;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
margin-bottom: 50rpx;
|
|
|
|
|
|
|
|
.day-header-item {
|
|
|
|
width: calc(702rpx / 7);
|
|
|
|
text-align: center;
|
|
|
|
flex-shrink: 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.day-box {
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
font-size: 35rpx;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
color: #999;
|
|
|
|
|
|
|
|
.day-item {
|
|
|
|
width: calc(702rpx / 7);
|
|
|
|
text-align: center;
|
|
|
|
flex-shrink: 0;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
margin-bottom: 30rpx;
|
|
|
|
|
|
|
|
.date-item-in {
|
|
|
|
width: 87rpx;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
flex-direction: column;
|
|
|
|
height: 87rpx;
|
|
|
|
|
|
|
|
.date-num {
|
|
|
|
line-height: 40rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.date-num.active {
|
|
|
|
color: #000;
|
|
|
|
}
|
|
|
|
|
|
|
|
.price {
|
|
|
|
font-size: 23rpx;
|
|
|
|
color: #F84A56;
|
|
|
|
line-height: 20rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.price::after {
|
|
|
|
content: '起';
|
|
|
|
font-size: 17rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.date-price-place {
|
|
|
|
height: 20rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.day-item.active {
|
|
|
|
.date-item-in {
|
|
|
|
background: #6A8A27;
|
|
|
|
color: #fff;
|
|
|
|
border-radius: 7rpx;
|
|
|
|
|
|
|
|
.price {
|
|
|
|
color: #fff;
|
|
|
|
}
|
|
|
|
|
|
|
|
.date-num {
|
|
|
|
color: #fff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.box {
|
|
|
|
background: white;
|
|
|
|
margin: 25rpx;
|
|
|
|
background: #ffffff;
|
|
|
|
border-radius: 9rpx;
|
|
|
|
padding: 35rpx 20rpx;
|
|
|
|
|
|
|
|
.box-top {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
line-height: 50rpx;
|
|
|
|
font-size: 28rpx;
|
|
|
|
color: #666;
|
|
|
|
|
|
|
|
.box-title {
|
|
|
|
font-size: 31rpx;
|
|
|
|
color: #000;
|
|
|
|
}
|
|
|
|
|
|
|
|
.box-tip {
|
|
|
|
flex: 1;
|
|
|
|
margin-left: 30rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.iconfont {
|
|
|
|
color: #000;
|
|
|
|
font-size: 34rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.iconfont.disable {
|
|
|
|
color: #666;
|
|
|
|
}
|
|
|
|
|
|
|
|
.number {
|
|
|
|
width: 67rpx;
|
|
|
|
height: 50rpx;
|
|
|
|
background: #f0f0f0;
|
|
|
|
border-radius: 7rpx;
|
|
|
|
text-align: center;
|
|
|
|
margin: 0 23rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.single-price {
|
|
|
|
font-size: 33rpx;
|
|
|
|
color: #F84A56;
|
|
|
|
text-align: right;
|
|
|
|
margin-top: 20rpx;
|
|
|
|
}
|
|
|
|
|
|
|
|
.single-price::before {
|
|
|
|
content: '¥';
|
|
|
|
font-size: 24rpx;
|
|
|
|
margin-right: 4rpx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.fixed-bottom {
|
|
|
|
position: fixed;
|
|
|
|
left: 0;
|
|
|
|
right: 0;
|
|
|
|
bottom: 0;
|
|
|
|
height: 113rpx;
|
|
|
|
background: white;
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
padding-left: 25rpx;
|
|
|
|
box-shadow: 0px 0px 16rpx 0px rgba(6, 0, 1, 0.1);
|
|
|
|
z-index: 999;
|
|
|
|
|
|
|
|
.fixed-text {
|
|
|
|
font-weight: bold;
|
|
|
|
font-size: 32rpx;
|
|
|
|
color: #000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
.price {
|
|
|
|
flex: 1;
|
|
|
|
font-size: 40rpx;
|
|
|
|
color: #DC2525;
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
.price::before {
|
|
|
|
font-size: 24rpx;
|
|
|
|
content: '¥';
|
|
|
|
}
|
|
|
|
|
|
|
|
.btn {
|
|
|
|
width: 233rpx;
|
|
|
|
text-align: center;
|
|
|
|
line-height: 73rpx;
|
|
|
|
background: #6A8A27;
|
|
|
|
border-radius: 11rpx;
|
|
|
|
font-weight: bold;
|
|
|
|
font-size: 32rpx;
|
|
|
|
color: #FFFFFF;
|
|
|
|
margin: 0 26rpx 0 auto;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|