支付页面调整

This commit is contained in:
ren
2025-03-28 18:08:55 +08:00
parent 75b228e866
commit 34b4adfb3a
7 changed files with 396 additions and 159 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -74,5 +74,13 @@ export const DaxPayRoute: RouteRecordRaw = {
title: '支付失败页面',
},
},
{
path: '/PayExcessTime',
name: 'PayExcessTime',
component: () => import('@/views/daxpay/result/PayExcessTime.vue'),
meta: {
title: '支付超时页面',
},
},
],
}

View File

@@ -87,17 +87,11 @@ const transform: AxiosTransform = {
}
// 接口请求成功,直接返回相应结果
if (code === ResultEnum.SUCCESS) {
if (code) {
return result
}
// 接口请求错误,统一提示错误信息 这里逻辑可以根据项目进行修改
const errorMsg = msg
// 请求失败
console.log(code)
if (code) {
showFailToast(errorMsg)
}
throw new Error(errorMsg)
},

View File

@@ -11,6 +11,17 @@ export function getOrderAndConfig(orderNo) {
params: { orderNo, cashierType: 'h5' },
})
}
/**
* 发起支付
*/
export function payOrder(data:payParam){
return http.request<Result<payConfig>>({
url: '/unipay/gateway/pay',
method: 'POST',
data,
})
}
/**
* 收银台配置
@@ -38,7 +49,7 @@ export interface GatewayOrder {
description?: string
/** 金额(元) */
amount?: number
expiredTime?: string;
}
/**
* 聚合支付配置信息
@@ -85,3 +96,30 @@ export interface CashierConfig {
/** 是否推荐 */
recommend?: boolean
}
/**
* 支付配置项参数
*/
export interface payParam{
// 订单号
orderNo?:string,
//支付配置项ID
itemId?:number,
// 唯一标识
openId?:string,
// 付款码
anthCode?:string,
}
/**
* 支付配置项参数返回值
*/
export interface payConfig{
// 商户订单号
bizOrderNo?:string,
// 订单号
orderNo?:string,
//支付状态
status?:string,
//支付参数体
payBody?:string
}

View File

