feat(daxpay): 实现微信和支付宝聚合支付功能

- 新增 AliAggregate 和 WechatAggregate组件用于聚合支付页面
- 实现了获取聚合配置、认证、支付等核心逻辑
- 优化了错误处理和页面跳转逻辑
- 重构了部分 API接口和数据结构
This commit is contained in:
bootx
2024-12-03 22:11:17 +08:00
parent ba00dbd561
commit 42791aa2a6
7 changed files with 271 additions and 81 deletions

1
components.d.ts vendored
View File

@@ -17,6 +17,7 @@ declare module 'vue' {
VanLoading: typeof import('vant/es')['Loading']
VanNumberKeyboard: typeof import('vant/es')['NumberKeyboard']
VanOverlay: typeof import('vant/es')['Overlay']
VanSubmitBar: typeof import('vant/es')['SubmitBar']
VanTextEllipsis: typeof import('vant/es')['TextEllipsis']
}
}

View File

@@ -19,6 +19,14 @@ export enum PayMethodEnum {
JSAPI = 'jsapi',
}
/**
* 收银台类型
*/
export enum CashierTypeEnum {
WECHAT_PAY = 'wechat_pay',
ALIPAY = 'alipay',
}
/**
* 收银台类型
*/
@@ -29,8 +37,7 @@ export enum CheckoutTypeEnum {
AGGREGATE = 'aggregate',
}
export enum AggregateEnum{
ALI = 'ali',
export enum AggregateTypeEnum {
ALI = 'alipay',
WECHAT = 'wechat_pay',
}

View File

@@ -82,7 +82,7 @@ import { useKeyboard } from '@/hooks/daxpay/useKeyboard'
const route = useRoute()
const { code } = route.params
const { code : authCode } = route.query
const { code: authCode } = route.query
const show = ref<boolean>(false)
const showRemark = ref<boolean>(false)
@@ -94,8 +94,8 @@ const openId = ref<string>('')
// 认证参数
const authParam = ref<CashierAuthParam>({
code: code as string,
type: CashierTypeEnum.WECHAT_PAY,
cashierCode: code as string,
cashierType: CashierTypeEnum.WECHAT_PAY,
})
const { input, del } = useKeyboard(amount)
@@ -110,7 +110,7 @@ function init() {
// 如果不是重定向跳转过来, 跳转到到重定向授权地址
if (!authCode) {
// 重定向跳转到微信授权地址
generateAuthUrl({ cashierType: CashierTypeEnum.WECHAT_PAY, cashierCode: code as string}).then((res) => {
generateAuthUrl({ cashierType: CashierTypeEnum.WECHAT_PAY, cashierCode: code as string }).then((res) => {
const url = res.data
location.replace(url)
}).catch((res) => {

View File

@@ -1,7 +1,7 @@
import { http } from '@/utils/http/axios'
import type { Result } from '#/axios'
import type { AuthResult } from '@/views/daxpay/auth/ChannelAuth.api'
import {PayResult} from "@/views/daxpay/cashier/CashierCode.api";
import type { PayResult } from '@/views/daxpay/cashier/CashierCode.api'
/**
* 获取收银台订单和配置信息
@@ -43,7 +43,7 @@ export function generateAuthUrl(param: CheckoutAuthUrlParam) {
* 获取授权结果
*/
export function auth(param: CheckoutAuthCodeParam) {
return http.request<AuthResult>({
return http.request<Result<AuthResult>>({
url: '/unipay/checkout/auth',
method: 'post',
data: param,
@@ -53,7 +53,7 @@ export function auth(param: CheckoutAuthCodeParam) {
* 发起普通支付
*/
export function checkoutPay(param: CheckoutPayParam) {
return http.request<Result<CheckoutPayResult>>({
return http.request<Result<PayResult>>({
url: '/unipay/checkout/pay',
method: 'post',
data: param,
@@ -75,30 +75,20 @@ export function aggregatePay(param: CheckoutAggregatePayParam) {
* 收银台认证链接生成参数
*/
export interface CheckoutAuthUrlParam {
/**
* 要支付的订单号
*/
/** 要支付的订单号 */
orderNo?: string
/**
* 聚合支付类型
*/
/** 聚合支付类型 */
aggregateType?: string
}
/**
* 获取收银台认证结果参数
*/
export interface CheckoutAuthCodeParam {
/**
* 要支付的订单号
*/
/** 要支付的订单号 */
orderNo?: string
/**
* 聚合支付类型
*/
/** 聚合支付类型 */
aggregateType?: string
/**
* 认证Code
*/
/** 认证Code */
authCode?: string
}
@@ -106,25 +96,16 @@ export interface CheckoutAuthCodeParam {
* 收银台支付参数
*/
export interface CheckoutPayParam {
/**
* 订单号
*/
/** 订单号 */
orderNo?: string
/**
* 支付配置项ID
*/
/** 支付配置项ID */
itemId?: string
/**
* 唯一标识
*/
/** 唯一标识 */
openId?: string
/**
* 付款码
*/
/** 付款码 */
barCode?: string
}
/**
* 聚合支付参数
*/
@@ -137,22 +118,27 @@ export interface CheckoutAggregatePayParam {
openId?: string
}
/**
* 收银台配置
*/
export interface CheckoutOrderAndConfigResult {
/** 订单信息 */
order: CheckoutOrderResult
/** 收银台配置信息 */
config: CheckoutConfigResult
/** 收银台分类配置信息 */
groupConfigs: CheckoutGroupConfigResult[]
}
/**
* 收银台聚合支付配置
*/
export interface AggregateOrderAndConfigResult {
/**
* 订单信息
*/
/** 订单信息 */
order: CheckoutOrderResult
/**
* 收银台配置信息
*/
/** 收银台配置信息 */
config: CheckoutConfigResult
/**
* 收银台聚合配置信息
*/
/** 收银台聚合配置信息 */
aggregateConfig: AggregateConfigResult
}
@@ -183,6 +169,33 @@ export interface CheckoutConfigResult {
/** h5收银台自动升级聚合支付 */
h5AutoUpgrade?: boolean
}
/**
* 收银台分类配置
*/
export interface CheckoutGroupConfigResult {
/** 类型 */
type?: string
/** 名称 */
name?: string
/** 配置项列表 */
items?: CheckoutItemConfigResult[]
}
/**
* 收银台配置项
*/
export interface CheckoutItemConfigResult {
/** 发起调用的类型 */
callType?: string
/** 名称 */
name?: string
/** 支付通道 */
channel?: string
/** 支付方式 */
payMethod?: string
}
/**
* 收银台聚合配置信息
*/
@@ -196,18 +209,3 @@ export interface AggregateConfigResult {
/** 自动拉起支付 */
autoLaunch?: boolean
}
/**
* 收银台支付结果
*/
export interface CheckoutPayResult {
/**
* 链接
*/
url?: string
/**
* 支付状态
*/
payStatus?: string
}

View File

@@ -1,19 +1,67 @@
<template>
<div>
</div>
</template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
import { onMounted, ref } from 'vue'
import type { CheckoutOrderAndConfigResult } from './CheckoutPay.api'
import { getOrderAndConfig } from './CheckoutPay.api'
import { CheckoutTypeEnum } from '@/enums/daxpay/DaxPayEnum'
import router from '@/router'
const route = useRoute()
const { orderNo } = route.params
const { orderNo } = route.params
const ua = navigator.userAgent
onMounted(()=>{
const orderAndConfig = ref<CheckoutOrderAndConfigResult>({
order: {},
config: {},
groupConfigs: [],
})
/**
* 初始化
*/
onMounted(() => {
initData()
})
/**
* 初始化数据
*/
async function initData() {
// 获取收银台配置
await getOrderAndConfig(orderNo, CheckoutTypeEnum.H5).then(({ data }) => {
orderAndConfig.value = data
})
// 判断是否自动升级为聚合控制台
if (orderAndConfig.value.config.h5AutoUpgrade) {
goAggregate()
}
}
/**
* 跳转到聚合收银台
*/
function goAggregate() {
if (ua.includes('MicroMessenger')) {
router.push({ path: `/checkout/wechat/${orderNo}`, replace: true })
}
else if (ua.includes('Alipay')) {
router.push({ path: `/checkout/alipay/${orderNo}`, replace: true })
}
}
/**
* 发起支付
*/
function pay(){
}
</script>
<style scoped lang="less">

View File

@@ -6,13 +6,14 @@
</div>
<div class="amount-display">
<p style="font-size: 20px">
付款金额
订单
</p>
<p style="font-size: 32px;">
¥ {{ aggregateInfo.order.amount || 0.00 }}
</p>
</div>
</div>
<van-submit-bar :price="aggregateInfo.order.amount || 0.00" button-text="支付" @submit="pay" />
</div>
</template>
@@ -20,14 +21,16 @@
import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import { AggregateEnum } from '@/enums/daxpay/DaxPayEnum'
import { AggregateTypeEnum } from '@/enums/daxpay/DaxPayEnum'
import router from '@/router'
import {
import type {
AggregateOrderAndConfigResult,
aggregatePay,
CheckoutAggregatePayParam,
getAggregateConfig
} from "@/views/daxpay/checkout/CheckoutPay.api";
} from '@/views/daxpay/checkout/CheckoutPay.api'
import {
aggregatePay,
getAggregateConfig,
} from '@/views/daxpay/checkout/CheckoutPay.api'
const route = useRoute()
const { orderNo } = route.params
@@ -36,7 +39,7 @@ const loading = ref<boolean>(false)
const aggregateInfo = ref<AggregateOrderAndConfigResult>({
aggregateConfig: {},
config: {},
order: {}
order: {},
})
onMounted(() => {
@@ -48,7 +51,7 @@ onMounted(() => {
*/
async function initData() {
// 查询订单和配置
await getAggregateConfig(orderNo, AggregateEnum.ALI).then(({ data }) => {
await getAggregateConfig(orderNo, AggregateTypeEnum.ALI).then(({ data }) => {
aggregateInfo.value = data
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
@@ -57,7 +60,6 @@ async function initData() {
if (aggregateInfo.value.aggregateConfig.autoLaunch) {
pay()
}
}
/**
@@ -67,7 +69,7 @@ function pay() {
loading.value = true
const from = {
orderNo: aggregateInfo.value.order.orderNo,
aggregateType: AggregateEnum.ALI,
aggregateType: AggregateTypeEnum.ALI,
} as CheckoutAggregatePayParam
aggregatePay(from)
.then(({ data }) => {

View File

@@ -1,11 +1,145 @@
<script setup lang="ts">
</script>
<template>
<div>
<div class="container">
<div style="font-size: 28px;margin-top: 10px;">
{{ aggregateInfo.config.name || '微信收银台' }}
</div>
<div class="amount-display">
<p style="font-size: 20px">
付款金额
</p>
<p style="font-size: 32px;">
¥ {{ aggregateInfo.order.amount || 0.00 }}
</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import { AggregateTypeEnum } from '@/enums/daxpay/DaxPayEnum'
import router from '@/router'
import type {
AggregateOrderAndConfigResult,
CheckoutAuthCodeParam,
CheckoutPayParam,
} from '@/views/daxpay/checkout/CheckoutPay.api'
import { auth, checkoutPay, generateAuthUrl, getAggregateConfig } from '@/views/daxpay/checkout/CheckoutPay.api'
import type { WxJsapiSignResult } from '@/views/daxpay/cashier/CashierCode.api'
const route = useRoute()
const { orderNo } = route.params
const { code: authCode } = route.query
const show = ref<boolean>(false)
const loading = ref<boolean>(false)
const openId = ref<string>('')
// 认证参数
const authParam = ref<CheckoutAuthCodeParam>({
aggregateType: AggregateTypeEnum.WECHAT,
})
const aggregateInfo = ref<AggregateOrderAndConfigResult>({
aggregateConfig: {},
config: {},
order: {},
})
onMounted(() => {
init()
})
/**
* 进入页面的初始化
*/
function init() {
// 如果不是重定向跳转过来, 跳转到到重定向授权地址
if (!authCode) {
// 重定向跳转到微信授权地址
generateAuthUrl({ orderNo: orderNo as string, aggregateType: AggregateTypeEnum.WECHAT }).then((res) => {
const url = res.data
location.replace(url)
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
})
}
else {
authParam.value.authCode = authCode as string
// 初始化数据
initData()
}
}
/**
* 初始化数据
*/
async function initData() {
show.value = true
// 获取聚合配置
getAggregateConfig(orderNo, AggregateTypeEnum.WECHAT).then(({ data }) => {
aggregateInfo.value = data
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
})
// 认证获取OpenId
await auth(authParam.value).then(({ data }) => {
openId.value = data.openId as string
}).catch((res) => {
router.push({ name: 'ErrorResult', query: { msg: res.message } })
})
// 判断是否自动拉起支付
if (aggregateInfo.value.aggregateConfig.autoLaunch) {
pay()
}
}
/**
* 微信jsapi方式支付
*/
function pay() {
loading.value = true
const from = {
orderNo: orderNo as string,
openId: openId.value,
} as CheckoutPayParam
checkoutPay(from)
.then(({ data }) => {
loading.value = false
// 拉起jsapi支付
const json = JSON.parse(data.payBody)
jsapiPay(json)
})
}
/**
* 拉起Jsapi支付窗口
*/
function jsapiPay(data: WxJsapiSignResult) {
const form = {
appId: data.appId, // 公众号ID由商户传入
timeStamp: data.timeStamp, // 时间戳自1970年以来的秒数
nonceStr: data.nonceStr, // 随机串
package: data.package, // 预支付ID
signType: data.signType, // 微信签名方式:
paySign: data.paySign, // 微信签名
}
// 使用微信JsSdk拉起支付
WeixinJSBridge.invoke('getBrandWCPayRequest', form, (res) => {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
// 跳转到成功页面
router.push({ name: 'SuccessResult', query: { msg: '支付成功' }, replace: true })
}
})
}
</script>
<style scoped lang="less">
</style>