@ -0,0 +1,236 @@ | |||
<template> | |||
<view class="flex card"> | |||
<view> | |||
<uv-checkbox-group | |||
v-model="checkboxValue" | |||
shape="circle" | |||
@change="onCheckChange" | |||
> | |||
<uv-checkbox | |||
size="36rpx" | |||
icon-size="36rpx" | |||
activeColor="#7451DE" | |||
:name="1" | |||
></uv-checkbox> | |||
</uv-checkbox-group> | |||
</view> | |||
<view class="flex right" @click="jumpToProductDetail"> | |||
<view class="img-box"> | |||
<image class="img" :src="data.url" mode="aspectFit"></image> | |||
</view> | |||
<view class="info"> | |||
<view class="title">{{ data.name }}</view> | |||
<view class="desc">{{ data.desc }}</view> | |||
<view class="flex price-box"> | |||
<view class="flex price">¥<text class="highlight">{{ data.price.toFixed(2) }}</text></view> | |||
</view> | |||
<view class="flex tool"> | |||
<view class="flex count"> | |||
规格:<text class="highlight">{{ data.countDesc || data.count }}</text> | |||
<uv-icon name="arrow-down" color="#7451DE" size="24rpx" :bold="true"></uv-icon> | |||
</view> | |||
<button class="flex btn" @click.stop="openPicker">编辑</button> | |||
</view> | |||
</view> | |||
</view> | |||
<view v-if="data.customized" class="sup customized"> | |||
定制组合 | |||
</view> | |||
<view v-else-if="data.free" class="sup free"> | |||
自定组合 | |||
</view> | |||
<uv-picker ref="picker" :columns="[data.options]" keyName="label" confirmColor="#7451DE" @confirm="onChange"></uv-picker> | |||
</view> | |||
</template> | |||
<script> | |||
export default { | |||
props: { | |||
data: { | |||
type: Object, | |||
default() { | |||
return {} | |||
} | |||
}, | |||
mode: { | |||
type: String, | |||
default: 'read' | |||
}, | |||
}, | |||
data() { | |||
return { | |||
checkboxValue : [], | |||
} | |||
}, | |||
computed: { | |||
checked: { | |||
set(val) { | |||
this.checkboxValue = val ? [1] : [] | |||
if (this.data.selected == val) { | |||
return | |||
} | |||
this.$emit('select', val) | |||
}, | |||
get() { | |||
return this.checkboxValue[0] == 1 ? true : false | |||
} | |||
} | |||
}, | |||
watch: { | |||
data: { | |||
handler(val) { | |||
this.checked = val.selected | |||
}, | |||
immediate: true, | |||
deep: true, | |||
} | |||
}, | |||
methods: { | |||
onCheckChange(arr) { | |||
this.checked = arr[0] == 1 ? true : false | |||
}, | |||
openPicker() { | |||
console.log(this.data.id, 'openPicker') | |||
this.$refs.picker.open(); | |||
}, | |||
onChange(e) { | |||
const target = e.value[0] | |||
console.log('onChange', target) | |||
this.$emit('change', { price: target.value, count: target.count, countDesc: target.label }) | |||
}, | |||
jumpToProductDetail() { | |||
console.log(this.data.id, 'jumpToProductDetail') | |||
this.$utils.navigateTo(`/pages_order/product/productDetail?id=${this.data.id}`) | |||
}, | |||
}, | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.card { | |||
position: relative; | |||
height: 240rpx; | |||
padding: 0 32rpx; | |||
background-image: linear-gradient(#FAFAFF, #F3F3F3); | |||
border: 2rpx solid #FFFFFF; | |||
border-radius: 32rpx; | |||
box-sizing: border-box; | |||
column-gap: 24rpx; | |||
overflow: hidden; | |||
/deep/ .uv-checkbox__label-wra { | |||
padding: 0; | |||
} | |||
} | |||
.right { | |||
flex: 1; | |||
column-gap: 24rpx; | |||
} | |||
.img { | |||
&-box { | |||
width: 144rpx; | |||
height: 144rpx; | |||
border-radius: 16rpx; | |||
overflow: hidden; | |||
} | |||
width: 100%; | |||
height: 100%; | |||
} | |||
.info { | |||
flex: 1; | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
line-height: 1.4; | |||
font-size: 26rpx; | |||
color: #8B8B8B; | |||
.title { | |||
font-weight: 600; | |||
font-size: 28rpx; | |||
color: #000000; | |||
} | |||
.desc { | |||
margin-top: 8rpx; | |||
line-height: 1.5; | |||
} | |||
.price { | |||
&-box { | |||
margin-top: 8rpx; | |||
justify-content: flex-start; | |||
column-gap: 20rpx; | |||
} | |||
font-weight: 600; | |||
font-size: 24rpx; | |||
color: #7451DE; | |||
.highlight { | |||
margin: 0 8rpx; | |||
font-size: 32rpx; | |||
} | |||
&-origin { | |||
font-size: 28rpx; | |||
line-height: 1; | |||
text-decoration: line-through; | |||
} | |||
} | |||
.tool { | |||
margin-top: 8rpx; | |||
justify-content: space-between; | |||
.count { | |||
.highlight { | |||
margin: 0 8rpx; | |||
color: #252545; | |||
} | |||
} | |||
.btn { | |||
padding: 8rpx 40rpx; | |||
font-family: PingFang SC; | |||
font-weight: 600; | |||
font-size: 28rpx; | |||
line-height: 1.5; | |||
color: #FFFFFF; | |||
background: #7451DE; | |||
border-radius: 30rpx; | |||
} | |||
} | |||
} | |||
.sup { | |||
position: absolute; | |||
top: 28rpx; | |||
right: -60rpx; | |||
padding: 5rpx 52rpx; | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 28rpx; | |||
line-height: 1.5; | |||
white-space: nowrap; | |||
transform: rotate(45deg); | |||
&.customized { | |||
color: #FFFFFF; | |||
background: #252545; | |||
} | |||
&.free { | |||
color: #252545; | |||
background: #D7D7FF; | |||
} | |||
} | |||
</style> |
@ -0,0 +1,260 @@ | |||
<template> | |||
<view class="page"> | |||
<navbar/> | |||
<view class="user"> | |||
<uv-checkbox-group | |||
shape="circle" | |||
v-model="checkboxValue"> | |||
<uv-swipe-action> | |||
<view | |||
v-for="(item, index) in list" | |||
:key="index"> | |||
<view style="margin-top: 20rpx;"></view> | |||
<uv-swipe-action-item | |||
:options="options"> | |||
<view class="item"> | |||
<view class="checkbox"> | |||
<uv-checkbox | |||
:name="item.id" | |||
activeColor="#FA5A0A" | |||
size="40rpx" | |||
icon-size="35rpx" | |||
></uv-checkbox> | |||
</view> | |||
<image | |||
class="image" | |||
src="https://img95.699pic.com/photo/50058/1378.jpg_wh860.jpg" | |||
mode=""></image> | |||
<view class="info"> | |||
<view class="title"> | |||
<view class=""> | |||
{{ item.title }} | |||
</view> | |||
<view class=""> | |||
<uv-number-box v-model="item.num" | |||
@change="valChange"></uv-number-box> | |||
</view> | |||
</view> | |||
<view class="unit"> | |||
规格:{{ item.unit }} | |||
<uv-icon name="arrow-down"></uv-icon> | |||
</view> | |||
<view class="price"> | |||
¥<text>{{ item.price }}</text>元 | |||
</view> | |||
</view> | |||
</view> | |||
</uv-swipe-action-item> | |||
</view> | |||
</uv-swipe-action> | |||
</uv-checkbox-group> | |||
<view class="action"> | |||
<view class="icon"> | |||
<image src="/static/image/cart/1.png" mode=""></image> | |||
<view class="num"> | |||
{{ checkboxValue.length }} | |||
</view> | |||
</view> | |||
<view class="price"> | |||
<view class="count"> | |||
合计 | |||
<view class=""> | |||
¥<text>{{ totalPrice }}</text> | |||
</view> | |||
</view> | |||
<view class="text"> | |||
共{{ checkboxValue.length }}件,已享受更低优惠 | |||
</view> | |||
</view> | |||
<view class="btn"> | |||
去结算 | |||
</view> | |||
</view> | |||
</view> | |||
<tabber select="cart" /> | |||
</view> | |||
</template> | |||
<script> | |||
import tabber from '@/components/base/tabbar.vue' | |||
export default { | |||
components: { | |||
tabber, | |||
}, | |||
data() { | |||
return { | |||
value : 0, | |||
checkboxValue : [], | |||
options: [ | |||
{ | |||
text: '删除', | |||
style: { | |||
backgroundColor: '#FA5A0A' | |||
} | |||
}, | |||
], | |||
list : [ | |||
{ | |||
id : 1, | |||
title : '桌布租赁', | |||
num : 1, | |||
price : 299, | |||
unit : '120*40*75【桌子尺寸】', | |||
}, | |||
{ | |||
id : 2, | |||
title : '桌布租赁', | |||
num : 1, | |||
price : 299, | |||
unit : '120*40*75【桌子尺寸】', | |||
}, | |||
], | |||
} | |||
}, | |||
computed: { | |||
totalPrice(){ | |||
if (!this.checkboxValue.length) { | |||
return 0 | |||
} | |||
let price = 0 | |||
this.list.forEach(n => { | |||
if(this.checkboxValue.includes(n.id)){ | |||
price += n.price * n.num | |||
} | |||
}) | |||
return price | |||
}, | |||
}, | |||
methods: { | |||
valChange(){ | |||
}, | |||
} | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.page { | |||
padding-bottom: 200rpx; | |||
/deep/ .uv-swipe-action{ | |||
width: 100%; | |||
} | |||
} | |||
.user { | |||
.item{ | |||
background-color: #fff; | |||
display: flex; | |||
padding: 30rpx; | |||
.checkbox{ | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
} | |||
.image{ | |||
width: 200rpx; | |||
height: 200rpx; | |||
border-radius: 20rpx; | |||
} | |||
.info{ | |||
flex: 1; | |||
.title{ | |||
display: flex; | |||
padding: 10rpx 20rpx; | |||
justify-content: space-between; | |||
} | |||
.unit{ | |||
font-size: 24rpx; | |||
padding: 10rpx 20rpx; | |||
color: #717171; | |||
display: flex; | |||
align-items: center; | |||
} | |||
.price{ | |||
color: $uni-color; | |||
font-size: 28rpx; | |||
padding: 10rpx 20rpx; | |||
text{ | |||
font-size: 36rpx; | |||
font-weight: 900; | |||
} | |||
} | |||
} | |||
} | |||
.action{ | |||
width: 700rpx; | |||
position: fixed; | |||
bottom: 220rpx; | |||
left: 25rpx; | |||
background-color: #fff; | |||
height: 100rpx; | |||
border-radius: 50rpx; | |||
box-shadow: 0 0 6rpx 6rpx #00000010; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
overflow: hidden; | |||
z-index: 999; | |||
.icon{ | |||
position: relative; | |||
width: 80rpx; | |||
height: 80rpx; | |||
margin: 0 20rpx; | |||
image{ | |||
width: 80rpx; | |||
height: 80rpx; | |||
} | |||
.num{ | |||
position: absolute; | |||
right: 10rpx; | |||
top: 0rpx; | |||
background-color: $uni-color; | |||
color: #fff; | |||
font-size: 18rpx; | |||
border-radius: 50%; | |||
height: 30rpx; | |||
width: 30rpx; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
} | |||
} | |||
.price{ | |||
.count{ | |||
display: flex; | |||
font-size: 26rpx; | |||
align-items: center; | |||
view{ | |||
color: $uni-color; | |||
margin-left: 10rpx; | |||
text{ | |||
font-size: 32rpx; | |||
font-weight: 900; | |||
} | |||
} | |||
} | |||
.text{ | |||
font-size: 20rpx; | |||
color: #717171; | |||
} | |||
} | |||
.btn{ | |||
margin-left: auto; | |||
background-color: $uni-color; | |||
height: 100%; | |||
padding: 0 50rpx; | |||
color: #fff; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
} | |||
} | |||
} | |||
</style> |
@ -1,260 +1,502 @@ | |||
<template> | |||
<view class="page"> | |||
<navbar/> | |||
<view class="page__view"> | |||
<navbar bgColor="#F3F2F7" > | |||
<image class="nav-icon" src="@/static/image/icon-nav.png" mode="widthFix"></image> | |||
</navbar> | |||
<view class="user"> | |||
<uv-checkbox-group | |||
shape="circle" | |||
v-model="checkboxValue"> | |||
<uv-swipe-action> | |||
<view | |||
v-for="(item, index) in list" | |||
:key="index"> | |||
<view style="margin-top: 20rpx;"></view> | |||
<uv-swipe-action-item | |||
:options="options"> | |||
<view class="item"> | |||
<view class="checkbox"> | |||
<uv-checkbox | |||
:name="item.id" | |||
activeColor="#FA5A0A" | |||
size="40rpx" | |||
icon-size="35rpx" | |||
></uv-checkbox> | |||
</view> | |||
<image | |||
class="image" | |||
src="https://img95.699pic.com/photo/50058/1378.jpg_wh860.jpg" | |||
mode=""></image> | |||
<view class="info"> | |||
<view class="title"> | |||
<view class=""> | |||
{{ item.title }} | |||
</view> | |||
<view class=""> | |||
<uv-number-box v-model="item.num" | |||
@change="valChange"></uv-number-box> | |||
</view> | |||
</view> | |||
<view class="unit"> | |||
规格:{{ item.unit }} | |||
<uv-icon name="arrow-down"></uv-icon> | |||
</view> | |||
<view class="price"> | |||
¥<text>{{ item.price }}</text>元 | |||
</view> | |||
</view> | |||
</view> | |||
</uv-swipe-action-item> | |||
</view> | |||
</uv-swipe-action> | |||
</uv-checkbox-group> | |||
<view class="action"> | |||
<view class="icon"> | |||
<image src="/static/image/cart/1.png" mode=""></image> | |||
<view class="num"> | |||
{{ checkboxValue.length }} | |||
<view class="main"> | |||
<view class="top"> | |||
<view class="flex header"> | |||
<view class="flex label"> | |||
<view>购物车</view> | |||
<view v-if="total" class="desc">{{ `(${total})` }}</view> | |||
</view> | |||
<button v-if="mode == 'edit'" class="btn" @click="onLeaveEdit">完成</button> | |||
<button v-else class="btn" @click="onEnterEdit">管理</button> | |||
</view> | |||
<view class="price"> | |||
<view class="count"> | |||
合计 | |||
<view class=""> | |||
¥<text>{{ totalPrice }}</text> | |||
</view> | |||
<!-- 搜索栏 --> | |||
<view class="search"> | |||
<uv-search | |||
v-model="keyword" | |||
placeholder="请输入要查询的内容" | |||
placeholderColor="#C6C6C6" | |||
searchIconColor="#8B8B8B" | |||
:searchIconSize="40" | |||
:inputStyle="{ | |||
'font-family': 'PingFang SC', | |||
'font-weight': 400, | |||
'font-size': '28rpx', | |||
'line-height': 1.4, | |||
'padding': '12rpx 0', | |||
}" | |||
bgColor="#fff" | |||
:showAction="false" | |||
@search="search" | |||
></uv-search> | |||
</view> | |||
</view> | |||
<template v-if="total"> | |||
<view> | |||
<view class="card" v-for="(item, index) in list" :key="item.id"> | |||
<productCard | |||
:data="item" | |||
@select="onSelect(index, $event)" | |||
@change="onChange(index, $event)" | |||
></productCard> | |||
</view> | |||
<view class="text"> | |||
共{{ checkboxValue.length }}件,已享受更低优惠 | |||
</view> | |||
</template> | |||
<template v-else> | |||
<view class="flex flex-column empty"> | |||
<view class="empty-title">购物车为空</view> | |||
<view class="empty-desc">请将喜欢的商品加入购物袋</view> | |||
</view> | |||
<view class="recommend"> | |||
<view v-for="item in recommendList" :key="item.id"> | |||
<recommendProductCard | |||
:data="item" | |||
cardStyle="width: 100%; height: 210px;" | |||
imgStyle="width: 100%; height: 110px;" | |||
></recommendProductCard> | |||
</view> | |||
</view> | |||
<view class="btn"> | |||
去结算 | |||
</template> | |||
</view> | |||
<view class="flex bottom"> | |||
<template v-if="mode == 'edit'"> | |||
<view class="flex bar bar-edit"> | |||
<button class="btn" @click="onLeaveEdit">取消</button> | |||
<button class="btn" @click="onDelete">删除</button> | |||
</view> | |||
</view> | |||
</template> | |||
<template v-else> | |||
<view class="flex bar bar-settle"> | |||
<view class="flex info"> | |||
<image class="icon" src="@/pages_order/static/cart/cart-icon.png" mode="widthFix"></image> | |||
<view> | |||
<view class="flex row">已选<text class="count">{{ `${selectedList.length} 件` }}</text>已享受更低优惠</view> | |||
<view class="flex row">合计<text class="unit">¥</text><text class="price">{{ totalPrice }}</text></view> | |||
</view> | |||
</view> | |||
<button class="btn">去结算</button> | |||
</view> | |||
</template> | |||
</view> | |||
<tabber select="cart" /> | |||
</view> | |||
</template> | |||
<script> | |||
import mixinsList from '@/mixins/list.js' | |||
import tabber from '@/components/base/tabbar.vue' | |||
import productCard from '@/components/cart/productCard.vue' | |||
import recommendProductCard from '@/components/product/productCard.vue' | |||
export default { | |||
mixins: [mixinsList], | |||
components: { | |||
productCard, | |||
recommendProductCard, | |||
tabber, | |||
}, | |||
data() { | |||
return { | |||
// todo | |||
mixinsListApi: '', | |||
// todo | |||
keyword: '', | |||
mode: 'read', | |||
selectedList: [], | |||
recommendList: [], | |||
} | |||
}, | |||
computed: { | |||
// selectedList() { | |||
// return this.list.filter(item => item.selected) | |||
// }, | |||
totalPrice() { | |||
return this.selectedList.reduce((price, item) => { | |||
// return price + item.price * (item.count || 1) | |||
return price + item.price | |||
}, 0) | |||
}, | |||
}, | |||
data() { | |||
return { | |||
value : 0, | |||
checkboxValue : [], | |||
options: [ | |||
methods: { | |||
// 搜素 | |||
search() { | |||
// todo | |||
}, | |||
getData() { | |||
this.list = [ | |||
{ | |||
text: '删除', | |||
style: { | |||
backgroundColor: '#FA5A0A' | |||
} | |||
}, | |||
], | |||
list : [ | |||
id: '001', | |||
url: '/pages_order/static/index/recommend-pic.png', | |||
name: '月度装定制营养包', | |||
price: 688, | |||
count: 1, | |||
countDesc: '1月装', | |||
options: [ | |||
{ id: '001', label: '1月装', count: 1, value: 688 }, | |||
{ id: '002', label: '3月装', count: 3, value: 688*3 }, | |||
{ id: '003', label: '6月装', count: 6, value: 688*6 }, | |||
], | |||
customized: true, | |||
checked: false, | |||
}, | |||
{ | |||
id : 1, | |||
title : '桌布租赁', | |||
num : 1, | |||
price : 299, | |||
unit : '120*40*75【桌子尺寸】', | |||
id: '002', | |||
url: '/pages_order/static/index/recommend-pic.png', | |||
name: '月度装定制营养包', | |||
price: 688, | |||
count: 1, | |||
countDesc: '1月装', | |||
options: [ | |||
{ id: '001', label: '1月装', count: 1, value: 688 }, | |||
{ id: '002', label: '3月装', count: 3, value: 688*3 }, | |||
{ id: '003', label: '6月装', count: 6, value: 688*6 }, | |||
], | |||
free: true, | |||
checked: false, | |||
}, | |||
{ | |||
id : 2, | |||
title : '桌布租赁', | |||
num : 1, | |||
price : 299, | |||
unit : '120*40*75【桌子尺寸】', | |||
id: '003', | |||
url: '/pages_order/static/index/recommend-pic.png', | |||
name: '月度装定制营养包', | |||
price: 688, | |||
count: 1, | |||
countDesc: '1月装', | |||
options: [ | |||
{ id: '001', label: '1月装', count: 1, value: 688 }, | |||
{ id: '002', label: '3月装', count: 3, value: 688*3 }, | |||
{ id: '003', label: '6月装', count: 6, value: 688*6 }, | |||
], | |||
free: true, | |||
checked: false, | |||
}, | |||
], | |||
} | |||
}, | |||
computed: { | |||
totalPrice(){ | |||
if (!this.checkboxValue.length) { | |||
return 0 | |||
{ | |||
id: '004', | |||
url: '/pages_order/static/index/recommend-pic.png', | |||
name: '月度装定制营养包', | |||
price: 688, | |||
count: 1, | |||
countDesc: '1月装', | |||
options: [ | |||
{ id: '001', label: '1月装', count: 1, value: 688 }, | |||
{ id: '002', label: '3月装', count: 3, value: 688*3 }, | |||
{ id: '003', label: '6月装', count: 6, value: 688*6 }, | |||
], | |||
free: true, | |||
checked: false, | |||
}, | |||
{ | |||
id: '005', | |||
url: '/pages_order/static/index/recommend-pic.png', | |||
name: '月度装定制营养包', | |||
price: 688, | |||
count: 1, | |||
countDesc: '1月装', | |||
options: [ | |||
{ id: '001', label: '1月装', count: 1, value: 688 }, | |||
{ id: '002', label: '3月装', count: 3, value: 688*3 }, | |||
{ id: '003', label: '6月装', count: 6, value: 688*6 }, | |||
], | |||
free: true, | |||
checked: false, | |||
}, | |||
] | |||
this.total = this.list.length | |||
this.getDataThen && this.getDataThen(this.list, this.total) | |||
}, | |||
getDataThen(records, total) { | |||
console.log('getDataThen') | |||
// todo | |||
if (total) { | |||
return | |||
} | |||
let price = 0 | |||
this.list.forEach(n => { | |||
if(this.checkboxValue.includes(n.id)){ | |||
price += n.price * n.num | |||
} | |||
}) | |||
return price | |||
this.recommendList = [ | |||
{ | |||
id: '001', | |||
url: '/pages_order/static/index/recommend-pic.png', | |||
name: '月度装定制营养包', | |||
sales: 24770, | |||
price: 688.00, | |||
originalPrice: 1664, | |||
}, | |||
{ | |||
id: '002', | |||
url: '/pages_order/static/index/recommend-pic.png', | |||
name: '月度装定制营养包', | |||
sales: 24770, | |||
price: 688.00, | |||
originalPrice: 1664, | |||
}, | |||
{ | |||
id: '003', | |||
url: '/pages_order/static/index/recommend-pic.png', | |||
name: '月度装定制营养包', | |||
sales: 24770, | |||
price: 688.00, | |||
originalPrice: 1664, | |||
}, | |||
{ | |||
id: '004', | |||
url: '/pages_order/static/index/recommend-pic.png', | |||
name: '月度装定制营养包', | |||
sales: 24770, | |||
price: 688.00, | |||
originalPrice: 1664, | |||
}, | |||
] | |||
}, | |||
}, | |||
methods: { | |||
valChange(){ | |||
updateSelectedList() { | |||
this.selectedList = this.list.filter(item => item.selected) | |||
}, | |||
onSelect(index, selected) { | |||
console.log('onSelect', index, selected) | |||
this.list[index].selected = selected | |||
// todo | |||
this.updateSelectedList() | |||
}, | |||
onChange(index, obj) { | |||
console.log('onChange', index, obj) | |||
// todo: check | |||
this.list[index].price = obj.price | |||
this.list[index].count = obj.count | |||
this.list[index].countDesc = obj.countDesc | |||
// todo | |||
this.updateSelectedList() | |||
}, | |||
onEnterEdit() { | |||
this.mode = 'edit' | |||
}, | |||
} | |||
onLeaveEdit() { | |||
this.mode = 'read' | |||
}, | |||
onDelete() { | |||
uni.showModal({ | |||
title: '确认删除?', | |||
success : e => { | |||
if(e.confirm){ | |||
// todo | |||
this.list = this.list.filter(item => !item.selected) | |||
this.total = this.list.length | |||
} | |||
} | |||
}) | |||
}, | |||
}, | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.page { | |||
padding-bottom: 200rpx; | |||
/deep/ .uv-swipe-action{ | |||
width: 100%; | |||
.page__view { | |||
width: 100vw; | |||
min-height: 100vh; | |||
background-color: $uni-bg-color; | |||
position: relative; | |||
/deep/ .nav-bar__view { | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
} | |||
.nav-icon { | |||
width: 200rpx; | |||
height: auto; | |||
vertical-align: top; | |||
} | |||
/deep/ .tabbar-box .tabbar { | |||
z-index: 9999; | |||
} | |||
} | |||
.user { | |||
.item{ | |||
background-color: #fff; | |||
display: flex; | |||
padding: 30rpx; | |||
.checkbox{ | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
} | |||
.image{ | |||
width: 200rpx; | |||
height: 200rpx; | |||
border-radius: 20rpx; | |||
} | |||
.info{ | |||
.main { | |||
padding: calc(var(--status-bar-height) + 288rpx) 32rpx 186rpx 32rpx; | |||
} | |||
.top { | |||
position: fixed; | |||
top: calc(var(--status-bar-height) + 120rpx); | |||
left: 0; | |||
width: 100%; | |||
height: 168rpx; | |||
padding: 16rpx 32rpx 8rpx 32rpx; | |||
background-color: $uni-bg-color; | |||
box-sizing: border-box; | |||
z-index: 1; | |||
} | |||
.header { | |||
justify-content: space-between; | |||
column-gap: 4rpx; | |||
.label { | |||
font-family: PingFang SC; | |||
font-weight: 600; | |||
font-size: 36rpx; | |||
line-height: 1.2; | |||
color: #252545; | |||
} | |||
.desc { | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 24rpx; | |||
line-height: 1.4; | |||
color: #2A2A2A; | |||
} | |||
.btn { | |||
font-family: PingFang SC; | |||
font-weight: 600; | |||
font-size: 28rpx; | |||
line-height: 1.5; | |||
color: #FFFFFF; | |||
padding: 8rpx 32rpx; | |||
background-image: linear-gradient(to right, #4B348F, #845CFA); | |||
border-radius: 30rpx; | |||
} | |||
} | |||
.search { | |||
margin: 24rpx 0 40rpx 0; | |||
/deep/ .uv-search__content__icon { | |||
margin-top: 2rpx; | |||
} | |||
} | |||
.empty { | |||
width: 100%; | |||
font-family: PingFang SC; | |||
line-height: 1.4; | |||
padding: 104rpx 0; | |||
box-sizing: border-box; | |||
&-title { | |||
font-weight: 500; | |||
font-size: 32rpx; | |||
color: #000000; | |||
} | |||
&-desc { | |||
margin-top: 16rpx; | |||
font-weight: 400; | |||
font-size: 26rpx; | |||
color: #8B8B8B; | |||
} | |||
} | |||
.recommend { | |||
margin-top: 40rpx; | |||
display: grid; | |||
grid-template-columns: repeat(2, 1fr); | |||
gap: 32rpx; | |||
} | |||
.card { | |||
margin-top: 32rpx; | |||
} | |||
.bottom { | |||
position: fixed; | |||
left: 0; | |||
bottom: calc(env(safe-area-inset-bottom) + #{$tabbar-height}); | |||
width: 100vw; | |||
height: 122rpx; | |||
padding: 0 40rpx; | |||
background: #FFFFFF; | |||
box-sizing: border-box; | |||
} | |||
.bar { | |||
width: 100%; | |||
&-edit { | |||
column-gap: 32rpx; | |||
.btn { | |||
flex: 1; | |||
.title{ | |||
display: flex; | |||
padding: 10rpx 20rpx; | |||
justify-content: space-between; | |||
} | |||
.unit{ | |||
font-size: 24rpx; | |||
padding: 10rpx 20rpx; | |||
color: #717171; | |||
display: flex; | |||
align-items: center; | |||
} | |||
.price{ | |||
color: $uni-color; | |||
font-size: 28rpx; | |||
padding: 10rpx 20rpx; | |||
text{ | |||
font-size: 36rpx; | |||
font-weight: 900; | |||
} | |||
} | |||
padding: 16rpx 0; | |||
font-family: PingFang SC; | |||
font-weight: 500; | |||
font-size: 36rpx; | |||
line-height: 1; | |||
color: #252545; | |||
border: 2rpx solid #252545; | |||
border-radius: 41rpx; | |||
} | |||
} | |||
.action{ | |||
width: 700rpx; | |||
position: fixed; | |||
bottom: 220rpx; | |||
left: 25rpx; | |||
background-color: #fff; | |||
height: 100rpx; | |||
border-radius: 50rpx; | |||
box-shadow: 0 0 6rpx 6rpx #00000010; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
overflow: hidden; | |||
z-index: 999; | |||
.icon{ | |||
position: relative; | |||
width: 80rpx; | |||
height: 80rpx; | |||
margin: 0 20rpx; | |||
image{ | |||
width: 80rpx; | |||
height: 80rpx; | |||
&-settle { | |||
justify-content: space-between; | |||
.info { | |||
column-gap: 16rpx; | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 24rpx; | |||
line-height: 1.4; | |||
color: #626262; | |||
.icon { | |||
width: 76rpx; | |||
height: auto; | |||
} | |||
.num{ | |||
position: absolute; | |||
right: 10rpx; | |||
top: 0rpx; | |||
background-color: $uni-color; | |||
color: #fff; | |||
font-size: 18rpx; | |||
border-radius: 50%; | |||
height: 30rpx; | |||
width: 30rpx; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
.row { | |||
justify-content: flex-start; | |||
} | |||
} | |||
.price{ | |||
.count{ | |||
display: flex; | |||
font-size: 26rpx; | |||
align-items: center; | |||
view{ | |||
color: $uni-color; | |||
margin-left: 10rpx; | |||
text{ | |||
font-size: 32rpx; | |||
font-weight: 900; | |||
} | |||
} | |||
.count, | |||
.unit, | |||
.price { | |||
font-weight: 500; | |||
color: #7451DE; | |||
} | |||
.count { | |||
margin: 0 12rpx; | |||
} | |||
.text{ | |||
font-size: 20rpx; | |||
color: #717171; | |||
.unit { | |||
margin: 0 8rpx; | |||
} | |||
.price { | |||
font-size: 40rpx; | |||
} | |||
} | |||
.btn{ | |||
margin-left: auto; | |||
background-color: $uni-color; | |||
height: 100%; | |||
padding: 0 50rpx; | |||
color: #fff; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
.btn { | |||
padding: 16rpx 46rpx; | |||
color: #FFFFFF; | |||
font-family: PingFang SC; | |||
font-weight: 500; | |||
font-size: 36rpx; | |||
line-height: 1; | |||
background-image: linear-gradient(to right, #4B348F, #845CFA); | |||
border-radius: 41rpx; | |||
} | |||
} | |||
} | |||
</style> |
@ -0,0 +1,137 @@ | |||
<template> | |||
<view class="card"> | |||
<view class="flex header"> | |||
<view class="avatar"> | |||
<image class="avatar-img" :src="data.avatar"></image> | |||
</view> | |||
<view class="info"> | |||
<view class="name">{{ data.userName }}</view> | |||
<view>{{ `${data.countDesc} | ${$dayjs(data.createTime).format('YYYY-MM-DD')}` }}</view> | |||
</view> | |||
</view> | |||
<view class="section content">{{ data.content }}</view> | |||
<view class="flex section imgs"> | |||
<image class="img" | |||
v-for="(item, iIdx) in data.images" | |||
:key="iIdx" :src="item" | |||
mode="scaleToFill" | |||
></image> | |||
</view> | |||
<view class="section score"> | |||
<view class="flex score-item"> | |||
<view class="score-item-label">产品服务度</view> | |||
<uv-rate :value="data.productServeScore" size="48rpx" gutter="16rpx" activeColor="#F7BA1E" :allowHalf="true" readonly></uv-rate> | |||
</view> | |||
<view class="flex score-item"> | |||
<view class="score-item-label">问卷体验</view> | |||
<uv-rate :value="data.questionExperienceScore" size="48rpx" gutter="16rpx" activeColor="#F7BA1E" :allowHalf="true" readonly></uv-rate> | |||
</view> | |||
<view class="flex score-item"> | |||
<view class="score-item-label">物流速度</view> | |||
<uv-rate :value="data.deliverySpeedScore" size="48rpx" gutter="16rpx" activeColor="#F7BA1E" :allowHalf="true" :minCount="0.5" readonly></uv-rate> | |||
</view> | |||
</view> | |||
</view> | |||
</template> | |||
<script> | |||
export default { | |||
props: { | |||
data: { | |||
type: Object, | |||
default() { | |||
return {} | |||
} | |||
}, | |||
} | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.card { | |||
width: 100%; | |||
padding: 32rpx; | |||
box-sizing: border-box; | |||
background: #FAFAFF; | |||
border: 2rpx solid #FFFFFF; | |||
border-radius: 32rpx; | |||
} | |||
.header { | |||
justify-content: flex-start; | |||
column-gap: 24rpx; | |||
.avatar { | |||
width: 100rpx; | |||
height: 100rpx; | |||
border: 4rpx solid #FFFFFF; | |||
border-radius: 50%; | |||
overflow: hidden; | |||
&-img { | |||
width: 100%; | |||
height: 100%; | |||
} | |||
} | |||
.info { | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 24rpx; | |||
line-height: 1.5; | |||
color: #8B8B8B; | |||
.name { | |||
font-weight: 600; | |||
font-size: 36rpx; | |||
line-height: 1.2; | |||
color: #252545; | |||
margin-bottom: 8rpx; | |||
} | |||
} | |||
} | |||
.section { | |||
margin-top: 24rpx; | |||
} | |||
.content { | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 32rpx; | |||
line-height: 1.4; | |||
color: #181818; | |||
} | |||
.imgs { | |||
justify-content: flex-start; | |||
flex-wrap: wrap; | |||
gap: 24rpx; | |||
.img { | |||
width: 190rpx; | |||
height: 190rpx; | |||
} | |||
} | |||
.score { | |||
&-item { | |||
padding: 12rpx 0; | |||
justify-content: space-between; | |||
& + & { | |||
margin-top: 4rpx; | |||
} | |||
&-label { | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 26rpx; | |||
line-height: 1.4; | |||
color: #181818; | |||
} | |||
} | |||
} | |||
</style> |
@ -0,0 +1,196 @@ | |||
<template> | |||
<view class="page__view"> | |||
<navbar :title="title" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="#FFFFFF" /> | |||
<view class="main"> | |||
<view class="tabs"> | |||
<uv-tabs | |||
:list="tabs" | |||
:scrollable="false" | |||
lineColor="#7451DE" | |||
lineWidth="48rpx" | |||
lineHeight="4rpx" | |||
:activeStyle="{ | |||
'font-family': 'PingFang SC', | |||
'font-weight': 500, | |||
'font-size': '32rpx', | |||
'line-height': 1.4, | |||
'color': '#7451DE', | |||
}" | |||
:inactiveStyle="{ | |||
'font-family': 'PingFang SC', | |||
'font-weight': 400, | |||
'font-size': '32rpx', | |||
'line-height': 1.4, | |||
'color': '#181818', | |||
}" | |||
@click="clickTabs" | |||
></uv-tabs> | |||
</view> | |||
<view class="comment"> | |||
<view class="comment-item" v-for="item in list" :key="item.id"> | |||
<commentCard :data="item"></commentCard> | |||
</view> | |||
</view> | |||
</view> | |||
</view> | |||
</template> | |||
<script> | |||
import mixinsList from '@/mixins/list.js' | |||
import commentCard from '@/pages_order/comment/commentCard.vue' | |||
export default { | |||
mixins: [mixinsList], | |||
components: { | |||
commentCard, | |||
}, | |||
data() { | |||
return { | |||
title: '用户评价', | |||
tabs: [ | |||
{ name: '全部' }, | |||
{ name: '有图/视频' }, | |||
{ name: '最新' }, | |||
], | |||
id: null, | |||
creator: null, | |||
mixinsListApi: '', | |||
} | |||
}, | |||
onShow() { | |||
console.log('onShow') | |||
}, | |||
onLoad(arg) { | |||
console.log('onLoad') | |||
const { title, id, creator } = arg | |||
title && (this.title = title) | |||
this.id = id | |||
this.creator = creator | |||
// todo set queryParams | |||
this.getData() | |||
}, | |||
methods: { | |||
//点击tab栏 | |||
clickTabs({ index }) { | |||
if (index == 0) { | |||
delete this.queryParams.status | |||
} else { | |||
this.queryParams.status = index - 1 | |||
} | |||
this.getData() | |||
}, | |||
// todo: delete | |||
getData() { | |||
this.list = [ | |||
{ | |||
id: '001', | |||
userName: '战斗世界', | |||
avatar: '/pages_order/static/report/avatar.png', | |||
countDesc: '三月装', | |||
createTime: '2023-04-18', | |||
content: '包装很精致,性价比非常高,终于收到啦,期待效果,每日一包,超级方便,真的能坚持服用', | |||
images: [ | |||
'/pages_order/static/index/medicine-1.png', | |||
'/pages_order/static/index/medicine-2.png', | |||
'/pages_order/static/index/medicine-3.png', | |||
], | |||
productServeScore: 5, | |||
questionExperienceScore: 4, | |||
deliverySpeedScore: 4.5, | |||
}, | |||
{ | |||
id: '002', | |||
userName: '战斗世界', | |||
avatar: '/pages_order/static/report/avatar.png', | |||
countDesc: '三月装', | |||
createTime: '2023-04-18', | |||
content: '包装很精致,性价比非常高,终于收到啦,期待效果,每日一包,超级方便,真的能坚持服用', | |||
images: [ | |||
'/pages_order/static/index/medicine-1.png', | |||
'/pages_order/static/index/medicine-2.png', | |||
'/pages_order/static/index/medicine-3.png', | |||
], | |||
productServeScore: 5, | |||
questionExperienceScore: 4, | |||
deliverySpeedScore: 4.5, | |||
}, | |||
{ | |||
id: '003', | |||
userName: '战斗世界', | |||
avatar: '/pages_order/static/report/avatar.png', | |||
countDesc: '三月装', | |||
createTime: '2023-04-18', | |||
content: '包装很精致,性价比非常高,终于收到啦,期待效果,每日一包,超级方便,真的能坚持服用', | |||
images: [ | |||
'/pages_order/static/index/medicine-1.png', | |||
'/pages_order/static/index/medicine-2.png', | |||
'/pages_order/static/index/medicine-3.png', | |||
], | |||
productServeScore: 5, | |||
questionExperienceScore: 4, | |||
deliverySpeedScore: 4.5, | |||
}, | |||
] | |||
this.total = this.list.length | |||
}, | |||
}, | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.page__view { | |||
width: 100vw; | |||
min-height: 100vh; | |||
background-color: $uni-bg-color; | |||
position: relative; | |||
/deep/ .nav-bar__view { | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
} | |||
} | |||
.main { | |||
width: 100vw; | |||
padding-top: calc(var(--status-bar-height) + 204rpx); | |||
box-sizing: border-box; | |||
.tabs { | |||
position: fixed; | |||
top: calc(var(--status-bar-height) + 120rpx); | |||
left: 0; | |||
width: 100%; | |||
height: 84rpx; | |||
background: #FFFFFF; | |||
/deep/ .uv-tabs__wrapper__nav__line { | |||
border-radius: 2rpx; | |||
bottom: 0; | |||
} | |||
} | |||
} | |||
.comment { | |||
padding: 40rpx 32rpx; | |||
&-item { | |||
& + & { | |||
margin-top: 40rpx; | |||
} | |||
} | |||
} | |||
</style> |
@ -0,0 +1,98 @@ | |||
<template> | |||
<view> | |||
<uv-popup ref="popup" mode="center" bgColor="none" > | |||
<view class="popup__view"> | |||
<view class="header">温馨提示</view> | |||
<view class="content"> | |||
<uv-parse :content="content"></uv-parse> | |||
</view> | |||
<view class="footer"> | |||
<button class="flex btn" @click="onConfirm">我知道了</button> | |||
</view> | |||
</view> | |||
</uv-popup> | |||
</view> | |||
</template> | |||
<script> | |||
import { mapState } from 'vuex' | |||
export default { | |||
data() { | |||
return { | |||
content : '', | |||
} | |||
}, | |||
computed : { | |||
...mapState(['configList']) | |||
}, | |||
methods: { | |||
open() { | |||
// todo | |||
// this.content = this.configList[key] | |||
this.content = ` | |||
<p> | |||
亲爱的用户,欢迎选购我们的健康营养素包。<br/> | |||
在购买前请仔细阅读以下内容:我们所提供的营养素包,均严格遵循国际健康标准与规范进行研发和生产,旨在根据您的问卷调查或个人体检情况,精准匹配适合您的营养补充方案。<br/> | |||
在下单购买时,请确保您所提供的身体信息真实准确,以便我们为您推荐最合适的营养素组合。同时,由于海外运输及海关政策可能会影响包裹的送达时间,我们会在发货后第一时间为您更新物流信息,预计送达时间仅供参考,请耐心等待。<br/> | |||
若您在购买过程中有任何疑问,或是收到产品后遇到任何问题,我们的客服团队将竭诚为您提供 24 小时服务,祝您健康常伴! | |||
</p> | |||
` | |||
this.$refs.popup.open() | |||
}, | |||
onConfirm() { | |||
this.$refs.popup.close() | |||
this.$emit('confirm') | |||
}, | |||
}, | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
.popup__view { | |||
width: 550rpx; | |||
display: flex; | |||
flex-direction: column; | |||
padding: 32rpx; | |||
box-sizing: border-box; | |||
background-image: linear-gradient(#F2EDFF, #FCFEFE); | |||
border-radius: 64rpx; | |||
} | |||
.header { | |||
text-align: center; | |||
font-family: PingFang SC; | |||
font-weight: 500; | |||
font-size: 40rpx; | |||
line-height: 1.4; | |||
color: #181818; | |||
} | |||
.content { | |||
padding: 40rpx 0; | |||
text-align: left; | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 28rpx; | |||
line-height: 1.4; | |||
color: #5B5B5B; | |||
} | |||
.footer { | |||
.btn { | |||
width: 100%; | |||
padding: 16rpx 0; | |||
font-family: PingFang SC; | |||
font-weight: 500; | |||
font-size: 36rpx; | |||
line-height: 1.4; | |||
color: #FFFFFF; | |||
background-image: linear-gradient(to right, #4B348F, #845CFA); | |||
border-radius: 41rpx; | |||
} | |||
} | |||
</style> |
@ -0,0 +1,232 @@ | |||
<template> | |||
<view> | |||
<uv-popup ref="popup" mode="bottom" bgColor="none" > | |||
<view class="popup__view"> | |||
<view class="flex header"> | |||
<view class="title">选择规格</view> | |||
<button class="btn" @click="close">关闭</button> | |||
</view> | |||
<view class="section info"> | |||
<view class="flex card"> | |||
<view class="left"> | |||
<image class="img" :src="coverImg" mode="aspectFill"></image> | |||
</view> | |||
<view class="right"> | |||
<view class="name">{{ data.name }}</view> | |||
<view class="desc">可在以下安全剂量内,根据你的额外需求选择颗数</view> | |||
</view> | |||
</view> | |||
</view> | |||
<view class="section option"> | |||
<view | |||
v-for="item in data.options" | |||
:key="item.id" | |||
:class="['option-item', selectId == item.id ? 'is-active' : '']" | |||
@click="selectId = item.id" | |||
> | |||
{{ item.label }} | |||
</view> | |||
</view> | |||
<view class="footer"> | |||
<button class="flex btn" @click="onConfirm">下一步</button> | |||
</view> | |||
</view> | |||
</uv-popup> | |||
</view> | |||
</template> | |||
<script> | |||
import { mapState } from 'vuex' | |||
export default { | |||
props: { | |||
data: { | |||
type: Object, | |||
default() { | |||
return {} | |||
} | |||
} | |||
}, | |||
data() { | |||
return { | |||
selectId: null, | |||
} | |||
}, | |||
computed : { | |||
...mapState(['configList']), | |||
coverImg() { | |||
const { image } = this.data | |||
if (!image) { | |||
return '' | |||
} | |||
let arr = Array.isArray(image) ? image : image.split(',') | |||
return arr[0] | |||
}, | |||
}, | |||
methods: { | |||
open() { | |||
this.$refs.popup.open() | |||
}, | |||
close() { | |||
this.$refs.popup.close() | |||
this.selectId = null | |||
}, | |||
onConfirm() { | |||
if (!this.selectId) { | |||
uni.showToast({ | |||
title: '请选择规格', | |||
icon: 'none', | |||
}) | |||
return | |||
} | |||
this.$emit('confirm', this.selectId) | |||
this.close() | |||
}, | |||
}, | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
.popup__view { | |||
width: 100vw; | |||
display: flex; | |||
flex-direction: column; | |||
box-sizing: border-box; | |||
background: #FFFFFF; | |||
border-top-left-radius: 32rpx; | |||
border-top-right-radius: 32rpx; | |||
} | |||
.header { | |||
position: relative; | |||
width: 100%; | |||
padding: 24rpx 0; | |||
box-sizing: border-box; | |||
.title { | |||
font-family: PingFang SC; | |||
font-weight: 500; | |||
font-size: 34rpx; | |||
line-height: 1.4; | |||
color: #181818; | |||
} | |||
.btn { | |||
font-family: PingFang SC; | |||
font-weight: 500; | |||
font-size: 32rpx; | |||
line-height: 1.4; | |||
color: #8B8B8B; | |||
position: absolute; | |||
top: 26rpx; | |||
left: 40rpx; | |||
} | |||
} | |||
.section { | |||
border-top: 2rpx solid #EEEEEE; | |||
} | |||
.info { | |||
width: 100%; | |||
padding: 32rpx; | |||
box-sizing: border-box; | |||
.card { | |||
width: 100%; | |||
padding: 32rpx; | |||
box-sizing: border-box; | |||
background-image: linear-gradient(#FAFAFF, #F3F3F3); | |||
border-radius: 32rpx; | |||
column-gap: 24rpx; | |||
.left { | |||
width: 144rpx; | |||
height: 144rpx; | |||
border-radius: 16rpx; | |||
overflow: hidden; | |||
.img { | |||
width: 100%; | |||
height: 100%; | |||
} | |||
} | |||
.right { | |||
flex: 1; | |||
.name { | |||
font-family: PingFang SC; | |||
font-weight: 500; | |||
font-size: 28rpx; | |||
line-height: 1.4; | |||
color: #000000; | |||
} | |||
.desc { | |||
margin-top: 8rpx; | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 26rpx; | |||
line-height: 1.5; | |||
color: #8B8B8B; | |||
} | |||
} | |||
} | |||
} | |||
.option { | |||
width: 100%; | |||
padding: 44rpx; | |||
box-sizing: border-box; | |||
display: grid; | |||
grid-template-columns: repeat(2, 1fr); | |||
gap: 24rpx; | |||
&-item { | |||
padding: 18rpx 14rpx; | |||
text-align: center; | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 28rpx; | |||
line-height: 1.4; | |||
color: #181818; | |||
background: #F9F9F9; | |||
border: 2rpx solid #F9F9F9; | |||
border-radius: 16rpx; | |||
&.is-active { | |||
color: #7451DE; | |||
background: #F2EEFF; | |||
border-color: #7451DE; | |||
} | |||
} | |||
} | |||
.footer { | |||
width: 100%; | |||
padding: 32rpx 40rpx; | |||
box-sizing: border-box; | |||
.btn { | |||
width: 100%; | |||
padding: 16rpx 0; | |||
font-family: PingFang SC; | |||
font-weight: 500; | |||
font-size: 36rpx; | |||
line-height: 1.4; | |||
color: #FFFFFF; | |||
background-image: linear-gradient(to right, #4B348F, #845CFA); | |||
border-radius: 41rpx; | |||
} | |||
} | |||
</style> |
@ -0,0 +1,444 @@ | |||
<template> | |||
<view class="page__view"> | |||
<navbar title="商品详情页" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="#FFFFFF" /> | |||
<view class="main"> | |||
<uv-swiper :list="bannerList" indicator indicatorMode="dot" height="680rpx" keyName="image"></uv-swiper> | |||
<view class="summary"> | |||
<view class="card info"> | |||
<view class="name">{{ detail.fullName }}</view> | |||
<view class="flex tags"> | |||
<view class="tag" v-for="(tag, tIdx) in detail.tags" :key="tIdx"> | |||
{{ tag }} | |||
</view> | |||
</view> | |||
<view class="flex price"> | |||
<view class="flex price-val">¥<text class="highlight">{{ (detail.price || 0).toFixed(2) }}</text>/份</view> | |||
<view class="price-bef">¥<text>{{ detail.originalPrice }}</text>/份</view> | |||
</view> | |||
</view> | |||
<view class="card bar"> | |||
<view class="flex row"> | |||
<view class="flex row-content"> | |||
<view class="label">品类:</view> | |||
<view class="value">{{ detail.category }}</view> | |||
</view> | |||
</view> | |||
<view class="flex row" @click="openPicker"> | |||
<view class="flex row-content"> | |||
<view class="label">规格:</view> | |||
<view class="value">{{ detail.countDesc || '请选择规格' }}</view> | |||
</view> | |||
<uv-picker ref="picker" :columns="[detail.options]" keyName="label" confirmColor="#7451DE" @confirm="onChange"></uv-picker> | |||
<uv-icon name="arrow-right" color="#C6C6C6" size="24rpx"></uv-icon> | |||
</view> | |||
<view class="flex row"> | |||
<view class="flex row-content"> | |||
<view class="label">服务:</view> | |||
<view class="value">{{ detail.deliverService }}</view> | |||
</view> | |||
</view> | |||
</view> | |||
</view> | |||
<view class="detail"> | |||
<uv-parse :content="detail.details"></uv-parse> | |||
</view> | |||
<view class="comment"> | |||
<view class="header"> | |||
<view class="highlight">用户评价</view> | |||
<view>User reviews</view> | |||
</view> | |||
<view class="comment-item" v-for="item in commentList" :key="item.id"> | |||
<commentCard :data="item"></commentCard> | |||
</view> | |||
</view> | |||
</view> | |||
<view class="flex bottom"> | |||
<button class="flex flex-column btn btn-simple" @click="jumpToComment"> | |||
<image class="icon" src="@/pages_order/static/product/comment.png" mode="widthFix"></image> | |||
<view>评价</view> | |||
</button> | |||
<button class="flex btn btn-palin">加入购物车</button> | |||
<button class="flex btn btn-primary" @click="onBuy">立即购买</button> | |||
</view> | |||
<countSelectPopup ref="countSelectPopup" :data="detail" @confirm="onSelectCount"></countSelectPopup> | |||
<agreementPopup ref="agreementPopup" @confirm="jumpToCreateOrder"></agreementPopup> | |||
</view> | |||
</template> | |||
<script> | |||
import commentCard from '@/pages_order/comment/commentCard.vue' | |||
import agreementPopup from './agreementPopup.vue' | |||
import countSelectPopup from './countSelectPopup.vue' | |||
export default { | |||
components: { | |||
commentCard, | |||
agreementPopup, | |||
countSelectPopup, | |||
}, | |||
data() { | |||
return { | |||
id: null, | |||
detail: {}, | |||
commentList: [], | |||
} | |||
}, | |||
computed: { | |||
bannerList() { | |||
const { image } = this.detail | |||
if (!image) { | |||
return [] | |||
} | |||
return Array.isArray(image) ? image : image.split(',') | |||
}, | |||
}, | |||
onLoad(arg) { | |||
console.log('onLoad', arg) | |||
this.id = arg.id | |||
// todo: fetch detail data | |||
this.detail = { | |||
id: '001', | |||
image: new Array(4).fill('/pages_order/static/product/product-detail.png'), | |||
name: 'NMN', | |||
fullName: 'NMN 是 NAD* 的前体,在细胞能量代谢、DNA 修复和抗衰老等方面发挥重要作用。提高 NAD*水平能改善代谢健康1-8。', | |||
tags: ['专业设备', '科学流程', '质量保证'], | |||
sales: 24770, | |||
price: 688.00, | |||
originalPrice: 1664, | |||
category: '逆龄抗衰', | |||
count: null, | |||
countDesc: null, | |||
options: [ | |||
{ id: '001', label: '每天1颗', count: 1, value: 688, originValue: 1664 }, | |||
{ id: '002', label: '每天2颗', count: 2, value: 688*2, originValue: 1664*2 }, | |||
{ id: '003', label: '每天3颗', count: 3, value: 688*3, originValue: 1664*3 }, | |||
{ id: '004', label: '每天4颗', count: 4, value: 688*4, originValue: 1664*4 }, | |||
], | |||
deliverService: '上门取件·送货上门', | |||
details: `<p>商品详情↓<br/><br/><br/><br/>商品详情↑</p>` | |||
} | |||
this.commentList = [ | |||
{ | |||
id: '001', | |||
userName: '战斗世界', | |||
avatar: '/pages_order/static/report/avatar.png', | |||
countDesc: '三月装', | |||
createTime: '2023-04-18', | |||
content: '包装很精致,性价比非常高,终于收到啦,期待效果,每日一包,超级方便,真的能坚持服用', | |||
images: [ | |||
'/pages_order/static/index/medicine-1.png', | |||
'/pages_order/static/index/medicine-2.png', | |||
'/pages_order/static/index/medicine-3.png', | |||
], | |||
productServeScore: 5, | |||
questionExperienceScore: 4, | |||
deliverySpeedScore: 4.5, | |||
}, | |||
{ | |||
id: '002', | |||
userName: '战斗世界', | |||
avatar: '/pages_order/static/report/avatar.png', | |||
countDesc: '三月装', | |||
createTime: '2023-04-18', | |||
content: '包装很精致,性价比非常高,终于收到啦,期待效果,每日一包,超级方便,真的能坚持服用', | |||
images: [ | |||
'/pages_order/static/index/medicine-1.png', | |||
'/pages_order/static/index/medicine-2.png', | |||
'/pages_order/static/index/medicine-3.png', | |||
], | |||
productServeScore: 5, | |||
questionExperienceScore: 4, | |||
deliverySpeedScore: 4.5, | |||
}, | |||
{ | |||
id: '003', | |||
userName: '战斗世界', | |||
avatar: '/pages_order/static/report/avatar.png', | |||
countDesc: '三月装', | |||
createTime: '2023-04-18', | |||
content: '包装很精致,性价比非常高,终于收到啦,期待效果,每日一包,超级方便,真的能坚持服用', | |||
images: [ | |||
'/pages_order/static/index/medicine-1.png', | |||
'/pages_order/static/index/medicine-2.png', | |||
'/pages_order/static/index/medicine-3.png', | |||
], | |||
productServeScore: 5, | |||
questionExperienceScore: 4, | |||
deliverySpeedScore: 4.5, | |||
}, | |||
] | |||
}, | |||
methods: { | |||
openPicker() { | |||
this.$refs.picker.open(); | |||
}, | |||
onChange(e) { | |||
const target = e.value[0] | |||
console.log('onChange', target) | |||
this.detail.price = target.value | |||
this.detail.count = target.count | |||
this.detail.countDesc = target.label | |||
}, | |||
jumpToComment() { | |||
this.$utils.navigateTo('/pages_order/comment/commentRecords') | |||
}, | |||
jumpToCreateOrder() { | |||
// todo | |||
}, | |||
onSelectCount(optionId) { | |||
const { options } = this.detail | |||
let target = options.find(item => item.id === optionId) | |||
this.detail.price = target.value | |||
this.detail.count = target.count | |||
this.detail.countDesc = target.label | |||
this.onBuy() | |||
}, | |||
onBuy() { | |||
const { count, options } = this.detail | |||
if (!count && options?.length) { | |||
this.$refs.countSelectPopup.open() | |||
return | |||
} | |||
// todo | |||
this.$refs.agreementPopup.open() | |||
// this.jumpToCreateOrder() | |||
}, | |||
}, | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.page__view { | |||
width: 100vw; | |||
min-height: 100vh; | |||
background-color: $uni-bg-color; | |||
position: relative; | |||
/deep/ .nav-bar__view { | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
} | |||
} | |||
.main { | |||
width: 100vw; | |||
padding: calc(var(--status-bar-height) + 120rpx) 0 198rpx 0; | |||
box-sizing: border-box; | |||
} | |||
.summary { | |||
width: 100%; | |||
padding: 40rpx 32rpx; | |||
box-sizing: border-box; | |||
} | |||
.card { | |||
border-radius: 24rpx; | |||
& + & { | |||
margin-top: 40rpx; | |||
} | |||
&.info { | |||
width: 100%; | |||
padding: 32rpx; | |||
box-sizing: border-box; | |||
background: #FFFFFF; | |||
.name { | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 32rpx; | |||
line-height: 1.4; | |||
color: #181818; | |||
} | |||
.tags { | |||
margin-top: 16rpx; | |||
justify-content: flex-start; | |||
flex-wrap: wrap; | |||
gap: 16rpx; | |||
.tag { | |||
padding: 2rpx 14rpx; | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 24rpx; | |||
line-height: 1.4; | |||
color: #7451DE; | |||
background: #EFEAFF; | |||
border: 2rpx solid #7451DE; | |||
border-radius: 8rpx; | |||
} | |||
} | |||
.price { | |||
margin-top: 32rpx; | |||
justify-content: flex-start; | |||
column-gap: 20rpx; | |||
&-val { | |||
font-family: PingFang SC; | |||
font-weight: 500; | |||
font-size: 24rpx; | |||
line-height: 1.4; | |||
color: #7451DE; | |||
.highlight { | |||
margin: 0 8rpx; | |||
font-size: 48rpx; | |||
} | |||
} | |||
&-bef { | |||
font-family: PingFang SC; | |||
text-decoration: line-through; | |||
font-weight: 400; | |||
font-size: 28rpx; | |||
line-height: 1; | |||
color: #8B8B8B; | |||
} | |||
} | |||
} | |||
&.bar { | |||
width: 100%; | |||
padding: 20rpx 32rpx; | |||
box-sizing: border-box; | |||
background: #FAFAFF; | |||
box-shadow: -4rpx -4rpx 20rpx 0 #FFFFFFC4, | |||
4rpx 4rpx 20rpx 0 #AAAACC1F, | |||
2rpx 2rpx 4rpx 0 #AAAACC40, | |||
-2rpx -2rpx 4rpx 0 #FFFFFF; | |||
.row { | |||
padding: 8rpx 0; | |||
&-content { | |||
flex: 1; | |||
justify-content: flex-start; | |||
column-gap: 4rpx; | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 28rpx; | |||
line-height: 1.4; | |||
.label { | |||
color: #8B8B8B; | |||
} | |||
.value { | |||
color: #393939; | |||
} | |||
} | |||
} | |||
.row + .row { | |||
margin-top: 24rpx; | |||
} | |||
} | |||
} | |||
.comment { | |||
padding: 40rpx 32rpx; | |||
.header { | |||
margin-bottom: 24rpx; | |||
font-family: PingFang SC; | |||
font-weight: 400; | |||
font-size: 26rpx; | |||
line-height: 1.4; | |||
color: #252545; | |||
.highlight { | |||
font-weight: 600; | |||
font-size: 48rpx; | |||
} | |||
} | |||
&-item { | |||
& + & { | |||
margin-top: 32rpx; | |||
} | |||
} | |||
} | |||
.bottom { | |||
position: fixed; | |||
left: 0; | |||
bottom: 0; | |||
align-items: flex-start; | |||
column-gap: 32rpx; | |||
width: 100vw; | |||
height: 198rpx; | |||
padding: 24rpx 40rpx 0 40rpx; | |||
background: #FFFFFF; | |||
box-sizing: border-box; | |||
.btn { | |||
font-family: PingFang SC; | |||
&-simple { | |||
font-weight: 400; | |||
font-size: 22rpx; | |||
line-height: 1.1; | |||
color: #999999; | |||
.icon { | |||
width: 52rpx; | |||
height: auto; | |||
} | |||
} | |||
&-palin { | |||
flex: 1; | |||
padding: 14rpx 0; | |||
font-weight: 500; | |||
font-size: 36rpx; | |||
line-height: 1.4; | |||
color: #252545; | |||
border: 2rpx solid #252545; | |||
border-radius: 41rpx; | |||
} | |||
&-primary { | |||
flex: 1; | |||
padding: 16rpx 0; | |||
font-weight: 500; | |||
font-size: 36rpx; | |||
line-height: 1.4; | |||
color: #FFFFFF; | |||
background-image: linear-gradient(to right, #4B348F, #845CFA); | |||
border-radius: 41rpx; | |||
} | |||
} | |||
} | |||
</style> |