Vue2电商项目(七)、订单与支付

文章目录

  • 一、交易业务Trade
    • 1. 获取用户地址
    • 2. 获取订单信息
  • 二、提交订单
  • 三、支付
    • 1. 获取支付信息
    • 2. 支付页面--ElementUI
      • (1) 引入Element UI
      • (2) 弹框支付的业务逻辑(这个逻辑其实没那么全)
      • (3) 支付逻辑知识点小总结
  • 四、个人中心
    • 1. 搭建二级路由
    • 2. 展示动态数据
      • (1). 接口
      • (2). 组件获取数据
      • (3). 页面表格的合并与展示
      • (4). 页面分页器

一、交易业务Trade

首先要配置静态组件及路由,这里没什么重点,不多说了。然后是动态数据的展示

1. 获取用户地址

在这里插入图片描述

(1) 接口
用文档里的接口向服务器发送请求时,电商系统的账号和密码得用视频里老师的账号密码登录,才会有数据返回。如果用自己的账号密码,那就自己mock模拟一些数据。

// 文档的接口
export const reqAddressList = () => {return requests({ url: 'user/userAddress/auth/findUserAddressList', method: 'get' })
}
// 自己mock的请求接口
export const reqAddressList = () => {return mockRequests({ url: '/userAddress/auth/findUserAddressList', method: 'get' })
}

