feat(share): 分享注册商品列表添加临时购物车

This commit is contained in:
woody 2025-10-30 13:41:48 +08:00
parent f08d22400d
commit d7111956ed
2 changed files with 616 additions and 170 deletions

View File

@ -97,34 +97,17 @@
>已售罄</text
>
</view>
<!-- <img @click.stop="addCar(item)"
src="@/static/images/cart.png"
alt=""> -->
</view>
<!-- 数量控制区域 -->
<view class="quantity-section" v-if="item.isSale !== 1">
<view class="quantity-control">
<view
class="quantity-btn minus"
:class="{ disabled: item.quantity <= 1 }"
@click.stop="updateQuantity(item, -1)"
>
<text class="quantity-icon"></text>
</view>
<view class="quantity-display">
<text class="quantity-text">{{
item.quantity || 1
}}</text>
</view>
<view
class="quantity-btn plus"
@click.stop="updateQuantity(item, 1)"
>
<text class="quantity-icon">+</text>
</view>
<!-- 加入购物车按钮区域 -->
<view class="add-cart-section" v-if="item.isSale !== 1">
<view class="add-cart-btn" @click.stop="addToCart(item)">
<u-icon
color="#fff"
size="20"
name="shopping-cart"
></u-icon>
</view>
<view class="toBuy" @click.stop="goBuy(item)">购买</view>
</view>
<!-- 禁售状态 -->
@ -160,32 +143,13 @@
<text class="price">{{ formatCurrency(item.waresPrice) }}</text>
<text v-if="item.isSale === 1" class="sale-status">已售罄</text>
</view>
<!-- <img @click.stop="addCar(item)"
src="@/static/images/cart.png"
alt=""> -->
</view>
<!-- 数量控制区域 -->
<view class="quantity-section" v-if="item.isSale !== 1">
<view class="quantity-control">
<view
class="quantity-btn minus"
:class="{ disabled: item.quantity <= 1 }"
@click.stop="updateQuantity(item, -1)"
>
<text class="quantity-icon"></text>
</view>
<view class="quantity-display">
<text class="quantity-text">{{ item.quantity || 1 }}</text>
</view>
<view
class="quantity-btn plus"
@click.stop="updateQuantity(item, 1)"
>
<text class="quantity-icon">+</text>
</view>
<!-- 加入购物车按钮区域 -->
<view class="add-cart-section" v-if="item.isSale !== 1">
<view class="add-cart-btn" @click.stop="addToCart(item)">
<u-icon color="#fff" size="20" name="shopping-cart"></u-icon>
</view>
<view class="toBuy" @click.stop="goBuy(item)">购买</view>
</view>
<!-- 禁售状态 -->
@ -199,6 +163,112 @@
</view>
</scroll-view>
</view>
<!-- 底部购物车栏 -->
<view class="cart-bar">
<view class="cart-bar-left" @click="toggleCartDrawer">
<view class="cart-icon-wrapper">
<text class="cart-icon"
><u-icon color="#fff" size="36" name="shopping-cart"> </u-icon
></text>
<view class="cart-badge" v-if="cartTotalCount > 0">
{{ cartTotalCount > 99 ? '99+' : cartTotalCount }}
</view>
</view>
<view class="cart-price" v-if="cartTotalCount > 0">
<text class="cart-price-label">总计</text>
<text class="cart-price-value">{{
formatCurrency(cartTotalAmount)
}}</text>
</view>
<!-- <view class="cart-empty-tip" v-else>
<text class="cart-empty-text">购物车是空的</text>
</view> -->
</view>
<view
class="cart-bar-btn"
@click="goCheckout"
:class="{ disabled: cartTotalCount === 0 }"
>
去结算
</view>
</view>
<!-- 购物车抽屉 -->
<u-popup
v-if="showCartDrawer"
:show="showCartDrawer"
mode="bottom"
border-radius="30"
:closeable="true"
@close="showCartDrawer = false"
>
<view class="cart-drawer">
<view class="cart-drawer-header">
<text class="cart-drawer-title">购物车</text>
<text class="cart-drawer-count">({{ cartTotalCount }}件商品)</text>
</view>
<scroll-view class="cart-drawer-content" scroll-y="true">
<view
v-for="(item, index) in currentCart"
:key="item.waresCode"
class="cart-item"
>
<view class="cart-item-top">
<image
:src="item.cover1"
class="cart-item-image"
mode="aspectFill"
></image>
<view class="cart-item-info">
<view class="cart-item-name">{{ item.waresName }}</view>
<view class="cart-item-price">{{
formatCurrency(item.waresPrice)
}}</view>
</view>
</view>
<view class="cart-item-actions">
<view class="cart-quantity-control">
<view
class="cart-quantity-btn"
:class="{ disabled: item.quantity <= 1 }"
@click="updateCartQuantity(index, -1)"
>
<text class="cart-quantity-icon"></text>
</view>
<view class="cart-quantity-display">
<text class="cart-quantity-text">{{ item.quantity }}</text>
</view>
<view
class="cart-quantity-btn"
@click="updateCartQuantity(index, 1)"
>
<text class="cart-quantity-icon">+</text>
</view>
</view>
<view class="cart-item-delete" @click="removeFromCart(index)">
<text class="cart-delete-icon">删除</text>
</view>
</view>
</view>
<view v-if="currentCart.length === 0" class="cart-empty">
<text class="cart-empty-text">购物车空空如也~</text>
</view>
</scroll-view>
<view class="cart-drawer-footer" v-if="currentCart.length > 0">
<view class="cart-footer-total">
<text class="cart-footer-label">合计</text>
<text class="cart-footer-amount">{{
formatCurrency(cartTotalAmount)
}}</text>
</view>
<view class="cart-footer-btn" @click="goCheckout"> 去结算 </view>
</view>
</view>
</u-popup>
</view>
</template>
@ -235,8 +305,32 @@ export default {
userInfo: {}, //
pkCountry: 1, // ID
categoryLoaded: false, //
// - tab
cartData: {
43: [], //
41: [], //
},
showCartDrawer: false, //
}
},
computed: {
// tab
currentCart() {
return this.cartData[this.activeTab] || []
},
//
cartTotalCount() {
return this.currentCart.reduce((total, item) => total + item.quantity, 0)
},
//
cartTotalAmount() {
return this.currentCart.reduce(
(total, item) => total + item.waresPrice * item.quantity,
0
)
},
},
onLoad(options) {
this.pkParent = options.pkParent
this.userInfo = uni.getStorageSync('User') || {}
@ -279,11 +373,7 @@ export default {
specialArea: this.activeTab,
})
.then(res => {
// quantity
this.goodList = res.data.map(item => ({
...item,
quantity: item.quantity || 1,
}))
this.goodList = res.data || []
})
},
switchTab(value) {
@ -304,21 +394,106 @@ export default {
}
}
},
updateQuantity(item, change) {
const newQuantity = (item.quantity || 1) + change
if (newQuantity >= 1) {
// 使Vue.set
this.$set(item, 'quantity', newQuantity)
//
addToCart(item) {
const cart = this.cartData[this.activeTab]
const existingIndex = cart.findIndex(
cartItem => cartItem.waresCode === item.waresCode
)
if (existingIndex > -1) {
// +1
this.$set(
cart[existingIndex],
'quantity',
cart[existingIndex].quantity + 1
)
uni.showToast({
title: '已添加到购物车',
icon: 'success',
duration: 1500,
})
} else {
//
cart.push({
...item,
quantity: 1,
})
uni.showToast({
title: '添加成功',
icon: 'success',
duration: 1500,
})
}
},
goBuy(item) {
const params = {
...item,
//
updateCartQuantity(index, change) {
const cart = this.cartData[this.activeTab]
const newQuantity = cart[index].quantity + change
if (newQuantity >= 1) {
this.$set(cart[index], 'quantity', newQuantity)
} else if (newQuantity === 0) {
// 0
this.removeFromCart(index)
}
},
//
removeFromCart(index) {
uni.showModal({
title: '提示',
content: '确定要删除该商品吗?',
success: res => {
if (res.confirm) {
this.cartData[this.activeTab].splice(index, 1)
uni.showToast({
title: '删除成功',
icon: 'success',
duration: 1500,
})
}
},
zIndex: 10076, //
})
},
//
toggleCartDrawer() {
if (this.cartTotalCount === 0) {
uni.showToast({
title: '购物车是空的',
icon: 'none',
duration: 1500,
})
return
}
this.showCartDrawer = true
},
//
goCheckout() {
if (this.currentCart.length === 0) {
uni.showToast({
title: '购物车是空的',
icon: 'none',
duration: 1500,
})
return
}
//
this.showCartDrawer = false
//
const orderData = {
cartList: this.currentCart,
pkParent: this.pkParent,
specialArea: this.activeTab,
}
uni.navigateTo({
url: '/pages/shareArea/hiOrder?allData=' + JSON.stringify(item),
url: '/pages/shareArea/hiOrder?allData=' + JSON.stringify(orderData),
})
},
//
@ -381,11 +556,7 @@ export default {
api
.queryWares(params)
.then(res => {
// quantity
this.goodList = (res.data || []).map(item => ({
...item,
quantity: item.quantity || 1,
}))
this.goodList = res.data || []
})
.catch(err => {
console.log(err, '...err')
@ -434,7 +605,6 @@ export default {
background: #ffffff;
border-bottom: 1rpx solid #e2e8f0;
flex: 1;
height: 0;
display: flex;
flex-direction: column;
@ -559,6 +729,7 @@ export default {
flex: 1;
overflow: hidden;
background: #fff;
padding-bottom: 140rpx;
.goodList {
padding: 0;
.goodList_i {
@ -700,7 +871,7 @@ export default {
.goods-container {
flex: 1;
background: #f8fafc;
padding: 24rpx 24rpx 0;
padding: 24rpx 24rpx 140rpx;
position: relative;
z-index: 3;
overflow: hidden;
@ -735,19 +906,7 @@ export default {
display: flex;
background: #ffffff;
border-radius: 24rpx;
margin-bottom: 24rpx;
padding: 32rpx;
box-shadow: 0 4rpx 20rpx rgba(102, 126, 234, 0.08);
border: 1rpx solid rgba(102, 126, 234, 0.08);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
animation: slideInUp 0.6s ease-out both;
opacity: 0;
&:hover {
transform: translateY(-6rpx);
box-shadow: 0 16rpx 40rpx rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.15);
}
.cover {
width: 240rpx;
@ -823,69 +982,28 @@ export default {
}
}
//
.quantity-section {
//
.add-cart-section {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
justify-content: flex-end;
margin-top: 16rpx;
.quantity-control {
.add-cart-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
background: #f8fafc;
border-radius: 20rpx;
border: 1rpx solid #e2e8f0;
overflow: hidden;
justify-content: center;
background: linear-gradient(135deg, #005bac 0%, #003d7a 100%);
color: #ffffff;
border-radius: 50%;
border: none;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2rpx 8rpx rgba(0, 91, 172, 0.3);
.quantity-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
transition: all 0.2s ease;
cursor: pointer;
.quantity-icon {
font-size: 32rpx;
font-weight: 600;
color: #667eea;
}
&.minus {
&.disabled {
opacity: 0.3;
cursor: not-allowed;
.quantity-icon {
color: #9ca3af;
}
}
}
&:not(.disabled):active {
background: #f1f5f9;
transform: scale(0.95);
}
}
.quantity-display {
min-width: 80rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border-left: 1rpx solid #e2e8f0;
border-right: 1rpx solid #e2e8f0;
.quantity-text {
font-size: 28rpx;
font-weight: 600;
color: #1f2937;
}
&:active {
transform: scale(0.9);
box-shadow: 0 1rpx 4rpx rgba(0, 91, 172, 0.2);
}
}
}
@ -1075,4 +1193,323 @@ export default {
.goodList_i:nth-child(n + 6) {
animation-delay: 0.6s;
}
//
.cart-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 120rpx;
background: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32rpx;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
z-index: 1000;
.cart-bar-left {
display: flex;
align-items: center;
gap: 24rpx;
flex: 1;
cursor: pointer;
.cart-icon-wrapper {
position: relative;
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #005bac 0%, #003d7a 100%);
border-radius: 50%;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
}
.cart-icon {
font-size: 40rpx;
}
.cart-badge {
position: absolute;
top: -8rpx;
right: -8rpx;
background: #ff4d4f;
color: #ffffff;
font-size: 20rpx;
font-weight: 600;
padding: 4rpx 8rpx;
border-radius: 20rpx;
min-width: 32rpx;
text-align: center;
border: 2rpx solid #ffffff;
}
}
.cart-price {
display: flex;
align-items: baseline;
.cart-price-label {
font-size: 28rpx;
color: #64748b;
margin-right: 8rpx;
}
.cart-price-value {
font-size: 36rpx;
font-weight: 700;
color: #ff6b35;
}
}
}
.cart-bar-btn {
background: linear-gradient(135deg, #005bac 0%, #003d7a 100%);
color: #ffffff;
padding: 20rpx 48rpx;
border-radius: 60rpx;
font-size: 28rpx;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(0, 91, 172, 0.4);
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
box-shadow: 0 2rpx 8rpx rgba(0, 91, 172, 0.3);
}
&.disabled {
background: #cbd5e1;
color: #94a3b8;
box-shadow: none;
cursor: not-allowed;
&:active {
transform: none;
}
}
}
.cart-empty-tip {
.cart-empty-text {
font-size: 26rpx;
color: #94a3b8;
}
}
}
//
.cart-drawer {
background: #ffffff;
max-height: 80vh;
display: flex;
flex-direction: column;
.cart-drawer-header {
padding: 32rpx;
border-bottom: 1rpx solid #f1f5f9;
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
.cart-drawer-title {
font-size: 32rpx;
font-weight: 600;
color: #1e293b;
}
.cart-drawer-count {
font-size: 28rpx;
color: #64748b;
}
}
.cart-drawer-content {
flex: 1;
max-height: 60vh;
overflow-y: auto;
.cart-item {
display: flex;
flex-direction: column;
padding: 24rpx 32rpx;
border-bottom: 1rpx solid #f1f5f9;
gap: 20rpx;
.cart-item-top {
display: flex;
align-items: center;
gap: 24rpx;
.cart-item-image {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
background: #f8fafc;
border: 1rpx solid #e2e8f0;
flex-shrink: 0;
}
.cart-item-info {
flex: 1;
min-width: 0;
.cart-item-name {
font-size: 28rpx;
color: #1e293b;
font-weight: 500;
margin-bottom: 12rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.cart-item-price {
font-size: 32rpx;
color: #ff6b35;
font-weight: 700;
}
}
}
.cart-item-actions {
display: flex;
align-items: center;
justify-content: space-between;
.cart-quantity-control {
display: flex;
align-items: center;
background: #f8fafc;
border-radius: 12rpx;
border: 1rpx solid #e2e8f0;
overflow: hidden;
.cart-quantity-btn {
width: 48rpx;
height: 48rpx;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
transition: all 0.2s ease;
.cart-quantity-icon {
font-size: 28rpx;
font-weight: 600;
color: #005bac;
}
&.disabled {
opacity: 0.3;
.cart-quantity-icon {
color: #9ca3af;
}
}
&:not(.disabled):active {
background: #f1f5f9;
transform: scale(0.9);
}
}
.cart-quantity-display {
min-width: 60rpx;
height: 48rpx;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border-left: 1rpx solid #e2e8f0;
border-right: 1rpx solid #e2e8f0;
.cart-quantity-text {
font-size: 26rpx;
font-weight: 600;
color: #1f2937;
}
}
}
.cart-item-delete {
padding: 12rpx 24rpx;
background: rgba(239, 68, 68, 0.1);
border-radius: 8rpx;
transition: all 0.2s ease;
.cart-delete-icon {
font-size: 26rpx;
color: #ef4444;
font-weight: 500;
}
&:active {
background: rgba(239, 68, 68, 0.2);
transform: scale(0.95);
}
}
}
}
.cart-empty {
padding: 120rpx 0;
text-align: center;
.cart-empty-text {
font-size: 28rpx;
color: #9ca3af;
}
}
}
.cart-drawer-footer {
padding: 24rpx 32rpx;
border-top: 1rpx solid #f1f5f9;
display: flex;
align-items: center;
justify-content: space-between;
background: #ffffff;
.cart-footer-total {
display: flex;
align-items: baseline;
.cart-footer-label {
font-size: 28rpx;
color: #64748b;
margin-right: 8rpx;
}
.cart-footer-amount {
font-size: 40rpx;
font-weight: 700;
color: #ff6b35;
}
}
.cart-footer-btn {
background: linear-gradient(135deg, #005bac 0%, #003d7a 100%);
color: #ffffff;
padding: 20rpx 48rpx;
border-radius: 60rpx;
font-size: 28rpx;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(0, 91, 172, 0.4);
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
box-shadow: 0 2rpx 8rpx rgba(0, 91, 172, 0.3);
}
}
}
}
</style>

View File

@ -84,7 +84,7 @@
<u-form-item
:label="'收货地址'"
prop="diqu"
@click="getDiqu"
@click="addressHandle"
required
borderBottom
>
@ -124,25 +124,29 @@
<view class="subTxt1">商品信息</view>
</view>
<view class="goodList">
<view class="goodList_i">
<view
v-for="item in allData.cartList"
:key="item.pkId"
class="goodList_i"
>
<view class="goodList_it">
<img :src="allData.cover1" class="cover" alt="" />
<img :src="item.cover1" class="cover" alt="" />
<view class="goodList_ir">
<view class="goodList_ib">
<view class="tit1">
{{ allData.waresName }}
{{ item.waresName }}
</view>
<view class="tit5"> x{{ allData.quantity }} </view>
<view class="tit5"> x{{ item.quantity }} </view>
</view>
<view class="goodList_ib">
<view class="tit2">
{{ allData.waresPrice | numberToCurrency }}
{{ item.waresPrice | numberToCurrency }}
</view>
<!-- <view class="tit3">业绩: {{ item.achieve | numberToCurrency | isLocal}}</view> -->
</view>
</view>
</view>
<view
<!-- <view
v-for="(item, sndex) in allData.specsSkuParamsList"
:key="sndex"
class="product_i"
@ -154,7 +158,7 @@
>
<view class="tit5">x{{ item.quantity }}</view>
</view>
</view>
</view> -->
<view class="fen">
<!-- <view class="disFlex justBwn">
<view class="tit3">{{'商品业绩'}}</view>
@ -163,7 +167,7 @@
<view class="disFlex justBwn">
<view class="tit3">{{ '金额小计' }}</view>
<view class="tit1">{{
(allData.waresPrice * allData.quantity) | numberToCurrency
(item.waresPrice * item.quantity) | numberToCurrency
}}</view>
</view>
</view>
@ -319,11 +323,6 @@ export default {
this.centerCodeId = this.user.memberCode
this.pkCountry = 1
this.allData = JSON.parse(options.allData)
console.log(
'%c [ this.allData ]-336',
'font-size:13px; background:#f67b85; color:#ffbfc9;',
this.allData
)
this.placeParent = uni.getStorageSync('placeParent')
this.setGoodlistType()
this.getGenerate()
@ -334,16 +333,16 @@ export default {
onShow() {},
computed: {
totalPrice() {
if (!this.allData?.cartList?.length) return 0
return (
this.allData.waresPrice * this.allData.quantity +
Number(this.form.postage)
this.allData.cartList?.reduce(
(total, item) => total + item.waresPrice * item.quantity,
0
) + Number(this.form.postage)
)
},
},
methods: {
regionSelectHandle() {
this.$refs.regionAddress.setShow(this.provinceList[0].pkId)
},
phonePass(rule, value, callback) {
if (!value) {
callback(new Error('请输入联系电话'))
@ -436,25 +435,26 @@ export default {
})
},
setGoodlistType() {
let carList = {
quantity: this.allData?.quantity || 1,
pkWares: this.allData.pkId,
skuList: [],
}
this.allData.productGroup.forEach(item => {
carList.skuList.push({
pkWaresSku: item.pkSkuId,
console.log(this.allData.cartList, 'this.allData.cartList')
const cartList = this.allData.cartList.map(item => {
return {
quantity: item.quantity,
})
pkWares: item.pkId,
skuList: item.productGroup.map(item => ({
pkWaresSku: item.pkSkuId,
quantity: item.quantity,
})),
}
})
this.waresList = [carList]
this.waresList = cartList
},
checkboxChange() {},
getDiqu() {
addressHandle() {
this.$refs.address.setShow()
},
confirmPopup() {},
addressData(diqu, obj) {
console.log(diqu, obj, 'diqu, obj')
this.form.diqu = diqu
this.form.recProvince = obj.province
this.form.recCity = obj.city
@ -464,6 +464,12 @@ export default {
// this.setGoodlistType()
// this.queryAdressPostage()
},
getPrice(good) {
return good.waresPrice * good.quantity
},
getTotalPrice() {
this.totalPrice = this.priceAmount + this.form.postage
},
},
}
</script>
@ -672,6 +678,7 @@ export default {
padding: 20rpx;
border-bottom: 1px solid #eee;
background: #fff;
flex-direction: column;
}
.cover {
width: 136rpx;
@ -682,6 +689,7 @@ export default {
}
.goodList_i {
flex: 1;
margin-bottom: 20rpx;
}
.goodList_it {
display: flex;
@ -726,7 +734,8 @@ export default {
}
.fen {
background: #f6f6f6;
padding: 0 28rpx 28rpx 28rpx;
// padding: 0 28rpx 28rpx 28rpx;
line-height: 60rpx;
}
.u-form-item {
::v-deep .u-form-item__body {