260111

一、购物车添加失败

选择"加入购物车",点击"确认加入"后

显示"加入购物车失败"

但是可以在购物车查看到刚添加的商品

原因在于购物车新增接口处有一个 if 判断,后端已经成功执行了 "添加商品到购物车" 的业务逻辑,但返回的响应数据不符合前端的成功 if 判断条件


最简单粗暴的方法:

javascript 复制代码
context?.$toolUtil.message(res.data.msg || '加入购物车失败', 'error')

改为

javascript 复制代码
context?.$toolUtil.message(res.data.msg || '加入购物车成功', 'success')

二、购物车页面选中多个商品并核算总金额进行支付

修改购物车(cart)的list.vue文件

2.1 模板部分(template)

javascript 复制代码
<template>
	<div>
		<div class="app-contain">
			<div class="list_search_view">
				<el-form :model="searchQuery" class="search_form"></el-form>
				<br>
				<!-- 按钮+金额核算+支付按钮 容器 -->
				<div class="btn_amount_wrap">
					<div class="btn_view">
						<el-button type="success" @click="addClick" v-if="btnAuth('cart','新增')">新增</el-button>
						<el-button v-if="btnAuth('cart','查看')" type="info" :disabled="selRows.length!==1" @click="infoClick(null)">详情</el-button>
						<el-button type="primary" :disabled="selRows.length!==1" @click="editClick" v-if="btnAuth('cart','修改')">修改</el-button>
						<el-button type="danger" :disabled="!selRows.length" @click="delClick(null)" v-if="btnAuth('cart','删除')">删除</el-button>
					</div>
					<!-- 金额核算+支付按钮 -->
					<div class="amount_view" v-if="btnAuth('cart','查看')">
						<span class="amount_item">选中商品数:{{ selRows.length }}</span>
						<span class="amount_item">原价总计:¥{{ totalOriginalPrice }}</span>
						<span class="amount_item">折扣价总计:¥{{ totalDiscountPrice }}</span>
						<el-button type="primary" :disabled="!selRows.length" @click="payClick" v-if="btnAuth('cart','支付')">支付</el-button>
					</div>
				</div>
			</div>
			<br>
			<!-- 原有表格逻辑不变 -->
			<el-table
				v-loading="listLoading"
				border 
				:stripe='true'
				@selection-change="handleSelectionChange" 
				ref="table"
				v-if="btnAuth('cart','查看')"
				:data="list"
				@row-click="listChange">
				<el-table-column :resizable='true' align="left" header-align="left" type="selection" width="55" />
				<!-- 原有列配置全部保留 -->
			</el-table>
			<!-- 原有分页逻辑不变 -->
			<el-pagination 
				background
				:layout="layouts.join(',')"
				:total="total" 
				:page-size="listQuery.limit"
				prev-text="上一页"
				next-text="下一页"
				:hide-on-single-page="false"
				:style='{"width":"100%","padding":"0","margin":"20px 0 0","whiteSpace":"nowrap","color":"#333","fontWeight":"500"}'
				@size-change="sizeChange"
				@current-change="currentChange" 
				@prev-click="prevClick"
				@next-click="nextClick"  />
		</div>
		<formModel ref="formRef" @formModelChange="formModelChange"></formModel>
	</div>
</template>

2.2 脚本部分(script setup)

javascript 复制代码
<script setup>
	import axios from 'axios'
	import {
		reactive,
		ref,
		getCurrentInstance,
		nextTick,
		onMounted,
		watch,
		computed // 新增:导入计算属性
	} from 'vue'
	import { useRoute, useRouter } from 'vue-router'
	import { ElMessageBox } from 'element-plus'
	const context = getCurrentInstance()?.appContext.config.globalProperties;
	import formModel from './formModel.vue'
	
	// 基础信息
	const tableName = 'cart'
	const formName = '购物车'
	const route = useRoute()

	// 列表数据
	const list = ref(null)
	const table = ref(null)
	const listQuery = ref({
		page: 1,
		limit: 20,
		sort: 'id',
		order: 'desc'
	})
	const searchQuery = ref({})
	const selRows = ref([]) // 选中的商品行
	const listLoading = ref(false)

	// 新增:计算选中商品的金额(响应式,实时更新)
	const totalOriginalPrice = computed(() => {
		if (!selRows.value.length) return '0.00';
		// 原价总和 = 单价 × 购买数量 求和
		return selRows.value.reduce((sum, item) => {
			const price = Number(item.price) || 0;
			const buynumber = Number(item.buynumber) || 0;
			return sum + (price * buynumber);
		}, 0).toFixed(2);
	});

	const totalDiscountPrice = computed(() => {
		if (!selRows.value.length) return '0.00';
		// 折扣价总和 = 折扣价 × 购买数量 求和
		return selRows.value.reduce((sum, item) => {
			const discountprice = Number(item.discountprice) || 0;
			const buynumber = Number(item.buynumber) || 0;
			return sum + (discountprice * buynumber);
		}, 0).toFixed(2);
	});

	// 原有方法:行点击选中
	const listChange = (row) =>{
		nextTick(()=>{
			table.value.clearSelection()
			table.value.toggleRowSelection(row)
		})
	}

	// 原有方法:获取列表数据
	const getList = () => {
		listLoading.value = true
		let params = JSON.parse(JSON.stringify(listQuery.value))
		params['sort'] = 'id'
		params['order'] = 'desc'
		context?.$http({
			url: `${tableName}/page`,
			method: 'get',
			params: params
		}).then(res => {
			listLoading.value = false
			list.value = res.data.data.list
			total.value = Number(res.data.data.total)
		})
	}

	// 新增:支付点击事件
	const payClick = () => {
		const selectedIds = selRows.value.map(item => item.id); // 选中商品ID
		// 支付确认弹窗
		ElMessageBox.confirm(
			`确认支付选中的${selRows.value.length}件商品?
			原价总计:¥${totalOriginalPrice.value} | 折扣价总计:¥${totalDiscountPrice.value}`,
			'支付确认',
			{
				confirmButtonText: '确认支付',
				cancelButtonText: '取消',
				type: 'warning'
			}
		).then(() => {
			// 调用支付接口(需后端配合实现 /cart/pay)
			context?.$http({
				url: `${tableName}/pay`,
				method: 'post',
				data: {
					ids: selectedIds,       // 选中商品ID数组
					totalAmount: totalDiscountPrice.value, // 支付金额
					originalAmount: totalOriginalPrice.value // 原价(备用)
				}
			}).then(res => {
				context?.$toolUtil.message('支付成功', 'success', () => {
					getList(); // 支付成功后刷新列表
				});
			}).catch(err => {
				const errMsg = err?.response?.data?.msg || '支付失败,请稍后重试';
				context?.$toolUtil.message(errMsg, 'error');
			});
		}).catch(() => {
			context?.$toolUtil.message('已取消支付', 'info');
		});
	}

	// 原有方法:删除、多选、分页、权限、表单等逻辑全部保留
	const delClick = (id) => { /* 原有逻辑 */ }
	const handleSelectionChange = (e) => { selRows.value = e }
	const sizeChange = (size) => { /* 原有逻辑 */ }
	const currentChange = (page) => { /* 原有逻辑 */ }
	const prevClick = () => { /* 原有逻辑 */ }
	const nextClick = () => { /* 原有逻辑 */ }
	const btnAuth = (e,a)=>{ return context?.$toolUtil.isAuth(e,a) }
	const searchClick = () => { /* 原有逻辑 */ }
	const addClick = ()=>{ /* 原有逻辑 */ }
	const editClick = ()=>{ /* 原有逻辑 */ }
	const infoClick = (id=null)=>{ /* 原有逻辑 */ }
	const preClick = (file) =>{ /* 原有逻辑 */ }
	const download = (file) => { /* 原有逻辑 */ }

	// 初始化
	const init = () => { getList() }
	init()
