1、调整websocket的初始化

2、完善支付的倒计时
This commit is contained in:
ywyonui 2025-07-21 14:34:20 +08:00
parent 47bf0977cc
commit ee7de58ba4
5 changed files with 293 additions and 109 deletions

View File

@ -101,6 +101,12 @@ export const xsKscjApi = async (params: any) => {
export const jzXkQkjApi = async (params: any) => {
return await post("/mobile/jz/xk/qk", params);
};
/**
*
*/
export const jzGetQkExpiredTime = async (params: any) => {
return await get("/mobile/jz/xk/getQkExpiredTime", params);
};
/**
*
*/

View File

@ -52,7 +52,7 @@
{ active: zc.djz === curZc.djz },
]" @click="selectWeek(zc)">
<text>{{ zc.mc }}</text>
<text v-if="zc.djz === curZc.djz" class="current-tag">当前周</text>
<text v-if="zc.dnDjz === dnDjz" class="current-tag">当前周</text>
</view>
</scroll-view>
</view>
@ -63,16 +63,27 @@
<script lang="ts" setup>
import { ref, reactive, computed, onMounted, nextTick } from "vue";
import { dqpkApi, drpkkbApi, gzlGetDqXqAndZcApi } from "@/api/base/server";
import { dqpkApi, drpkkbApi } from "@/api/base/server";
import { useUserStore } from "@/store/modules/user";
const { getCurXs } = useUserStore();
import dayjs from "dayjs";
import "dayjs/locale/zh-cn";
import weekOfYear from "dayjs/plugin/weekOfYear";
import isoWeek from "dayjs/plugin/isoWeek";
dayjs.locale("zh-cn");
dayjs.extend(weekOfYear);
dayjs.extend(isoWeek);
let dqZc = 0;
let xqId = '';
//
//
const dnDjz = ref(dayjs().isoWeek());
//
const curZc = ref<any>({});
//
//
const curRqIndex = ref(0)
//
const zcList = ref<any>([])

View File