(2) Vuex三连环
新建trade小仓库存放交易业务的数据

  state: {addressList: [],},actions: {// 获取用户地址信息async getUserAddress (context) {let res = await reqAddressList()console.log('用户地址', res);if (res.code === 200) {context.commit('GETUSERADDRESS', res.data)}}},mutations: {GETUSERADDRESS (state, data) {state.addressList = data},},

在这里插入图片描述

(3)动态数据渲染组件页面

在mounted函数里dispatch请求,通过mapState获取Vuex的数据。
第一个业务逻辑是修改默认地址。点击哪个标签,哪个成为默认地址。
在这里插入图片描述

 // 修改默认地址,排他思想changeDefault (address) {this.addressList.forEach(el => {el.isDefault = 0 });address.isDefault = 1 // 值为1表示为选中的默认地址},

第二个业务逻辑是获取到默认地址的对象信息,动态展示在页面低端。
在这里插入图片描述
采用计算属性。需要注意,这里用到了Vuex的值,可能会有undefined的错误(因为addressList是异步请求获得的数据,页面刚加载完时,addressList的值还未获取到,则会报undefined的错误),所以要 || {}

 <div class="receiveInfo">寄送至:<!--这里会报undefined的错误,fullAddress属性undefined--><span>{{ userDefAddress.fullAddress }}</span>收货人:<span>{{ userDefAddress.consignee }}</span><span>{{ userDefAddress.phoneNum }}</span></div>
<script>computed: {...mapState('trade', ['addressList']),// 将来提交订单最终选中的地址 表达式:undefined || {} 的值是{}userDefAddress () {return this.addressList.find((item) => {return item.isDefault == 1}) || {}}},
</script>

2. 获取订单信息

就是trade页面的这部分信息
在这里插入图片描述

(1) 接口

export const reqOrderInfo = () => {return requests({url: '/order/auth/trade',method: 'get',})
}

(2) vuex存储数据

state: {addressList: [],
},
actions: {// 获取订单交易信息async getOrderInfo (context) {let res = await reqOrderInfo()if (res.code === 200) {context.commit('GETORDERINFO', res.data)}}
},
mutations: {GETORDERINFO (state, data) {state.orderInfo = data}
},

在这里插入图片描述

(3) 动态数据渲染界面。
这部分没什么重点,组件内取到orderInfo之后,渲染到页面即可。
在这里插入图片描述

二、提交订单

这个功能主要包括收集参数、提交订单,跳转页面。
(测试这个功能用的老师的账号 :账号:13700000000,密码:111111)

1. 提交订单的接口
//URL:/api/order/auth/submitOrder?tradeNo={tradeNo}  method:post
export const reqSubmitOrder = (tradeNo, data) => requests({url: `/order/auth/submitOrder?tradeNo=${tradeNo}`,data,method: 'post'});

接下来我们不再用vuex了。发请求就直接在组件内发了。为了方便使用接口,我们不再按需引入,直接配置到Vue原型上(类似于全局事件总线)。

// main.js
// 引入所有接口
import * as API from '@/api'
console.log(API); // 打印测试一下
new Vue({// KV一致时省略V[router小写的r]router,store,render: h => h(App),beforeCreate () {// 全局事件总线Vue.prototype.$bus = this// 接口挂在原型上Vue.prototype.$API = API }
}).$mount('#app')

打印API得:
在这里插入图片描述

2. 组件内点击提交按钮,发送请求 trade组件
methods:{// 提交订单async submitOrder () {//交易编码,对象解构let { tradeNo } = this.orderInfo;//其余的六个参数let data = {consignee: this.userDefAddress.consignee, //最终收件人的名字consigneeTel: this.userDefAddress.phoneNum, //最终收件人的手机号deliveryAddress: this.userDefAddress.fullAddress, //收件人的地址paymentWay: 'ONLINE', //支付方式orderComment: this.notes, //订单备注。data里定义了notes属性,与文本框v-model双向绑定。orderDetailList: this.orderInfo.detailArrayList, //商品清单};// 参数: 订单编号tradeNo, 订单信息 datalet res = await this.$API.reqSubmitOrder(tradeNo, data)console.log('提交订单', res);if (res.code === 200) {// 请求成功,跳转到支付页面。路由跳转+路由传参;res.data是服务器返回的订单编号this.$router.push('/pay?orderId=' + res.data)} else {alert(res.message)}},

但是尝试了好多次,都是201失败,不知道为啥。
找出原因了,参数orderDetailList写错了,写成orderDetaiList,少了个字母l。
在这里插入图片描述
这里服务器返回的订单编号需要带到支付页面。在支付页面根据订单编号发送请求,获取这个订单的支付信息。

三、支付

在这里插入图片描述
这两处是需要支付信息payInfo动态渲染的地方。

1. 获取支付信息

(1). 接口

// 获取订单支付信息 /api/payment/weixin/createNative/{orderId} get
export const reqOrderPay = (orderId) => {return requests({ url: `/payment/weixin/createNative/${orderId}`, method: 'get' })
}

(2). 组件中发送请求
在这里插入图片描述
请求成功返回的结果:
在这里插入图片描述

2. 支付页面–ElementUI

在这里插入图片描述
ElementUI主要用来实现这个点击按钮,弹窗的效果。
ElementUI网址:ElementUI官网

(1) 引入Element UI

  • 安装: npm i element-ui -S

引入方式分为按需引入和全部引入,按需引入可减少项目体积。本系统采用按需引入:

  • 安装babel-plugin-component:npm install babel-plugin-component -D
  • 修改配置文件,看官网,直接粘贴复制

在这里插入图片描述

  • 按需引入, main.js文件中

    // 按需引入Element-ui组件
    import { MessageBox } from 'element-ui'
    // Vue.use(MessageBox)  这样引入刚进入界面就会有弹窗
    Vue.component(MessageBox.name, MessageBox)
    Vue.prototype.$msgbox = MessageBox
    Vue.prototype.$alert = MessageBox.alert;
    

修改配置文件,需要重新启动项目

(2) 弹框支付的业务逻辑(这个逻辑其实没那么全)

这里弹框页面好写,重要的是支付的逻辑。盘一下逻辑,弹出支付的小窗口,窗口上有两个按钮:

  • 如果用户不点击这两个按钮,直接进行支付:
    ① 发请求获取支付信息,判断是否支付成功。问题是什么时候判断呢?当小窗口弹出来之后,不知道用户什么时候会判断,所以就需要一直发请求进行判断,采用定时器最合适了。
    ② 如果判断支付成功,清除定时器,关闭窗口,保存支付成功这个信息。进行路由跳转。
    ❌③如果支付失败,则,这时候用户只能去点窗口上的按钮了。

  • 如果用户点击窗口上的已支付成功按钮
    ① 判断用户是否真的支付(用到了上边②保存支付成功的信息)。真的支付成功的话,那就清除定时器,关闭窗口,跳转路由。

  • 如果点击窗口上 支付遇到问题按钮
    ① 给出提示信息,关闭弹框,清除定时器。

定时器部分<script>// 支付
async open () {// 如果没有定时器,就开启一个定时器if (!this.timer) {this.timer = setInterval(async () => {// 发请求判断是否已支付,需要一直判断;这个接口一会儿再说let res = await this.$API.reqPaymentState(this.payInfo.orderId)if (res.code === 200) {// 支付成功,清除定时器clearInterval(this.timer);this.timer = nullthis.code = res.code // 保存支付成功的信息this.$msgbox.close() // 关闭弹出框// 路由跳转this.$router.push("/paysuccess")}}, 1000)}
}
</script>

在这里插入图片描述

弹框部分
async open () {// 支付弹框this.$alert(`<img src=${url} />`, '请微信支付', {// 将dangerouslyUseHTMLString属性设置为 true,message 就会被当作 HTML 片段处理。dangerouslyUseHTMLString: true,   center: true, // 布局居中showClose: false,// 取消显示右上角的叉showCancelButton: true,  // 显示取消按钮confirmButtonText: '已支付成功', // 确认按钮cancelButtonText: '取消支付', // 取消按钮/* beforeClose MessageBox弹出框关闭前的回调action:区分取消|确定按钮 instance:当前组件实例done:关闭弹出框的方法*/beforeClose: (action, instance, done) => {// 如果点击支付遇到问题if (action == 'cancel') {alert('支付有问题,请联系xxxx')clearInterval(this.timer) // 清除定时器this.timer = nulldone() // 关闭弹出框} else {// 点击已支付成功,判断是否真的支付成功if (this.code === 200) {// 清除定时器clearInterval(this.timer)this.timer = null;done();              // 关闭弹出框this.$router.push("/paysuccess"); // 路由跳转}}}}}).then(() => { })  // 添加错误捕获,具体解释在下边.catch(() => { });
}

当点击支付遇到问题按钮时,会报这个错误。和Promise有关,等看完Promise再来看这个地方。

参考博客:Uncaught (in promise) cancel 报错 及 解决方法
在这里插入图片描述
解决方法就是加上错误捕获。

(3) 支付逻辑知识点小总结

① 展示二维码。QRcode
可以在npm官网搜索QRcode;

  • 安装:npm i qrcode
  • 引入及使用
import QRcode from 'qrcode'
// 生成二维码,let url = await QRcode.toDataURL(this.payInfo.codeUrl) //这个url就是图片地址

② 获取订单支付状态reqPaymentState接口

// 查询支付订单状态 /api/payment/weixin/queryPayStatus/{orderId}
export const reqPaymentState = (orderId) => {return requests({ url: `/payment/weixin/queryPayStatus/${orderId}`, method: 'get' })
}

③ 路由跳转的支付成功页面paySuccess
这是一个新组件,配置好路由即可。没什么重点。
在这里插入图片描述

④ 完整代码
⑤⑥⑦⑧⑨⑩

四、个人中心

个人中心里,点击不同的订单,右侧显示对应的内容。
在这里插入图片描述
结构类似于之前学Vue2搭的Home、About;

1. 搭建二级路由

(1) 路由
在这里插入图片描述
注意
(1)、子路由的路径不要写/
(2)、如果不写重定向,进入个人中心时,右侧内容就一片空白。重定向是进入个人中心,默认跳转到我的订单这个路由上。
在这里插入图片描述

(2) 组件内的声明式导航
在这里插入图片描述

2. 展示动态数据

(1). 接口

//获取个人中心的数据
//api/order/auth/{page}/{limit}  get 
export const reqMyOrderList = (page, limit) => requests({ url: `/order/auth/${page}/${limit}`, method: 'get' });

(2). 组件获取数据

在这里插入图片描述

(3). 页面表格的合并与展示

数据结构与页面的对应关系:
在这里插入图片描述
每一个订单都是一个表格,所以v-for循环订单数组records,records有几条数据,就有几个表格。
在这里插入图片描述
表头thead,把对应的数据渲染上去即可

<!-- 显示订单时间,编号和删除操作 -->
<thead>
<tr><th colspan="5"><span class="ordertitle">{{ order.createTime }} 订单编号:{{ order.outTradeNo }}<span class="pull-right delete" ><img src="../images/delete.png" /></span></span></th>
</tr>
</thead>

tbody,每一行都是一类商品信息,所以v-for循环订单详细信息orderDetailList,orderDetailList有几条数据,表格就有几个行标签tr
在这里插入图片描述
效果:
在这里插入图片描述
  对于一个订单,收货人等信息都是一样的,所以我们更希望红框里的收货人等信息,展示一行就行了。用到合并单元格:rowspan 跨行合并单元格tdrospan的值取决于表格有几行,也就是orderDetailList数组的长度。
在这里插入图片描述

效果:
在这里插入图片描述
原因分析:如果orderDetailList只有一条数据,那orderDetailList[0]的收货人等信息就会跨一行合并。如果有两条数据,orderDetailList[0]的收货人等信息就会跨两行合并,而orderDetailList[1]的收货人就会被挤到后边。
解决方法:这些信息都一样,那就只展示orderDetailList[0]的收货人等信息。其余的都不显示。
在这里插入图片描述
template包裹这些标签,只展示第一行的所有信息。

(4). 页面分页器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/441092.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【计算机网络 - 基础问题】每日 3 题(二十九)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

【Docker】03-自制镜像

1. 自制镜像 2. Dockerfile # 基础镜像 FROM openjdk:11.0-jre-buster # 设定时区 ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 拷贝jar包 COPY docker-demo.jar /app.jar # 入口 ENTRYPOINT ["ja…

Redis:通用命令 数据类型

Redis&#xff1a;通用命令 & 数据类型 通用命令SETGETKEYSEXISTSDELEXPIRETTLTYPEFLUSHALL 数据类型 Redis的客户端提供了很多命令用于操控Redis&#xff0c;在Redis中&#xff0c;key的类型都是字符串&#xff0c;而value有多种类型&#xff0c;每种类型都有自己的操作命…

Redis篇(最佳实践)(持续更新迭代)

介绍一&#xff1a;键值设计 一、优雅的key结构 Redis 的 Key 虽然可以自定义&#xff0c;但最好遵循下面的几个最佳实践约定&#xff1a; 遵循基本格式&#xff1a;[业务名称]:[数据名]:[id]长度不超过 44 字节不包含特殊字符 例如&#xff1a; 我们的登录业务&#xff0…

Leetcode—76. 最小覆盖子串【困难】

2024每日刷题&#xff08;167&#xff09; Leetcode—76. 最小覆盖子串 C实现代码 class Solution { public:string minWindow(string s, string t) {int bestL -1;int l 0, r 0;vector<int> cnt(128);for(const char c: t) {cnt[c];}int require t.length();int m…

【实战教程】SpringBoot全面指南:快速上手到项目实战(SpringBoot)

文章目录 【实战教程】SpringBoot全面指南&#xff1a;快速上手到项目实战(SpringBoot)1. SpringBoot介绍1.1 SpringBoot简介1.2系统要求1.3 SpringBoot和SpringMVC区别1.4 SpringBoot和SpringCloud区别 2.快速入门3. Web开发3.1 静态资源访问3.2 渲染Web页面3.3 YML与Properti…

[SpringBoot] 苍穹外卖--面试题总结--上

前言 1--苍穹外卖-SpringBoot项目介绍及环境搭建 详解-CSDN博客 2--苍穹外卖-SpringBoot项目中员工管理 详解&#xff08;一&#xff09;-CSDN博客 3--苍穹外卖-SpringBoot项目中员工管理 详解&#xff08;二&#xff09;-CSDN博客 4--苍穹外码-SpringBoot项目中分类管理 详…

pytest(六)——allure-pytest的基础使用

前言 一、allure-pytest的基础使用 二、需要掌握的allure特性 2.1 Allure报告结构 2.2 Environment 2.3 Categories 2.4 Flaky test 三、allure的特性&#xff0c;allure.step()、allure.attach的详细使用 3.1 allure.step 3.2 allure.attach&#xff08;挺有用的&a…

Redis入门第四步:Redis发布与订阅

欢迎继续跟随《Redis新手指南&#xff1a;从入门到精通》专栏的步伐&#xff01;在本文中&#xff0c;我们将深入探讨Redis的发布与订阅&#xff08;Pub/Sub&#xff09;模式。这是一种强大的消息传递机制&#xff0c;适用于各种实时通信场景&#xff0c;如聊天应用、实时通知和…

3、Redis Stack扩展功能

文章目录 一、了解Redis产品二、申请RedisCloud实例三、Redis Stack体验1、RedisStack有哪些扩展&#xff1f;2、Redis JSON1、Redis JSON是什么2、Redis JSON有什么用3、Redis JSON的优势 3、Search And Query1、传统Scan搜索2、Search And Query搜索 4、Bloom Filter1、布隆过…

LabVIEW提高开发效率技巧----阻塞时钟

在LabVIEW开发中&#xff0c;阻塞时钟&#xff08;Blocking Timed Loops&#xff09;是一种常见且强大的技术&#xff0c;尤其适用于时间关键的应用。在这些应用中&#xff0c;精确控制循环的执行频率是关键任务。阻塞时钟通过等待循环的执行完成后再进入下一次迭代&#xff0c…

如何设置LTE端到端系统

LTE Setup Guide Baseline Hardware Requirements 基础硬件要求 需要2个RF前端和2个装有基于Linux的操作系统的PC。系统架构如下&#xff1a; srsUE&#xff1a;需要1个RF前端和1个PC。srsENB&#xff1a;需要1个RF前端和1个PC。srsEPC&#xff1a;需要1个PC。 系统硬件要…

python实现RC4加解密算法

RC4算法 一、算法介绍1.1 背景1.2 密钥调度算法(KSA)1.3 伪随机生成算法(PRGA) 二、代码实现三、演示效果 一、算法介绍 1.1 背景 RC4算法是由Ron Rivest在1987年为RSA数据安全公司设计的一种流密码算法&#xff0c;其安全性主要依赖于其密钥流的随机性和不可预测性。该算法因…

碰撞检测 | 图解视线生成Bresenham算法(附ROS C++/Python/Matlab实现)

目录 0 专栏介绍1 Bresenham算法介绍2 图解Bresenham算法3 算法流程4 仿真实现4.1 ROS C实现4.2 Python实现4.3 Matlab实现 0 专栏介绍 &#x1f525;课设、毕设、创新竞赛必备&#xff01;&#x1f525;本专栏涉及更高阶的运动规划算法轨迹优化实战&#xff0c;包括&#xff…

架构设计之解析CQRS架构模式!

文章首发到公众号&#xff1a;月伴飞鱼 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://har…

【可视化大屏】Python Flask框架介绍

为了能显示真实数据&#xff0c;使用flask快速搭建了一个web应用&#xff0c;然后连接数据库&#xff0c;读取数据库里的数据来进行大屏可视化显示&#xff08;btw&#xff1a;数据是从车主之家网站上爬虫爬的&#xff09; 家人们&#xff01;记得使用专业版的pycharm&#xf…

保证文件只能在公司打开,走出公司就打不开这一神操作如何实现?一文告诉你详情!

在现代企业中&#xff0c;信息安全已经成为一项至关重要的任务。随着企业数据量的不断增加&#xff0c;如何确保敏感信息不被泄露成为企业面临的重要挑战。 其中&#xff0c;一种常见的需求是确保文件只能在公司内部环境中打开&#xff0c;一旦离开公司就无法访问。 本文将详…

计算机组成原理实验三 数据寄存器组R0..R3, MAR, ST, OUT

实验目的和要求 目的&#xff1a;了解模型机中各种寄存器结构、工作原理及其控制方法。 要求&#xff1a;利用CP226 实验系统上的K16..K23 开关做为DBUS 的数据&#xff0c;其它开关做为控制信号&#xff0c;将数据写入寄存器&#xff0c;数据寄存器组R0..R3&#xff0c;地址…

stm32开发环境的配置

keli5的安装 安装上以后&#xff0c;用管理员身份打开软件 复制里面的CID到破解软件里面 将Target调到ARM&#xff0c;然后生成 将注册码复制进软件那个界面&#xff0c;然后AddLIC就破解成功了 调试工具STLink驱动的安装 如果发现带感叹号代表驱动没有安装&#xff0c;但是设…

JavaEE之多线程进阶-面试问题

一.常见的锁策略 锁策略不是指某一个具体的锁&#xff0c;所有的锁都可以往这些锁策略中套 1.悲观锁与乐观锁 预测所冲突的概率是否高&#xff0c;悲观锁为预测锁冲突的概率较高&#xff0c;乐观锁为预测锁冲突的概率更低。 2.重量级锁和轻量级锁 从加锁的开销角度判断&am…