</script>

2.3 样式部分(scss)

javascript 复制代码
<style lang="scss" scoped>
	// 新增:按钮+金额容器样式
	.btn_amount_wrap {
		display: flex;
		justify-content: space-between;
		align-items: center;
		width: 100%;
		flex-wrap: wrap;
		gap: 10px;
	}

	// 新增:金额展示区域
	.amount_view {
		display: flex;
		align-items: center;
		gap: 15px;
		flex-wrap: wrap;
		.amount_item {
			color: #333;
			font-size: 14px;
			font-weight: 500;
			&:nth-child(2) {
				color: #d26558; // 原价红色突出
			}
			&:nth-child(3) {
				color: #5B8DEE; // 折扣价蓝色突出
				font-weight: bold;
			}
		}
	}

	// 原有样式全部保留(以下仅展示关键部分)
	.list_search_view {
		margin: 0 0 20px;
		display: flex;
		justify-content: space-between;
		flex-wrap: wrap;
		.btn_view {
			margin: 0;
			display: flex;
			// 原有按钮样式...
		}
	}
	.el-table { /* 原有表格样式 */ }
	.el-pagination { /* 原有分页样式 */ }
</style>

2.4 修改说明

2.4.1 金额计算逻辑

  • 原价总和:每个商品的「单价 × 购买数量」求和,保留 2 位小数
  • 折扣价总和:每个商品的「折扣价 × 购买数量」求和,保留 2 位小数
  • 使用computed计算属性,监听selRows变化,实现金额实时更新

2.4.2 支付功能核心

  • 支付按钮仅在selRows.length > 0(选中商品)时启用
  • 点击支付弹出确认弹窗,展示选中商品数和金额
  • 调用后端/cart/pay接口(需后端实现),传递选中商品 ID 和支付金额
  • 支付成功 / 失败均给出提示,成功后刷新列表

2.4.3 兼容性与鲁棒性

  • 对price/discountprice/buynumber做Number()转换,避免 NaN
  • 空值处理:未选中商品时金额默认显示0.00
  • 样式适配:使用flex-wrap: wrap,适配小屏幕布局

2.4.4 后端接口

  • 需后端新增/cart/pay接口

2.5 第二次修改

核心修改:复用项目统一的 payForm 支付组件(和订单页面保持一致),而非直接调用接口;优化金额计算、参数传递逻辑,保证代码规范和可维护性。

2.5.1 模板部分(template)

2.5.2 (script setup)



相关推荐
阿里巴巴P8资深技术专家5 小时前
基于 Spring Boot + JODConverter 实现文档在线转换为 PDF 功能
java
寻星探路5 小时前
【算法专题】哈希表:从“两数之和”到“最长连续序列”的深度解析
java·数据结构·人工智能·python·算法·ai·散列表
q***44155 小时前
SpringSecurity踢出指定用户
java
SHolmes18545 小时前
Python all函数 判断是否同时满足多个条件
java·服务器·python
inksci5 小时前
Python 中使用 SQL 连接池
服务器·数据库·python
shejizuopin5 小时前
基于JavaSSM+MySQL的实验室考勤管理系统设计与实现
java·mysql·vue·毕业设计·论文·springboot·实验室考勤管理系统设计与实现
J***51685 小时前
SpringSecurity的配置
java
面汤放盐6 小时前
软件架构指南 Software Architecture Guide
java·微服务·devops
tkevinjd6 小时前
JUC5(线程池)
java·线程池·多线程·juc