PC端收银台添加聚合支付 以及 功能优化

This commit is contained in:
ren
2025-04-07 18:07:26 +08:00
parent 9215fe6913
commit c5746d7b44
7 changed files with 232 additions and 32 deletions

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -37,9 +37,9 @@ export function auth(param: GatewayAuthCodeParam) {
} }
/** /**
* 支付成功获取信息 * 支付成功获取状态
*/ */
export function getSuccessOrder(orderNo) { export function getSuccessOrderStatus(orderNo) {
return http.request<Result<paySuccess>>({ return http.request<Result<paySuccess>>({
url: '/unipay/gateway/findStatusByOrderNo', url: '/unipay/gateway/findStatusByOrderNo',
method: 'POST', method: 'POST',
@@ -47,6 +47,17 @@ export function getSuccessOrder(orderNo) {
}) })
} }
/**
* 支付成功获取信息
*/
export function getSuccessOrderMessage(orderNo) {
return http.request<Result<paySuccess>>({
url: '/unipay/gateway/findOrderByOrderNo',
method: 'get',
params: { orderNo },
})
}
/** /**
* 发起支付 * 发起支付
*/ */

View File

@@ -40,7 +40,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { getSuccessOrder } from '@/views/daxpay/h5/aggregate/Aggregate.api' import { getSuccessOrderMessage } from '@/views/daxpay/h5/aggregate/Aggregate.api'
import type { paySuccess } from '@/views/daxpay/h5/aggregate/Aggregate.api' import type { paySuccess } from '@/views/daxpay/h5/aggregate/Aggregate.api'
import { getBrowserUA } from '@/utils/uaUtil' import { getBrowserUA } from '@/utils/uaUtil'
// 获取路由参数 // 获取路由参数
@@ -70,7 +70,7 @@ onMounted(() => {
}) })
function init() { function init() {
getSuccessOrder(orderNo).then(({ data }) => { getSuccessOrderMessage(orderNo).then(({ data }) => {
orderAndConfig.value = data orderAndConfig.value = data
}) })
} }

View File

