| @ -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> | <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> | </view> | ||||
| <button v-if="mode == 'edit'" class="btn" @click="onLeaveEdit">完成</button> | |||||
| <button v-else class="btn" @click="onEnterEdit">管理</button> | |||||
| </view> | </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> | ||||
| <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> | </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> | ||||
| </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> | </view> | ||||
| <tabber select="cart" /> | <tabber select="cart" /> | ||||
| </view> | </view> | ||||
| </template> | </template> | ||||
| <script> | <script> | ||||
| import mixinsList from '@/mixins/list.js' | |||||
| import tabber from '@/components/base/tabbar.vue' | import tabber from '@/components/base/tabbar.vue' | ||||
| import productCard from '@/components/cart/productCard.vue' | |||||
| import recommendProductCard from '@/components/product/productCard.vue' | |||||
| export default { | export default { | ||||
| mixins: [mixinsList], | |||||
| components: { | components: { | ||||
| productCard, | |||||
| recommendProductCard, | |||||
| tabber, | 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> | </script> | ||||
| <style scoped lang="scss"> | <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; | 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> | </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> | |||||