10 changed files with 537 additions and 442 deletions
@ -1,226 +1,376 @@ |
|||||
<template> |
<template> |
||||
<div class="bg"> |
<div class="bg"> |
||||
<div class="cart-page common-card"> |
|
||||
<!-- 购物车标题与全选 --> |
|
||||
<div class="cart-header"> |
<div> |
||||
购物车(全部 {{ totalCount }} 件) |
<div class="order-products" style="padding:0 20px;background: #f8f9fa; border-top: 1px solid #eee; border-bottom: 1px solid #eee;margin-bottom: 20px;"> |
||||
|
<div class="product-item" > |
||||
|
<div class="product-select"> |
||||
|
<el-checkbox v-model="selectAll" @change="handleSelectAll">全选</el-checkbox> |
||||
|
</div> |
||||
|
<div class="product-details"> |
||||
|
<div class="product-name">商品</div> |
||||
</div> |
</div> |
||||
|
<div class="product-box">单价(元)</div> |
||||
|
<div class="product-quantity">数量</div> |
||||
|
<div class="product-box">收货方式</div> |
||||
|
<div class="product-box">小计(元)</div> |
||||
|
<div class="product-box">操作</div> |
||||
|
|
||||
<!-- 商品列表表格 --> |
</div> |
||||
<el-table :data="currentPageData" style="width: 100%" |
</div> |
||||
@select="selectRow" @select-all="selectAll" |
|
||||
ref="multipleTable"> |
<!-- 订单卡片 - 按商家合并商品 --> |
||||
<!-- 多选框列 --> |
<div class="order-card" v-for="shop in list" :key="shop.id"> |
||||
<el-table-column type="selection" width="55" align="center"/> |
<!-- 订单头部 - 包含商家信息 --> |
||||
<!-- 商品图片 --> |
<div class="order-header flex-between"> |
||||
<el-table-column label="商品" prop="image" > |
<div class="product-select"> |
||||
<template slot-scope="scope"> |
<el-checkbox v-model="shop.selected" @change="handleSelectShop(shop)"><span style="opacity: 0;">全选</span></el-checkbox> |
||||
<div style="display: flex;align-items: center;"> |
</div> |
||||
<img src="https://picsum.photos/200/200?random=1" alt="商品" class="product-img"> |
<div class="product-details"> |
||||
<div style="padding-left: 10px;">{{ scope.row.title }}</div> |
<div class="product-name">供应商名称:{{ shop.shop_name }}</div> |
||||
</div> |
</div> |
||||
</template> |
</div> |
||||
</el-table-column> |
|
||||
<!-- 规格 --> |
<!-- 订单商品列表 --> |
||||
<el-table-column label="规格" prop="spec" align="center" /> |
<div class="order-products"> |
||||
<!-- 单价 --> |
<div class="product-item" v-for="goods in shop.goods" :key="goods.id"> |
||||
<el-table-column label="单价(元)" prop="price" align="center" width="100"/> |
<div class="product-select"> |
||||
<!-- 数量 --> |
<el-checkbox v-model="goods.selected" @change="handleSelect"><span style="opacity: 0;">全选</span></el-checkbox> |
||||
<el-table-column label="数量" prop="quantity" width="160" align="center"> |
</div> |
||||
<template slot-scope="scope"> |
<div class="product-details flex-between"> |
||||
<el-input-number size="small" |
<img :src="goods.product.headimg" class="product-image"> |
||||
v-model="scope.row.quantity" :min="1" :step="1"/> |
<div class="product-details"> |
||||
</template> |
<div class="product-name">{{ goods.product.title }}</div> |
||||
</el-table-column> |
<div class="product-spec">{{ goods.sku.sku_name }}</div> |
||||
<!-- 金额 --> |
</div> |
||||
<el-table-column label="金额(元)" prop="amount" width="100" align="center"> |
</div> |
||||
<template slot-scope="scope"> |
<div class="product-box ">¥{{ (goods.sku.price/100).toFixed(2) }}</div> |
||||
¥{{ scope.row.price * scope.row.quantity }} |
<div class="product-quantity"> |
||||
</template> |
<el-input-number size="small" v-model="goods.num" @change="handleNumChange(goods)" :min="1" :step="1"/> |
||||
</el-table-column> |
</div> |
||||
<!-- 操作 --> |
<div class="product-box">邮寄</div> |
||||
<el-table-column label="操作" width="100" align="center"> |
<div class="product-box product-price">¥{{ (goods.num * goods.sku.price/100).toFixed(2) }}</div> |
||||
<template slot-scope="scope"> |
<div class="product-box"> |
||||
<el-button type="text" @click="handleDelete(scope.row)">删除</el-button> |
<el-button type="text" size="mini" @click="delItem(goods)">删除</el-button> |
||||
</template> |
</div> |
||||
</el-table-column> |
</div> |
||||
</el-table> |
</div> |
||||
|
|
||||
<!-- 分页组件 --> |
|
||||
<el-pagination |
</div> |
||||
@size-change="handleSizeChange" |
<el-empty description="暂无数据" v-if="list.length<=0"></el-empty> |
||||
@current-change="handleCurrentChange" |
|
||||
:current-page="currentPage" |
|
||||
:page-sizes="[3, 5, 10]" |
|
||||
:page-size="pageSize" |
<!-- 分页 --> |
||||
layout="total, sizes, prev, pager, next, jumper" |
<!-- <div style="text-align: right; margin-top: 20px;"> |
||||
:total="totalCount" |
<el-pagination |
||||
style="margin-top: 20px; text-align: right;" |
@size-change="handleSizeChange" |
||||
/> |
@current-change="handleCurrentChange" |
||||
|
:current-page="currentPage" |
||||
<!-- 底部结算栏 --> |
:page-sizes="[5, 10, 20]" |
||||
<div class="cart-footer"> |
:page-size="pageSize" |
||||
|
layout="total, sizes, prev, pager, next, jumper" |
||||
|
:total="list.length" |
||||
|
></el-pagination> |
||||
|
</div> --> |
||||
|
<div class="cart-footer"> |
||||
|
<el-button :disabled="selectedRows.length === 0" type="text" size="mini" @click="deleteSelected"> |
||||
|
删除选中商品 |
||||
|
</el-button> |
||||
|
<div class="flex-between"> |
||||
<div class="selected-info"> |
<div class="selected-info"> |
||||
已选商品 {{ selectedRows.length }} 件 |
已选商品 <span class="import-text">{{ selectedRows.length }}</span> 件 |
||||
总价: ¥0 (不含运费) |
|
||||
|
总价: <span class="import-text total-price">{{ totalPrice }}</span> (不含运费) |
||||
</div> |
</div> |
||||
<el-button |
<el-button type="primary" @click="handleCheckout" :disabled="selectedRows.length === 0">去结算</el-button> |
||||
type="primary" |
|
||||
@click="handleCheckout" |
|
||||
:disabled="selectedRows.length === 0" |
|
||||
>去结算</el-button> |
|
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
|
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default { |
export default { |
||||
name: 'CartPage', |
name: 'OrderList', |
||||
data() { |
data () { |
||||
return { |
return { |
||||
// 模拟购物车数据(实际可从接口获取) |
activeTab: 'all', |
||||
cartData: [ |
currentPage: 1, |
||||
{ id: 1, image: 'https://via.placeholder.com/60', title: '产品标题产品标题', spec: '规格名称一', price: 349, quantity: 1 }, |
pageSize: 10, |
||||
{ id: 2, image: 'https://via.placeholder.com/60', title: '产品标题产品标题', spec: '规格名称一', price: 199, quantity: 1 }, |
|
||||
{ id: 3, image: 'https://via.placeholder.com/60', title: '产品标题产品标题', spec: '规格名称一', price: 389, quantity: 1 }, |
// 订单数据 - 按商家合并商品 |
||||
{ id: 4, image: 'https://via.placeholder.com/60', title: '产品标题产品标题', spec: '规格名称一', price: 249, quantity: 1 }, |
list: [], |
||||
{ id: 5, image: 'https://via.placeholder.com/60', title: '产品标题产品标题', spec: '规格名称一', price: 449, quantity: 1 }, |
selectAll: false, |
||||
{ id: 6, image: 'https://via.placeholder.com/60', title: '产品标题产品标题', spec: '规格名称二', price: 129, quantity: 1 }, |
} |
||||
{ id: 7, image: 'https://via.placeholder.com/60', title: '产品标题产品标题', spec: '规格名称二', price: 279, quantity: 1 } |
|
||||
], |
|
||||
|
|
||||
// 分页相关 |
|
||||
pageSize: 3, // 每页条数 |
|
||||
currentPage: 1, // 当前页码 |
|
||||
|
|
||||
// 多选相关 |
|
||||
selectedRows: [{id:1}] // 记录选中的行ID |
|
||||
} |
|
||||
}, |
|
||||
computed: { |
|
||||
// 总数量 |
|
||||
totalCount() { |
|
||||
return this.cartData.length |
|
||||
}, |
}, |
||||
// 当前页数据 |
mounted() { |
||||
currentPageData() { |
this.getList() |
||||
const start = (this.currentPage - 1) * this.pageSize |
|
||||
const end = start + this.pageSize |
|
||||
return this.cartData.slice(start, end) |
|
||||
}, |
}, |
||||
|
computed: { |
||||
}, |
selectedRows() { |
||||
mounted() { |
let rows = [] |
||||
this.refreshTableCheck(); |
this.list.forEach(v=>{ |
||||
}, |
v.goods.forEach(goods=>{ |
||||
methods: { |
if (goods.selected) { |
||||
refreshTableCheck () { |
rows.push(goods) |
||||
this.$nextTick(()=>{ |
} |
||||
let selectIds = this.selectedRows.map(item => item.id) |
}) |
||||
this.currentPageData.forEach(item => { |
}) |
||||
if (selectIds.includes(item.id)) { |
return rows |
||||
this.$refs.multipleTable.toggleRowSelection(item, true); |
}, |
||||
} else { |
totalPrice() { |
||||
this.$refs.multipleTable.toggleRowSelection(item, false); |
let price = 0 |
||||
} |
this.selectedRows.forEach(v=>{ |
||||
|
price += v.num * v.sku.price/100 |
||||
|
}) |
||||
|
return price.toFixed(2) |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
getList(){ |
||||
|
this.post({customBaseURL:"/api"},"/api/cart/get_list",true).then(res=>{ |
||||
|
let resData = (res.data ||[]) |
||||
|
let currentSelectGoodsIds = this.selectedRows.map(v=>v.id) |
||||
|
resData.forEach(item=>{ |
||||
|
item.selected = false |
||||
|
item.goods.forEach(goods=>{ |
||||
|
goods.selected = currentSelectGoodsIds.includes(goods.id) |
||||
}) |
}) |
||||
|
}) |
||||
|
this.list = resData |
||||
|
this.judgeSelectAll() |
||||
}) |
}) |
||||
|
}, |
||||
|
handleSelectAll(val) { |
||||
|
if (val) { |
||||
|
this.list.forEach(t=>{ |
||||
|
t.goods.forEach(v=>{ |
||||
|
if (v && v.product &&v.sku && v.sku.flag== "off") { |
||||
|
v.selected = false |
||||
|
} else { |
||||
|
v.selected = true |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
} else { |
||||
|
this.cartList.forEach(t=>{ |
||||
|
t.selected = false |
||||
|
}) |
||||
|
} |
||||
|
this.judgeSelectAll() |
||||
|
}, |
||||
|
handleSelectShop(shop) { |
||||
|
if (shop.selected) { |
||||
|
shop.goods.forEach(v=>{ |
||||
|
if (v && v.product &&v.sku && v.sku.flag== "off") { |
||||
|
v.selected = false |
||||
|
} else { |
||||
|
v.selected = true |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
this.judgeSelectAll() |
||||
|
}, |
||||
|
handleSelect() { |
||||
|
this.judgeSelectAll() |
||||
|
}, |
||||
|
// 判断全选 |
||||
|
judgeSelectAll() { |
||||
|
this.selectedRows = [] |
||||
|
this.list.forEach(v=>{ |
||||
|
if (v.goods.some(x=>x.sku.flag=='on')) { |
||||
|
if(v.goods.some(x=>x.sku.flag=="on"&&!x.selected) ) { |
||||
|
v.selected = false; |
||||
|
} else { |
||||
|
v.selected = true; |
||||
|
} |
||||
|
} else { |
||||
|
v.selected = false |
||||
|
} |
||||
|
}) |
||||
|
|
||||
}, |
if (this.list.every(v=>v.selected) && this.list.length>0) { |
||||
|
this.selectAll = true |
||||
|
} else { |
||||
|
this.selectAll = false |
||||
|
} |
||||
|
}, |
||||
|
|
||||
// 表格行选中事件(跨页多选核心:手动维护selectedRows) |
// 购物车加减 |
||||
selectRow(selection ,row) { |
handleNumChange(goods) { |
||||
// 提取选中行的ID |
this.post({id: goods.id, num: goods.num,customBaseURL:"/api"},'/api/cart/update_sku').then(res =>{ |
||||
let index = this.selectedRows.findIndex(v=>v.id === row.id) |
|
||||
console.log(index) |
|
||||
if(index>=0){ |
|
||||
this.selectedRows.splice(index,1) |
|
||||
} else { |
|
||||
this.selectedRows.push(row) |
|
||||
} |
|
||||
console.log(this.selectedRows) |
|
||||
}, |
|
||||
selectAll (selection) { |
|
||||
|
|
||||
if (selection.length>0) { |
|
||||
let currentNotInselection = selection.filter(v => !this.selectedRows.some(x=>x.id==v.id)) |
|
||||
this.selectedRows = this.selectedRows.concat(currentNotInselection) |
|
||||
} else { |
|
||||
// 从selectRows 删掉当前页面的的 |
|
||||
this.selectedRows = this.selectedRows.filter(v => !this.currentPageData.some(x=>x.id==v.id)) |
|
||||
} |
|
||||
console.log(selection) |
|
||||
}, |
|
||||
|
|
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
delItem(item){ |
||||
|
this.post({id: item.id,customBaseURL:"/api"},'/api/cart/del_sku').then(res =>{ |
||||
|
this.getList() |
||||
|
}) |
||||
|
}, |
||||
|
deleteSelected() { |
||||
|
let ids = this.selectedRows.map(v=>v.id).join(',') |
||||
|
this.post({ids: ids,customBaseURL:"/api"},'/api/cart/del_skus').then(res =>{ |
||||
|
this.getList() |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
// 删除事件 |
|
||||
handleDelete(row) { |
|
||||
// 从cartData中移除对应商品 |
|
||||
this.cartData = this.cartData.filter(item => item.id!== row.id) |
|
||||
// 若删除的商品处于选中状态,同步更新selectedRowKeys |
|
||||
this.selectedRows = this.selectedRows.filter(v => v.id!== row.id) |
|
||||
console.log('删除商品:', row) |
|
||||
// 这里可添加接口请求,删除购物车商品逻辑 |
|
||||
this.refreshTableCheck(); |
|
||||
|
|
||||
}, |
|
||||
|
|
||||
// 分页-每页条数改变 |
|
||||
|
// 分页大小改变 |
||||
handleSizeChange(val) { |
handleSizeChange(val) { |
||||
this.pageSize = val |
this.pageSize = val; |
||||
this.currentPage = 1 // 切换条数时重置页码到第1页 |
|
||||
this.refreshTableCheck(); |
|
||||
}, |
}, |
||||
|
|
||||
// 分页-当前页改变 |
// 当前页改变 |
||||
handleCurrentChange(val) { |
handleCurrentChange(val) { |
||||
this.currentPage = val |
this.currentPage = val; |
||||
this.refreshTableCheck(); |
}, |
||||
|
|
||||
|
|
||||
|
// 去付款 |
||||
|
payOrder(orderId) { |
||||
|
this.$message({ |
||||
|
message: `订单 ${orderId} 去付款`, |
||||
|
type: 'info' |
||||
|
}); |
||||
}, |
}, |
||||
|
|
||||
// 结算事件 |
|
||||
handleCheckout() { |
|
||||
console.log('去结算,选中商品ID:', this.selectedRows) |
|
||||
// 这里可跳转结算页,或调用接口提交订单 |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
</script> |
</script> |
||||
|
|
||||
<style scoped lang="scss"> |
<style lang="scss" scoped> |
||||
.common-card{ |
.bg{ |
||||
width: 100%; |
display: flex; |
||||
background-color: white; |
flex-direction: column; |
||||
padding: 20px; |
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1); |
::v-deep .el-button--text { |
||||
} |
color: #6a8a27; |
||||
.cart-page { |
} |
||||
.cart-header { |
::v-deep .el-tabs__item.is-active{ |
||||
margin-bottom: 10px; |
color: #6a8a27; |
||||
} |
} |
||||
.product-img { |
::v-deep .el-tabs__active-bar{ |
||||
width: 60px; |
background-color: #6a8a27 |
||||
height: 60px; |
} |
||||
object-fit: cover; |
::v-deep .el-tabs__item:hover{ |
||||
} |
color: #6a8a27; |
||||
.cart-footer { |
} |
||||
display: flex; |
|
||||
justify-content: space-between; |
|
||||
align-items: center; |
|
||||
margin-top: 10px; |
|
||||
padding: 15px; |
|
||||
background-color: #f5f7fa; |
|
||||
border-radius: 4px; |
|
||||
} |
|
||||
.selected-info { |
|
||||
color: #666; |
|
||||
font-size: 14px; |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
/* 订单卡片样式 */ |
||||
|
.order-card { |
||||
|
border-radius: 4px; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
/* 订单头部 - 包含商家信息 */ |
||||
|
.order-header { |
||||
|
padding: 12px 20px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
background: rgb(248, 249, 250); |
||||
|
border-bottom: 1px solid #999; |
||||
|
color: #666; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
/* 订单商品列表 */ |
||||
|
.order-products { |
||||
|
padding: 10px 20px; |
||||
|
} |
||||
|
|
||||
|
.product-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 15px 0; |
||||
|
border-bottom: 1px dashed #eee; |
||||
|
font-size: 14px; |
||||
|
} |
||||
|
|
||||
|
.product-item:last-child { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
|
||||
|
.product-image { |
||||
|
width: 80px; |
||||
|
height: 80px; |
||||
|
object-fit: cover; |
||||
|
margin-right: 15px; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
|
||||
|
.product-details { |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.product-name { |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.product-spec { |
||||
|
color: #999; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
.product-box { |
||||
|
width: 100px; |
||||
|
text-align: center; |
||||
|
color: #333; |
||||
|
} |
||||
|
.product-quantity{ |
||||
|
width: 160px; |
||||
|
text-align: center; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.product-select { |
||||
|
width: 80px; |
||||
|
color: #333; |
||||
|
} |
||||
|
.product-price{ |
||||
|
color: #ff5252; |
||||
|
} |
||||
|
|
||||
|
.cart-footer { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
margin-top: 10px; |
||||
|
padding: 15px; |
||||
|
background-color: #f5f7fa; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
.selected-info { |
||||
|
color: #666; |
||||
|
font-size: 14px; |
||||
|
padding-right: 50px; |
||||
|
} |
||||
|
.import-text{ |
||||
|
color: #c7020b; |
||||
|
font-size: 20px; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
.total-price{ |
||||
|
&::before{ |
||||
|
content: "¥"; |
||||
|
margin-right: 5px; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
} |
||||
</style> |
</style> |
||||
|
|
||||
|
|
||||
|
|
||||
|
@ -1,5 +1,16 @@ |
|||||
const { defineConfig } = require('@vue/cli-service') |
const { defineConfig } = require('@vue/cli-service') |
||||
module.exports = defineConfig({ |
module.exports = defineConfig({ |
||||
transpileDependencies: true, |
transpileDependencies: true, |
||||
runtimeCompiler: true |
runtimeCompiler: true, |
||||
|
devServer: { |
||||
|
proxy: { |
||||
|
'/api':{ |
||||
|
target: "https://swsz.api.js-dyyj.com", |
||||
|
changeOrigin: true, |
||||
|
pathRewrite: { |
||||
|
'/api':'' |
||||
|
}, |
||||
|
} |
||||
|
} |
||||
|
} |
||||
}) |
}) |
||||
|
Loading…
Reference in new issue