@@ -30,7 +30,14 @@ export function orderStatus(orderNo) {
params: { orderNo }, params: { orderNo },
}) })
} }
// 查询订单信息
export function orderMessage(orderNo) {
return http.request<Result<boolean>>({
url: '/unipay/gateway/findOrderByOrderNo',
method: 'GET',
params: { orderNo },
})
}
/** /**
* 收银台配置 * 收银台配置
*/ */
@@ -41,6 +48,8 @@ export interface OrderAndConfig {
config: GatewayPayConfig config: GatewayPayConfig
/** 收银台分类配置信息 */ /** 收银台分类配置信息 */
groupConfigs: CashierGroupConfig[] groupConfigs: CashierGroupConfig[]
/** 聚合二维码 */
aggregateUrl?: string
} }
/** /**

View File

@@ -1,5 +1,13 @@
<template> <template>
<div class="pcPayTai"> <div class="pcPayTai">
<van-overlay :show="loading" class-name="loadingOverlay">
<div class="loading-wrapper" @click.stop>
<van-loading size="24px">
请稍后...
</van-loading>
</div>
</van-overlay>
<div class="pcPayBox"> <div class="pcPayBox">
<div class="header"> <div class="header">
<h1>支付收银台</h1> <h1>支付收银台</h1>
@@ -39,15 +47,19 @@
:class="{ methodItemClick: payMethObj.payClickItemId === item.id }" :class="{ methodItemClick: payMethObj.payClickItemId === item.id }"
@click="payMethObj.payClick(item)" @click="payMethObj.payClick(item)"
> >
<!-- <img :src="item.icon" alt=""> --> <img v-if="item.icon === 'aggregate-pay'" :src="getImageUrl(item.icon)" alt="">
<img src="@/assets/images/alipay.png" alt=""> <img v-else src="@/assets/images/alipay.png" alt="">
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
<div v-if="item.recommend" class="recommon"> <div v-if="item.recommend" class="recommon">
推荐 推荐
</div> </div>
</div> </div>
</div> </div>
<div class="payMethodChildBox"> <!-- 聚合支付 -->
<div v-if="isAggregateShow" class="payMethodCode">
<vue-qr :text="orderObj?.aggregateUrl" :size="200" />
</div>
<div v-else class="payMethodChildBox">
<div <div
v-for="item in childRenList" v-for="item in childRenList"
:key="item.id" :key="item.id"
@@ -60,7 +72,13 @@
</div> </div>
</div> </div>
</div> </div>
<van-popup v-model:show="codeshow" round closeable :close-on-click-overlay="false"> <van-popup
v-model:show="codeshow"
round
closeable
:close-on-click-overlay="false"
@click-close-icon="closeCode"
>
<template #default> <template #default>
<div class="codeBox"> <div class="codeBox">
<div class="title"> <div class="title">
@@ -80,7 +98,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted, reactive, ref } from 'vue' import { onMounted, onUnmounted, reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { showDialog, showFailToast } from 'vant' import { showConfirmDialog, showDialog, showFailToast } from 'vant'
import { result } from 'lodash-es' import { result } from 'lodash-es'
import vueQr from 'vue-qr/src/packages/vue-qr.vue' import vueQr from 'vue-qr/src/packages/vue-qr.vue'
import { getOrderAndConfig, orderStatus, payOrder } from '@/views/daxpay/pc/cashier/Cashier.api' import { getOrderAndConfig, orderStatus, payOrder } from '@/views/daxpay/pc/cashier/Cashier.api'
@@ -91,6 +109,7 @@ import { GatewayCallTypeEnum } from '@/enums/daxpay/DaxPayEnum'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const { orderNo } = route.params const { orderNo } = route.params
const loading = ref<boolean>(false)
// 页面信息对象 // 页面信息对象
const orderObj = ref<OrderAndConfig>() const orderObj = ref<OrderAndConfig>()
// 分组下的支付列表 // 分组下的支付列表
@@ -104,6 +123,25 @@ function getImageUrl(icon) {
const codeshow = ref<boolean>(false) const codeshow = ref<boolean>(false)
// 二维码链接 // 二维码链接
const codeLink = ref<string>('') const codeLink = ref<string>('')
// 判断是否含有聚合支付
const isAggregateShow = ref<boolean>(false)
// 关闭菜单触发
function closeCode() {
showConfirmDialog({
title: '是否关闭支付弹窗?',
message: '关闭弹窗后该订单会被取消',
className: 'confirmDialogPC',
overlayClass: 'confirmOverlayPC',
})
.then(() => {
codeshow.value = false
router.replace({ path: `/pc/payFail`, query: { msg: '订单已取消,请重新发起支付!' } })
})
.catch(() => {
codeshow.value = true
})
}
// 倒计时对象 // 倒计时对象
const orderTime = reactive({ const orderTime = reactive({
@@ -133,17 +171,21 @@ const orderTime = reactive({
return time.toString().padStart(2, '0') return time.toString().padStart(2, '0')
}, },
}) })
// 定时器 // 倒计时定时器
const { pause, resume } = useIntervalFn(() => { const { pause: timePause, resume: timeResume } = useIntervalFn(() => {
orderTime.getMinter() // 每秒获取分秒方法 orderTime.getMinter() // 每秒获取分秒方法
}, 1000) }, 1000)
// 轮询监听定时器
const { pause: lunPause, resume: lunResume } = useIntervalFn(() => {
queryOrderStatus() // 执行订单状态查询
}, 3000)
// 监听倒计时,到时间跳转超时页面 // 监听倒计时,到时间跳转超时页面
watch( watch(
() => orderTime.totalTme, () => orderTime.totalTme,
(newValue) => { (newValue) => {
if (newValue === 0) { if (newValue === 0) {
router.replace({ path: `/pc/payFail`, replace: true }) router.replace({ path: `/pc/payFail`, query: { msg: '支付超时,请重新发起支付!' } })
} }
}, },
) )
@@ -158,11 +200,13 @@ const payMethObj = reactive({
}, },
// 点击支付 // 点击支付
toPayTypeClick: (item) => { toPayTypeClick: (item) => {
loading.value = true
payOrder({ orderNo: orderNo as string, itemId: item.id }).then(({ code, data, msg }) => { payOrder({ orderNo: orderNo as string, itemId: item.id }).then(({ code, data, msg }) => {
if (code !== 0) { if (code !== 0) {
router.replace({ path: `/pc/payFail`, query: { msg } }) router.replace({ path: `/pc/payFail`, query: { msg } })
return return
} }
loading.value = false
// 如果是二维码方式 打开支付弹窗 // 如果是二维码方式 打开支付弹窗
if (item.callType === GatewayCallTypeEnum.qr_code) { if (item.callType === GatewayCallTypeEnum.qr_code) {
codeshow.value = true codeshow.value = true
@@ -181,21 +225,24 @@ watch(
() => payMethObj.payClickItemId, () => payMethObj.payClickItemId,
(newValue) => { (newValue) => {
if (newValue) { if (newValue) {
// 判断是否为聚合支付
if (newValue === '111111111111111111') {
isAggregateShow.value = true
return
}
isAggregateShow.value = false
// 查找点击的分组下面的子项 // 查找点击的分组下面的子项
childRenList.value = orderObj.value?.groupConfigs.find(item => item.id === newValue)?.items childRenList.value = orderObj.value?.groupConfigs.find(item => item.id === newValue)?.items
} }
}, },
) )
// 轮询定时器
const timer = ref()
onMounted(() => { onMounted(() => {
init() // 初始化数据 init() // 初始化数据
}) })
onUnmounted(() => { onUnmounted(() => {
pause() timePause() // 关闭倒计时
timer.value = null lunPause() // 关闭轮询
clearInterval(timer.value)
}) })
// 初始化 // 初始化
@@ -206,12 +253,21 @@ function init() {
router.replace({ path: `/pc/payFail`, query: { msg } }) router.replace({ path: `/pc/payFail`, query: { msg } })
return return
} }
queryOrderStatus() // 查询订单状态开启 lunResume() // 开始轮询查询状态
// 判断是否存在聚合支付
if (data.config.aggregateShow) {
data.groupConfigs.unshift({
id: '111111111111111111',
name: '聚合支付',
recommend: false,
icon: 'aggregate-pay',
})
}
orderObj.value = data orderObj.value = data
payMethObj.payClickItemId = orderObj.value.groupConfigs[0].id || '' // 赋值第一个 payMethObj.payClickItemId = orderObj.value.groupConfigs[0].id || '' // 赋值第一个
orderTime.getDownTotalTime(data.order.expiredTime) // 计算倒计时 orderTime.getDownTotalTime(data.order.expiredTime) // 计算倒计时
orderTime.getMinter() // 先执行一下 解决进入页面一秒后才显示倒计时 orderTime.getMinter() // 先执行一下 解决进入页面一秒后才显示倒计时
resume() // 开启倒计时 timeResume() // 开启倒计时
}) })
.catch((error) => { .catch((error) => {
console.log(error) console.log(error)
@@ -220,19 +276,31 @@ function init() {
// 查询订单状态 // 查询订单状态
function queryOrderStatus() { function queryOrderStatus() {
timer.value = setInterval(() => { orderStatus(orderNo).then((res) => {
orderStatus(orderNo).then((res) => { // 判断订单是否支付成功
// 判断订单是否支付成功 if (res.data) {
if (res.data) { codeshow.value = false
codeshow.value = false router.replace({ path: `/pc/paySuccess/${orderNo}`, replace: true })
router.replace({ path: `/pc/paySuccess/${orderNo}`, replace: true }) }
} })
})
}, 3000) as unknown as number
} }
</script> </script>
<style lang="less"> <style lang="less">
.loadingOverlay {
.van-loading__circular {
color: #fff;
}
.van-loading__text {
color: #fff;
font-weight: 400;
}
}
.confirmOverlayPC {
left: 0;
width: 100%;
height: 100%;
}
.pcPayTai { .pcPayTai {
.van-overlay { .van-overlay {
left: 0; left: 0;
@@ -406,7 +474,12 @@ function queryOrderStatus() {
border-bottom: none; border-bottom: none;
} }
} }
.payMethodCode {
padding: 2.0833vw 0;
display: flex;
justify-content: center;
align-items: center;
}
.payMethodChildBox { .payMethodChildBox {
padding: 2.0833vw 0 2.0833vw 15.625vw; padding: 2.0833vw 0 2.0833vw 15.625vw;
display: flex; display: flex;

View File

@@ -2,7 +2,9 @@
<div class="pcPayTai"> <div class="pcPayTai">
<div class="pcPayBox"> <div class="pcPayBox">
<img src="@/assets/images/fail1.png" alt=""> <img src="@/assets/images/fail1.png" alt="">
<p class="errMessage">{{ msg ? msg : "支付失败,请重新尝试!" }}</p> <p class="errMessage">
{{ msg ? msg : "支付失败,请重新尝试!" }}
</p>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -3,12 +3,63 @@
<div class="pcPayBox"> <div class="pcPayBox">
<img src="@/assets/images/success1.png" alt=""> <img src="@/assets/images/success1.png" alt="">
<p>支付成功</p> <p>支付成功</p>
<div class="payPrice">
<span class="unit"></span>
<div class="price">
{{ orderAndConfig?.amount }}
</div>
</div>
<div class="payMessBox">
<div class="payMessItem">
<div class="itemTitle">
支付标题
</div>
<div class="itemContent">
{{ orderAndConfig?.title }}
</div>
</div>
<div class="payMessItem">
<div class="itemTitle">
订单编号
</div>
<div class="itemContent">
{{ orderAndConfig?.orderNo }}
</div>
</div>
</div>
<div class="payBtnBox" @click="closeSuccessClick">
完成
</div>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useRoute } from 'vue-router'
import { onMounted } from 'vue'
import { orderMessage } from '@/views/daxpay/pc/cashier/Cashier.api'
const route = useRoute()
const { orderNo } = route.params
const orderAndConfig = ref()
onMounted(() => {
init()
console.log(route)
})
// 初始化函数
function init() {
orderMessage(orderNo).then(({ data }) => {
orderAndConfig.value = data
})
}
// 点击关闭
function closeSuccessClick() {
window.close()
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
@@ -35,7 +86,7 @@
overflow: hidden; // 防止内容溢出 overflow: hidden; // 防止内容溢出
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; padding: 7.2083vw 0;
align-items: center; align-items: center;
gap: 1.5625vw; gap: 1.5625vw;
p { p {
@@ -43,5 +94,59 @@
color: #1e90ff; color: #1e90ff;
} }
} }
.payPrice {
display: flex;
gap: 0.2604vw;
align-items: center;
.unit {
font-size: 0.625vw;
transform: translateY(0.4167vw);
}
.price {
font-size: 1.6667vw;
font-weight: 700;
}
}
.payMessBox {
width: 100%;
padding: 0px 1.0417vw;
display: flex;
flex-direction: column;
gap: 0.5208vw;
.payMessItem {
width: 100%;
display: flex;
justify-content: center;
.itemTitle {
font-size: 0.8333vw;
color: #797d81;
}
.itemContent {
font-size: 0.8333vw;
font-weight: 500;
font-size: '微软雅黑';
}
}
}
.payBtnBox {
width: 20%;
margin: 0 auto;
background-color: #0d6eff;
color: #fff;
height: 2.7083vw;
position: absolute;
bottom: 7.6042vw;
text-align: center;
line-height: 2.7083vw;
border-radius: 0.5208vw;
cursor: pointer;
}
} }
</style> </style>