结算&支付
结算-页面布局

落的代码:
- 定义组件基础解构和配置路由
src/views/member/pay/checkout.vue
<template><div class="xtx-pay-checkout-page"><div class="container"><XtxBread><XtxBreadItem to="/">首页</XtxBreadItem><XtxBreadItem to="/cart">购物车</XtxBreadItem><XtxBreadItem >填写订单</XtxBreadItem></XtxBread><div class="wrapper"><!-- 收货地址 --><!-- 商品信息 --><!-- 配送时间 --><!-- 支付方式 --><!-- 金额明细 --><!-- 提交订单 --></div></div></div></template><script>export default {name: 'XtxPayCheckoutPage'}</script><style scoped lang="less">.xtx-pay-checkout-page {.wrapper {background: #fff;}}</style>
- 配置路由
src/router/index.js
const PayCheckout = () => import('@/views/member/pay/checkout')
{ path: '/cart', component: Cart },+ { path: '/member/checkout', component: PayCheckout }
- 完成页面布局效果
<template><div class="xtx-pay-checkout-page"><div class="container"><XtxBread><XtxBreadItem to="/">首页</XtxBreadItem><XtxBreadItem to="/cart">购物车</XtxBreadItem><XtxBreadItem >填写订单</XtxBreadItem></XtxBread><div class="wrapper"><!-- 收货地址 --><h3 class="box-title">收货地址</h3><div class="box-body"><div class="address"><div class="text"><!-- <div class="none">您需要先添加收货地址才可提交订单。</div> --><ul><li><span>收<i/>货<i/>人:</span>朱超</li><li><span>联系方式:</span>132****2222</li><li><span>收货地址:</span>海南省三亚市解放路108号物质大厦1003室</li></ul><a href="javascript:;">修改地址</a></div><div class="action"><XtxButton class="btn">切换地址</XtxButton><XtxButton class="btn">添加地址</XtxButton></div></div></div><!-- 商品信息 --><h3 class="box-title">商品信息</h3><div class="box-body"><table class="goods"><thead><tr><th width="520">商品信息</th><th width="170">单价</th><th width="170">数量</th><th width="170">小计</th><th width="170">实付</th></tr></thead><tbody><tr v-for="i in 4" :key="i"><td><a href="javascript:;" class="info"><img src="https://yanxuan-item.nosdn.127.net/cd9b2550cde8bdf98c9d083d807474ce.png" alt=""><div class="right"><p>轻巧多用锅雪平锅 麦饭石不粘小奶锅煮锅</p><p>颜色:白色 尺寸:10cm 产地:日本</p></div></a></td><td>¥100.00</td><td>2</td><td>¥200.00</td><td>¥200.00</td></tr></tbody></table></div><!-- 配送时间 --><h3 class="box-title">配送时间</h3><div class="box-body"><a class="my-btn active" href="javascript:;">不限送货时间:周一至周日</a><a class="my-btn" href="javascript:;">工作日送货:周一至周五</a><a class="my-btn" href="javascript:;">双休日、假日送货:周六至周日</a></div><!-- 支付方式 --><h3 class="box-title">支付方式</h3><div class="box-body"><a class="my-btn active" href="javascript:;">在线支付</a><a class="my-btn" href="javascript:;">货到付款</a><span style="color:#999">货到付款需付5元手续费</span></div><!-- 金额明细 --><h3 class="box-title">金额明细</h3><div class="box-body"><div class="total"><dl><dt>商品件数:</dt><dd>5件</dd></dl><dl><dt>商品总价:</dt><dd>¥5697.00</dd></dl><dl><dt>运<i></i>费:</dt><dd>¥0.00</dd></dl><dl><dt>应付总额:</dt><dd class="price">¥5697.00</dd></dl></div></div><!-- 提交订单 --><div class="submit"><XtxButton type="primary">提交订单</XtxButton></div></div></div></div></template><script>export default {name: 'XtxPayCheckoutPage'}</script><style scoped lang="less">.xtx-pay-checkout-page {.wrapper {background: #fff;padding: 0 20px;.box-title {font-size: 16px;font-weight: normal;padding-left: 10px;line-height: 70px;border-bottom: 1px solid #f5f5f5;}.box-body {padding: 20px 0;}}}.address {border: 1px solid #f5f5f5;display: flex;align-items: center;.text {flex: 1;min-height: 90px;display: flex;align-items: center;.none {line-height: 90px;color: #999;text-align: center;width: 100%;}> ul {flex: 1;padding: 20px;li {line-height: 30px;span {color: #999;margin-right: 5px;> i {width: 0.5em;display: inline-block;}}}}> a {color: @xtxColor;width: 160px;text-align: center;height: 90px;line-height: 90px;border-right: 1px solid #f5f5f5;}}.action {width: 420px;text-align: center;.btn {width: 140px;height: 46px;line-height: 44px;font-size: 14px;&:first-child {margin-right: 10px;}}}}.goods {width: 100%;border-collapse: collapse;border-spacing: 0;.info {display: flex;text-align: left;img {width: 70px;height: 70px;margin-right: 20px;}.right {line-height: 24px;p {&:last-child {color: #999;}}}}tr {th {background: #f5f5f5;font-weight: normal;}td,th {text-align: center;padding: 20px;border-bottom: 1px solid #f5f5f5;&:first-child {border-left: 1px solid #f5f5f5;}&:last-child {border-right: 1px solid #f5f5f5;}}}}.my-btn {width: 228px;height: 50px;border: 1px solid #e4e4e4;text-align: center;line-height: 48px;margin-right: 25px;color: #666666;display: inline-block;&.active,&:hover {border-color: @xtxColor;}}.total {dl {display: flex;justify-content: flex-end;line-height: 50px;dt {i {display: inline-block;width: 2em;}}dd {width: 240px;text-align: right;padding-right: 70px;&.price {font-size: 20px;color: @priceColor;}}}}.submit {text-align: right;padding: 60px;border-top: 1px solid #f5f5f5;}</style>
结算-渲染页面
目的:分离收货地址组件,渲染页面默认内容。
大致步骤:
- 分离收货地址组件
- 定义获结算信息API接口
- 页面组件获取数据,传入地址组件,渲染剩余内容
- 渲染地址组件
落的代码:
- 分离收货地址组件
src/member/pay/components/checkout-address.vue
<template><div class="checkout-address"><div class="text"><!-- <div class="none">您需要先添加收货地址才可提交订单。</div> --><ul><li><span>收<i/>货<i/>人:</span>朱超</li><li><span>联系方式:</span>132****2222</li><li><span>收货地址:</span>海南省三亚市解放路108号物质大厦1003室</li></ul><a href="javascript:;">修改地址</a></div><div class="action"><XtxButton class="btn">切换地址</XtxButton><XtxButton class="btn">添加地址</XtxButton></div></div></template><script>export default {name: 'CheckoutAddress'}</script><style scoped lang="less">.checkout-address {border: 1px solid #f5f5f5;display: flex;align-items: center;.text {flex: 1;min-height: 90px;display: flex;align-items: center;.none {line-height: 90px;color: #999;text-align: center;width: 100%;}> ul {flex: 1;padding: 20px;li {line-height: 30px;span {color: #999;margin-right: 5px;> i {width: 0.5em;display: inline-block;}}}}> a {color: @xtxColor;width: 160px;text-align: center;height: 90px;line-height: 90px;border-right: 1px solid #f5f5f5;}}.action {width: 420px;text-align: center;.btn {width: 140px;height: 46px;line-height: 44px;font-size: 14px;&:first-child {margin-right: 10px;}}}}</style>
- 使用组件
src/views/member/pay/checkout.vue 
+import CheckoutAddress from './components/checkout-address'export default {name: 'XtxPayCheckoutPage',+ components: { CheckoutAddress }}
<!-- 收货地址 --><h3 class="box-title">收货地址</h3><div class="box-body">+ <CheckoutAddress /></div>
- 定义获结算信息API接口
src/api/order.js定义接口
import request from '@/utils/request'/*** 获取结算信息*/export const findCheckoutInfo = () => {return request({method: 'get',url: '/member/order/pre'})}
- 页面组件获取数据,传入地址组件,渲染剩余内容
src/views/member/pay/checkout.vue
+import { findCheckoutInfo } from '@/api/order'export default {name: 'XtxPayCheckoutPage',components: { CheckoutAddress },setup () {+ const checkoutInfo = ref(null)+ findCheckoutInfo().then(data => {+ checkoutInfo.value = data.result+ })+ return { checkoutInfo }}}
- 传入地址组件,地址列表
src/views/member/pay/checkout.vue
+ <div class="wrapper" v-if="checkoutInfo"><!-- 收货地址 --><h3 class="box-title">收货地址</h3><div class="box-body">+ <CheckoutAddress :list="checkoutInfo.userAddresses" /></div>
- 渲染剩余内容
src/views/member/pay/checkout.vue
<tbody><tr v-for="item in checkoutInfo.goods" :key="item.id"><td><a href="javascript:;" class="info"><img :src="item.picture" alt=""><div class="right"><p>{{item.name}}</p><p>{{item.attrsText}}</p></div></a></td><td>¥{{item.payPrice}}</td><td>{{item.count}}</td><td>¥{{item.totalPrice}}</td><td>¥{{item.totalPayPrice}}</td></tr></tbody>
<div class="total"><dl><dt>商品件数:</dt><dd>{{checkoutInfo.summary.goodsCount}}件</dd></dl><dl><dt>商品总价:</dt><dd>¥{{checkoutInfo.summary.totalPrice}}</dd></dl><dl><dt>运<i></i>费:</dt><dd>¥{{checkoutInfo.summary.postFee}}</dd></dl><dl><dt>应付总额:</dt><dd class="price">¥{{checkoutInfo.summary.totalPayPrice}}</dd></dl></div>
- 渲染地址组件
src/member/pay/components/checkout-address.vue
- 接收数据
props: {list: {type: Array,default: () => []}},
- 得到默认显示地址
setup (props) {// 显示的地址const showAddress = ref(null)if (props.list.length) {const defaultAddress = props.list.find(item => item.isDefault === 1)if (defaultAddress) {showAddress.value = defaultAddress} else {// eslint-disable-next-line vue/no-setup-props-destructureshowAddress.value = props.list[0]}}return { showAddress }}
- 渲染组件
<div class="text"><div v-if="!showAddress" class="none">您需要先添加收货地址才可提交订单。</div><ul v-if="showAddress"><li><span>收<i/>货<i/>人:</span>{{showAddress.receiver}}</li><li><span>联系方式:</span>{{showAddress.contact}}</li><li><span>收货地址:</span>{{showAddress.fullLocation.replace(/ /g,'')+showAddress.address}}</li></ul><a v-if="showAddress" href="javascript:;">修改地址</a></div>
结算-提交订单
目的:汇总提交订单需要的数据,进行提交。
大致步骤:
- 定义需要提交的数据对象
- 绑定提交订单点击事件,进行提交即可
落的代码:
- 定义需要提交的数据对象
src/views/member/pay/checkout.vue
setup () {const checkoutInfo = ref(null)// 需要提交的字段const requestParams = reactive({addressId: null,+ deliveryTimeType: 1,+ payType: 1,+ buyerMessage: '',+ goods: []})findCheckoutInfo().then(data => {checkoutInfo.value = data.result+ // 设置提交时候的商品+ requestParams.goods = checkoutInfo.value.goods.map(item => {+ return {+ skuId: item.skuId,+ count: item.count+ }+ })})
- 绑定提交订单点击事件,进行提交即可
src/api/order.js提交订单API函数
/*** 提交订单* @param {Object} order - 订单信息对象*/export const createOrder = (order) => {return request({method: 'post',url: '/member/order',data: order})}
- 提交订单
src/views/member/pay/checkout.vue
<!-- 提交订单 --><div class="submit"><XtxButton @click="submitOrder" type="primary">提交订单</XtxButton></div>
// 提交订单const router = useRouter()const submitOrder = () => {if (!requestParams.addressId) return Message({ text: '请选择收货地址' })createOrder(requestParams).then(data => {router.push({ path: '/member/pay', query: { id: data.result.id } })})}return { checkoutInfo, changeAddress, submitOrder }
支付-支付页面-基础布局
目的:配置路由和支付页面基础布局。

- 支付页面基本布局
src/views/member/pay/index.vue
<template><div class="xtx-pay-page"><div class="container"><XtxBread><XtxBreadItem to="/">首页</XtxBreadItem><XtxBreadItem to="/cart">购物车</XtxBreadItem><XtxBreadItem>支付订单</XtxBreadItem></XtxBread><!-- 付款信息 --><div class="pay-info"><span class="icon iconfont icon-queren2"></span><div class="tip"><p>订单提交成功!请尽快完成支付。</p><p>支付还剩 <span>24分59秒</span>, 超时后将取消订单</p></div><div class="amount"><span>应付总额:</span><span>¥5673.00</span></div></div><!-- 付款方式 --><div class="pay-type"><p class="head">选择以下支付方式付款</p><div class="item"><p>支付平台</p><a class="btn wx" href="javascript:;"></a><a class="btn alipay" href="javascript:;"></a></div><div class="item"><p>支付方式</p><a class="btn" href="javascript:;">招商银行</a><a class="btn" href="javascript:;">工商银行</a><a class="btn" href="javascript:;">建设银行</a><a class="btn" href="javascript:;">农业银行</a><a class="btn" href="javascript:;">交通银行</a></div></div></div></div></template><script>export default {name: 'XtxPayPage'}</script><style scoped lang="less">.pay-info {background: #fff;display: flex;align-items: center;height: 240px;padding: 0 80px;.icon {font-size: 80px;color: #1dc779;}.tip {padding-left: 10px;flex: 1;p {&:first-child {font-size: 20px;margin-bottom: 5px;}&:last-child {color: #999;font-size: 16px;}}}.amount {span {&:first-child {font-size: 16px;color: #999;}&:last-child {color: @priceColor;font-size: 20px;}}}}.pay-type {margin-top: 20px;background-color: #fff;padding-bottom: 70px;p {line-height: 70px;height: 70px;padding-left: 30px;font-size: 16px;&.head {border-bottom: 1px solid #f5f5f5;}}.btn {width: 150px;height: 50px;border: 1px solid #e4e4e4;text-align: center;line-height: 48px;margin-left: 30px;color: #666666;display: inline-block;&.active,&:hover {border-color: @xtxColor;}&.alipay {background: url(https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/7b6b02396368c9314528c0bbd85a2e06.png) no-repeat center / contain;}&.wx {background: url(https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/c66f98cff8649bd5ba722c2e8067c6ca.jpg) no-repeat center / contain;}}}</style>
- 路由配置
src/router/index.js
const PayIndex = () => import('@/views/member/pay/index')
{ path: '/member/checkout', component: PayCheckout },+ { path: '/member/pay', component: PayIndex }
支付-支付页面-信息展示
目的:展示支付的订单相关信息。
大致步骤:
- 准备API接口函数获取订单详情
- 在组件获取数据渲染
落的代码:
- 准备API接口函数获取订单详情
src/api/order.js
/*** 获取订单详情* @param {String} id - 订单ID*/export const findOrder = (id) => {return request({method: 'get',url: '/member/order/' + id})}
- 在组件获取数据渲染
src/views/component/pay/index.vue
import { ref } from 'vue'import { findOrder } from '@/api/order'import { useRoute } from 'vue-router'export default {name: 'XtxPayPage',setup () {// 订单const order = ref(null)// 路由信息const route = useRoute()// 查询订单findOrder(route.query.id).then(data => {// 设置订单order.value = data.result})return { order }}}
+ <div class="pay-info" v-if="order">
<div class="amount"><span>应付总额:</span>+ <span>¥{{order.payMoney}}</span></div>
支付-支付流程
目的:知道小兔鲜支付流程。

总结:
- PC前台点击支付按钮,新开标签页打开后台提供的支付链接带上订单ID还有回跳地址
- 后台服务发起支付,等待支付结果,修改订单状态,回跳PC前台结果页
- PC前台在结果页获取回跳URL参数订单ID查询支付状态,展示支付结果
# 支付地址回调地址(可变)http://www.corho.com:8080/#/pay/callback
测试:如果使用客户端需要下载 沙箱支付宝 开放平台扫码下载。
买家账号jfjbwb4477@sandbox.com登录密码111111支付密码111111
支付-跳转支付
目的:支付打开新页,当前页打开提示框。
- 准备支付跳转链接
src/utils/request.js
export const baseURL = 'http://pcapi-xiaotuxian-front-devtest.itheima.net/'
- 拼接回跳地址链接
src/views/member/pay/index.vue
// 支付地址// const payUrl = '后台服务基准地址+支付页面地址+订单ID+回跳地址'const redirect = encodeURIComponent('http://www.corho.com:8080/#/pay/callback')const payUrl = `${baseURL}pay/aliPay?orderId=${route.query.orderId}&redirect=${redirect}`return { order, countdownText, payUrl }
<a class="btn alipay" :href="payUrl" target="_blank"></a>2.
支付-结果展示
目的:准备一个支付完成的回调页面,展示支付后订单状态。

大致步骤:
- 准备一个基础页面
- 根据地址订单ID查询订单状态进行展示,或者是地址栏支付结果。
落的代码:
- 准备一个基础页面
<template><div class="xtx-pay-page"><div class="container"><XtxBread><XtxBreadItem to="/">首页</XtxBreadItem><XtxBreadItem to="/cart">购物车</XtxBreadItem><XtxBreadItem>支付结果</XtxBreadItem></XtxBread><!-- 支付结果 --><div class="pay-result"><span class="iconfont icon-queren2 green"></span><!-- <span class="iconfont icon-shanchu red" ></span> --><p class="tit">订单支付成功</p><p class="tip">我们将尽快为您发货,收货期间请保持手机畅通</p><p>支付方式:<span>微信支付</span></p><p>支付金额:<span>¥1899.00</span></p><div class="btn"><XtxButton type="primary" style="margin-right:20px">查看订单</XtxButton><XtxButton type="gray">进入首页</XtxButton></div><p class="alert"><span class="iconfont icon-tip"></span>温馨提示:小兔鲜儿不会以订单异常、系统升级为由要求您点击任何网址链接进行退款操作,保护资产、谨慎操作。</p></div></div></div></template><script>export default {name: 'XtxPayResultPage'}</script><style scoped lang="less">.pay-result {padding: 100px 0;background: #fff;text-align: center;> .iconfont {font-size: 100px;}.green {color: #1dc779;}.red {color: @priceColor;}.tit {font-size: 24px;}.tip {color: #999;}p {line-height: 40px;font-size: 16px;}.btn {margin-top: 50px;}.alert {font-size: 12px;color: #999;margin-top: 50px;}}</style>
- 根据地址订单ID查询订单状态进行展示
<template><div class="xtx-pay-page"><div class="container"><XtxBread><XtxBreadItem to="/">首页</XtxBreadItem><XtxBreadItem to="/cart">购物车</XtxBreadItem><XtxBreadItem>支付结果</XtxBreadItem></XtxBread><!-- 支付结果 --><div class="pay-result" v-if="order"><span v-if="$route.query.payResult" class="iconfont icon-queren2 green"></span><span v-else class="iconfont icon-shanchu red" ></span><p class="tit">订单支付{{$route.query.payResult?'成功':'失败'}}</p><p class="tip">我们将尽快为您发货,收货期间请保持手机畅通</p><p>支付方式:<span>支付宝支付</span></p><p>支付金额:<span class="red">¥{{order.payMoney}}</span></p><div class="btn"><XtxButton @click="$router.push('/member/order')" type="primary" style="margin-right:20px">查看订单</XtxButton><XtxButton @click="$router.push('/')" type="gray">进入首页</XtxButton></div><p class="alert"><span class="iconfont icon-tip"></span>温馨提示:小兔鲜儿不会以订单异常、系统升级为由要求您点击任何网址链接进行退款操作,保护资产、谨慎操作。</p></div></div></div></template><script>import { ref } from 'vue'import { findOrderDetail } from '@/api/order'import { useRoute } from 'vue-router'export default {name: 'XtxPayResultPage',setup () {const order = ref(null)const route = useRoute()findOrderDetail(route.query.orderId).then(data => {order.value = data.result})return { order }}}</script><style scoped lang="less">.pay-result {padding: 100px 0;background: #fff;text-align: center;> .iconfont {font-size: 100px;}.green {color: #1dc779;}.red {color: @priceColor;}.tit {font-size: 24px;}.tip {color: #999;}p {line-height: 40px;font-size: 16px;}.btn {margin-top: 50px;}.alert {font-size: 12px;color: #999;margin-top: 50px;}}</style>
