Browse Source

购物车

dev_des
1054425342@qq.com 1 month ago
parent
commit
e68764777f
  1. 6
      subPackages/techan/detail.vue
  2. 201
      subPackages/techan/order.vue
  3. 277
      subPackages/user/gwc.vue

6
subPackages/techan/detail.vue

@ -295,7 +295,9 @@
...goods,
specUrl:goods.imageUrl,
goodsName:this.info.goodsName,
quantity:goods.buyNum
quantity:goods.buyNum,
supplierId:this.info.supplierId,
supplierName:this.info.supplierName,
}]
this.$store.commit("changeOrderSCart", list);
this.gotoPath("/subPackages/techan/order");
@ -303,7 +305,7 @@
addToCart () {
let goods = this.sku[this.productIndex]
goods.buyNum = this.buyNum
this.Post({goodsId: this.info.goodsId, specCombinationId: goods.specCombinationId,quantity: this.buyNum,method:'post' },
this.Post({goodsId: this.info.goodsId, specCombinationId: goods.specCombinationId,quantity: this.buyNum,method:'post',supplierId:this.info.supplierId, },
'/framework/cart/add',"DES").then(res => {
if (res.code==200) {
let selectedData = []

201
subPackages/techan/order.vue

@ -63,10 +63,18 @@
</view>
</view>
</view>
<view class="new-box" v-for="(sku, index) in info" :key="index">
<!-- <view class="box shop-name text-overflow" v-if="sku.goodsInfo.merchant_name">
{{sku.goodsInfo.merchant_name}}
</view> -->
<!-- 按供应商分组显示商品 -->
<view v-for="(supplierGroup, supplierIndex) in groupedGoods" :key="supplierGroup.supplierId">
<!-- 供应商卡片 -->
<view class="supplier-card">
<!-- 供应商名称 -->
<view class="supplier-header">
<text class="supplier-name">{{ supplierGroup.supplierName }}</text>
</view>
<!-- 该供应商的商品列表 -->
<view class="supplier-goods">
<view class="commodity-item" v-for="(sku, index) in supplierGroup.goods" :key="index">
<view class="commodity box">
<image
class="img"
@ -91,10 +99,9 @@
<view class="commodity box sb" style="padding-left: 10rpx" v-if="false">
<view class="title" style="font-weight: bold"> 购买数量 </view>
<view class="num-box">
<!-- <image src="https://yjdtadmin.sz-trip.com/uploads/20231225/4b61998e657784d08c8dfdb08da84553.png" mode="aspectFill" class="ctrl" @click="reduce()"></image> -->
<view
:class="['ctrl', sku.quantity > 1 ? '' : 'disabled']"
@click="reduce(sku, index)"
@click="reduce(sku, supplierIndex, index)"
>-</view
>
<input
@ -107,31 +114,15 @@
</view>
</view>
</view>
<!-- 订单信息卡片 -->
<view class="order-info-card" style="margin-bottom: 36rpx">
<!-- 积分兑换 -->
<view class="card-section">
<view class="section-row" @click="openPointsPopup">
<text class="section-label">积分兑换</text>
<div style="display: flex; align-items: center">
<view class="section-value coupon">{{
usePoints > 0
? `已抵扣¥${(usePoints / POINTS_TO_YUAN_RATIO).toFixed(2)}`
: "可用积分" + userPoints
}}</view>
<uni-icons type="right" color="#999999" size="16"></uni-icons>
</div>
</view>
</view>
<!-- 备注 -->
<view class="card-section">
<!-- 该供应商的备注 -->
<view class="supplier-remark">
<view class="section-row">
<text class="section-label">备注</text>
<view class="note-input">
<input
v-model="remark"
v-model="supplierRemarks[supplierGroup.supplierId]"
placeholder="选填"
placeholder-class="placeholder"
maxlength="200"
@ -139,12 +130,23 @@
</view>
</view>
</view>
</view>
</view>
<!-- 运费 -->
<!-- 订单信息卡片 -->
<view class="order-info-card" style="margin-bottom: 36rpx">
<!-- 积分兑换 -->
<view class="card-section">
<view class="section-row">
<text class="section-label">运费</text>
<text class="section-value">包邮</text>
<view class="section-row" @click="openPointsPopup">
<text class="section-label">积分兑换</text>
<div style="display: flex; align-items: center">
<view class="section-value coupon">{{
usePoints > 0
? `已抵扣¥${(usePoints / POINTS_TO_YUAN_RATIO).toFixed(2)}`
: "可用积分" + userPoints
}}</view>
<uni-icons type="right" color="#999999" size="16"></uni-icons>
</div>
</view>
</view>
@ -154,6 +156,10 @@
<view class="text">商品总价:</view>
<view class="price">{{ getGoodsTotal() }}</view>
</view>
<view class="price-detail">
<view class="text">运费:</view>
<view class="price">包邮</view>
</view>
<view class="price-detail" v-if="usePoints > 0">
<view class="text">积分抵扣:</view>
<view class="price deduction"
@ -358,7 +364,9 @@ export default {
reserve_name: "",
reserve_idcard: "",
reserve_phone: "",
remark: "",
remark: "", //
supplierRemarks: {}, // ID
groupedGoods: [], //
coupon: "",
allprice: 0,
@ -398,7 +406,7 @@ export default {
this.isPost = this.info.is_post || "1";
// this.info.is_post = this.isPost==3?1:this.isPost
}
// this.handleOrderGoods()
this.handleOrderGoods();
// console.log(this.isPost);
},
onShow() {
@ -421,6 +429,37 @@ export default {
//
},
methods: {
//
handleOrderGoods() {
if (!this.info || !Array.isArray(this.info)) {
this.groupedGoods = [];
return;
}
// supplierId
const supplierMap = new Map();
this.info.forEach(item => {
const supplierId = item.supplierId || 'default';
const supplierName = item.supplierName || '默认供应商';
if (!supplierMap.has(supplierId)) {
supplierMap.set(supplierId, {
supplierId,
supplierName,
goods: []
});
//
this.$set(this.supplierRemarks, supplierId, '');
}
supplierMap.get(supplierId).goods.push(item);
});
this.groupedGoods = Array.from(supplierMap.values());
console.log('分组后的商品:', this.groupedGoods);
},
//
async getTotalPoints() {
try {
@ -582,7 +621,7 @@ export default {
}
});
},
reduce(sku, index) {
reduce(sku, supplierIndex, index) {
if (sku.quantity > 1) {
this.$nextTick(() => {
sku.quantity -= 1;
@ -592,10 +631,20 @@ export default {
});
} else if (sku.quantity == 1) {
this.$nextTick(() => {
this.info.splice(index, 1);
// info
const skuIndex = this.info.findIndex(item =>
item.goodsName === sku.goodsName &&
item.specValueOne === sku.specValueOne &&
item.specValueTwo === sku.specValueTwo
);
if (skuIndex !== -1) {
this.info.splice(skuIndex, 1);
}
if (this.flag) {
this.getPost();
}
//
this.handleOrderGoods();
});
}
@ -865,10 +914,20 @@ export default {
this.isOrderLoading = true; //
// createDtos
let createDtos = [];
this.groupedGoods.forEach(supplierGroup => {
const supplierRemark = this.supplierRemarks[supplierGroup.supplierId] || '';
createDtos.push({
supplierId: supplierGroup.supplierId,
remark: supplierRemark,
shoppingCartBoList: supplierGroup.goods
});
});
let data = {
shoppingCartBoList: this.info,
createDtos: createDtos,
userContactId: this.contacts.id,
remark: this.remark,
expectedAmount: this.allprice,
usePoints: this.usePoints ? 0 : 1, // 使
pointsQuantity: parseInt(this.usePoints) || 0, // 使
@ -1890,6 +1949,78 @@ $bg-light: #f9f9f9;
border-radius: 14rpx;
}
//
.supplier-card {
background-color: #ffffff;
border-radius: 16rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
width: 697rpx;
margin: 30rpx auto;
overflow: hidden;
border: 1rpx solid #f0f0f0;
}
//
.supplier-header {
padding: 20rpx 24rpx;
background: #ffffff;
.supplier-name {
font-size: 30rpx;
font-weight: 600;
color: #333333;
}
}
//
.supplier-goods {
padding: 0;
.commodity-item {
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
}
}
//
.supplier-remark {
background-color: #ffffff;
padding: 20rpx 24rpx;
border-top: 1rpx solid #f0f0f0;
.section-row {
display: flex;
justify-content: space-between;
align-items: center;
min-height: 60rpx;
.section-label {
font-size: 28rpx;
color: #333333;
font-weight: 500;
}
.note-input {
flex: 1;
margin-left: 40rpx;
input {
font-size: 26rpx;
color: #333333;
text-align: right;
width: 100%;
}
.placeholder {
color: #999999;
}
}
}
}
.tickets-box {
width: 698rpx;
margin: 26rpx auto 0;

277
subPackages/user/gwc.vue

@ -4,33 +4,56 @@
operate
}}</view>
<view>
<view class="goodBox" v-if="list.length">
<!-- <view class="title" v-if="item.data.some((v) => v.flag == 1)">{{ item.merchant_name }}<uni-icons
size="16" color="#000000" type="arrowright" /></view> -->
<view class="goodItem" v-for="(goodItem, goodIndex) in list" :key="goodIndex" v-if="goodItem.flag != 0">
<view class="noSelect" v-if="!goodItem.is_select" @click="changeSelect(goodItem)"></view>
<view class="selectBox flex-around" v-else @click="changeSelect(goodItem)">
<img src="https://static.ticket.sz-trip.com/cgc/images/order/dui.png" />
<!-- 按供应商分组显示商品 -->
<view
class="goodBox"
v-for="(supplierGroup, supplierIndex) in list"
:key="supplierIndex"
v-if="supplierGroup.goods && supplierGroup.goods.length > 0"
>
<view class="title">{{ supplierGroup.supplierName }}</view>
<view
class="goodItem"
v-for="(goodItem, goodIndex) in supplierGroup.goods"
:key="goodIndex"
v-if="goodItem.flag != 0"
>
<view
class="noSelect"
v-if="!goodItem.is_select"
@click="changeSelect(goodItem)"
></view>
<view
class="selectBox flex-around"
v-else
@click="changeSelect(goodItem)"
>
<img
src="https://static.ticket.sz-trip.com/cgc/images/order/dui.png"
/>
</view>
<image :src="showImg(goodItem.specUrl)" mode="aspectFill" @click="goDetails(goodItem.goodsId)">
<image
:src="showImg(goodItem.specUrl)"
mode="aspectFill"
@click="goDetails(goodItem.goodsId)"
>
</image>
<view class="contentBox">
<view class="title text-overflow">{{ goodItem.goodsName }}</view>
<view class="subTitle text-overflow">{{
goodItem.specValueOne
}}-{{
goodItem.specValueTwo
}}</view>
<view class="subTitle text-overflow"
>{{ goodItem.specValueOne }}-{{ goodItem.specValueTwo }}</view
>
<view class="priceBox flex-between">
<view class="price">{{
goodItem.salePrice
}}</view>
<view class="price">{{ goodItem.salePrice }}</view>
<view class="quantity-control">
<view :class="[
<view
:class="[
'quantity-btn',
'minus-btn',
goodItem.quantity == 1 ? 'disabled' : '',
]" @click="delNum(goodItem)">
]"
@click="delNum(goodItem)"
>
-
</view>
<view class="quantity-input">{{ goodItem.quantity }}</view>
@ -45,17 +68,21 @@
</view>
<view class="loseGood" v-if="loseList && loseList.length > 0">
<view class="title flex-between">失效商品<span @click="delLoseGood('', 1)">清空失效商品</span></view>
<view class="goodItem" v-for="(goodItem, goodIndex) in loseList" :key="goodIndex">
<view class="title flex-between"
>失效商品<span @click="delLoseGood('', 1)">清空失效商品</span></view
>
<view
class="goodItem"
v-for="(goodItem, goodIndex) in loseList"
:key="goodIndex"
>
<view class="noSelect"></view>
<image :src="showImg(goodItem.specUrl)" mode="aspectFill"></image>
<view class="contentBox">
<view class="title text-overflow">{{ goodItem.goodsName }}</view>
<view class="subTitle text-overflow">{{
goodItem.specValueOne
}}-{{
goodItem.specValueTwo
}}</view>
<view class="subTitle text-overflow"
>{{ goodItem.specValueOne }}-{{ goodItem.specValueTwo }}</view
>
<view class="priceBox flex-between">
<view class="price">{{ goodItem.salePrice }}</view>
<view class="btn" @click="delLoseGood(goodItem.id, 0)">删除</view>
@ -79,8 +106,15 @@
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="list.length == 0 && loseList.length == 0">
<image class="empty-icon" :src="showImg('/uploads/20250826/empty-cart.png')" mode="aspectFit"></image>
<view
class="empty-state"
v-if="getTotalGoodsCount() == 0 && loseList.length == 0"
>
<image
class="empty-icon"
:src="showImg('/uploads/20250826/empty-cart.png')"
mode="aspectFit"
></image>
<text class="empty-title">购物车空空如也</text>
<text class="empty-desc">快去挑选心仪的商品吧</text>
<view class="empty-btn" @click="goShopping">去逛逛</view>
@ -89,11 +123,11 @@
</template>
<script>
export default {
export default {
data() {
return {
operate: "管理",
list: [],
list: [], //
loseList: [],
allSelect: false,
};
@ -104,20 +138,32 @@
},
methods: {
getShoppingList() {
this.Post({},
"/framework/cart/list", "DES"
)
this.Post({}, "/framework/cart/list", "DES")
.then((res) => {
const list = res.data || [];
this.loseList = [];
this.list = [];
//
const supplierGroups = {};
list.forEach((item) => {
if (item.effectStatus == 1) {
this.loseList.push(item);
} else {
this.list.push(item)
const supplierId = item.supplierId || "default";
if (!supplierGroups[supplierId]) {
supplierGroups[supplierId] = {
supplierId: supplierId,
supplierName: item.supplierName || "默认供应商",
goods: [],
};
}
supplierGroups[supplierId].goods.push(item);
}
});
//
this.list = Object.values(supplierGroups);
console.log("购物车数据更新:", this.list);
console.log("失效商品:", this.loseList);
})
@ -155,13 +201,15 @@
updateCart(item) {
let that = this;
that
.Post({
.Post(
{
cartId: item.id,
quantity: item.quantity,
},
"/framework/cart/updateQuantity", "DES"
"/framework/cart/updateQuantity",
"DES"
)
.then(function(res) {
.then(function (res) {
if (res) {
// that.$toast.clear()
}
@ -170,14 +218,18 @@
//
changeSelect(item) {
item.is_select = !item.is_select;
let checkAll = this.list.findIndex((items) => {
return !items.is_select;
});
if (checkAll == -1) {
this.allSelect = true;
} else {
this.allSelect = false;
//
let allSelected = true;
for (let supplierGroup of this.list) {
for (let goods of supplierGroup.goods) {
if (!goods.is_select) {
allSelected = false;
break;
}
}
if (!allSelected) break;
}
this.allSelect = allSelected;
this.$forceUpdate();
},
//
@ -196,10 +248,10 @@
//
changeAllSelect() {
this.allSelect = !this.allSelect;
this.list.forEach((item) => {
item.data.forEach((items) => {
if (this.allSelect) items.is_select = true;
else items.is_select = false;
this.list.forEach((supplierGroup) => {
supplierGroup.goods.forEach((item) => {
if (this.allSelect) item.is_select = true;
else item.is_select = false;
});
});
},
@ -212,9 +264,10 @@
content: "确定要删除这个失效商品吗?",
success: (res) => {
if (res.confirm) {
this.Post({
this.Post(
{
s_id: id,
method: 'delete'
method: "delete",
},
`/framework/cart/remove/${id}`,
"DES"
@ -250,9 +303,10 @@
this.loseList.forEach((item) => {
ids.push(item.id);
});
this.Post({
this.Post(
{
s_id: ids.toString(),
method: 'delete'
method: "delete",
},
`/framework/cart/remove/${ids.toString()}`,
"DES"
@ -282,11 +336,13 @@
//
delGood() {
let ids = [];
this.list.forEach((items) => {
if (items.is_select == true) {
ids.push(items.id);
this.list.forEach((supplierGroup) => {
supplierGroup.goods.forEach((item) => {
if (item.is_select == true) {
ids.push(item.id);
}
});
});
if (ids.length === 0) {
uni.showToast({
@ -301,9 +357,10 @@
content: `确定要删除选中的${ids.length}件商品吗?`,
success: (res) => {
if (res.confirm) {
this.Post({
this.Post(
{
s_id: ids.toString(),
method: 'delete'
method: "delete",
},
`/framework/cart/remove/${ids.toString()}`,
"DES"
@ -333,23 +390,27 @@
//
getAllPrice() {
let allPrice = 0;
this.list.forEach((item) => {
this.list.forEach((supplierGroup) => {
supplierGroup.goods.forEach((item) => {
if (item.is_select == true) {
allPrice += item.salePrice * item.quantity;
}
});
});
return allPrice.toFixed(2);
},
//
order() {
let list = [];
let ids = [];
this.list.forEach((item) => {
this.list.forEach((supplierGroup) => {
supplierGroup.goods.forEach((item) => {
if (item.is_select == true) {
ids.push(item.merchant_id);
list.push(item);
}
});
});
// if (Array.from(new Set(ids)).length > 1) {
// uni.showToast({
// title: '',
@ -364,9 +425,10 @@
});
return;
}
this.Post({
this.Post(
{
bos: list,
method: 'post'
method: "post",
},
`/framework/cart/check-cart-items`,
"DES"
@ -375,41 +437,48 @@
if (res.data.canOrder) {
this.$store.commit("changeOrderSCart", list);
this.gotoPath("/subPackages/techan/order");
} else {
uni.showToast({
title: res.message,
icon: 'none'
})
this.getShoppingList()
icon: "none",
});
this.getShoppingList();
}
}).catch((res) => {
uni.showToast({
title: '部分商品无法下单,请重新加载购物车',
icon: 'none'
})
setTimeout(() =>{
this.getShoppingList()
},800)
})
.catch((res) => {
uni.showToast({
title: "部分商品无法下单,请重新加载购物车",
icon: "none",
});
setTimeout(() => {
this.getShoppingList();
}, 800);
});
// this.gotoPath('/subPackages/goods/goodsOrder')
},
//
getTotalGoodsCount() {
let count = 0;
this.list.forEach((supplierGroup) => {
count += supplierGroup.goods.length;
});
return count;
},
};
},
};
</script>
<style scoped lang="scss">
.bg {
.bg {
width: 100%;
min-height: 100vh;
padding: 0 27rpx 200rpx;
box-sizing: border-box;
background-color: #f8f8f8;
}
}
.guanli {
.guanli {
height: 76rpx;
text-align: right;
font-size: 32rpx;
@ -425,9 +494,9 @@
background: rgba(108, 165, 170, 0.1);
transform: scale(0.95);
}
}
}
.goodBox {
.goodBox {
width: 697rpx;
height: auto;
background: #ffffff;
@ -437,10 +506,9 @@
box-sizing: border-box;
.title {
font-size: 35rpx;
font-family: PingFang SC;
font-weight: 500;
color: #000000;
font-size: 30rpx;
font-weight: 600;
color: #333333;
}
.goodItem {
@ -551,7 +619,8 @@
font-weight: 500;
color: #333;
.btn-text {}
.btn-text {
}
}
.quantity-input {
@ -569,9 +638,9 @@
}
}
}
}
}
.loseGood {
.loseGood {
width: 697rpx;
height: auto;
background: #ffffff;
@ -664,10 +733,10 @@
}
}
}
}
}
/* 空状态样式 */
.empty-state {
/* 空状态样式 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
@ -713,9 +782,9 @@
box-shadow: 0 4rpx 10rpx rgba(108, 165, 170, 0.2);
}
}
}
}
.orderBox {
.orderBox {
width: 750rpx;
height: 151rpx;
background: #ffffff;
@ -784,16 +853,16 @@
font-weight: 500;
color: #ffffff;
}
}
}
/* 移除旧的样式 */
.zhihui {
/* 移除旧的样式 */
.zhihui {
background: #e8e8e8 !important;
color: #999999 !important;
}
}
/* 优化商品卡片样式 */
.goodBox {
/* 优化商品卡片样式 */
.goodBox {
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
@ -801,22 +870,22 @@
transform: translateY(-2rpx);
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.12);
}
}
}
/* 优化选择框样式 */
.noSelect {
/* 优化选择框样式 */
.noSelect {
transition: all 0.3s ease;
&:active {
transform: scale(0.9);
}
}
}
.selectBox {
.selectBox {
transition: all 0.3s ease;
&:active {
transform: scale(0.9);
}
}
}
</style>
Loading…
Cancel
Save