| @ -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> | |||