7.vue3医疗在线问诊项目 - _极速问诊-支付功能实现 ==> 预支付信息渲染、支付流程解析、订单生成、支付完成
问诊支付-路由和预支付信息渲染{#pay-html}
实现:问诊页面路由配置,获取问诊预支付信息并渲染。
需求:
- 配置预订单信息页面路由
- 定义 API 函数,获取预支付和患者信息
- 获取数据渲染
1)路由配置
路由 router/index.ts
{
path: '/consult/pay',
component: () => import('@/views/consult/ConsultPay.vue'),
meta: { title: '问诊支付' }
}
2)定义 API 函数,获取预支付信息
types/consult.d.ts
// 问诊订单预支付传参
export type ConsultOrderPreParams = Pick<PartialConsult, 'type' | 'illnessType'>
// 问诊订单预支付信息
export type ConsultOrderPreData = {
pointDeduction: number
couponDeduction: number
couponId: string
payment: number // 应付
couponId: number
actualPayment: number // 实付
}
api/consult.ts
import type { ConsultOrderPreData, ConsultOrderPreParams } from '@/types/consult'
// 拉取预支付订单信息
export const getConsultOrderPre = (params: ConsultOrderPreParams) =>
request.get<ConsultOrderPreData>('/patient/consult/order/pre', { params })
api/user.ts
// 查询患者详情
export const getPatientDetail = (id: string) => request.get<Patient>(`/patient/info/${id}`)
3)获取数据渲染 Consult/ConsultPay.vue
<script setup lang="ts">
import { getConsultOrderPre } from '@/api/consult'
import { getPatientDetail } from '@/api/user'
import { useConsultStore } from '@/stores'
import type { ConsultOrderPreData } from '@/types/consult'
import type { Patient } from '@/types/user'
import { onMounted, ref } from 'vue'
const store = useConsultStore()
// 1. 查询预订单信息
const payInfo = ref<ConsultOrderPreData>()
const loadData = async () => {
const res = await getConsultOrderPre({
type: store.consult.type,
illnessType: store.consult.illnessType
})
payInfo.value = res.data
// 设置默认优惠券
store.setCunpon(payInfo.value.couponId)
}
// 2. 查询患者信息
const patient = ref<Patient>()
const loadPatient = async () => {
if (!store.consult.patientId) return
const res = await getPatientDetail(store.consult.patientId)
patient.value = res.data
}
onMounted(() => {
loadData()
loadPatient()
})
const agree = ref(false)
</script>
<template>
<div class="consult-pay-page" v-if="payInfo">
<cp-nav-bar title="支付" />
<div class="pay-info">
+ <p class="tit">图文问诊 {{ payInfo?.payment }} 元</p>
<img class="img" src="@/assets/avatar-doctor.svg" />
<p class="desc">
<span>极速问诊</span>
<span>自动分配医生</span>
</p>
</div>
<van-cell-group>
+ <van-cell title="优惠券" :value="`-¥${payInfo.couponDeduction}`" />
+ <van-cell title="积分抵扣" :value="`-¥${payInfo.pointDeduction}`" />
+ <van-cell title="实付款" :value="`¥${payInfo.actualPayment}`" class="pay-price" />
</van-cell-group>
<div class="pay-space"></div>
<van-cell-group>
<van-cell
title="患者信息"
+ :value="`${patient?.name} | ${patient?.genderValue} | ${patient?.age}岁`"
></van-cell>
+ <van-cell title="病情描述" :label="store.consult.illnessDesc"></van-cell>
</van-cell-group>
<div class="pay-schema">
<van-checkbox v-model="agree">我已同意 <span class="text">支付协议</span></van-checkbox>
</div>
<van-submit-bar
button-type="primary"
+ :price="payInfo.actualPayment * 100"
button-text="立即支付"
text-align="left"
/>
</div>
</template>
注意❓:van-submit-bar
组件price要乘于100
问诊支付-流程{#pay-line}
了解支付流程
支付流程:
-
点击支付按钮,调用生成订单接口,得到
订单ID
,打开选择支付方式对话框 -
选择
支付方式
,(测试环境需要配置回跳地址
)调用获取支付地址接口,得到支付地址,跳转到支付宝页面-
使用支付宝APP支付(在手机上且安装沙箱支付宝)
-
使用浏览器账号密码支付 (测试推荐)
-
-
支付成功回跳到问诊室页面
回跳地址:开发中自行定义
http://localhost/room
支付宝沙箱账号:
买家账号:jfjbwb4477@sandbox.com
登录密码:111111
支付密码:111111
问诊支付-生成订单{#pay-create-order}
实现:打开弹层选择支付方式,创建订单,进行支付
1)打开选择支付方式抽屉
const agree = ref(false)
const show = ref(false)
// 支付方式
const paymentMethod = ref<0 | 1>()
const submit = async () => {
if (!agree.value) return Toast('请勾选我已同意支付协议')
// 打开
show.value = true
}
<div class="pay-schema">
+ <van-checkbox v-model="agree">我已同意 <span class="text">支付协议</span></van-checkbox>
</div>
<!-- 3. 支付 -->
<van-submit-bar
button-type="primary"
:price="payInfo.actualPayment * 100"
button-text="立即支付"
text-align="left"
+ loading
+ @click="submit"
/>
<!-- 支付弹层 -->
<van-action-sheet v-model:show="show" title="选择支付方式">
<div class="pay-type">
<p class="amount">¥{{ payInfo.actualPayment.toFixed(2) }}</p>
<van-cell-group>
<van-cell title="微信支付" @click="paymentMethod = 0">
<template #icon><cp-icon name="consult-wechat" /></template>
<template #extra><van-checkbox :checked="paymentMethod === 0" /></template>
</van-cell>
<van-cell title="支付宝支付" @click="paymentMethod = 1">
<template #icon><cp-icon name="consult-alipay" /></template>
<template #extra><van-checkbox :checked="paymentMethod === 1" /></template>
</van-cell>
</van-cell-group>
<div class="btn">
<van-button type="primary" round block>立即支付</van-button>
</div>
</div>
</van-action-sheet>
2)准备创建订单api函数
// 生成订单
export const createConsultOrder = (data: PartialConsult) =>
request.post<{ id: string }>('/patient/consult/order', data)
3)打开抽屉的时候生成订单ID,成功后清空本地存储的问诊订单信息
+ import { ...,createConsultOrder } from '@/api/consult'
const agree = ref(false)
const show = ref(false)
const paymentMethod = ref<0 | 1>()
+ const orderId = ref('')
+ const loading = ref(false)
const submit = async () => {
if (!agree.value) return Toast('请勾选我已同意支付协议')
+ loading.value = true
+ const res = await createConsultOrder(store.consult)
+ orderId.value = res.data.id
+ loading.value = false
+ store.clear() // 订单生成后清除pinia中的数据
// 打开
show.value = true
}
说明❓:订单创建成功后,清除store中数据,刷新页面接口异常
问诊支付-进行支付{#pay-logic}
实现:获取支付地址,进行订单支付
需求:
- 生成订单后:不可回退,用户离开页面前确认
- 生成订单后:不可关闭支付抽屉
- 获取后台支付地址,跳转支付
1)生成订单后不可回退
import { onBeforeRouteLeave } from 'vue-router'
onBeforeRouteLeave(() => {
if (orderId.value) return false
})
2)生成订单后不可关闭支付抽屉
<van-action-sheet
v-model:show="show"
title="选择支付方式"
:close-on-popstate="false"
+ :before-close="onClose"
+ :closeable="false"
>
const router = useRouter()
const onClose = () => {
return Dialog.confirm({
title: '关闭支付',
message: '取消支付将无法获得医生回复,医生接诊名额有限,是否确认关闭?',
cancelButtonText: '仍要关闭',
confirmButtonText: '继续支付',
confirmButtonColor: 'var(--cp-primary)'
})
.then(() => {
return false
})
.catch(() => {
orderId.value = '' // 清空后才能跳转页面
router.push('/user/consult')
return true
})
}
3)生成支付地址的 API 函数
// 获取支付地址 0 是微信 1 支付宝
export const getConsultOrderPayUrl = (data: {
paymentMethod: 0 | 1
orderId: string
payCallback: string
}) => request.post<{ payUrl: string }>('/patient/consult/pay', data)
4)点击抽屉支付按钮,跳转到支付宝页面
<div class="btn">
<van-button @click="pay" type="primary" round block>立即支付</van-button>
</div>
// 跳转支付
const pay = async () => {
if (paymentMethod.value === undefined) return Toast('请选择支付方式')
Toast.loading('跳转支付')
const res = await getConsultOrderPayUrl({
orderId: orderId.value,
paymentMethod: paymentMethod++.value,
payCallback: 'http://localhost/room'
})
window.location.href = res.data.payUrl
}
说明❓:选择继续浏览器支付,使用账号密码登录即可
小结:
前端支付准备什么?
- 创建订单
- 获取支付地址,跳转支付宝平台支付,支付成功回跳