@@ -3,28 +3,22 @@
<div class="cash_topBox">
<div class="payPrice">
<span class="unit"></span>
<div class="price">
{{ orderAndConfig.order.amount }}
</div>
<div class="price">{{ orderAndConfig.order.amount }} </div>
</div>
<div class="excessTime">
<span class="exTitle">剩余支付时间</span>
<span class="number">{{ orderTime.currentMiute }}</span>
<span class="number">{{ orderTime.currentMinute }}</span>
<span class="point">:</span>
<span class="number">{{ orderTime.currentSeconds }}</span>
</div>
<div class="payMessItem">
<div class="itemTitle">
标题:
</div>
<div class="itemTitle">标题:</div>
<div class="itemContent">
{{ orderAndConfig.order.title }}
</div>
</div>
<div class="payMessItem">
<div class="itemTitle">
订单编号:
</div>
<div class="itemTitle">订单编号:</div>
<div class="itemContent">
{{ orderAndConfig.order.orderNo }}
</div>
@@ -40,84 +34,152 @@
@click="payTypeClick(item)"
>
<div class="itemType">
<img :src="item.icon" alt="">
<img src="@/assets/images/new_wx_pay.png" alt="" v-if="item.icon == 'wechat'" />
<img src="@/assets/images/zfb_pay.png" alt="" v-if="item.icon == 'alipay'" />
<!-- <img src="@/assets/images/quick_pay.png" alt=""> -->
<p>{{ item.name }}</p>
<span v-if="item.recommend"> 推荐</span>
</div>
<div class="selectBox">
<img
v-if="item.id === selectId"
src="@/assets/images/selected-arrow-icon.png"
alt=""
>
<img v-if="item.id === selectId" src="@/assets/images/selected-arrow-icon.png" alt="" />
</div>
</div>
</div>
<div class="payBtnBox">
<div class="payBtnBox" @click="payClick" v-if="selectId">
支付<span>{{ orderAndConfig.order.amount }}</span>
</div>
<div class="payBtnBox noSelect" v-else>
支付<span>{{ orderAndConfig.order.amount }}</span>
</div>
</div>
<!-- loading -->
<div class="loadingMask hide" id="loadingMask" v-if="loading">
<div class="content">
<img class="loadingImg" src="@/assets/images/loading.png" alt="" />
<div class="loadingTxt">处理中请耐心等待</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
// 导入图片文件
import { onMounted, onUnmounted, reactive, ref } from 'vue'
import { useRoute } from 'vue-router'
import type { OrderAndConfig } from '@/views/daxpay/cashier/Cashier.api'
import { getOrderAndConfig } from '@/views/daxpay/cashier/Cashier.api'
import { onMounted, onUnmounted, reactive, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import type { OrderAndConfig, payConfig } from "@/views/daxpay/cashier/Cashier.api";
import { getOrderAndConfig, payOrder } from "@/views/daxpay/cashier/Cashier.api";
const route = useRoute()
const route = useRoute();
const router = useRouter();
const { code: orderNo } = route.params
const orderAndConfig = ref<OrderAndConfig>()
//获取传入的参数
const { code: orderNo } = route.params;
//储存初始化的数据
const orderAndConfig = ref<OrderAndConfig>();
// 选中的支付方式
const selectId = ref()
const selectId = ref<string>();
function payTypeClick(item) {
selectId.value = item.id
selectId.value = item.id;
}
// 倒计时对象
const orderTime = reactive({
totalTme: 300, // 总共时间
currentMinute: '05', // 当前分钟
currentSeconds: '00', // 当前秒数
})
totalTme: 0, // 总共时间
currentMinute: "00", // 当前分钟
currentSeconds: "00", // 当前秒数
});
// 定时器
const { pause, resume } = useIntervalFn(() => {
orderTime.totalTme--
orderTime.currentMinute = formatTime(Math.floor(orderTime.totalTme / 60))
orderTime.currentSeconds = formatTime(Math.floor(orderTime.totalTme % 60))
}, 1000)
getMinter(); //每秒获取分秒方法
}, 1000);
function formatTime(time: number){
// 格式化时间
return time.toString().padStart(2, '0')
function formatTime(time: number) {
return time.toString().padStart(2, "0");
}
//获取倒计时秒数
function getDownTotalTime(expiredTime: string) {
let nowTime = new Date(); //获取当前时间
let excessTime = new Date(expiredTime); //获取失效时间
let interval = excessTime.getTime() - nowTime.getTime(); //获取倒计时毫秒数
if (interval > 0) {
orderTime.totalTme = Math.floor(interval / 1000);
} else {
console.log("失效了");
}
}
//获取分秒
function getMinter() {
orderTime.totalTme--;
orderTime.currentMinute = formatTime(Math.floor(orderTime.totalTme / 60));
orderTime.currentSeconds = formatTime(Math.floor(orderTime.totalTme % 60));
}
//监听倒计时,到时间跳转超时页面
watch(
() => orderTime.totalTme,
(newValue) => {
if (newValue == 0) {
router.replace("/PayExcessTime");
}
}
);
const loading = ref(false);
// 发起支付
function payClick() {
loading.value = true;
const form = {
orderNo: orderNo,
itemId: selectId.value,
};
payOrder(form as any)
.then(({ data }) => {
loading.value = false;
location.replace(data.payBody as any);
})
.catch((error) => {
console.log(error);
});
}
onMounted(() => {
init()
})
init();
});
onUnmounted(() => {
pause()
})
pause();
});
/**
* 初始化
*/
function init() {
getOrderAndConfig(orderNo).then(({ data }) => {
orderAndConfig.value = data
// orderTime.totalTme = data.order.expireTime
resume()
getOrderAndConfig(orderNo)
.then(({ data, code, msg }) => {
if (code != 0) {
//如果异常,跳转异常页面
router.replace({
path: "/PayExcessTime",
query: { msg },
});
return;
}
orderAndConfig.value = data; //赋值初始化数据
getDownTotalTime(data.order?.expiredTime); //计算倒计时
getMinter(); //先执行一下 解决进入页面一秒后才显示倒计时
resume(); //开启倒计时
})
.catch((error) => {
console.log(error);
});
}
</script>
<style scoped lang="less">
.cashier {
font-family: 'Microsoft YaHei', '微软雅黑', sans-serif;
font-family: "Microsoft YaHei", "微软雅黑", sans-serif;
width: 100%;
height: 100vh;
background-color: #f5f5f5;
@@ -170,8 +232,11 @@ function init() {
height: 68.5%;
font-weight: 600;
background-color: #ffffff;
padding: 0.9375rem 0.625rem;
padding: 0.9375rem 1.625rem;
position: relative;
h2 {
margin-bottom: 1.25rem;
}
.payGoupList {
width: 100%;
overflow: scroll;
@@ -229,6 +294,63 @@ function init() {
line-height: 3.25rem;
border-radius: 0.625rem;
}
.noSelect {
background-color: #ccc;
}
}
/* loading */
.loadingMask {
position: fixed;
width: 100%;
height: 100%;
margin: 0 auto;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 99;
border-radius: 0 0 0.2rem 0.2rem;
.content {
position: absolute;
width: 15rem;
background: #ffffff;
border-radius: 0.2rem;
box-shadow: 0px 12px 48px 16px rgba(0, 0, 0, 0.03), 0px 9px 28px 0px rgba(0, 0, 0, 0.05),
0px 6px 16px -8px rgba(0, 0, 0, 0.08);
display: flex;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
flex-direction: column;
align-items: center;
}
.loadingImg {
width: 1.6rem;
height: 1.6rem;
margin-top: 2rem;
animation: 1.6s linear ratate infinite;
}
.loadingTxt {
font-size: 1.125rem;
color: #22242e;
margin-top: 1.2rem;
margin-bottom: 2rem;
}
@keyframes ratate {
0% {
transform: rotate(0deg);
}
40% {
transform: rotate(144deg);
}
80% {
transform: rotate(288deg);
}
100% {
transform: rotate(360deg);
}
}
}
}
</style>

View File

@@ -0,0 +1,76 @@
<template>
<div class="payExcess">
<div class="payLogo">
<img src="@/assets/images/fail1.png" alt="">
<p>支付失败</p>
<span>{{errorMsg?errorMsg:"订单超时自动关闭,请重新发起支付"}}</span>
</div>
<div class="payBtnBox" @click="closeClick">
关闭
</div>
</div>
</template>
<script setup lang="ts">
import { useRoute, useRouter } from "vue-router";
//获取路由参数
const route=useRoute()
const { msg: errorMsg} = route.params;
//点击关闭
const closeClick=()=>{
window.close()
}
</script>
<style scoped lang="less">
.payExcess {
padding: 3.5rem 0rem;
width: 100%;
height: 100vh;
background-color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 3rem;
position: relative;
.payLogo {
display: flex;
flex-direction: column;
gap: 1.25rem;
align-items: center;
transform: translateY(-50%);
img {
width: 3.125rem;
height: 3.125rem;
}
p {
font-size: 1.5rem;
color: #e74e4e;
font-weight: 700;
}
span {
letter-spacing: 2px;
font-size: 0.875rem;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
}
}
.payBtnBox {
width: 90%;
margin: 0 auto;
background-color: #e74e4e;
color: #fff;
height: 3.25rem;
position: absolute;
bottom: 3.75rem;
text-align: center;
line-height: 3.25rem;
border-radius: 0.625rem;
}
}
</style>

View File

@@ -1,32 +1,22 @@
<template>
<div class="payFail">
<div class="payLogo">
<img src="@/assets/images/fail1.png" alt="">
<img src="@/assets/images/fail1.png" alt="" />
<p>支付失败</p>
<span>订单超时自动关闭请重新发起支付</span>
</div>
<div class="payPrice">
<span class="unit"></span>
<div class="price">
793.21
</div>
<div class="price">793.21</div>
</div>
<div class="payMessBox">
<div class="payMessItem">
<div class="itemTitle">
支付标题
</div>
<div class="itemContent">
商业版 1288 预购版
</div>
<div class="itemTitle">支付标题</div>
<div class="itemContent">商业版 1288 预购版</div>
</div>
<div class="payMessItem">
<div class="itemTitle">
订单编号
</div>
<div class="itemContent">
20708483506
</div>
<div class="itemTitle">订单编号</div>
<div class="itemContent">20708483506</div>
</div>
</div>
@@ -36,7 +26,9 @@
</div>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { useRoute, useRouter } from "vue-router";
</script>
<style scoped lang="less">
.payFail {
@@ -64,19 +56,22 @@
font-weight: 700;
}
span{
font-size:.75rem;
letter-spacing: 2px;
font-size: 0.875rem;
font-size: .875rem;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
}
}
.payPrice{
display: flex;
gap: 0.315rem;
gap: .315rem;
align-items: center;
.unit{
font-size: 0.75rem;
transform: translateY(0.525rem);
font-size:.75rem;
transform: translateY(.525rem);
}
.price{
font-size:2rem;
@@ -85,10 +80,10 @@
}
.payMessBox{
width: 100%;
padding: 0 1.25rem;
padding: 0px 1.25rem;
display: flex;
flex-direction: column;
gap: 0.625rem;
gap: .625rem;
.payMessItem{
width: 100%;
display: flex;
@@ -100,6 +95,7 @@
.itemContent{
font-size:1rem;
font-weight: 500;
font-size: "微软雅黑";
}
}
}
@@ -113,7 +109,10 @@
bottom:3.75rem;
text-align: center;
line-height: 3.25rem;
border-radius: 0.625rem;
border-radius:.625rem;
}
}
</style>