vue前台十(1)
一,订单交易页trade的数据展示
1.trade组件静态页面完成,创建trade.js的vuex,在总vuex中引入,注册
2.封装请求订单交易信息的函数接口
//请求订单交易信息 /api/order/auth/trade
export const reqTradeInfo = () => Ajax.get('/order/auth/trade')
3.在trade.js的vuex中发送请求
import {reqTradeInfo} from '@/api'
const state = {
tradeInfo:{}
}
const mutations = {
RECEIVETRADEINFO(state,tradeInfo){
state.tradeInfo = tradeInfo
}
}
const actions = {
async getTradeInfo({commit}){
const result = await reqTradeInfo()
if(result.code === 200){
commit('RECEIVETRADEINFO',result.data)
}
}
}
const getters = {
detailArrayList(state){
return state.tradeInfo.detailArrayList || []
},
userAddressList(state){
return state.tradeInfo.userAddressList || []
}
}
export default {
state,
mutations,
actions,
getters
}
mounted() {
this.getTradeInfo();
},
getTradeInfo() {
this.$store.dispatch("getTradeInfo");
},
computed: {
...mapGetters(["userAddressList", "detailArrayList"]),
...mapState({
tradeInfo: state => state.trade.tradeInfo
}),
deaultAddress() {
return this.userAddressList.find(item => item.isDefault === "1") || {}; //找到默认的地址那一项
}
}
<div class="address clearFix" v-for="(address, index) in userAddressList" :key="address.id"> <span class="username" :class="{selected:address.isDefault === '1'}">{{address.consignee}}</span> <p @click="changeDefaultAddress(index)"> <span class="s1">{{address.userAddress}}</span> <span class="s2">{{address.phoneNum}}</span> <span class="s3" v-if="address.isDefault === '1'">默认地址</span> </p> </div>
changeDefaultAddress(index) {
this.userAddressList.forEach(item => {
item.isDefault = "0";
});
this.userAddressList[index].isDefault = "1";
},
7,左边还有一个选中的边框按钮需要调整,点击哪个地址,选中框就是哪个,对selected类需要判断
<div class="address clearFix" v-for="(user, index) in userAddressList" :key="user.id"> <span class="username " :class="{selected:user.isDefault === '1'}">{{user.consignee}}</span> <p @click="changeDefaultAddress(index)"> <span class="s1">{{user.userAddress}}</span> <span class="s2">{{user.phoneNum}}</span> <span class="s3" v-if="user.isDefault === '1'">默认地址</span> </p> </div>
<div class="receiveInfo"> 寄送至: <span>{{deaultAddress.userAddress}}</span> 收货人: <span>{{deaultAddress.consignee}}</span> <span>{{deaultAddress.phoneNum}}</span> </div>
此时需要计算属性,找到那个isDefault为1的对象
deaultAddress() {
return this.userAddressList.find(item => item.isDefault === "1") || {}; //找到默认的地址那一项
}
二,提交订单分析及接口请求函数封装
逻辑分析,此时在订单页面,底部有个提交订单按钮,点击提交按钮,这里是要发送提交订单的请求,这个订单需要携带请求体对象,而且所有的数据都在订单页面,那么就不需要在vuex中发送ajax请求,
只在订单trade组件中发送即可,此时,需要根据api接口的请求体参数,
来收集各种参数,去发送请求,
请求体参数,我们需要收集这些参数
{
"consignee": "admin",
"consigneeTel": "15011111111",
"deliveryAddress": "北京市昌平区2",
"paymentWay": "ONLINE",
"orderComment": "xxx",
"orderDetailList": [
{
"id": null,
"orderId": null,
"skuId": 6,
"skuName": " Apple iPhone 11 (A2223) 128GB 红色 移动联通电信22",
"imgUrl": "http://182.92.128.115:8080//rBFUDF6V0JmAG9XGAAGL4LZv5fQ163.png",
"orderPrice": 4343,
"skuNum": 2,
"hasStock": null
},
{
"id": null,
"orderId": null,
"skuId": 4,
"skuName": "Apple iPhone 11 (A2223) 128GB 红色",
"imgUrl": "http://182.92.128.115:80800/rBFUDF6VzaeANzIOAAL1X4gVWEE035.png",
"orderPrice": 5999,
"skuNum": 1,
"hasStock": null
}
]
}
1,封装提交订单接口的函数
//请求提交订单(其实本质就是创建订单,返回的是订单编号)
// /api/order/auth/submitOrder?tradeNo={tradeNo} post
export const reqSubmitOrder = (tradeNo,tradeInfo) =>Ajax.post(`/order/auth/submitOrder?tradeNo=${tradeNo}`,tradeInfo)
<a href="javascript:;" class="subBtn" @click="submitOrder">提交订单</a>
js代码,发送请求,跳转到支付页面,此时接口函数在入口文件main.js配置下,在原型配置,让组件可以自动获取
new Vue({
beforeCreate() {
Vue.prototype.$bus = this
Vue.prototype.$API = API
},
el:'#app',
render: h => h(App),
router,
store
})
//提交按钮,发送请求,跳转到支付页面,携带订单编号到支付页面
async submitOrder() {
//准备query参数和data参数
let tradeNo = this.tradeInfo.tradeNo;
let tradeInfo = {
consignee: this.deaultAddress.consignee,
consigneeTel: this.deaultAddress.phoneNum,
deliveryAddress: this.deaultAddress.userAddress,
paymentWay: "ONLINE",
orderComment: this.message,
orderDetailList: this.detailArrayList
};
//调用接口请求函数去发送请求创建订单
const result = await this.$API.reqSubmitOrder(tradeNo, tradeInfo);
if(result.code === 200){
//请求提交创建订单成功,会返回一个订单编号,有了这个订单编号,再去跳转到支付页面
//接下来就可以携带这个订单编号去到支付页面
alert('创建订单成功,自动跳转到支付页面')
this.$router.push('/pay?orderNo='+result.data)
}
}
注;此时返回的响应信息有个订单编号,需要路由到t支付页面pay, 订单编号需要传递过去
响应信息的事例
{
"code": 200,
"message": "成功",
"data": 71, // orderId 订单号
"ok": true
}
注;关于API模块的配置,将API配置成vue的原型,可以让组件实例直接访问到,在入口文件main.js配置
new Vue({
beforeCreate() {
Vue.prototype.$bus = this
Vue.prototype.$API = API
},
此时组件实例访问,
<span class="fl"> 请您在提交订单 <em class="orange time">4小时</em>之内完成支付,超时订单会自动取消。订单号: <em>{{$route.query.orderNo}}</em> </span>
2.而对支付的总金额,需要发送请求获取
配置接口函数, orderId是订单编号,作为请求参数
//请求获取订单信息 /api/payment/weixin/createNative/{orderId} get
export const reqOrderInfo = (orderId) => Ajax.get(`/payment/weixin/createNative/${orderId}`)
3.在pay支付组件中,发送请求,我们可以不在vuex中发送请求,而直接在组件中发送请求,更方便。页面加载完后,即可发送请求
mounted() {
this.getOrderInfo();
},
methods: {
async getOrderInfo() {
const result = await this.$API.reqOrderInfo(this.$route.query.orderNo);
if (result.code === 200) {
this.orderInfo = result.data;
}
},
响应信息事例, orderId为订单编号。 totalFee为支付总费用
{
"code": 200,
"message": "成功",
"data": {
"codeUrl": "weixin://wxpay/bizpayurl?pr=P0aPBJK",
"orderId": 71,
"totalFee": 23996,
"resultCode": "SUCCESS"
},
"ok": true
}
在html中填充支付费用
<span class="fr"> <em class="lead">应付金额:</em> <em class="orange money">¥{{orderInfo.totalFee}}</em> </span>
四, element-ui的引入消息盒子,弹出alert,message消息提示
element-ui库:https://element.eleme.cn/#/zh-CN/component/quickstart
1.安装element-ui, npm i element-ui -S
2.按需引入组件,可参考官网
支付整体逻辑
点击立即支付
1、我们需要根据codeUrl 使用qrcode生成要显示的微信二维码url
2、使用element-ui的this.$alert 弹出消息框显示二维码图片,使用需要显示html的消息框
3、弹出消息框的时候,我们需要循环定时器去查询支付状态
4、如果支付成功,那么把支付成功的状态码保存在data当中,并且清除定时器,自动跳转到支付成功页面
5、如果点击我已经支付成功,那么需要判断状态码是不是成功,如果成功那就关闭提示框,不成功就提示不关闭
(需要放在messageBox的beforeClose回调当中去,判断 然后手动关闭)
6、如果点击支付失败,那么需要提示信息 清除定时器 关闭提示框 关闭也要去手动关闭
(需要放在messageBox的beforeClose回调当中去,判断 然后手动关闭)
7、支付成功才能到支付成功页面,那么我们都要去花钱,所以把支付功能简化,直接点击就能跳
import { MessageBox, Message } from 'element-ui';
Vue.prototype.$msgbox = MessageBox; //消息盒子
Vue.prototype.$alert = MessageBox.alert; //弹出框
Vue.prototype.$message = Message; //提示信息
注;将element-ui组件挂载在vue原型上,组件对象可以直接访问
五,使用qrcode生成微信支付二维码,npm install --save qrcode ,github去搜索的时候,搜索node-qrcode
1.点击立即支付按钮,弹出一个支付框,需要element-ui来创建,并且有一个二维码图片,需要借助qrcode来完成
<div class="submit"> <!-- <router-link class="btn" to="/paysuccess">立即支付</router-link> --> <a href="javascript:;" class="btn" @click="pay">立即支付</a> </div>
2. js逻辑代码, 点击立即支付, 弹出一个框。需要对返回的微信连接,转换成二维码。 发送一个查看支付信息的请求,搞个定时器去实时查看,
async pay() { //1、弹出一个消息盒子 //2、这个消息盒子内部需要二维码,所以得去准备二维码 //codeUrl:"weixin://wxpay/bizpayurl?pr=DcuIayu" 是微信官方返回的支付链接信息 //我们需要把这个信息转化为一张二维码图片的路径 //使用qrcode可以把这个支付链接信息转化为二维码 //3、this.$alert返回的也是一个promise,而且这个promise成功代表点了确认按钮 失败代表点了取消按钮,必须处理 //哪怕什么都不做 // 4、 二维码显示成功后,我们需要时时刻刻去查看订单的支付状态信息,如果支付状态信息是成功那么就自动跳转。,如果是失败继续查看 // 5、 处理用户点击行为 点击确认和点击取消 在beforeClose当中去处理,可以让我们选择的去关闭消息盒子 // With promises try { const imgUrl = await QRCode.toDataURL(this.orderInfo.codeUrl); //会把支付链接信息转化为二维码图片的路径 this.$alert(`<img src="${imgUrl}" />`, "请使用微信扫码支付", { dangerouslyUseHTMLString: true, showClose: false, showCancelButton: true, cancelButtonText: "支付中遇到了问题", confirmButtonText: "我已经成功支付", center: true,
//取消弹框之前的操作 beforeClose: (action, instance, done) => { if (action === "confirm") { //确认按钮 if (this.status !== 200) { clearInterval(this.timer); this.timer = null; this.$router.push("/paysuccess"); done(); //手动关闭消息盒子,如果不调,那么就永远不关闭 } else { this.$message.warning("请确保支付成功"); } } else if (action === "cancel") { //取消按钮 clearInterval(this.timer); this.timer = null; this.$message.warning("请联系前台小姐姐"); done() } } }) .then(() => {}) //代表你点了确认按钮后的逻辑 都会强制关闭消息盒子 .catch(() => {}); //代表你点了取消按钮后的逻辑 都会强制关闭消息盒子 } catch (error) { this.$message.error(error.message); } // 循环定时器 每3秒发请求查看支付状态信息 // 定时器设置后返回的是一个编号,是一个数字,我们使用变量存储的是这个数字 // 定时器又是一个异步操作,所以会有对应得管理模块去管理 ,依赖的是编号 // 清除定时器,其实是把这个编号的定时器任务清除,但是这个编号还是存在你之前保存的变量当中 // 因此以后清除定时器 记得把保存编号的变量也去置为null,代表彻底清除 if (!this.timer) { this.timer = setInterval(async () => { const result = await this.$API.reqPayStatus(this.orderInfo.orderId); if (result.code === 200) { //支付成功 //支付成功的状态码保存一下,为了用户点击成功支付按钮的时候去判断 this.status = 200; clearInterval(this.timer); //取消定时器 this.timer = null; this.$router.push("/paysuccess"); this.$msgbox.close(); //手动关闭消息盒子 } }, 3000); } }
注;1,qrcode的git连接: https://github.com/soldair/node-qrcode
2.QRCode.toDataURL(this.orderInfo.codeUrl) 是一个promise,返回的是一个二维码图片路径
3, codeUrl:"weixin://wxpay/bizpayurl?pr=DcuIayu" 是之前返回的响应数据
3, 封装请求查看订单的支付状态信息接口,需要查看订单支付是否成功,
//请求查看订单的支付状态信息 /api/payment/weixin/queryPayStatus/{orderId} get
// 返回状态200代表支付成功 205代表支付中
export const reqPayStatus = (orderId) => Ajax.get(`/payment/weixin/queryPayStatus/${orderId}`)