feat: 商品提交列表
This commit is contained in:
Generated
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "points-mall",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
Generated
+7
@@ -8,6 +8,7 @@
|
||||
"name": "supplied-h5",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@vant/area-data": "^1.5.2",
|
||||
"core-js": "^3.37.1",
|
||||
"pinia": "^2.3.1",
|
||||
"vant": "^2.13.9",
|
||||
@@ -1851,6 +1852,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@vant/area-data": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@vant/area-data/-/area-data-1.5.2.tgz",
|
||||
"integrity": "sha512-Gtxgt6Rjgopt6234ANpO0bBsSwtjZ23lBlVDHIy8Mi2NJqyoj1vgVWY0dri8/2LCZAWzQ6EnwRrUVViUZ0cvMA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vant/icons": {
|
||||
"version": "3.0.2",
|
||||
"license": "MIT"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"build": "vue-cli-service build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vant/area-data": "^1.5.2",
|
||||
"core-js": "^3.37.1",
|
||||
"pinia": "^2.3.1",
|
||||
"vant": "^2.13.9",
|
||||
|
||||
@@ -11,6 +11,8 @@ import JoyfulSelectionCheckout from '@/view/joyful-selection/cart/checkout/index
|
||||
import JoyfulSelectionPayment from '@/view/joyful-selection/cart/payment/index.vue'
|
||||
import JoyfulSelectionPaymentConfirm from '@/view/joyful-selection/cart/payment-confirm/index.vue'
|
||||
import JoyfulSelectionPaymentSuccess from '@/view/joyful-selection/cart/payment-success/index.vue'
|
||||
import JoyfulSelectionAddressList from '@/view/joyful-selection/address/index.vue'
|
||||
import JoyfulSelectionAddressEdit from '@/view/joyful-selection/address/edit/index.vue'
|
||||
import JoyfulSelectionOrders from '@/view/joyful-selection/profile/orders/index.vue'
|
||||
import JoyfulSelectionProfile from '@/view/joyful-selection/profile/index.vue'
|
||||
import JoyfulSelectionPoints from '@/view/joyful-selection/profile/points/index.vue'
|
||||
@@ -38,6 +40,8 @@ export default new Router({
|
||||
{ path: 'payment', component: JoyfulSelectionPayment },
|
||||
{ path: 'payment-confirm', component: JoyfulSelectionPaymentConfirm },
|
||||
{ path: 'payment-success', component: JoyfulSelectionPaymentSuccess },
|
||||
{ path: 'address', component: JoyfulSelectionAddressList },
|
||||
{ path: 'address/edit', component: JoyfulSelectionAddressEdit },
|
||||
{ path: 'orders', component: JoyfulSelectionOrders },
|
||||
{ path: 'profile', component: JoyfulSelectionProfile },
|
||||
{ path: 'points', component: JoyfulSelectionPoints }
|
||||
|
||||
@@ -45,6 +45,14 @@ export const useCartStore = defineStore('joyfulSelectionCart', {
|
||||
this.items.unshift(item)
|
||||
}
|
||||
|
||||
this.persistCart()
|
||||
},
|
||||
removeItems(cartIds) {
|
||||
if (!this.loaded) {
|
||||
this.loadCart()
|
||||
}
|
||||
|
||||
this.items = this.items.filter(item => !cartIds.includes(item.cartId))
|
||||
this.persistCart()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
const ADDRESS_KEY = 'joyful-selection-addresses'
|
||||
const CHOSEN_ADDRESS_KEY = 'joyful-selection-chosen-address-id'
|
||||
|
||||
const defaultAddresses = [
|
||||
{
|
||||
id: 'addr-1',
|
||||
name: '张三',
|
||||
tel: '13888888888',
|
||||
province: '浙江省',
|
||||
city: '杭州市',
|
||||
county: '余杭区',
|
||||
addressDetail: '文一西路 888 号未来科技城海创园5幢1203室',
|
||||
areaCode: '330110',
|
||||
postalCode: '310000',
|
||||
isDefault: true
|
||||
}
|
||||
]
|
||||
|
||||
export const readAddresses = () => {
|
||||
try {
|
||||
const addresses = JSON.parse(localStorage.getItem(ADDRESS_KEY) || '[]')
|
||||
return addresses.length ? addresses : defaultAddresses
|
||||
} catch (error) {
|
||||
return defaultAddresses
|
||||
}
|
||||
}
|
||||
|
||||
export const saveAddresses = addresses => {
|
||||
localStorage.setItem(ADDRESS_KEY, JSON.stringify(addresses))
|
||||
}
|
||||
|
||||
export const readChosenAddressId = () => {
|
||||
return localStorage.getItem(CHOSEN_ADDRESS_KEY) || readAddresses().find(item => item.isDefault)?.id || readAddresses()[0]?.id || ''
|
||||
}
|
||||
|
||||
export const saveChosenAddressId = id => {
|
||||
localStorage.setItem(CHOSEN_ADDRESS_KEY, id)
|
||||
}
|
||||
|
||||
export const formatAddress = address => {
|
||||
if (!address) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return `${address.province}${address.city}${address.county}${address.addressDetail}`
|
||||
}
|
||||
|
||||
export const createAddressId = () => `addr-${Date.now()}`
|
||||
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<main class="address-edit-page">
|
||||
<van-nav-bar :title="pageTitle" left-arrow @click-left="$router.back()" />
|
||||
<van-address-edit
|
||||
:area-list="areaList"
|
||||
:address-info="addressInfo"
|
||||
show-postal
|
||||
show-delete
|
||||
show-set-default
|
||||
show-search-result
|
||||
:search-result="searchResult"
|
||||
:area-columns-placeholder="['请选择', '请选择', '请选择']"
|
||||
@save="onSave"
|
||||
@delete="onDelete"
|
||||
@change-detail="onChangeDetail"
|
||||
/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Toast } from 'vant'
|
||||
import { areaList } from '@vant/area-data'
|
||||
import { createAddressId, readAddresses, saveAddresses, saveChosenAddressId } from '../address-data'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionAddressEdit',
|
||||
data: () => ({
|
||||
areaList,
|
||||
searchResult: [],
|
||||
addressInfo: {}
|
||||
}),
|
||||
computed: {
|
||||
editId() {
|
||||
return this.$route.query.id
|
||||
},
|
||||
pageTitle() {
|
||||
return this.editId ? '编辑地址' : '新增地址'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const address = readAddresses().find(item => item.id === this.editId)
|
||||
|
||||
if (address) {
|
||||
this.addressInfo = { ...address }
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSave(content) {
|
||||
const addresses = readAddresses()
|
||||
const nextAddress = {
|
||||
...content,
|
||||
id: this.editId || content.id || createAddressId()
|
||||
}
|
||||
const nextAddresses = addresses.filter(item => item.id !== nextAddress.id)
|
||||
|
||||
if (nextAddress.isDefault) {
|
||||
nextAddresses.forEach(item => { item.isDefault = false })
|
||||
}
|
||||
|
||||
if (!nextAddresses.length && !nextAddress.isDefault) {
|
||||
nextAddress.isDefault = true
|
||||
}
|
||||
|
||||
saveAddresses([nextAddress, ...nextAddresses])
|
||||
saveChosenAddressId(nextAddress.id)
|
||||
Toast('保存成功')
|
||||
this.$router.back()
|
||||
},
|
||||
onDelete() {
|
||||
if (!this.editId) {
|
||||
this.$router.back()
|
||||
return
|
||||
}
|
||||
|
||||
const addresses = readAddresses().filter(item => item.id !== this.editId)
|
||||
|
||||
if (addresses.length && !addresses.some(item => item.isDefault)) {
|
||||
addresses[0].isDefault = true
|
||||
}
|
||||
|
||||
saveAddresses(addresses)
|
||||
saveChosenAddressId(addresses[0]?.id || '')
|
||||
Toast('删除成功')
|
||||
this.$router.back()
|
||||
},
|
||||
onChangeDetail(value) {
|
||||
this.searchResult = value
|
||||
? [
|
||||
{
|
||||
name: '未来科技城',
|
||||
address: '浙江省杭州市余杭区文一西路'
|
||||
},
|
||||
{
|
||||
name: '海创园',
|
||||
address: '浙江省杭州市余杭区文一西路998号'
|
||||
}
|
||||
]
|
||||
: []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.address-edit-page {
|
||||
min-height: 100vh;
|
||||
padding-top: 46px;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.address-edit-page ::v-deep .van-nav-bar {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
.address-edit-page ::v-deep .van-address-edit {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.address-edit-page ::v-deep .van-button--danger {
|
||||
background: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
}
|
||||
|
||||
.address-edit-page ::v-deep .van-switch--on {
|
||||
background: #ff5b20;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<main class="address-page">
|
||||
<van-nav-bar title="地址管理" left-arrow @click-left="$router.back()" />
|
||||
<van-address-list
|
||||
v-model="chosenAddressId"
|
||||
:list="addressList"
|
||||
:disabled-list="disabledList"
|
||||
disabled-text="以下地址超出配送范围"
|
||||
default-tag-text="默认"
|
||||
@add="onAdd"
|
||||
@edit="onEdit"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { formatAddress, readAddresses, readChosenAddressId, saveChosenAddressId } from './address-data'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionAddressList',
|
||||
data: () => ({
|
||||
chosenAddressId: '',
|
||||
addresses: [],
|
||||
disabledList: []
|
||||
}),
|
||||
computed: {
|
||||
addressList() {
|
||||
return this.addresses.map(item => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
tel: item.tel,
|
||||
address: formatAddress(item),
|
||||
isDefault: item.isDefault
|
||||
}))
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.addresses = readAddresses()
|
||||
this.chosenAddressId = readChosenAddressId()
|
||||
},
|
||||
methods: {
|
||||
onSelect(item) {
|
||||
this.chosenAddressId = item.id
|
||||
saveChosenAddressId(item.id)
|
||||
|
||||
if (this.$route.query.from === 'checkout') {
|
||||
this.$router.back()
|
||||
}
|
||||
},
|
||||
onAdd() {
|
||||
this.$router.push('/joyful-selection/address/edit')
|
||||
},
|
||||
onEdit(item) {
|
||||
this.$router.push({ path: '/joyful-selection/address/edit', query: { id: item.id } })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.address-page {
|
||||
min-height: 100vh;
|
||||
padding-top: 46px;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.address-page ::v-deep .van-nav-bar {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
.address-page ::v-deep .van-address-list {
|
||||
padding: 12px 12px 86px;
|
||||
}
|
||||
|
||||
.address-page ::v-deep .van-address-item {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.address-page ::v-deep .van-address-item .van-radio__icon--checked .van-icon,
|
||||
.address-page ::v-deep .van-address-list__add {
|
||||
border-color: #ff5b20;
|
||||
background: #ff5b20;
|
||||
}
|
||||
|
||||
.address-page ::v-deep .van-tag--danger {
|
||||
background: #ff5b20;
|
||||
}
|
||||
</style>
|
||||
@@ -1,50 +1,393 @@
|
||||
<template>
|
||||
<main class="checkout-page">
|
||||
<van-nav-bar title="确认订单" left-arrow @click-left="$router.back()" />
|
||||
<van-cell-group inset>
|
||||
<van-cell title="收货人:张三 138****8888" label="浙江省杭州市余杭区文一西路 888 号 1203 室" is-link />
|
||||
</van-cell-group>
|
||||
<van-cell-group inset title="配送方式">
|
||||
<van-cell title="预计送达:5月20日(周二)" value="快速配送 免邮" />
|
||||
</van-cell-group>
|
||||
<van-cell-group inset>
|
||||
<van-card
|
||||
v-for="item in goods"
|
||||
:key="item.id"
|
||||
:title="item.name"
|
||||
:desc="item.desc"
|
||||
:price="item.price"
|
||||
:thumb="item.image"
|
||||
num="1"
|
||||
/>
|
||||
</van-cell-group>
|
||||
<van-field v-model="remark" label="订单备注" placeholder="选填,给商家留言" />
|
||||
<section class="amount">
|
||||
<p>商品金额 <b>¥297.90</b></p>
|
||||
<p>运费 <b>¥0.00</b></p>
|
||||
<p>优惠券 <b>暂无优惠券</b></p>
|
||||
|
||||
<section class="address-card" @click="$router.push({ path: '/joyful-selection/address', query: { from: 'checkout' } })">
|
||||
<van-icon class="address-icon" name="location" />
|
||||
<div class="address-info">
|
||||
<h3>收货人:{{ chosenAddress.name }} <span>{{ maskTel(chosenAddress.tel) }}</span></h3>
|
||||
<p>{{ chosenAddress.province }}{{ chosenAddress.city }}{{ chosenAddress.county }}</p>
|
||||
<p>{{ chosenAddress.addressDetail }}</p>
|
||||
</div>
|
||||
<van-icon class="arrow-icon" name="arrow" />
|
||||
</section>
|
||||
<van-submit-bar :price="29790" button-text="提交订单" @submit="$router.push('/joyful-selection/payment')" />
|
||||
|
||||
<section class="delivery-card">
|
||||
<div class="delivery-row">
|
||||
<span>配送方式</span>
|
||||
<b>快速配送 免邮</b>
|
||||
</div>
|
||||
<div class="delivery-row delivery-date">
|
||||
<span>预计送达:</span>
|
||||
<em>5月20日(周二)</em>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="goods-card">
|
||||
<article v-for="item in visibleGoods" :key="item.cartId || item.id" class="order-item">
|
||||
<van-image class="order-thumb" :src="item.image" fit="cover" />
|
||||
<div class="order-info">
|
||||
<h3>{{ item.name }}</h3>
|
||||
<p>¥{{ item.price }}</p>
|
||||
</div>
|
||||
<span class="order-count">x{{ item.count || 1 }}</span>
|
||||
</article>
|
||||
<button v-if="showLoadMore" type="button" class="load-more" @click="showAllGoods = true">
|
||||
加载更多
|
||||
<van-icon name="arrow-down" />
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="remark-card">
|
||||
<span>订单备注</span>
|
||||
<input v-model="remark" type="text" placeholder="选填,给商家留言" />
|
||||
</section>
|
||||
|
||||
<section class="amount-card">
|
||||
<p><span>商品金额</span><b>¥{{ formatYuan(goodsAmount) }}</b></p>
|
||||
<p><span>运费</span><b>¥0.00</b></p>
|
||||
<p><span>优惠券</span><b class="muted">选择优惠券</b></p>
|
||||
</section>
|
||||
|
||||
<van-submit-bar :price="goodsAmount" button-text="提交订单" @submit="onSubmit" />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { joyfulProducts } from '../../product-data'
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
import { readAddresses, readChosenAddressId } from '../../address/address-data'
|
||||
import { createOrderNo, savePaymentInfo } from '../payment/payment-data'
|
||||
|
||||
const CHECKOUT_ITEMS_KEY = 'joyful-selection-checkout-items'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionCheckout',
|
||||
data: () => ({
|
||||
remark: '',
|
||||
goods: joyfulProducts.slice(0, 3)
|
||||
})
|
||||
goods: [],
|
||||
showAllGoods: false,
|
||||
chosenAddress: {}
|
||||
}),
|
||||
computed: {
|
||||
...mapState(useCartStore, ['items']),
|
||||
visibleGoods() {
|
||||
return this.showAllGoods ? this.goods : this.goods.slice(0, 3)
|
||||
},
|
||||
showLoadMore() {
|
||||
return !this.showAllGoods && this.goods.length > 3
|
||||
},
|
||||
goodsAmount() {
|
||||
return this.goods.reduce((total, item) => total + Math.round(Number(item.price) * 100) * Number(item.count || 1), 0)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadCart()
|
||||
this.goods = this.getCheckoutGoods()
|
||||
this.loadAddress()
|
||||
},
|
||||
activated() {
|
||||
this.loadAddress()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useCartStore, ['loadCart']),
|
||||
getCheckoutGoods() {
|
||||
const storedItems = this.readCheckoutItems()
|
||||
|
||||
if (storedItems.length) {
|
||||
return storedItems
|
||||
}
|
||||
|
||||
if (this.$route.query.source === 'cart') {
|
||||
return this.items
|
||||
}
|
||||
|
||||
return []
|
||||
},
|
||||
readCheckoutItems() {
|
||||
try {
|
||||
return JSON.parse(sessionStorage.getItem(CHECKOUT_ITEMS_KEY) || '[]')
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
formatYuan(price) {
|
||||
return (Number(price || 0) / 100).toFixed(2)
|
||||
},
|
||||
loadAddress() {
|
||||
const addresses = readAddresses()
|
||||
const chosenId = readChosenAddressId()
|
||||
this.chosenAddress = addresses.find(item => item.id === chosenId) || addresses[0] || {}
|
||||
},
|
||||
maskTel(tel = '') {
|
||||
return tel.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')
|
||||
},
|
||||
onSubmit() {
|
||||
savePaymentInfo({
|
||||
orderNo: createOrderNo(),
|
||||
amount: this.goodsAmount,
|
||||
receiverName: this.chosenAddress.name || '',
|
||||
receiverTel: this.maskTel(this.chosenAddress.tel || ''),
|
||||
goods: this.goods
|
||||
})
|
||||
this.$router.push('/joyful-selection/payment')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.checkout-page { min-height: 100vh; padding-bottom: 60px; background: #f7f7f7; }
|
||||
.van-cell-group { margin: 10px 12px; }
|
||||
.amount { margin: 10px 12px; padding: 10px 16px; border-radius: 10px; background: #fff; font-size: 13px; }
|
||||
.amount p { display: flex; justify-content: space-between; }
|
||||
.amount b { font-weight: normal; }
|
||||
.van-submit-bar { bottom: 0; }
|
||||
<style scoped lang="less">
|
||||
.checkout-page {
|
||||
min-height: 100vh;
|
||||
padding: 46px 0 62px;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.checkout-page ::v-deep .van-nav-bar {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
.address-card,
|
||||
.delivery-card,
|
||||
.goods-card,
|
||||
.remark-card,
|
||||
.amount-card {
|
||||
margin: 10px 12px 0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.address-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 14px 12px;
|
||||
}
|
||||
|
||||
.address-icon {
|
||||
flex: none;
|
||||
margin-right: 10px;
|
||||
color: #ff5b20;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.address-info {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.address-info h3 {
|
||||
margin: 0 0 5px;
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.address-info h3 span {
|
||||
margin-left: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.address-info p {
|
||||
overflow: hidden;
|
||||
margin: 2px 0 0;
|
||||
color: #555;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
flex: none;
|
||||
color: #999;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.delivery-card {
|
||||
padding: 13px 14px;
|
||||
}
|
||||
|
||||
.delivery-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.delivery-row b {
|
||||
color: #333;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.delivery-date {
|
||||
justify-content: flex-start;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.delivery-date em {
|
||||
margin-left: 8px;
|
||||
color: #999;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.goods-card {
|
||||
padding: 2px 14px;
|
||||
}
|
||||
|
||||
.order-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 86px;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.order-item + .order-item {
|
||||
border-top: 1px solid #f4f4f4;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
border: 0;
|
||||
border-top: 1px solid #f4f4f4;
|
||||
color: #ff5b20;
|
||||
font-size: 13px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.load-more .van-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.order-thumb {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
flex: none;
|
||||
overflow: hidden;
|
||||
border-radius: 4px;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.order-info {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.order-info h3 {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
margin: 0 0 8px;
|
||||
color: #222;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
line-height: 18px;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.order-info p {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.order-count {
|
||||
flex: none;
|
||||
color: #222;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.remark-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 46px;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.remark-card span {
|
||||
flex: none;
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.remark-card input {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
margin-left: 16px;
|
||||
border: 0;
|
||||
outline: none;
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
text-align: right;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.remark-card input::placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.amount-card {
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
.amount-card p {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
color: #777;
|
||||
font-size: 13px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.amount-card b {
|
||||
color: #333;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.amount-card .muted {
|
||||
color: #777;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.checkout-page ::v-deep .van-submit-bar {
|
||||
bottom: 0;
|
||||
height: 58px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.checkout-page ::v-deep .van-submit-bar__bar {
|
||||
height: 58px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.checkout-page ::v-deep .van-submit-bar__price {
|
||||
color: #ff5b20;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.checkout-page ::v-deep .van-submit-bar__button {
|
||||
width: 112px;
|
||||
height: 40px;
|
||||
border-radius: 22px;
|
||||
background: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
<template>
|
||||
<section class="cart-panel" :class="{ 'cart-panel--page': pageMode }">
|
||||
<van-notice-bar v-if="showNotice" text="满 199 元包邮,快去凑单吧~" left-icon="info-o" />
|
||||
<section class="cart-list">
|
||||
<van-empty v-if="!items.length" description="购物车还是空的" />
|
||||
<template v-else>
|
||||
<article
|
||||
v-for="item in items"
|
||||
:key="item.cartId"
|
||||
class="cart-item"
|
||||
>
|
||||
<van-checkbox
|
||||
:value="isItemChecked(item)"
|
||||
class="item-check"
|
||||
checked-color="#ff5b20"
|
||||
@input="toggleItem(item, $event)"
|
||||
/>
|
||||
<van-image class="item-thumb" :src="item.image" fit="cover" />
|
||||
<div class="item-info">
|
||||
<h3>{{ item.name }}</h3>
|
||||
<p class="item-desc">{{ item.desc }}</p>
|
||||
<van-tag class="item-tag" plain type="danger">{{ item.tag }}</van-tag>
|
||||
<div class="item-bottom">
|
||||
<b>¥{{ item.price }}</b>
|
||||
<van-stepper
|
||||
v-model="item.count"
|
||||
class="quantity-stepper"
|
||||
integer
|
||||
min="0"
|
||||
button-size="30"
|
||||
input-width="36"
|
||||
@change="onCountChange(item, $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</template>
|
||||
</section>
|
||||
<van-submit-bar
|
||||
:fixed="fixedSubmit"
|
||||
:price="selectedTotalPrice"
|
||||
:button-text="submitText"
|
||||
@submit="$emit('checkout', selectedItems)"
|
||||
>
|
||||
<van-checkbox
|
||||
:value="isAllChecked"
|
||||
:indeterminate="isPartChecked"
|
||||
checked-color="#ff5b20"
|
||||
@input="toggleAll"
|
||||
>全选</van-checkbox>
|
||||
</van-submit-bar>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulCartPanel',
|
||||
props: {
|
||||
fixedSubmit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
pageMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showNotice: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
selectedIds: []
|
||||
}),
|
||||
computed: {
|
||||
...mapState(useCartStore, ['items']),
|
||||
cartIds() {
|
||||
return this.items.map(item => item.cartId)
|
||||
},
|
||||
selectedItems() {
|
||||
return this.items.filter(item => this.selectedIds.includes(item.cartId))
|
||||
},
|
||||
selectedTotalCount() {
|
||||
return this.selectedItems.reduce((total, item) => total + Number(item.count || 0), 0)
|
||||
},
|
||||
selectedTotalPrice() {
|
||||
return this.selectedItems.reduce((total, item) => total + Math.round(Number(item.price) * 100) * Number(item.count || 0), 0)
|
||||
},
|
||||
isAllChecked() {
|
||||
return this.items.length > 0 && this.selectedIds.length === this.items.length
|
||||
},
|
||||
isPartChecked() {
|
||||
return this.selectedIds.length > 0 && this.selectedIds.length < this.items.length
|
||||
},
|
||||
submitText() {
|
||||
return `去结算(${this.selectedTotalCount})`
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
cartIds(newIds, oldIds) {
|
||||
const wasAllChecked = oldIds.length > 0 && oldIds.every(cartId => this.selectedIds.includes(cartId))
|
||||
const validSelectedIds = this.selectedIds.filter(cartId => newIds.includes(cartId))
|
||||
|
||||
this.selectedIds = wasAllChecked ? newIds : validSelectedIds
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadCart()
|
||||
this.selectAllItems()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useCartStore, ['loadCart', 'persistCart', 'removeItems']),
|
||||
selectAllItems() {
|
||||
this.selectedIds = this.items.map(item => item.cartId)
|
||||
},
|
||||
isItemChecked(item) {
|
||||
return this.selectedIds.includes(item.cartId)
|
||||
},
|
||||
toggleItem(item, checked) {
|
||||
if (checked && !this.isItemChecked(item)) {
|
||||
this.selectedIds = [...this.selectedIds, item.cartId]
|
||||
return
|
||||
}
|
||||
|
||||
if (!checked) {
|
||||
this.selectedIds = this.selectedIds.filter(cartId => cartId !== item.cartId)
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.selectedIds = checked ? this.items.map(item => item.cartId) : []
|
||||
},
|
||||
onCountChange(item, count) {
|
||||
if (Number(count) < 1) {
|
||||
this.removeItems([item.cartId])
|
||||
return
|
||||
}
|
||||
|
||||
this.persistCart()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.cart-panel {
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-panel--page {
|
||||
min-height: calc(100vh - 46px);
|
||||
padding-bottom: 108px;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-notice-bar {
|
||||
height: 34px;
|
||||
flex: none;
|
||||
color: #ff7a38;
|
||||
background: #fff3ea;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.cart-list {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 0 16px 12px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
display: flex;
|
||||
min-height: 128px;
|
||||
align-items: center;
|
||||
padding: 16px 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-item + .cart-item {
|
||||
border-top: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.item-check {
|
||||
flex: none;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-checkbox__icon--checked .van-icon {
|
||||
border-color: #ff5b20;
|
||||
background-color: #ff5b20;
|
||||
}
|
||||
|
||||
.item-thumb {
|
||||
width: 94px;
|
||||
height: 94px;
|
||||
flex: none;
|
||||
overflow: hidden;
|
||||
border-radius: 5px;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
min-height: 94px;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.item-info h3 {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
margin: 0 0 4px;
|
||||
color: #222;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
overflow: hidden;
|
||||
margin: 0 0 6px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-tag {
|
||||
width: fit-content;
|
||||
color: #ff5b20;
|
||||
border-color: #ff9b73;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.item-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.item-bottom b {
|
||||
color: #ff5b20;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.quantity-stepper {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__minus,
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__plus,
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__input {
|
||||
height: 30px;
|
||||
margin: 0;
|
||||
border: 1px solid #edf0f4;
|
||||
background: #fff;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__minus {
|
||||
width: 32px;
|
||||
border-radius: 6px 0 0 6px;
|
||||
color: #9aa0a6;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__input {
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .quantity-stepper .van-stepper__plus {
|
||||
width: 32px;
|
||||
border-radius: 0 6px 6px 0;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-submit-bar {
|
||||
position: relative;
|
||||
height: 58px;
|
||||
flex: none;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-panel--page ::v-deep .van-submit-bar {
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-submit-bar__bar {
|
||||
height: 58px;
|
||||
padding: 0 18px;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-submit-bar__price {
|
||||
color: #ff5b20;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cart-panel ::v-deep .van-submit-bar__button {
|
||||
width: 104px;
|
||||
height: 40px;
|
||||
border-radius: 22px;
|
||||
background: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
@@ -1,42 +1,227 @@
|
||||
<template>
|
||||
<main class="edit-page">
|
||||
<van-nav-bar title="购物车" right-text="完成" @click-right="$router.push('/joyful-selection/cart')" />
|
||||
<section>
|
||||
<van-card
|
||||
v-for="item in goods"
|
||||
:key="item.id"
|
||||
:title="item.name"
|
||||
:desc="item.desc"
|
||||
:price="item.price"
|
||||
:thumb="item.image"
|
||||
>
|
||||
<template #footer><van-stepper v-model="item.count" theme="round" button-size="22" /></template>
|
||||
</van-card>
|
||||
<section class="edit-list">
|
||||
<van-empty v-if="!items.length" description="购物车还是空的" />
|
||||
<article v-for="item in items" :key="item.cartId" class="edit-item">
|
||||
<van-checkbox
|
||||
:value="isItemChecked(item)"
|
||||
class="item-check"
|
||||
checked-color="#ff5b20"
|
||||
@input="toggleItem(item, $event)"
|
||||
/>
|
||||
<van-image class="item-thumb" :src="item.image" fit="cover" />
|
||||
<div class="item-info">
|
||||
<h3>{{ item.name }}</h3>
|
||||
<p>{{ item.desc }}</p>
|
||||
<van-tag class="item-tag" plain type="danger">{{ item.tag }}</van-tag>
|
||||
<div class="item-bottom">
|
||||
<b>¥{{ item.price }}</b>
|
||||
<span>x{{ item.count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
<van-submit-bar button-text="删除" @submit="remove">
|
||||
<van-checkbox v-model="checked">全选</van-checkbox>
|
||||
<van-submit-bar class="edit-submit" button-text="删除" @submit="remove">
|
||||
<van-checkbox
|
||||
:value="isAllChecked"
|
||||
:indeterminate="isPartChecked"
|
||||
checked-color="#ff5b20"
|
||||
@input="toggleAll"
|
||||
>全选</van-checkbox>
|
||||
</van-submit-bar>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Toast } from 'vant'
|
||||
import { joyfulProducts } from '../../product-data'
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionCartEdit',
|
||||
data: () => ({
|
||||
checked: false,
|
||||
goods: joyfulProducts.map(item => ({ ...item, count: 1 }))
|
||||
selectedIds: []
|
||||
}),
|
||||
computed: {
|
||||
...mapState(useCartStore, ['items']),
|
||||
isAllChecked() {
|
||||
return this.items.length > 0 && this.selectedIds.length === this.items.length
|
||||
},
|
||||
isPartChecked() {
|
||||
return this.selectedIds.length > 0 && this.selectedIds.length < this.items.length
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadCart()
|
||||
this.selectedIds = this.items.map(item => item.cartId)
|
||||
},
|
||||
methods: {
|
||||
remove() { Toast('请选择要删除的商品') }
|
||||
...mapActions(useCartStore, ['loadCart', 'removeItems']),
|
||||
isItemChecked(item) {
|
||||
return this.selectedIds.includes(item.cartId)
|
||||
},
|
||||
toggleItem(item, checked) {
|
||||
if (checked && !this.isItemChecked(item)) {
|
||||
this.selectedIds = [...this.selectedIds, item.cartId]
|
||||
return
|
||||
}
|
||||
|
||||
if (!checked) {
|
||||
this.selectedIds = this.selectedIds.filter(cartId => cartId !== item.cartId)
|
||||
}
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.selectedIds = checked ? this.items.map(item => item.cartId) : []
|
||||
},
|
||||
remove() {
|
||||
if (!this.selectedIds.length) {
|
||||
Toast('请选择要删除的商品')
|
||||
return
|
||||
}
|
||||
|
||||
this.removeItems(this.selectedIds)
|
||||
this.selectedIds = []
|
||||
Toast('已删除')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.edit-page { min-height: 100vh; padding-bottom: 60px; background: #f7f7f7; }
|
||||
.edit-page section { padding: 0 12px; }
|
||||
.edit-page .van-card { margin-top: 10px; border-radius: 10px; background: #fff; }
|
||||
<style scoped lang="less">
|
||||
.edit-page {
|
||||
min-height: 100vh;
|
||||
padding: 46px 0 58px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.edit-page ::v-deep .van-nav-bar {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
.edit-list {
|
||||
padding: 0 16px 14px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.edit-item {
|
||||
display: flex;
|
||||
min-height: 128px;
|
||||
align-items: center;
|
||||
padding: 16px 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.edit-item + .edit-item {
|
||||
border-top: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
.item-check {
|
||||
flex: none;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.edit-page ::v-deep .van-checkbox__icon--checked .van-icon {
|
||||
border-color: #ff5b20;
|
||||
background-color: #ff5b20;
|
||||
}
|
||||
|
||||
.item-thumb {
|
||||
width: 94px;
|
||||
height: 94px;
|
||||
flex: none;
|
||||
overflow: hidden;
|
||||
border-radius: 5px;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
min-height: 94px;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.item-info h3 {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
margin: 0 0 4px;
|
||||
color: #222;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.item-info p {
|
||||
overflow: hidden;
|
||||
margin: 0 0 6px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-tag {
|
||||
width: fit-content;
|
||||
color: #ff5b20;
|
||||
border-color: #ff9b73;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.item-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.item-bottom b {
|
||||
color: #ff5b20;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.item-bottom span {
|
||||
color: #777;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.edit-page ::v-deep .van-submit-bar {
|
||||
bottom: 0;
|
||||
height: 58px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.edit-page ::v-deep .van-submit-bar__bar {
|
||||
height: 58px;
|
||||
justify-content: space-between;
|
||||
padding: 0 18px;
|
||||
}
|
||||
|
||||
.edit-page ::v-deep .van-submit-bar__text {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.edit-page ::v-deep .van-submit-bar__button {
|
||||
width: 104px;
|
||||
height: 40px;
|
||||
border-radius: 22px;
|
||||
background: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,57 +1,40 @@
|
||||
<template>
|
||||
<main class="cart-page">
|
||||
<van-nav-bar title="购物车" right-text="编辑" @click-right="$router.push('/joyful-selection/cart/edit')" />
|
||||
<van-notice-bar text="满 199 元包邮,快去凑单吧~" left-icon="info-o" />
|
||||
<section class="cart-list">
|
||||
<van-empty v-if="!items.length" description="购物车还是空的" />
|
||||
<template v-else>
|
||||
<van-card
|
||||
v-for="item in items"
|
||||
:key="item.cartId"
|
||||
:title="item.name"
|
||||
:desc="item.desc"
|
||||
:price="item.price"
|
||||
:thumb="item.image"
|
||||
>
|
||||
<template #tags><van-tag plain type="danger">{{ item.tag }}</van-tag></template>
|
||||
<template #footer><van-stepper v-model="item.count" theme="round" button-size="22" @change="persistCart" /></template>
|
||||
</van-card>
|
||||
</template>
|
||||
</section>
|
||||
<van-submit-bar :price="totalPrice" :button-text="submitText" @submit="$router.push('/joyful-selection/checkout')">
|
||||
<van-checkbox v-model="checked">全选</van-checkbox>
|
||||
</van-submit-bar>
|
||||
<joyful-cart-panel fixed-submit page-mode @checkout="goCheckout" />
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
import JoyfulCartPanel from './components/JoyfulCartPanel.vue'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionCart',
|
||||
data: () => ({
|
||||
checked: true
|
||||
}),
|
||||
computed: {
|
||||
...mapState(useCartStore, ['items', 'totalCount', 'totalPrice']),
|
||||
submitText() {
|
||||
return `去结算(${this.totalCount})`
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadCart()
|
||||
components: {
|
||||
JoyfulCartPanel
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useCartStore, ['loadCart', 'persistCart'])
|
||||
goCheckout(items) {
|
||||
sessionStorage.setItem('joyful-selection-checkout-items', JSON.stringify(items))
|
||||
this.$router.push({ path: '/joyful-selection/checkout', query: { source: 'cart' } })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.cart-page { min-height: 100vh; padding-bottom: 106px; background: #f7f7f7; }
|
||||
.cart-list { padding: 0 12px; }
|
||||
.cart-list .van-card { margin-top: 10px; border-radius: 10px; background: #fff; }
|
||||
.cart-list ::v-deep .van-card__price { color: #ff5b20; font-weight: bold; }
|
||||
.van-submit-bar { bottom: 50px; }
|
||||
.cart-page {
|
||||
min-height: 100vh;
|
||||
padding-top: 46px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-page ::v-deep .van-nav-bar {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, .04);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,53 @@
|
||||
<template><main class="confirm-page"><van-nav-bar title="确认支付" left-arrow @click-left="$router.back()"/><section><p>支付金额</p><b>¥ 297.90</b></section><van-popup v-model="show" round position="bottom" :style="{height:'42%'}" :close-on-click-overlay="false"><article><h2>确认支付</h2><p>您即将使用微信支付</p><p>支付金额 <b>¥297.90</b></p><div><van-button round @click="$router.back()">取消</van-button><van-button round type="danger" @click="$router.push('/joyful-selection/payment-success')">确认支付</van-button></div></article></van-popup></main></template>
|
||||
<script>export default{name:'JoyfulSelectionPaymentConfirm',data:()=>({show:true})}</script>
|
||||
<style scoped>.confirm-page{min-height:100vh;background:#f7f7f7;text-align:center}.confirm-page section{margin:15px;padding:30px;border-radius:12px;background:#fff}.confirm-page section b{font-size:26px}.confirm-page article{padding:20px;text-align:center}.confirm-page article p{color:#666;font-size:13px}.confirm-page article div{display:flex;gap:10px;margin-top:40px}.confirm-page article .van-button{flex:1}</style>
|
||||
<template>
|
||||
<main class="confirm-page">
|
||||
<van-nav-bar title="确认支付" left-arrow @click-left="$router.back()" />
|
||||
<section>
|
||||
<p>支付金额</p>
|
||||
<b>¥ {{ amountText }}</b>
|
||||
</section>
|
||||
<van-popup v-model="show" round position="bottom" :style="{ height: '42%' }" :close-on-click-overlay="false">
|
||||
<article>
|
||||
<h2>确认支付</h2>
|
||||
<p>您即将使用{{ payTypeText }}</p>
|
||||
<p>支付金额 <b>¥{{ amountText }}</b></p>
|
||||
<div>
|
||||
<van-button round @click="$router.back()">取消</van-button>
|
||||
<van-button round type="danger" @click="$router.push({ path: '/joyful-selection/payment-success', query: { payType: $route.query.payType } })">确认支付</van-button>
|
||||
</div>
|
||||
</article>
|
||||
</van-popup>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { readPaymentInfo, formatYuan } from '../payment/payment-data'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionPaymentConfirm',
|
||||
data: () => ({
|
||||
show: true,
|
||||
paymentInfo: {}
|
||||
}),
|
||||
computed: {
|
||||
amountText() {
|
||||
return formatYuan(this.paymentInfo.amount)
|
||||
},
|
||||
payTypeText() {
|
||||
const map = {
|
||||
points: '积分支付',
|
||||
wechat: '微信支付',
|
||||
alipay: '支付宝支付'
|
||||
}
|
||||
|
||||
return map[this.$route.query.payType] || '积分支付'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.paymentInfo = readPaymentInfo()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.confirm-page{min-height:100vh;padding-top:46px;background:#f7f7f7;text-align:center}.confirm-page ::v-deep .van-nav-bar{position:fixed;z-index:20;top:0;right:0;left:0;box-shadow:0 1px 0 rgba(0,0,0,.04)}.confirm-page section{margin:15px;padding:30px;border-radius:12px;background:#fff}.confirm-page section b{font-size:26px}.confirm-page article{padding:20px;text-align:center}.confirm-page article p{color:#666;font-size:13px}.confirm-page article div{display:flex;gap:10px;margin-top:40px}.confirm-page article .van-button{flex:1}.confirm-page ::v-deep .van-button--danger{background:#ff5b20;border-color:#ff5b20}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,57 @@
|
||||
<template><main class="success-page"><van-icon name="checked" color="#20bd58" size="68"/><h2>支付成功</h2><b>¥ 297.90</b><section><p>订单编号 <span>YX2024051812345678</span></p><p>支付方式 <span>微信支付</span></p><p>支付时间 <span>2024-05-18 14:35:28</span></p></section><div><van-button round @click="$router.push('/joyful-selection/orders')">查看订单</van-button><van-button round type="danger" @click="$router.push('/joyful-selection/home')">继续购物</van-button></div></main></template>
|
||||
<script>export default{name:'JoyfulSelectionPaymentSuccess'}</script>
|
||||
<style scoped>.success-page{min-height:100vh;padding:80px 30px;text-align:center;background:#fff}.success-page h2{margin:15px 0 10px;font-size:17px}.success-page>b{font-size:22px}.success-page section{margin-top:42px;text-align:left;color:#888;font-size:12px}.success-page section p{display:flex;justify-content:space-between}.success-page section span{color:#333}.success-page>div{display:flex;gap:10px;margin-top:35px}.success-page .van-button{flex:1}</style>
|
||||
<template>
|
||||
<main class="success-page">
|
||||
<van-icon name="checked" color="#20bd58" size="68" />
|
||||
<h2>支付成功</h2>
|
||||
<b>¥ {{ amountText }}</b>
|
||||
<section>
|
||||
<p>订单编号 <span>{{ paymentInfo.orderNo || '-' }}</span></p>
|
||||
<p>支付方式 <span>{{ payTypeText }}</span></p>
|
||||
<p>支付时间 <span>{{ paidAt }}</span></p>
|
||||
</section>
|
||||
<div>
|
||||
<van-button round @click="$router.push('/joyful-selection/orders')">查看订单</van-button>
|
||||
<van-button round type="danger" @click="$router.push('/joyful-selection/home')">继续购物</van-button>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { readPaymentInfo, formatYuan } from '../payment/payment-data'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionPaymentSuccess',
|
||||
data: () => ({
|
||||
paymentInfo: {},
|
||||
paidAt: ''
|
||||
}),
|
||||
computed: {
|
||||
amountText() {
|
||||
return formatYuan(this.paymentInfo.amount)
|
||||
},
|
||||
payTypeText() {
|
||||
const map = {
|
||||
points: '积分支付',
|
||||
wechat: '微信支付',
|
||||
alipay: '支付宝支付'
|
||||
}
|
||||
|
||||
return map[this.$route.query.payType] || '积分支付'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.paymentInfo = readPaymentInfo()
|
||||
this.paidAt = this.formatTime(new Date())
|
||||
},
|
||||
methods: {
|
||||
formatTime(date) {
|
||||
const pad = value => String(value).padStart(2, '0')
|
||||
|
||||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.success-page{min-height:100vh;padding:80px 30px;text-align:center;background:#fff}.success-page h2{margin:15px 0 10px;font-size:17px}.success-page>b{font-size:22px}.success-page section{margin-top:42px;text-align:left;color:#888;font-size:12px}.success-page section p{display:flex;justify-content:space-between}.success-page section span{color:#333}.success-page>div{display:flex;gap:10px;margin-top:35px}.success-page .van-button{flex:1}.success-page .van-button--danger{background:#ff5b20;border-color:#ff5b20}
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,220 @@
|
||||
<template><main class="payment-page"><van-nav-bar title="确认支付" left-arrow @click-left="$router.back()"/><section class="pay-total"><p>支付金额</p><b>¥ 297.90</b></section><van-cell-group inset title="订单信息"><van-cell title="订单编号" value="YX2024051812345678"/><van-cell title="收货人" value="张三 138****8888"/></van-cell-group><van-radio-group v-model="payType"><van-cell-group inset title="支付方式"><van-cell title="微信支付" icon="wechat-pay" clickable @click="payType='wechat'"><template #right-icon><van-radio name="wechat"/></template></van-cell><van-cell title="支付宝支付" icon="alipay" clickable @click="payType='alipay'"><template #right-icon><van-radio name="alipay"/></template></van-cell><van-cell title="银联支付" icon="credit-pay" clickable @click="payType='union'"><template #right-icon><van-radio name="union"/></template></van-cell><van-cell title="余额支付(余额:¥32.00)" icon="gold-coin-o" clickable @click="payType='balance'"><template #right-icon><van-radio name="balance"/></template></van-cell></van-cell-group></van-radio-group><van-button class="pay-button" round type="danger" block @click="$router.push('/joyful-selection/payment-confirm')">立即支付 ¥297.90</van-button></main></template>
|
||||
<script>export default{name:'JoyfulSelectionPayment',data:()=>({payType:'wechat'})}</script>
|
||||
<style scoped>.payment-page{min-height:100vh;background:#f7f7f7}.pay-total{padding:25px;text-align:center;background:#fff}.pay-total p{margin:0;color:#666;font-size:13px}.pay-total b{display:block;margin-top:10px;font-size:26px}.van-cell-group{margin:10px 12px}.pay-button{position:fixed;right:16px;bottom:20px;left:16px;width:calc(100% - 32px)}</style>
|
||||
<template>
|
||||
<main class="payment-page">
|
||||
<van-nav-bar title="确认支付" left-arrow @click-left="$router.back()" />
|
||||
|
||||
<section class="amount-card">
|
||||
<p>支付金额</p>
|
||||
<b>¥ {{ amountText }}</b>
|
||||
</section>
|
||||
|
||||
<section class="info-card">
|
||||
<h3>订单信息</h3>
|
||||
<p><span>订单编号</span><b>{{ paymentInfo.orderNo || '-' }}</b></p>
|
||||
<p><span>收货人</span><b>{{ receiverText }}</b></p>
|
||||
</section>
|
||||
|
||||
<section class="pay-card">
|
||||
<h3>支付方式</h3>
|
||||
<van-radio-group v-model="payType">
|
||||
<van-cell
|
||||
v-for="item in payMethods"
|
||||
:key="item.name"
|
||||
clickable
|
||||
@click="payType = item.name"
|
||||
>
|
||||
<template #title>
|
||||
<div class="pay-method">
|
||||
<span class="pay-icon" :class="item.name">
|
||||
<van-icon :name="item.icon" />
|
||||
</span>
|
||||
<b>{{ item.label }}</b>
|
||||
</div>
|
||||
</template>
|
||||
<template #right-icon>
|
||||
<van-radio :name="item.name" checked-color="#ff5b20" />
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-radio-group>
|
||||
</section>
|
||||
|
||||
<van-button class="pay-button" round block @click="onPay">立即支付 ¥{{ amountText }}</van-button>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { readPaymentInfo, formatYuan } from './payment-data'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionPayment',
|
||||
data: () => ({
|
||||
payType: 'points',
|
||||
paymentInfo: {},
|
||||
pointsBalance: '32.00'
|
||||
}),
|
||||
computed: {
|
||||
amountText() {
|
||||
return formatYuan(this.paymentInfo.amount)
|
||||
},
|
||||
receiverText() {
|
||||
const name = this.paymentInfo.receiverName || '-'
|
||||
const tel = this.paymentInfo.receiverTel || ''
|
||||
|
||||
return tel ? `${name} ${tel}` : name
|
||||
},
|
||||
payMethods() {
|
||||
return [
|
||||
{ name: 'points', label: `积分支付(余额:¥${this.pointsBalance})`, icon: 'gold-coin-o' },
|
||||
{ name: 'wechat', label: '微信支付', icon: 'wechat-pay' },
|
||||
{ name: 'alipay', label: '支付宝支付', icon: 'alipay' }
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.paymentInfo = readPaymentInfo()
|
||||
},
|
||||
methods: {
|
||||
onPay() {
|
||||
this.$router.push({ path: '/joyful-selection/payment-confirm', query: { payType: this.payType } })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.payment-page {
|
||||
min-height: 100vh;
|
||||
padding: 46px 8px 84px;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.payment-page ::v-deep .van-nav-bar {
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, .04);
|
||||
}
|
||||
|
||||
.amount-card,
|
||||
.info-card,
|
||||
.pay-card {
|
||||
margin-top: 10px;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.amount-card {
|
||||
padding: 24px 16px 27px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.amount-card p {
|
||||
margin: 0 0 14px;
|
||||
color: #333;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.amount-card b {
|
||||
color: #222;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
padding: 14px 12px 12px;
|
||||
}
|
||||
|
||||
.info-card h3,
|
||||
.pay-card h3 {
|
||||
margin: 0 0 12px;
|
||||
color: #222;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.info-card p {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
color: #777;
|
||||
font-size: 12px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.info-card b {
|
||||
color: #333;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.pay-card {
|
||||
overflow: hidden;
|
||||
padding: 14px 0 4px;
|
||||
}
|
||||
|
||||
.pay-card h3 {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.pay-card ::v-deep .van-cell {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.pay-card ::v-deep .van-cell::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pay-method {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pay-method b {
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.pay-icon {
|
||||
display: flex;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 8px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.pay-icon .van-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.pay-icon.points {
|
||||
background: #ffb000;
|
||||
}
|
||||
|
||||
.pay-icon.wechat {
|
||||
background: #18c764;
|
||||
}
|
||||
|
||||
.pay-icon.alipay {
|
||||
background: #1989fa;
|
||||
}
|
||||
|
||||
.pay-button {
|
||||
position: fixed;
|
||||
right: 8px;
|
||||
bottom: 18px;
|
||||
left: 8px;
|
||||
width: calc(100% - 16px);
|
||||
height: 44px;
|
||||
border: 0;
|
||||
color: #fff;
|
||||
background: #ff5b20;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
const PAYMENT_KEY = 'joyful-selection-payment-info'
|
||||
|
||||
export const createOrderNo = () => {
|
||||
const now = new Date()
|
||||
const pad = value => String(value).padStart(2, '0')
|
||||
const timestamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`
|
||||
|
||||
return `YX${timestamp}`
|
||||
}
|
||||
|
||||
export const savePaymentInfo = info => {
|
||||
sessionStorage.setItem(PAYMENT_KEY, JSON.stringify(info))
|
||||
}
|
||||
|
||||
export const readPaymentInfo = () => {
|
||||
try {
|
||||
return JSON.parse(sessionStorage.getItem(PAYMENT_KEY) || '{}')
|
||||
} catch (error) {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
export const formatYuan = price => (Number(price || 0) / 100).toFixed(2)
|
||||
@@ -68,7 +68,7 @@ export default {
|
||||
{ name: '超值专区', icon: 'label', color: '#ec8c3d', background: '#fff4e9' },
|
||||
{ name: '全部分类', icon: 'apps-o', color: '#989898', background: '#f5f5f5' }
|
||||
],
|
||||
flashProducts: joyfulProducts,
|
||||
flashProducts: joyfulProducts.slice(0, 4),
|
||||
hotProducts: [joyfulProducts[2], joyfulProducts[0], joyfulProducts[1], joyfulProducts[3]]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -4,19 +4,32 @@
|
||||
<van-tabbar v-if="showTabbar" route active-color="#ff5b20" inactive-color="#777">
|
||||
<van-tabbar-item icon="wap-home-o" to="/joyful-selection/home">首页</van-tabbar-item>
|
||||
<van-tabbar-item icon="apps-o" to="/joyful-selection/products">分类</van-tabbar-item>
|
||||
<van-tabbar-item icon="cart-o" to="/joyful-selection/cart">购物车</van-tabbar-item>
|
||||
<van-tabbar-item icon="cart-o" :badge="cartBadge" to="/joyful-selection/cart">购物车</van-tabbar-item>
|
||||
<van-tabbar-item icon="user-o" to="/joyful-selection/profile">我的</van-tabbar-item>
|
||||
</van-tabbar>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionLayout',
|
||||
computed: {
|
||||
...mapState(useCartStore, ['totalCount']),
|
||||
cartBadge() {
|
||||
return this.totalCount > 0 ? this.totalCount : ''
|
||||
},
|
||||
showTabbar() {
|
||||
return ['/joyful-selection/home', '/joyful-selection/products', '/joyful-selection/cart', '/joyful-selection/profile'].includes(this.$route.path)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadCart()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useCartStore, ['loadCart'])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -3,6 +3,87 @@ import miniOvenImage from '@/assets/joyful-selection/products/mini-oven.png'
|
||||
import smartSpeakerImage from '@/assets/joyful-selection/products/smart-speaker.png'
|
||||
import giftBoxImage from '@/assets/joyful-selection/products/gift-box.png'
|
||||
|
||||
const productImages = {
|
||||
bluetoothEarbuds: bluetoothEarbudsImage,
|
||||
miniOven: miniOvenImage,
|
||||
smartSpeaker: smartSpeakerImage,
|
||||
giftBox: giftBoxImage
|
||||
}
|
||||
|
||||
const createProduct = ({ id, name, desc, detail, price, sales, image, categoryId, category, tag = '赠品' }) => ({
|
||||
id,
|
||||
name,
|
||||
desc,
|
||||
detail: detail || desc,
|
||||
price,
|
||||
originPrice: (Number(price) * 1.25).toFixed(2),
|
||||
sales,
|
||||
image,
|
||||
categoryId,
|
||||
category,
|
||||
tag
|
||||
})
|
||||
|
||||
export const joyfulCategories = [
|
||||
{ id: 'recommend', name: '推荐' },
|
||||
{ id: 'homeLiving', name: '居家生活' },
|
||||
{ id: 'digitalAppliance', name: '数码家电' },
|
||||
{ id: 'beautyCare', name: '美妆个护' },
|
||||
{ id: 'foodDrink', name: '食品饮料' },
|
||||
{ id: 'motherBaby', name: '母婴玩具' },
|
||||
{ id: 'fashionBag', name: '服饰鞋包' },
|
||||
{ id: 'sportsOutdoor', name: '运动户外' }
|
||||
]
|
||||
|
||||
const categoryNameMap = joyfulCategories.reduce((map, category) => {
|
||||
map[category.id] = category.name
|
||||
return map
|
||||
}, {})
|
||||
|
||||
const rawProducts = [
|
||||
['cream-oven', '奶油白家用迷你烤箱', '小巧不占地,早餐烘焙好帮手', '129.00', '1.2万件', productImages.miniOven, 'homeLiving'],
|
||||
['cotton-bedding', '100%纯棉舒适四件套', '柔软亲肤,安心睡眠', '179.00', '6453件', productImages.miniOven, 'homeLiving'],
|
||||
['aroma-gift', '橙意香薰礼盒套装', '淡雅留香,装点居家空间', '59.90', '8321件', productImages.giftBox, 'homeLiving'],
|
||||
['desktop-vase', '简约北欧陶瓷花瓶', '清新配色,点亮桌面角落', '39.90', '3180件', productImages.giftBox, 'homeLiving'],
|
||||
['earbuds-air2', '小米蓝牙耳机 Air2 SE', '轻盈半入耳,通勤运动都好听', '69.90', '1.2万件', productImages.bluetoothEarbuds, 'digitalAppliance'],
|
||||
['smart-speaker-pro', '黑曜智能音箱 Pro', '语音唤醒,沉浸听感', '99.00', '2.1万件', productImages.smartSpeaker, 'digitalAppliance'],
|
||||
['electric-toothbrush', '智能声波电动牙刷', '高频洁净,呵护口腔', '129.00', '2.1万件', productImages.bluetoothEarbuds, 'digitalAppliance'],
|
||||
['dual-charger', '双口快充充电器 30W', '小巧便携,多设备快充', '69.00', '5632件', productImages.smartSpeaker, 'digitalAppliance'],
|
||||
['skin-care-box', '植萃保湿护肤礼盒', '水润修护,清爽不粘腻', '99.90', '4820件', productImages.giftBox, 'beautyCare'],
|
||||
['aroma-wash', '香氛洗护旅行套装', '温和清洁,清新留香', '59.90', '7932件', productImages.giftBox, 'beautyCare'],
|
||||
['makeup-mirror', '便携补光化妆镜', '高清镜面,随时补妆', '49.90', '3651件', productImages.smartSpeaker, 'beautyCare'],
|
||||
['hand-cream', '滋润护手霜三支装', '细腻滋养,轻柔香气', '39.90', '5280件', productImages.giftBox, 'beautyCare'],
|
||||
['orange-gift', '橙意惊喜零食礼盒', '精致包装,送礼更有心意', '59.90', '6324件', productImages.giftBox, 'foodDrink'],
|
||||
['coffee-cup', '咖啡随行杯组合', '锁温防漏,醇香随行', '49.90', '3520件', productImages.bluetoothEarbuds, 'foodDrink'],
|
||||
['tea-snack', '下午茶点心礼盒', '多种风味,一盒满足', '69.90', '4891件', productImages.giftBox, 'foodDrink'],
|
||||
['fruit-drink', '轻享果饮礼盒', '清爽酸甜,聚会常备', '79.90', '2976件', productImages.giftBox, 'foodDrink'],
|
||||
['baby-bottle', '安心防摔儿童水杯', '轻巧易握,出门好携带', '39.90', '4250件', productImages.bluetoothEarbuds, 'motherBaby'],
|
||||
['toy-blocks', '益智拼搭积木套装', '色彩柔和,陪伴成长', '89.00', '2186件', productImages.giftBox, 'motherBaby'],
|
||||
['kids-night-light', '柔光儿童陪伴夜灯', '温和光线,安心入睡', '69.90', '3548件', productImages.smartSpeaker, 'motherBaby'],
|
||||
['baby-towel', '纯棉柔软浴巾两件装', '亲肤吸水,日常必备', '59.90', '2761件', productImages.miniOven, 'motherBaby'],
|
||||
['laptop-backpack', '大容量双肩电脑背包', '分区收纳,通勤出行轻松装', '149.00', '1.6万件', productImages.giftBox, 'fashionBag'],
|
||||
['mini-bag', '轻巧通勤斜挎小包', '简洁百搭,日常实用', '79.90', '5321件', productImages.giftBox, 'fashionBag'],
|
||||
['silk-scarf', '柔软撞色丝巾礼盒', '细腻亲肤,点亮穿搭', '69.90', '2680件', productImages.giftBox, 'fashionBag'],
|
||||
['canvas-tote', '简约帆布托特包', '大容量开口,随手能装', '49.90', '6412件', productImages.giftBox, 'fashionBag'],
|
||||
['sport-bottle', '运动便携保温水杯', '长效锁温,户外随行', '49.90', '7342件', productImages.bluetoothEarbuds, 'sportsOutdoor'],
|
||||
['neck-massager', '筋膜放松按摩仪 Mini', '轻巧便携,舒缓酸胀', '99.00', '3921件', productImages.smartSpeaker, 'sportsOutdoor'],
|
||||
['camping-light', '户外便携露营灯', '多档照明,夜晚更安心', '79.00', '2568件', productImages.smartSpeaker, 'sportsOutdoor'],
|
||||
['fitness-band', '弹力健身拉力带套装', '居家训练,轻松塑形', '29.90', '4396件', productImages.miniOven, 'sportsOutdoor']
|
||||
]
|
||||
|
||||
export const joyfulProductList = rawProducts.map(([id, name, desc, price, sales, image, categoryId]) =>
|
||||
createProduct({
|
||||
id,
|
||||
name,
|
||||
desc,
|
||||
price,
|
||||
sales,
|
||||
image,
|
||||
categoryId,
|
||||
category: categoryNameMap[categoryId]
|
||||
})
|
||||
)
|
||||
|
||||
export const joyfulProducts = [
|
||||
{
|
||||
id: 'bluetooth-earbuds',
|
||||
@@ -47,7 +128,8 @@ export const joyfulProducts = [
|
||||
category: '食品饮料',
|
||||
tag: '品质精选',
|
||||
image: giftBoxImage
|
||||
}
|
||||
},
|
||||
...joyfulProductList
|
||||
]
|
||||
|
||||
export const getJoyfulProduct = id => joyfulProducts.find(item => item.id === id) || joyfulProducts[0]
|
||||
|
||||
@@ -59,13 +59,24 @@
|
||||
|
||||
<van-goods-action>
|
||||
<van-goods-action-icon icon="chat-o" text="客服" dot />
|
||||
<van-goods-action-icon icon="cart-o" text="购物车" :badge="cartBadge" @click="$router.push('/joyful-selection/cart')" />
|
||||
<van-goods-action-icon icon="cart-o" text="购物车" :badge="cartBadge" @click="openCartPopup" />
|
||||
<van-goods-action-icon icon="star" text="已收藏" color="#ff5000" />
|
||||
<van-goods-action-button type="warning" text="加入购物车" @click="openSku('cart')" />
|
||||
<van-goods-action-button type="danger" text="立即购买" @click="openSku('buy')" />
|
||||
</van-goods-action>
|
||||
|
||||
<joyful-sku-popup ref="skuPopup" @add-cart="loadCart" />
|
||||
<van-popup v-model="showCartPopup" class="cart-popup" position="bottom" round>
|
||||
<header class="cart-popup-head">
|
||||
<b>购物车</b>
|
||||
<van-icon name="cross" @click="showCartPopup = false" />
|
||||
</header>
|
||||
<joyful-cart-panel
|
||||
ref="cartPanel"
|
||||
class="cart-popup-panel"
|
||||
@checkout="goCheckout"
|
||||
/>
|
||||
</van-popup>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
@@ -73,14 +84,17 @@
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
import { useCartStore } from '@/store/cart'
|
||||
import { getJoyfulProduct } from '../product-data'
|
||||
import JoyfulSkuPopup from '../components/JoyfulSkuPopup.vue'
|
||||
import JoyfulSkuPopup from '../products/components/JoyfulSkuPopup.vue'
|
||||
import JoyfulCartPanel from '../cart/components/JoyfulCartPanel.vue'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionProductDetail',
|
||||
components: {
|
||||
JoyfulSkuPopup
|
||||
JoyfulSkuPopup,
|
||||
JoyfulCartPanel
|
||||
},
|
||||
data: () => ({
|
||||
showCartPopup: false,
|
||||
count: 1,
|
||||
features: [
|
||||
{ icon: 'music-o', title: '舒适半入耳设计', desc: '长时间佩戴更舒适' },
|
||||
@@ -101,6 +115,20 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useCartStore, ['loadCart']),
|
||||
openCartPopup() {
|
||||
this.loadCart()
|
||||
this.showCartPopup = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.cartPanel) {
|
||||
this.$refs.cartPanel.selectAllItems()
|
||||
}
|
||||
})
|
||||
},
|
||||
goCheckout(items) {
|
||||
sessionStorage.setItem('joyful-selection-checkout-items', JSON.stringify(items))
|
||||
this.showCartPopup = false
|
||||
this.$router.push({ path: '/joyful-selection/checkout', query: { source: 'cart' } })
|
||||
},
|
||||
openSku(mode) {
|
||||
this.$refs.skuPopup.open(this.product, mode)
|
||||
}
|
||||
@@ -357,4 +385,39 @@ export default {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.cart-popup {
|
||||
display: flex;
|
||||
height: 76vh;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cart-popup-head {
|
||||
display: flex;
|
||||
height: 48px;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.cart-popup-head b {
|
||||
color: #222;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cart-popup-head .van-icon {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
color: #999;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.cart-popup-panel {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
+98
-25
@@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<van-sku
|
||||
v-model="show"
|
||||
:class="`sku-popup--${mode}`"
|
||||
:sku="sku"
|
||||
:goods="skuGoods"
|
||||
:goods-id="currentGoods.id"
|
||||
:initial-sku="initialSku"
|
||||
:hide-stock="sku.hide_stock"
|
||||
:show-add-cart-btn="mode === 'cart'"
|
||||
:show-buy-btn="mode === 'buy'"
|
||||
:show-stepper="false"
|
||||
:show-add-cart-btn="mode !== 'buy'"
|
||||
:show-buy-btn="true"
|
||||
:preview-on-click-image="true"
|
||||
add-cart-text="加入购物车"
|
||||
buy-text="立即购买"
|
||||
@@ -61,13 +63,19 @@ export default {
|
||||
},
|
||||
sku() {
|
||||
const price = Math.round(Number(this.currentGoods.price) * 100)
|
||||
const imageOptions = colorOptions.map(color => ({
|
||||
...color,
|
||||
imgUrl: this.currentGoods.image,
|
||||
previewImgUrl: this.currentGoods.image
|
||||
}))
|
||||
|
||||
return {
|
||||
tree: [
|
||||
{
|
||||
k: '颜色',
|
||||
k_s: 's1',
|
||||
v: colorOptions
|
||||
v: imageOptions,
|
||||
largeImageMode: true
|
||||
},
|
||||
{
|
||||
k: '尺寸',
|
||||
@@ -81,13 +89,13 @@ export default {
|
||||
s1: color.id,
|
||||
s2: size.id,
|
||||
price,
|
||||
stock_num: 99
|
||||
stock_num: 227
|
||||
}))
|
||||
),
|
||||
price: this.currentGoods.price,
|
||||
stock_num: 99,
|
||||
stock_num: 227,
|
||||
none_sku: false,
|
||||
hide_stock: true
|
||||
hide_stock: false
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -129,50 +137,115 @@ export default {
|
||||
this.$emit('add-cart')
|
||||
},
|
||||
onBuyClicked(data) {
|
||||
this.addCart(data)
|
||||
const item = this.getCartPayload(data)
|
||||
|
||||
sessionStorage.setItem('joyful-selection-checkout-items', JSON.stringify([item]))
|
||||
this.show = false
|
||||
this.$emit('buy')
|
||||
this.$router.push('/joyful-selection/checkout')
|
||||
this.$router.push({ path: '/joyful-selection/checkout', query: { source: 'buy' } })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
::v-deep .van-sku-container {
|
||||
overflow: hidden;
|
||||
border-radius: 14px 14px 0 0;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-header {
|
||||
min-height: 118px;
|
||||
min-height: 96px;
|
||||
padding: 18px 42px 12px 16px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-header__img-wrap {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
border-radius: 8px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-header__goods-info {
|
||||
min-height: 110px;
|
||||
padding-top: 2px;
|
||||
min-height: 66px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::v-deep .van-sku__goods-price {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
::v-deep .van-sku__goods-name {
|
||||
color: #111;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
margin-top: 7px;
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku__price-symbol,
|
||||
::v-deep .van-sku__price-num {
|
||||
color: #ff5b20;
|
||||
color: #f0182d;
|
||||
}
|
||||
|
||||
::v-deep .van-sku__price-symbol {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku__price-num {
|
||||
font-size: 22px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
::v-deep .van-sku__stock {
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku__selected-name {
|
||||
margin-top: 8px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-body {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-group-container {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-row {
|
||||
margin: 0;
|
||||
padding: 0 0 12px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-row__title {
|
||||
padding-bottom: 12px;
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-row__row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-row:not(:first-child) .van-sku-row__item {
|
||||
height: 31px;
|
||||
margin: 0 10px 8px 0;
|
||||
padding: 0 14px;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
background: #f6f7f9;
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
line-height: 31px;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-row__item--active {
|
||||
color: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
color: #ff5b20 !important;
|
||||
border-color: #ff5b20 !important;
|
||||
background: #fff8f4 !important;
|
||||
}
|
||||
|
||||
::v-deep .van-sku-actions .van-button--danger {
|
||||
background: #ff5b20;
|
||||
border-color: #ff5b20;
|
||||
}
|
||||
</style>
|
||||
@@ -52,103 +52,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { joyfulProducts } from '../product-data'
|
||||
import JoyfulSkuPopup from '../components/JoyfulSkuPopup.vue'
|
||||
|
||||
const productImages = joyfulProducts.map(item => item.image)
|
||||
|
||||
const categories = [
|
||||
{
|
||||
id: 'recommend',
|
||||
name: '推荐',
|
||||
products: []
|
||||
},
|
||||
{
|
||||
id: 'homeLiving',
|
||||
name: '居家生活',
|
||||
products: [
|
||||
['cream-oven', '奶油白家用迷你烤箱', '小巧不占地,早餐烘焙好帮手', '129.00', '1.2万件', productImages[1]],
|
||||
['cotton-bedding', '100%纯棉舒适四件套', '柔软亲肤,安心睡眠', '179.00', '6453件', productImages[1]],
|
||||
['aroma-gift', '橙意香薰礼盒套装', '淡雅留香,装点居家空间', '59.90', '8321件', productImages[3]],
|
||||
['desktop-vase', '简约北欧陶瓷花瓶', '清新配色,点亮桌面角落', '39.90', '3180件', productImages[3]]
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'digitalAppliance',
|
||||
name: '数码家电',
|
||||
products: [
|
||||
['earbuds-air2', '小米蓝牙耳机 Air2 SE', '轻盈半入耳,通勤运动都好听', '69.90', '1.2万件', productImages[0]],
|
||||
['smart-speaker-pro', '黑曜智能音箱 Pro', '语音唤醒,沉浸听感', '99.00', '2.1万件', productImages[2]],
|
||||
['electric-toothbrush', '智能声波电动牙刷', '高频洁净,呵护口腔', '129.00', '2.1万件', productImages[0]],
|
||||
['dual-charger', '双口快充充电器 30W', '小巧便携,多设备快充', '69.00', '5632件', productImages[2]]
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'beautyCare',
|
||||
name: '美妆个护',
|
||||
products: [
|
||||
['skin-care-box', '植萃保湿护肤礼盒', '水润修护,清爽不粘腻', '99.90', '4820件', productImages[3]],
|
||||
['aroma-wash', '香氛洗护旅行套装', '温和清洁,清新留香', '59.90', '7932件', productImages[3]],
|
||||
['makeup-mirror', '便携补光化妆镜', '高清镜面,随时补妆', '49.90', '3651件', productImages[2]],
|
||||
['hand-cream', '滋润护手霜三支装', '细腻滋养,轻柔香气', '39.90', '5280件', productImages[3]]
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'foodDrink',
|
||||
name: '食品饮料',
|
||||
products: [
|
||||
['orange-gift', '橙意惊喜零食礼盒', '精致包装,送礼更有心意', '59.90', '6324件', productImages[3]],
|
||||
['coffee-cup', '咖啡随行杯组合', '锁温防漏,醇香随行', '49.90', '3520件', productImages[0]],
|
||||
['tea-snack', '下午茶点心礼盒', '多种风味,一盒满足', '69.90', '4891件', productImages[3]],
|
||||
['fruit-drink', '轻享果饮礼盒', '清爽酸甜,聚会常备', '79.90', '2976件', productImages[3]]
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'motherBaby',
|
||||
name: '母婴玩具',
|
||||
products: [
|
||||
['baby-bottle', '安心防摔儿童水杯', '轻巧易握,出门好携带', '39.90', '4250件', productImages[0]],
|
||||
['toy-blocks', '益智拼搭积木套装', '色彩柔和,陪伴成长', '89.00', '2186件', productImages[3]],
|
||||
['kids-night-light', '柔光儿童陪伴夜灯', '温和光线,安心入睡', '69.90', '3548件', productImages[2]],
|
||||
['baby-towel', '纯棉柔软浴巾两件装', '亲肤吸水,日常必备', '59.90', '2761件', productImages[1]]
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'fashionBag',
|
||||
name: '服饰鞋包',
|
||||
products: [
|
||||
['laptop-backpack', '大容量双肩电脑背包', '分区收纳,通勤出行轻松装', '149.00', '1.6万件', productImages[3]],
|
||||
['mini-bag', '轻巧通勤斜挎小包', '简洁百搭,日常实用', '79.90', '5321件', productImages[3]],
|
||||
['silk-scarf', '柔软撞色丝巾礼盒', '细腻亲肤,点亮穿搭', '69.90', '2680件', productImages[3]],
|
||||
['canvas-tote', '简约帆布托特包', '大容量开口,随手能装', '49.90', '6412件', productImages[3]]
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'sportsOutdoor',
|
||||
name: '运动户外',
|
||||
products: [
|
||||
['sport-bottle', '运动便携保温水杯', '长效锁温,户外随行', '49.90', '7342件', productImages[0]],
|
||||
['neck-massager', '筋膜放松按摩仪 Mini', '轻巧便携,舒缓酸胀', '99.00', '3921件', productImages[2]],
|
||||
['camping-light', '户外便携露营灯', '多档照明,夜晚更安心', '79.00', '2568件', productImages[2]],
|
||||
['fitness-band', '弹力健身拉力带套装', '居家训练,轻松塑形', '29.90', '4396件', productImages[1]]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const productCategories = categories.filter(category => category.id !== 'recommend')
|
||||
|
||||
const goods = productCategories.flatMap(category =>
|
||||
category.products.map(([id, name, desc, price, sales, image]) => ({
|
||||
id,
|
||||
name,
|
||||
desc,
|
||||
price,
|
||||
sales,
|
||||
image,
|
||||
categoryId: category.id,
|
||||
tag: '赠品'
|
||||
}))
|
||||
)
|
||||
import { joyfulCategories, joyfulProductList } from '../product-data'
|
||||
import JoyfulSkuPopup from './components/JoyfulSkuPopup.vue'
|
||||
|
||||
export default {
|
||||
name: 'JoyfulSelectionProductList',
|
||||
@@ -158,8 +63,8 @@ export default {
|
||||
data: () => ({
|
||||
selectedCategoryId: 'recommend',
|
||||
keyword: '',
|
||||
categories,
|
||||
goods
|
||||
categories: joyfulCategories,
|
||||
goods: joyfulProductList
|
||||
}),
|
||||
computed: {
|
||||
visibleGoods() {
|
||||
|
||||
@@ -37,7 +37,8 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.orders-page { min-height: 100vh; background: #f7f7f7; }
|
||||
.orders-page { min-height: 100vh; padding-top: 46px; background: #f7f7f7; }
|
||||
.orders-page ::v-deep .van-nav-bar { position: fixed; z-index: 20; top: 0; right: 0; left: 0; box-shadow: 0 1px 0 rgba(0, 0, 0, .04); }
|
||||
.orders-page section { padding: 0 12px; }
|
||||
.orders-page article { margin-top: 10px; border-radius: 10px; background: #fff; }
|
||||
.orders-page header, .orders-page footer { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px; color: #999; font-size: 11px; }
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<template><main class="points-page"><van-nav-bar title="我的积分" left-arrow @click-left="$router.back()"/><section class="score"><small>可用积分</small><b>2368</b><van-button size="small" round @click="$router.push('/joyful-selection/products')">积分说明</van-button></section><van-grid :column-num="4" :border="false"><van-grid-item icon="gift-o" text="积分商城"/><van-grid-item icon="gift-card-o" text="积分抽奖"/><van-grid-item icon="balance-list-o" text="积分兑换"/><van-grid-item icon="todo-list-o" text="积分签到"/></van-grid><section class="details"><h3>积分明细</h3><van-cell v-for="item in items" :key="item.title" :title="item.title" :label="item.time" :value="item.value" :value-class="item.value[0] === '+' ? 'income' : 'cost'"/><p>没有更多了~</p></section></main></template>
|
||||
<script>export default{name:'JoyfulSelectionPoints',data:()=>({items:[{title:'签到奖励',time:'2024-05-18 09:30',value:'+10'},{title:'订单完成奖励',time:'2024-05-14 10:20',value:'+88'},{title:'积分兑换',time:'2024-05-08 15:11',value:'-200'},{title:'晒单奖励',time:'2024-05-02 08:30',value:'+20'},{title:'评价奖励',time:'2024-04-28 12:08',value:'+5'}]})}</script>
|
||||
<style scoped>.points-page{min-height:100vh;background:#f7f7f7}.score{position:relative;margin:10px 12px;padding:16px 18px;border-radius:10px;background:linear-gradient(135deg,#ffe0ac,#ffc66e)}.score small,.score b{display:block}.score small{font-size:11px}.score b{margin-top:6px;font-size:22px}.score .van-button{position:absolute;right:14px;top:24px;background:rgba(255,255,255,.6)}.points-page>.van-grid{margin:0 12px;border-radius:10px;background:#fff}.details{margin:10px 12px;padding:2px 0;border-radius:10px;background:#fff}.details h3{margin:14px;font-size:14px}.details p{text-align:center;color:#aaa;font-size:11px}.income{color:#14a44d}.cost{color:#f15b45}</style>
|
||||
<style scoped>.points-page{min-height:100vh;padding-top:46px;background:#f7f7f7}.points-page ::v-deep .van-nav-bar{position:fixed;z-index:20;top:0;right:0;left:0;box-shadow:0 1px 0 rgba(0,0,0,.04)}.score{position:relative;margin:10px 12px;padding:16px 18px;border-radius:10px;background:linear-gradient(135deg,#ffe0ac,#ffc66e)}.score small,.score b{display:block}.score small{font-size:11px}.score b{margin-top:6px;font-size:22px}.score .van-button{position:absolute;right:14px;top:24px;background:rgba(255,255,255,.6)}.points-page>.van-grid{margin:0 12px;border-radius:10px;background:#fff}.details{margin:10px 12px;padding:2px 0;border-radius:10px;background:#fff}.details h3{margin:14px;font-size:14px}.details p{text-align:center;color:#aaa;font-size:11px}.income{color:#14a44d}.cost{color:#f15b45}</style>
|
||||
|
||||
Reference in New Issue
Block a user