购物车
This commit is contained in:
@@ -2,7 +2,8 @@
|
|||||||
<div class="shopping-cart">
|
<div class="shopping-cart">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<sc-list @selected-change="(v) => (selectedList = v)" />
|
<sc-list @selected-change="(v) => (selectedList = v)" />
|
||||||
<order-summary :brands-list="selectedList" />
|
<!-- <sc-list is-mini is-view title="Order Summary" /> -->
|
||||||
|
<order-summary :list="selectedList" />
|
||||||
</div>
|
</div>
|
||||||
<my-footer />
|
<my-footer />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="title">Order Summary</div>
|
<div class="title">Order Summary</div>
|
||||||
<div class="count">
|
<div class="count">
|
||||||
<span class="label">Selected</span>
|
<span class="label">Selected</span>
|
||||||
<span class="value">3</span>
|
<span class="value">{{ brandsList.length }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="hr"></div>
|
<div class="hr"></div>
|
||||||
<div class="brands-header">
|
<div class="brands-header">
|
||||||
@@ -12,7 +12,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="brands-item" v-for="v in brandsList" :key="v.brand">
|
<div class="brands-item" v-for="v in brandsList" :key="v.brand">
|
||||||
<span class="label">{{ v.brand }}</span>
|
<span class="label">{{ v.brand }}</span>
|
||||||
<span class="value"><span>1</span>item</span>
|
<span class="value"
|
||||||
|
><span>{{ v.children.length }}</span
|
||||||
|
>item</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div class="total-file-size">
|
<div class="total-file-size">
|
||||||
@@ -42,24 +45,37 @@
|
|||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { FormatBytes, FormatDate } from '@/utils/tools'
|
import { FormatBytes, FormatDate } from '@/utils/tools'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
brandsList: {
|
list: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const brandsList = computed(() => {
|
||||||
|
const arr = []
|
||||||
|
props.list.forEach((v) => {
|
||||||
|
const index = arr.findIndex((v_) => v_.brand === v.brand)
|
||||||
|
if (index === -1) {
|
||||||
|
arr.push({
|
||||||
|
brand: v.brand,
|
||||||
|
children: [v]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
arr[index].children.push(v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return arr
|
||||||
|
})
|
||||||
const totalSize = computed(() => {
|
const totalSize = computed(() => {
|
||||||
const total = props.brandsList.reduce((pre, cur) => pre + cur.fileSize, 0)
|
const total = props.list.reduce((pre, cur) => pre + cur.fileSize, 0)
|
||||||
const str = FormatBytes(total)
|
const str = FormatBytes(total)
|
||||||
return {
|
return {
|
||||||
size: str.split(' ')[0],
|
size: str.split(' ')[0],
|
||||||
unit: str.split(' ')[1]
|
unit: str.split(' ')[1]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const totalAmount = computed(() =>
|
const totalAmount = computed(() => props.list.reduce((pre, cur) => pre + cur.amount, 0).toFixed(2))
|
||||||
props.brandsList.reduce((pre, cur) => pre + cur.amount, 0).toFixed(2)
|
|
||||||
)
|
|
||||||
const handleCheckout = () => {
|
const handleCheckout = () => {
|
||||||
console.log('购买:', props.brandsList)
|
console.log('购买:', props.list)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 购物车列表 -->
|
<!-- 购物车列表 -->
|
||||||
<div class="sc-list" :class="{ mini: isMini }">
|
<div class="sc-list" :class="{ mini: isMini, view: isView }">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<span class="text">Shopping Cart</span>
|
<span class="text">{{ title || 'Shopping Cart' }}</span>
|
||||||
<span class="close" v-if="isMini" @click="onClose"
|
<span class="close" v-if="isMini && !isView" @click="onClose"
|
||||||
><svg-icon name="close" size="13"
|
><svg-icon name="close" size="13"
|
||||||
/></span>
|
/></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,10 +52,10 @@
|
|||||||
<span class="icon"><svg-icon name="order-shop" size="24" /></span>
|
<span class="icon"><svg-icon name="order-shop" size="24" /></span>
|
||||||
<span class="text">{{ v.brand }}</span>
|
<span class="text">{{ v.brand }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tags" v-if="!isMini">
|
<div class="tags" v-if="!isMini || isView">
|
||||||
<span v-for="tag in v.tags" :key="tag" class="tag">{{ tag }}</span>
|
<span v-for="tag in v.tags" :key="tag" class="tag">{{ tag }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="size">
|
<div class="size" v-if="!isView">
|
||||||
<div class="icon"><svg-icon name="order-file" size="18" /></div>
|
<div class="icon"><svg-icon name="order-file" size="18" /></div>
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<span>{{ FormatBytes(v.fileSize) }}</span>
|
<span>{{ FormatBytes(v.fileSize) }}</span>
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<div class="amount">${{ v.amount }}<span> HKD</span></div>
|
<div class="amount">${{ v.amount }}<span> HKD</span></div>
|
||||||
<div class="remove">
|
<div class="remove" v-if="!isView">
|
||||||
<span class="icon"><svg-icon name="order-delete" size="18" /></span>
|
<span class="icon"><svg-icon name="order-delete" size="18" /></span>
|
||||||
<span class="text">Remove</span>
|
<span class="text">Remove</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -77,11 +77,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer" v-if="isMini">
|
<div class="footer" v-if="isMini">
|
||||||
|
<div class="total size" v-show="list.length > 0">
|
||||||
|
<span class="label">Total File Size</span>
|
||||||
|
<span class="value"
|
||||||
|
>{{ allTotalSize.size }}<span> {{ allTotalSize.unit }}</span></span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<div class="total" v-show="list.length > 0">
|
<div class="total" v-show="list.length > 0">
|
||||||
<span class="label">Total</span>
|
<span class="label">Total</span>
|
||||||
<span class="value">$45.00<span> HKD</span></span>
|
<span class="value">${{ allAmount }}<span> HKD</span></span>
|
||||||
</div>
|
</div>
|
||||||
<button custom="black">CHECKOUT</button>
|
|
||||||
|
<div class="tip" v-if="isView">Digital assets. Creator retains copyright.</div>
|
||||||
|
<button custom="black" v-if="!isView">CHECKOUT</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -91,11 +99,19 @@
|
|||||||
import { FormatBytes, FormatDate } from '@/utils/tools'
|
import { FormatBytes, FormatDate } from '@/utils/tools'
|
||||||
const emit = defineEmits(['close', 'selected-change'])
|
const emit = defineEmits(['close', 'selected-change'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isMini: {
|
title: { type: String, default: '' },
|
||||||
type: Boolean,
|
isMini: { type: Boolean, default: false },
|
||||||
default: false
|
isView: { type: Boolean, default: false }
|
||||||
|
})
|
||||||
|
const allTotalSize = computed(() => {
|
||||||
|
const total = list.value.reduce((pre, cur) => pre + cur.fileSize, 0)
|
||||||
|
const str = FormatBytes(total)
|
||||||
|
return {
|
||||||
|
size: str.split(' ')[0],
|
||||||
|
unit: str.split(' ')[1]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const allAmount = computed(() => list.value.reduce((pre, cur) => pre + cur.amount, 0).toFixed(2))
|
||||||
const selectedCount = computed(() => list.value.filter((v) => v.checked).length)
|
const selectedCount = computed(() => list.value.filter((v) => v.checked).length)
|
||||||
const allSelected = computed(() => list.value.every((v) => v.checked))
|
const allSelected = computed(() => list.value.every((v) => v.checked))
|
||||||
const sortBy = ref('')
|
const sortBy = ref('')
|
||||||
@@ -136,6 +152,39 @@
|
|||||||
amount: 9.99,
|
amount: 9.99,
|
||||||
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
||||||
checked: false
|
checked: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
url: 'http://118.31.39.42:3000/falls/shopping-cart-3.png',
|
||||||
|
title: 'Static Street Suit',
|
||||||
|
brand: 'Off Grid Apparel',
|
||||||
|
fileSize: 1024 * 18, // kb
|
||||||
|
date: '2026-5-21 13:14',
|
||||||
|
amount: 12,
|
||||||
|
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
||||||
|
checked: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
url: 'http://118.31.39.42:3000/falls/shopping-cart-4.png',
|
||||||
|
title: 'Maison Contour Suit',
|
||||||
|
brand: 'Ivory Muse Studio',
|
||||||
|
fileSize: 100, // kb
|
||||||
|
date: '2026-5-21 13:14',
|
||||||
|
amount: 18,
|
||||||
|
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
||||||
|
checked: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
url: 'http://118.31.39.42:3000/falls/shopping-cart-5.png',
|
||||||
|
title: 'Prime Atelier Set',
|
||||||
|
brand: 'Ivory Muse Studio',
|
||||||
|
fileSize: 1024 * 24, // kb
|
||||||
|
date: '2026-5-21 13:14',
|
||||||
|
amount: 20,
|
||||||
|
tags: ['female', 'skirt', 'blouse', 'outwear'],
|
||||||
|
checked: false
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
const handleAllAllClick = (checked?: boolean) => {
|
const handleAllAllClick = (checked?: boolean) => {
|
||||||
@@ -194,6 +243,61 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.mini.view {
|
||||||
|
--sc-list-title-padding-bottom: 2.4rem;
|
||||||
|
--sc-list-list-item-img-width: 9.6rem;
|
||||||
|
--sc-list-list-item-img-height: 12.2rem;
|
||||||
|
--sc-list-list-item-padding: 1.6rem;
|
||||||
|
--sc-list-list-item-margin-bottom: 0.8rem;
|
||||||
|
--sc-list-list-item-title-font-size: 2rem;
|
||||||
|
> .header {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
> .list {
|
||||||
|
> .item {
|
||||||
|
> .content {
|
||||||
|
margin-top: 1.2rem;
|
||||||
|
> .tags {
|
||||||
|
> .tag {
|
||||||
|
min-width: 0;
|
||||||
|
height: 2rem;
|
||||||
|
line-height: 2rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
padding: 0 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .right {
|
||||||
|
margin-top: 1.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .footer {
|
||||||
|
margin-top: 4.1rem;
|
||||||
|
> .total {
|
||||||
|
margin-bottom: 1.7rem;
|
||||||
|
> .label {
|
||||||
|
font-family: KaiseiOpti-Medium;
|
||||||
|
font-size: 2rem;
|
||||||
|
color: #232323;
|
||||||
|
}
|
||||||
|
> .value {
|
||||||
|
font-family: KaiseiOpti-Medium;
|
||||||
|
font-size: 2.2rem;
|
||||||
|
> span {
|
||||||
|
font-family: KaiseiOpti-Regular;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .tip {
|
||||||
|
font-family: KaiseiOpti-Regular;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #808080;
|
||||||
|
margin-top: 2.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
&:not(.mini) {
|
&:not(.mini) {
|
||||||
> .header {
|
> .header {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
|||||||
Reference in New Issue
Block a user