14 changed files with 1050 additions and 20 deletions
@ -1,8 +1,21 @@ |
|||||
<template> |
<template> |
||||
|
<view class="bg"> |
||||
|
|
||||
|
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<style> |
<style lang="scss" scoped> |
||||
|
.bg { |
||||
|
min-height: 100vh; |
||||
|
} |
||||
</style> |
</style> |
@ -1,5 +1,134 @@ |
|||||
<template> |
<template> |
||||
|
<view class="bg"> |
||||
|
<view class="item" v-for="(item,index) in list" :key="index" @click="gotoDetailByType(item)"> |
||||
|
<image :src="showImg(item.headimg)" mode="aspectFill "></image> |
||||
|
<view class="content flex-column"> |
||||
<view> |
<view> |
||||
|
<view class="title">{{item.title}}</view> |
||||
|
<view class="tags" v-if="item.display_tags"> |
||||
|
<view class="tag" v-for="(tagItem,tagIndex) in item.display_tags.split(',').slice(0,2)" :key="tagIndex"> |
||||
|
{{tagItem}} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="item-bottom flex-between"> |
||||
|
<view class="price">{{item.price / 100}}</view> |
||||
|
<view class="btn">预订</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
</view> |
</view> |
||||
</template> |
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
list: [], |
||||
|
finished: false |
||||
|
} |
||||
|
}, |
||||
|
onReady() { |
||||
|
this.getList() |
||||
|
}, |
||||
|
onReachBottom() { |
||||
|
setTimeout(() => { |
||||
|
if (!this.finished) this.getList() |
||||
|
},1000) |
||||
|
}, |
||||
|
methods: { |
||||
|
getList() { |
||||
|
this.Post({ |
||||
|
offset: this.list.length, |
||||
|
limit: 10, |
||||
|
type_id: 23, |
||||
|
tag_id: 17, |
||||
|
sort: 'weight' |
||||
|
},'/api/product/get_product_by_tag').then(res => { |
||||
|
this.list = [...this.list, ...res.data.list] |
||||
|
|
||||
|
if (res.data.list.length < 10) { |
||||
|
this.finished = true |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.bg { |
||||
|
min-height: 100vh; |
||||
|
background-color: rgba(249, 252, 243, 1); |
||||
|
padding-bottom: 100rpx; |
||||
|
} |
||||
|
|
||||
|
.item { |
||||
|
margin: 30rpx 26rpx; |
||||
|
display: flex; |
||||
|
|
||||
|
image { |
||||
|
width: 241rpx; |
||||
|
height: 295rpx; |
||||
|
border-radius: 20rpx; |
||||
|
margin-right: 20rpx; |
||||
|
flex-shrink: 0; |
||||
|
} |
||||
|
|
||||
|
.content { |
||||
|
height: 295rpx; |
||||
|
padding-top: 12rpx; |
||||
|
justify-content: space-between; |
||||
|
flex: 1; |
||||
|
|
||||
|
.title { |
||||
|
font-weight: bold; |
||||
|
font-size: 31rpx; |
||||
|
color: #333333; |
||||
|
} |
||||
|
|
||||
|
.tags { |
||||
|
display: flex; |
||||
|
margin-top: 23rpx; |
||||
|
|
||||
|
.tag { |
||||
|
font-size: 24rpx; |
||||
|
color: #6A8A27; |
||||
|
margin-right: 11rpx; |
||||
|
} |
||||
|
.tag:not(:last-child)::after{ |
||||
|
content: '|'; |
||||
|
display: inline-block; |
||||
|
margin-left: 11rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.item-bottom { |
||||
|
.price { |
||||
|
font-size: 34.67rpx; |
||||
|
color: rgba(220, 37, 37, 1); |
||||
|
} |
||||
|
.price::before { |
||||
|
font-size: 22.67rpx; |
||||
|
content: '¥'; |
||||
|
} |
||||
|
.price::after { |
||||
|
font-size: 22.67rpx; |
||||
|
content: '起'; |
||||
|
color: rgba(153, 153, 153, 1); |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
width: 133rpx; |
||||
|
line-height: 53rpx; |
||||
|
background: #6A8A27; |
||||
|
border-radius: 12rpx; |
||||
|
text-align: center; |
||||
|
font-weight: 500; |
||||
|
font-size: 31rpx; |
||||
|
color: #FFFFFF; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,278 @@ |
|||||
|
<template> |
||||
|
<view class="bg" v-if="detail"> |
||||
|
<swiper class="top-banner" :circular="true" :interval="6000" :duration="800" :indicator-dots="true" |
||||
|
:autoplay="true" indicator-active-color="#fff"> |
||||
|
<swiper-item v-for="(item, index) in detail.listimg" :key="index"> |
||||
|
<image class="top-banner" :src="showImg(item)" mode="aspectFill" lazy-load="true"></image> |
||||
|
</swiper-item> |
||||
|
</swiper> |
||||
|
|
||||
|
<view class="top-box"> |
||||
|
<view class="price">{{detail.price / 100}}</view> |
||||
|
<view class="title">{{detail.title}}</view> |
||||
|
<view class="subtitle">{{detail.subtitle}}</view> |
||||
|
<view class="tags" v-if="detail.display_tags"> |
||||
|
<view class="tag" v-for="(item,index) in detail.display_tags.split(',').slice(0,3)" :key="index"> |
||||
|
{{item}} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="scroll-all-box" id="menus"> |
||||
|
<view :class="'scroll-menus' + (fixed ? ' fixed-menus' : '')"> |
||||
|
<view :class="'scroll-menu-item' + (type == 1 ? ' active' : '')" @click="changeMenu(1)">产品详情</view> |
||||
|
<view :class="'scroll-menu-item' + (type == 2 ? ' active' : '')" @click="changeMenu(2)">预定须知</view> |
||||
|
<view :class="'scroll-menu-item' + (type == 3 ? ' active' : '')" @click="changeMenu(3)">退改说明</view> |
||||
|
<view :class="'scroll-menu-item' + (type == 4 ? ' active' : '')" @click="changeMenu(4)">费用说明</view> |
||||
|
</view> |
||||
|
<view style="height: 85rpx" v-if="fixed"></view> |
||||
|
<view class="info-box" id="box1"> |
||||
|
<view class="info-title">产品详情</view> |
||||
|
<view class="info-content" v-html="formateRichText(detail.content)"></view> |
||||
|
</view> |
||||
|
<view class="info-box" id="box2"> |
||||
|
<view class="info-title">预定须知</view> |
||||
|
<view class="info-content" v-html="formateRichText(detail.book_info)"></view> |
||||
|
</view> |
||||
|
<view class="info-box" id="box3"> |
||||
|
<view class="info-title">退改说明</view> |
||||
|
<view class="info-content" v-html="formateRichText(detail.cancel_info)"></view> |
||||
|
</view> |
||||
|
<view class="info-box" id="box4"> |
||||
|
<view class="info-title">费用说明</view> |
||||
|
<view class="info-content" v-html="formateRichText(detail.expense_info)"></view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="btn-box flex-center"> |
||||
|
<view @click="order">立即购买</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
const device = uni.getSystemInfoSync(); |
||||
|
const ratio = device.windowWidth / 750; |
||||
|
export default { |
||||
|
data() { |
||||
|
return { |
||||
|
id: '', |
||||
|
detail: {}, |
||||
|
top: 0, |
||||
|
fixed: false, |
||||
|
type: 0, |
||||
|
down: false, |
||||
|
} |
||||
|
}, |
||||
|
onLoad(option) { |
||||
|
if (option && option.id) this.id = option.id |
||||
|
this.getDetail() |
||||
|
let rect = uni.getMenuButtonBoundingClientRect(); |
||||
|
this.top = (rect.top - device.statusBarHeight) * 2 + rect.height + device.statusBarHeight; |
||||
|
}, |
||||
|
onPageScroll(e){ |
||||
|
let query = uni.createSelectorQuery() |
||||
|
query.select("#menus").boundingClientRect(res => { |
||||
|
if(res.top < 0){ |
||||
|
this.fixed = true |
||||
|
}else{ |
||||
|
this.fixed = false |
||||
|
} |
||||
|
}).exec() |
||||
|
|
||||
|
if (this.down) { |
||||
|
return |
||||
|
}else{ |
||||
|
this.down = true |
||||
|
for(let i = 1; i < 4; i++) { |
||||
|
query.select("#box" + i).boundingClientRect(res => { |
||||
|
if(res.top < 0) { |
||||
|
this.type = i |
||||
|
} |
||||
|
}).exec() |
||||
|
} |
||||
|
this.down = false |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
getDetail() { |
||||
|
this.Post({ |
||||
|
id: this.id |
||||
|
}, '/api/product/get_product_detail').then(res => { |
||||
|
this.detail = res.data |
||||
|
}) |
||||
|
}, |
||||
|
changeMenu(e) { |
||||
|
this.down = true |
||||
|
let index = e; |
||||
|
let that = this |
||||
|
const query = uni.createSelectorQuery(); //创建节点查询器 |
||||
|
query.select('#box' + index).boundingClientRect(); //选择toViewid获取位置信息 |
||||
|
query.selectViewport().scrollOffset(); //获取页面查询位置的 |
||||
|
query.exec(function (res) { |
||||
|
let scrollTop = res[0].top + res[1].scrollTop - 110 * ratio - that.top; |
||||
|
uni.pageScrollTo({ |
||||
|
scrollTop: scrollTop + 4, |
||||
|
duration: 0 |
||||
|
}); |
||||
|
that.type = index |
||||
|
setTimeout(()=>{ |
||||
|
that.down = false |
||||
|
},1000) |
||||
|
}); |
||||
|
}, |
||||
|
// 去下单 |
||||
|
order() { |
||||
|
uni.navigateTo({ |
||||
|
url: "/subPackages/line/order?id=" + this.id |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.bg { |
||||
|
min-height: 100vh; |
||||
|
background: #F7F7F7; |
||||
|
padding-bottom: 200rpx; |
||||
|
} |
||||
|
|
||||
|
.top-banner { |
||||
|
width: 750rpx; |
||||
|
height: 413rpx; |
||||
|
} |
||||
|
|
||||
|
.top-box { |
||||
|
background: #FFFFFF; |
||||
|
padding: 26rpx; |
||||
|
|
||||
|
.price { |
||||
|
font-weight: bold; |
||||
|
font-size: 36rpx; |
||||
|
color: #DC2525; |
||||
|
} |
||||
|
|
||||
|
.price::before { |
||||
|
content: '¥'; |
||||
|
font-size: 23rpx; |
||||
|
} |
||||
|
|
||||
|
.price::after { |
||||
|
content: '/人'; |
||||
|
font-size: 23rpx; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
margin-top: 20rpx; |
||||
|
font-weight: bold; |
||||
|
font-size: 31rpx; |
||||
|
color: #333333; |
||||
|
} |
||||
|
|
||||
|
.subtitle { |
||||
|
margin-top: 20rpx; |
||||
|
font-weight: 500; |
||||
|
font-size: 24rpx; |
||||
|
color: #888888; |
||||
|
} |
||||
|
|
||||
|
.tags { |
||||
|
margin-top: 26rpx; |
||||
|
display: flex; |
||||
|
|
||||
|
.tag { |
||||
|
margin-right: 13rpx; |
||||
|
line-height: 37rpx; |
||||
|
border-radius: 7rpx; |
||||
|
border: 1px solid #6A8A27; |
||||
|
padding: 0 10rpx; |
||||
|
font-size: 24rpx; |
||||
|
color: #6A8A27; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.scroll-all-box { |
||||
|
margin: 20rpx 0; |
||||
|
background-color: #fff; |
||||
|
|
||||
|
.scroll-menus { |
||||
|
padding: 0 40rpx; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
font-size: 29rpx; |
||||
|
color: #333; |
||||
|
height: 84rpx; |
||||
|
border-bottom: 1rpx solid #d9d9d9; |
||||
|
|
||||
|
.scroll-menu-item { |
||||
|
position: relative; |
||||
|
line-height: 84rpx; |
||||
|
} |
||||
|
|
||||
|
.scroll-menu-item.active::after { |
||||
|
content: '1'; |
||||
|
font-size: 0; |
||||
|
display: block; |
||||
|
position: absolute; |
||||
|
width: 46rpx; |
||||
|
height: 6rpx; |
||||
|
border-radius: 3rpx; |
||||
|
background: #6A8A27; |
||||
|
left: 50%; |
||||
|
margin-left: -23rpx; |
||||
|
bottom: 0rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.fixed-menus { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
background: white; |
||||
|
z-index: 1; |
||||
|
} |
||||
|
|
||||
|
.info-box { |
||||
|
padding: 20rpx 40rpx; |
||||
|
|
||||
|
.info-title { |
||||
|
font-size: 35rpx; |
||||
|
font-weight: bold; |
||||
|
color: #000; |
||||
|
} |
||||
|
|
||||
|
.info-content { |
||||
|
width: 697rpx; |
||||
|
background: #FFFFFF; |
||||
|
border-radius: 20rpx; |
||||
|
padding: 22rpx 14rpx; |
||||
|
margin-top: 20rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.btn-box { |
||||
|
width: 750rpx; |
||||
|
height: 153rpx; |
||||
|
background: #FFFFFF; |
||||
|
box-shadow: 0rpx 0rpx 13rpx 0rpx rgba(82,82,82,0.25); |
||||
|
position: fixed; |
||||
|
left: 0; |
||||
|
bottom: 0; |
||||
|
|
||||
|
view { |
||||
|
width: 697rpx; |
||||
|
line-height: 73rpx; |
||||
|
text-align: center; |
||||
|
background: #6A8A27; |
||||
|
border-radius: 11rpx; |
||||
|
font-weight: bold; |
||||
|
font-size: 32rpx; |
||||
|
color: #FFFFFF; |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,579 @@ |
|||||
|
<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> |
||||
|
<navigator url="/pages/user/service/index" class="kefu-box"> |
||||
|
<view class="iconfont icon-kefu"></view> |
||||
|
<view>客服</view> |
||||
|
</navigator> |
||||
|
<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); |
||||
|
if (info && info.product_price && info.product_price !== null && info.stock !== 0) { |
||||
|
info.selectMonth = selectMonth; |
||||
|
info.selectDate = day; |
||||
|
this.selectDate = info; |
||||
|
} |
||||
|
}, |
||||
|
// 减少数量 |
||||
|
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({}); |
||||
|
}, |
||||
|
// 规格排序 |
||||
|
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: #d62828; |
||||
|
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: #d62828; |
||||
|
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 { |
||||
|
flex-shrink: 0; |
||||
|
font-size: 29rpx; |
||||
|
} |
||||
|
|
||||
|
.price { |
||||
|
flex: 1; |
||||
|
font-size: 36rpx; |
||||
|
color: #d62828; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.kefu-box { |
||||
|
flex-shrink: 0; |
||||
|
text-align: center; |
||||
|
font-size: 23rpx; |
||||
|
color: #666; |
||||
|
width: 100rpx; |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
width: 267rpx; |
||||
|
text-align: center; |
||||
|
line-height: 113rpx; |
||||
|
background: #d62828; |
||||
|
color: #fff; |
||||
|
font-size: 36rpx; |
||||
|
font-weight: 500; |
||||
|
margin-left: 30rpx; |
||||
|
} |
||||
|
} |
||||
|
</style> |
Loading…
Reference in new issue