@ -1,17 +1,40 @@
<template>
<view class="wh-full">
<web-view :src="payUrl"></web-view>
<view class="payment-page">
<!-- 倒计时区域 -->
<view class="countdown-section">
<view class="countdown-icon">
<u-icon name="clock" size="22" color="#fff"></u-icon>
</view>
<view class="countdown-text">待支付</view>
<view class="countdown-timer">
<text>剩余</text>
<text class="time-value">{{ countdownTime }}</text>
</view>
</view>
<view class="scrollable-content">
<web-view :src="payUrl" style="flex: 1;"></web-view>
</view>
<!-- 底部支付区域 -->
<view class="payment-footer">
<view class="action-buttons">
<view class="cancel-btn" @click="cancelRegistration">取消报名</view>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { onLoad } from "@dcloudio/uni-app";
import { useWebSocket } from '@/utils/webSocket/webSocket'
import { jzGetQkExpiredTime, jzXkCancelApi } from "@/api/base/server";
import { useUserStore } from "@/store/modules/user";
const { getUser } = useUserStore();
import { useDataStore } from "@/store/modules/data";
const { getCurXs, getUser, setWsCallback } = useUserStore();
const { getData } = useDataStore();
const payUrl = ref("");
const ws = useWebSocket(`/zhxy/webSocket/${getUser.userId}`, (type: string, res: any) => {
setWsCallback((type: string, res: any) => {
console.log('收到WebSocket消息:', type, res.data);
// data
const dataObj = JSON.parse(res.data);
@ -20,7 +43,7 @@ const ws = useWebSocket(`/zhxy/webSocket/${getUser.userId}`, (type: string, res:
title: '支付成功',
icon: 'success',
});
ws.closeConnect();
setWsCallback((type: string, res: any) => {})
//
setTimeout(() => {
uni.reLaunch({
@ -29,10 +52,70 @@ const ws = useWebSocket(`/zhxy/webSocket/${getUser.userId}`, (type: string, res:
}, 1000)
}
});
onLoad((options: any) => {
//
const countdownTime = ref("1分20秒");
let timer: any = null;
let seconds = 1 * 60 + 20; // 120
//
const startCountdown = () => {
timer = setInterval(() => {
seconds--;
if (seconds <= 0) {
clearInterval(timer);
uni.showModal({
title: "支付超时",
content: "支付已超时,请重新选课",
showCancel: false,
success: () => {
cancelRegistration();
},
});
return;
}
const minutes = Math.floor(seconds / 60);
const remainSeconds = seconds % 60;
countdownTime.value = `${minutes}${remainSeconds}`;
}, 1000);
};
//
const goBack = () => {
uni.reLaunch({
url: getData.backUrl
});
};
//
const cancelRegistration = () => {
uni.showModal({
title: "取消报名",
content: "确定要取消报名吗?",
success: async (res) => {
if (res.confirm) {
await jzXkCancelApi({
xsId: getData.xsId,
xkId: getData.xkId
});
uni.showToast({
title: "已取消报名",
icon: "success",
});
goBack();
}
},
});
};
onLoad(async (options: any) => {
if (options.payUrl) {
payUrl.value = decodeURIComponent(options.payUrl);
ws.reconnect();
const res = await jzGetQkExpiredTime({ xsId: getCurXs.id} );
seconds = res.result;
startCountdown();
} else {
uni.showToast({ title: '缺少支付地址', icon: 'none' })
setTimeout(() => {
@ -42,8 +125,92 @@ onLoad((options: any) => {
});
onBeforeUnmount(() => {
ws.closeConnect();
if (timer) {
clearInterval(timer);
}
});
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.payment-page {
min-height: 100%;
background-color: #f5f7fa;
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
//
.scrollable-content {
flex: 1;
display: flex;
position: relative;
}
.countdown-section {
display: flex;
align-items: center;
padding: 15px;
background-color: #2879ff;
.countdown-icon {
margin-right: 10px;
}
.countdown-text {
font-size: 16px;
font-weight: 500;
color: #fff;
margin-right: auto;
}
.countdown-timer {
font-size: 15px;
color: #fff;
.time-value {
color: #ff4d4f;
font-weight: 500;
}
}
}
.payment-footer {
position: sticky;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
padding: 15px;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
.total-amount {
display: flex;
align-items: center;
margin-bottom: 15px;
font-size: 15px;
color: #333;
.amount-value {
color: #ff6b00;
font-size: 20px;
font-weight: 500;
}
}
.action-buttons {
.cancel-btn {
height: 44px;
line-height: 44px;
text-align: center;
border-radius: 22px;
font-size: 16px;
background-color: #fff;
color: #333;
border: 1px solid #ddd;
}
}
}
</style>

View File

@ -6,11 +6,13 @@
<u-icon name="clock" size="22" color="#fff"></u-icon>
</view>
<view class="countdown-text">待支付</view>
<!-- <view class="countdown-timer">
<view class="countdown-timer">
<text>剩余</text>
<text class="time-value">{{ countdownTime }}</text>
</view> -->
</view>
</view>
<view class="scrollable-content">
<!-- 学生信息卡片 -->
<XkPayXs />
@ -18,6 +20,8 @@
<!-- 课程信息卡片 -->
<XkPayXkqd />
</view>
<!-- 底部支付区域 -->
<view class="payment-footer">
<view class="total-amount">
@ -36,7 +40,7 @@
<script setup lang="ts">
import XkPayXs from "@/pages/base/components/XkPayXs/index.vue"
import XkPayXkqd from "@/pages/base/components/XkPayXkqd/index.vue"
import { jzXkCancelApi, jzXkFqJfjApi } from "@/api/base/server";
import { jzGetQkExpiredTime, jzXkCancelApi, jzXkFqJfjApi } from "@/api/base/server";
import { useUserStore } from "@/store/modules/user";
import { useDataStore } from "@/store/modules/data";
const { getCurXs, getUser } = useUserStore();
@ -60,32 +64,32 @@ const totalJe = computed(() => {
});
//
// const countdownTime = ref("120");
// let timer: any = null;
// let seconds = 1 * 60 + 20; // 120
const countdownTime = ref("1分20秒");
let timer: any = null;
let seconds = 1 * 60 + 20; // 120
//
// const startCountdown = () => {
// timer = setInterval(() => {
// seconds--;
// if (seconds <= 0) {
// clearInterval(timer);
// uni.showModal({
// title: "",
// content: "",
// showCancel: false,
// success: () => {
// goBack();
// },
// });
// return;
// }
const startCountdown = () => {
timer = setInterval(() => {
seconds--;
if (seconds <= 0) {
clearInterval(timer);
uni.showModal({
title: "支付超时",
content: "支付已超时,请重新选课",
showCancel: false,
success: () => {
cancelRegistration();
},
});
return;
}
// const minutes = Math.floor(seconds / 60);
// const remainSeconds = seconds % 60;
// countdownTime.value = `${minutes}${remainSeconds}`;
// }, 1000);
// };
const minutes = Math.floor(seconds / 60);
const remainSeconds = seconds % 60;
countdownTime.value = `${minutes}${remainSeconds}`;
}, 1000);
};
//
const goBack = () => {
@ -117,6 +121,7 @@ const cancelRegistration = () => {
//
const payNow = async () => {
try {
const res = await jzXkFqJfjApi({
xsId: getData.xsId,
xkId: getData.xkId,
@ -125,41 +130,31 @@ const payNow = async () => {
userId: getUser.userId,
openId: getUser.openId,
});
// const res = {
// resultCode: 1,
// result: "https://pay.weixin.qq.com/wxpay/pay.action?prepay_id=wx20191018103005f5c0c0f5c0c"
// }
if (res.resultCode === 1 && res.result) {
uni.redirectTo({
url: `/pages/base/course-selection/pay-wait?payUrl=${encodeURIComponent(res.result)}`
});
}
// uni.showLoading({
// title: "...",
// });
// //
// setTimeout(() => {
// uni.hideLoading();
// uni.redirectTo({
// url: "/pages/base/course-selection/payment-success",
// });
// // uni.redirectTo({
// // url: "/pages/base/course-selection/payment-fail",
// // });
// }, 2000);
} catch (error) {
console.log(error);
const url = "https://www.baidu.com";
uni.redirectTo({
url: `/pages/base/course-selection/pay-wait?payUrl=${encodeURIComponent(url)}`
});
}
};
onMounted(() => {
// startCountdown();
onMounted(async() => {
const res = await jzGetQkExpiredTime({ xsId: getCurXs.id} );
console.log('获取倒计时', res);
seconds = res.result;
startCountdown();
});
onUnmounted(() => {
// if (timer) {
// clearInterval(timer);
// }
if (timer) {
clearInterval(timer);
}
});
</script>
@ -167,34 +162,17 @@ onUnmounted(() => {
.payment-page {
min-height: 100%;
background-color: #f5f7fa;
}
.nav-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 15px;
height: 44px;
background-color: #2879ff;
.nav-left {
width: 40px;
height: 40px;
display: flex;
align-items: center;
flex-direction: column;
height: 100%;
overflow: hidden;
}
.nav-title {
font-size: 18px;
font-weight: 500;
color: #fff;
}
.nav-right {
width: 40px;
display: flex;
justify-content: flex-end;
}
//
.scrollable-content {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch; // iOS
}
.countdown-section {
@ -226,10 +204,10 @@ onUnmounted(() => {
}
.payment-footer {
position: fixed;
position: sticky;
bottom: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
padding: 15px;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);

View File

@ -2,12 +2,15 @@ import { defineStore } from "pinia";
import { authenticationApi, loginCode, loginPass, weChatLogin } from "@/api/system/login";
import { AUTH_KEY } from "@/config";
import { imagUrl } from "@/utils";
import { useWebSocket } from '@/utils/webSocket/webSocket'
interface UserState {
userdata: any;
curXs: any;
token: string;
auth: string[]
auth: string[],
ws: any,
wsCallback: any
}
export const useUserStore = defineStore({
@ -20,7 +23,9 @@ export const useUserStore = defineStore({
// token
token: '',
//用户注册信息
auth: []
auth: [],
ws: null,
wsCallback: (type: string, res: any) => {}
}),
getters: {
getToken(): string {
@ -49,6 +54,9 @@ export const useUserStore = defineStore({
setAuth(data: string[]) {
this.auth = data;
},
setWsCallback(callback: any) {
this.wsCallback = callback;
},
/**
* @description:
*/
@ -99,6 +107,15 @@ export const useUserStore = defineStore({
if (value[AUTH_KEY]) {
this.setToken(value[AUTH_KEY])
}
if (!this.ws) {
this.ws = useWebSocket(`/zhxy/webSocket/${value.userId}`, (type: string, res: any) => {
// 判断this.wsCallback是函数调用
if (typeof this.wsCallback === "function") {
this.wsCallback(type, res);
}
});
this.ws.reconnect();
}
authenticationApi({ userId: value.userId }).then(({ result }) => {
if (result) {
this.setAuth(result)
@ -113,6 +130,11 @@ export const useUserStore = defineStore({
this.setUser('')
this.setCurXs({})
this.setAuth([])
if (this.ws) {
this.ws.closeConnect();
this.ws = null;
}
this.wsCallback((type: string, res: any) => {});
},
},
persist: {