完善抢课和取消选课
This commit is contained in:
parent
542f7878bb
commit
717f32cdf3
@ -12,11 +12,11 @@
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
<view class="course-details">
|
||||
<view class="course-name">{{ xkqd.xkmc }}</view>
|
||||
<view class="course-teacher">开课老师:{{ xkqd.jsxm }}</view>
|
||||
<view class="course-name">{{ xkqd.xkmc || xkqd.kcmc }}</view>
|
||||
<view class="course-teacher">开课老师:{{ xkqd.jsxm || xkqd.jsName }}</view>
|
||||
<view class="course-location">上课地点:{{ xkqd.kcdd }}</view>
|
||||
<view class="course-price"
|
||||
>金额:<text class="price-value">¥{{ xkqd.jfje }}</text></view
|
||||
>金额:<text class="price-value">¥{{ xkqd.kcje || xkqd.jfje }}</text></view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
@ -27,10 +27,10 @@
|
||||
<script setup lang="ts">
|
||||
import { imagUrl } from "@/utils";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
const { getData } = useDataStore();
|
||||
const { getQk } = useDataStore();
|
||||
|
||||
// 课程信息
|
||||
const xkqdList = computed(() => getData.xkqdList);
|
||||
const xkqdList = computed(() => getQk.xkqdList);
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@ -105,7 +105,8 @@ const loadXkList = async () => {
|
||||
} else {
|
||||
const qk = getQk || {};
|
||||
if (props.xsId === qk.xsId && qk.xklxId === props.xklxId && qk.xsXkStatus === "KQK") {
|
||||
|
||||
xkList.value = qk.xkList || [];
|
||||
switchXk(xkList.value[0]);
|
||||
} else {
|
||||
const res = await getXsXkListApi(params);
|
||||
if (res.resultCode === 1) {
|
||||
|
||||
@ -53,11 +53,9 @@ const { setKcData } = useDataStore();
|
||||
const props = withDefaults(defineProps<{
|
||||
xk: any,
|
||||
canSelected: boolean,
|
||||
multiple: boolean,
|
||||
}>(), {
|
||||
xk: () => ({}),
|
||||
canSelected: false,
|
||||
multiple: false,
|
||||
});
|
||||
|
||||
// 定义一个上级传入的emit响应事件用于接收数据变更
|
||||
@ -75,16 +73,9 @@ const toggleSelection = (xkkc: any) => {
|
||||
let selectedXkkcIds = uni.getStorageSync("selectedXkkcIds") || [];
|
||||
if (xkkc.isSelected) {
|
||||
xkkc.isSelected = false;
|
||||
if (props.multiple) {
|
||||
// 如果是多选,则从已选数组中移除
|
||||
selectedXkkcIds = selectedXkkcIds.filter(
|
||||
(id: string) => id !== xkkc.id
|
||||
);
|
||||
} else {
|
||||
// 如果是单选,则清空已选数组
|
||||
selectedXkkcIds = [];
|
||||
}
|
||||
// xkkc.hasNum--;
|
||||
} else {
|
||||
// 选择课程时的验证逻辑
|
||||
const maxNum = xkkc.maxNum || 0;
|
||||
@ -98,9 +89,8 @@ const toggleSelection = (xkkc: any) => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查上课时间是否重复
|
||||
if (xkkc.studyTime && props.multiple) {
|
||||
if (xkkc.studyTime && props.xk.kxNum > 1) {
|
||||
const hasTimeConflict = xkkcList.value.some((item: any) => {
|
||||
// 检查已选课程中是否有相同上课时间
|
||||
return item.isSelected &&
|
||||
@ -117,9 +107,16 @@ const toggleSelection = (xkkc: any) => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 通过验证,可以选课
|
||||
if (props.multiple) {
|
||||
// 判断判断数量,如果是多选,需要再次判断一个逻辑
|
||||
if (props.xk.kxNum > 1) {
|
||||
if (selectedXkkcIds.length >= props.xk.kxNum) {
|
||||
uni.showToast({
|
||||
title: '已选课程数量已达上限!请取消其他课程再选择!',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 如果是多选,则添加到已选数组
|
||||
if (!selectedXkkcIds.includes(xkkc.id)) {
|
||||
selectedXkkcIds.push(xkkc.id);
|
||||
@ -147,7 +144,8 @@ const goToDetail = (xkkc: any) => {
|
||||
};
|
||||
|
||||
const switchXk = (xk: any) => {
|
||||
xkkcList.value = xk.xkkcs;
|
||||
xkkcList.value = xk.xkkcs || xk.xkkcList || [];
|
||||
console.log('switchXk', xk)
|
||||
|
||||
// 对课程列表进行排序:先按课程名称,再按课程名称中的序号,最后按上课时间
|
||||
xkkcList.value.sort((a: any, b: any) => {
|
||||
@ -217,13 +215,13 @@ const switchXk = (xk: any) => {
|
||||
|
||||
// 监听当前学生信息变更
|
||||
watch(() => props.xk, (newVal) => {
|
||||
if (newVal && newVal.xkkcs) {
|
||||
if (newVal && (newVal.xkkcs || newVal.xkkcList)) {
|
||||
switchXk(newVal);
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化
|
||||
if (props.xk && props.xk.xkkcs) {
|
||||
if (props.xk && (props.xk.xkkcs || props.xk.xkkcList)) {
|
||||
switchXk(props.xk);
|
||||
}
|
||||
|
||||
|
||||
@ -30,9 +30,11 @@
|
||||
</view>
|
||||
|
||||
<view class="action-buttons">
|
||||
<view class="cancel-btn" @click="cancelRegistration">取消报名</view>
|
||||
<view class="pay-btn" :class="{ 'pay-btn--disabled': isSubmitting }" @click="payNow">
|
||||
{{ isSubmitting ? '支付中...' : '立即支付' }}
|
||||
<view class="cancel-btn" @click="cancelRegistration">
|
||||
取消报名
|
||||
</view>
|
||||
<view class="pay-btn" :class="{ 'pay-btn--disabled': isPaySubmitting }" @click="payNow">
|
||||
{{ isPaySubmitting ? '支付中...' : '立即支付' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -42,37 +44,29 @@
|
||||
<script setup lang="ts">
|
||||
import XkPayXs from "@/pages/base/xk/components/XkPayXs/index.vue"
|
||||
import XkPayXkqd from "@/pages/base/xk/components/XkPayXkqd/index.vue"
|
||||
import { jzGetQkExpiredTime, jzXkCancelApi, jzXkFqJfjApi } from "@/api/base/xkApi";
|
||||
import { jzXkCancelApi, jzXkFqJfjApi } from "@/api/base/xkApi";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
const { getCurXs, getUser } = useUserStore();
|
||||
const { getData, setData } = useDataStore();
|
||||
import { useDebounce } from "@/utils/debounce";
|
||||
import { PageUtils } from "@/utils/pageUtil";
|
||||
const { getUser, setWsCallback } = useUserStore();
|
||||
const { getQk } = useDataStore();
|
||||
|
||||
// 学生信息
|
||||
const curXs = computed(() => getCurXs);
|
||||
// 课程信息
|
||||
const xkqdList = computed(() => getData.xkqdList);
|
||||
// 为支付按钮创建防抖函数和状态
|
||||
const { isProcessing: isPaySubmitting, debounce: payDebounce } = useDebounce(2000);
|
||||
|
||||
// 为取消报名按钮创建防抖函数和状态
|
||||
const { isProcessing: isCancelSubmitting, debounce: cancelDebounce } = useDebounce(2000);
|
||||
|
||||
const qk = ref<any>({});
|
||||
// 总金额
|
||||
const totalJe = computed(() => {
|
||||
// 循环xkqdList.value 求和
|
||||
if (!xkqdList.value || !xkqdList.value.length) {
|
||||
return 0;
|
||||
}
|
||||
let total = 0;
|
||||
for (let i = 0; i < xkqdList.value.length; i++) {
|
||||
total += xkqdList.value[i].jfje;
|
||||
}
|
||||
return total;
|
||||
});
|
||||
const totalJe = ref(0);
|
||||
|
||||
// 倒计时
|
||||
const countdownTime = ref("1分20秒");
|
||||
const countdownTime = ref("");
|
||||
let timer: any = null;
|
||||
let seconds = 1 * 60 + 20; // 1分20秒
|
||||
|
||||
// 防止重复提交状态
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
// 支付页面跳转函数
|
||||
const openPaymentPage = (payUrl: string) => {
|
||||
console.log('开始打开支付页面:', payUrl);
|
||||
@ -151,10 +145,14 @@ const startCountdown = () => {
|
||||
seconds--;
|
||||
if (seconds <= 0) {
|
||||
clearInterval(timer);
|
||||
try {
|
||||
jzXkCancelApi({
|
||||
xsId: getData.xsId,
|
||||
xkId: getData.xkId
|
||||
xsId: qk.value.xsId,
|
||||
xkId: qk.value.xkId
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
uni.showModal({
|
||||
title: "支付超时",
|
||||
content: "支付已超时,请重新选课",
|
||||
@ -165,7 +163,6 @@ const startCountdown = () => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const remainSeconds = seconds % 60;
|
||||
countdownTime.value = `${minutes}分${remainSeconds}秒`;
|
||||
@ -184,35 +181,33 @@ const cancelRegistration = () => {
|
||||
uni.showModal({
|
||||
title: "取消报名",
|
||||
content: "确定要取消报名吗?",
|
||||
success: async (res) => {
|
||||
success: cancelDebounce(async (res) => {
|
||||
if (res.confirm) {
|
||||
await jzXkCancelApi({
|
||||
xsId: getData.xsId,
|
||||
xkId: getData.xkId
|
||||
});
|
||||
uni.showToast({
|
||||
title: "已取消报名",
|
||||
icon: "success",
|
||||
try {
|
||||
const res = await jzXkCancelApi({
|
||||
xsId: qk.value.xsId,
|
||||
xkId: qk.value.xkId
|
||||
});
|
||||
if (res.resultCode === 1) {
|
||||
uni.showLoading({ title: "取消报名中,请稍后..." });
|
||||
} else {
|
||||
uni.showToast({ title: res.message, icon: "none" });
|
||||
goBack();
|
||||
}
|
||||
},
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
// 立即支付
|
||||
const payNow = async () => {
|
||||
// 防止重复点击
|
||||
if (isSubmitting.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const payNow = payDebounce(async () => {
|
||||
try {
|
||||
isSubmitting.value = true;
|
||||
|
||||
const res = await jzXkFqJfjApi({
|
||||
xsId: getData.xsId,
|
||||
xkId: getData.xkId,
|
||||
xsId: qk.value.xsId,
|
||||
xkId: qk.value.xkId,
|
||||
jffs: "线上缴费", // 线上,线下,无需缴费
|
||||
zfptLx: "四川农信", // TODO: 目前只支持四川农信
|
||||
jzId: getUser.jzId,
|
||||
@ -224,43 +219,51 @@ const payNow = async () => {
|
||||
const payUrl = res.result.cashierPayHtml;
|
||||
|
||||
openPaymentPage(payUrl);
|
||||
|
||||
/* setData({
|
||||
...getData,
|
||||
...res.result
|
||||
});
|
||||
uni.redirectTo({
|
||||
url: `/pages/base/xk/pay/wait?payUrl=${encodeURIComponent(res.result.cashierPayHtml)}`
|
||||
});*/
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log(error);
|
||||
uni.showToast({
|
||||
title: error.message || "发起支付失败",
|
||||
icon: "error",
|
||||
duration: 2000,
|
||||
});
|
||||
// const url = "https://www.baidu.com";
|
||||
// uni.redirectTo({
|
||||
// url: `/pages/base/xk/pay/wait?payUrl=${encodeURIComponent(url)}`
|
||||
// });
|
||||
} finally {
|
||||
// 延迟重置状态,避免快速重复点击
|
||||
setTimeout(() => {
|
||||
isSubmitting.value = false;
|
||||
}, 2000);
|
||||
goBack();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
onMounted(async() => {
|
||||
try {
|
||||
const res = await jzGetQkExpiredTime({ xsId: getCurXs.id} );
|
||||
console.log('获取倒计时', res);
|
||||
seconds = res.result;
|
||||
qk.value = getQk || {};
|
||||
const xkqdList = qk.value.xkqdList || [];
|
||||
totalJe.value = 0;
|
||||
for (let i = 0; i < xkqdList.length; i++) {
|
||||
const xkqd = xkqdList[i];
|
||||
const je = xkqd.kcje || xkqd.jfje;
|
||||
totalJe.value += je;
|
||||
}
|
||||
const expireTime = qk.value.expireTime || new Date().getTime();
|
||||
seconds = Math.floor((expireTime - new Date().getTime()) / 1000);
|
||||
startCountdown();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
goBack();
|
||||
}
|
||||
// 设置回调处理
|
||||
setWsCallback((type: string, res: any) => {
|
||||
// 将data从字符串转为对象
|
||||
const dataObj = JSON.parse(res.data);
|
||||
if (dataObj.action === 'qk') {
|
||||
uni.hideLoading();
|
||||
if (dataObj.data === "cancel") {
|
||||
uni.showToast({
|
||||
title: dataObj.message || '取消成功',
|
||||
icon: "none",
|
||||
duration: 3000
|
||||
});
|
||||
goBack();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<!-- 第二行:学生选择和倒计时 -->
|
||||
<view class="bottom-row">
|
||||
<XsPicker :is-bar="true" @change="switchXs" />
|
||||
<XkCountdown :xk="curXk" @over="xkTimeOver" v-if="curXk && curXk.id" />
|
||||
<XkCountdown :xk="curXk" @over="xkTimeOver" v-if="curXk && (curXk.id || curXk.xkId)" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -18,15 +18,20 @@
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<!-- 显示课程列表 -->
|
||||
<XkkcList :xk="curXk" :can-selected="true" :multiple="curXk.kxNum > 1" @change="changeXkkc" />
|
||||
<XkkcList :xk="curXk" :can-selected="true" @change="changeXkkc" />
|
||||
</view>
|
||||
|
||||
<!-- 底部报名按钮 - 固定部分 -->
|
||||
<view class="register-btn-container" v-if="curXk && curXk.id">
|
||||
<view class="register-btn-container" v-if="curXk && (curXk.id || curXk.xkId)">
|
||||
<view class="selected-count-info" v-if="selectedXkkcIds && selectedXkkcIds.length > 0">
|
||||
已选 {{ selectedXkkcIds.length }} 门课程
|
||||
</view>
|
||||
<view class="register-btn" @click="submit">点击报名</view>
|
||||
<view
|
||||
class="register-btn"
|
||||
:class="{ 'register-btn--disabled': isSubmitting }"
|
||||
@click="submit">
|
||||
{{ isSubmitting ? '报名中...' : '点击报名' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@ -40,9 +45,12 @@ import XkkcList from "@/pages/base/xk/components/XkkcList/index.vue"
|
||||
import { jzXkQkjApi } from "@/api/base/xkApi";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { useDebounce } from "@/utils/debounce";
|
||||
import dayjs from "dayjs";
|
||||
import { PageUtils } from "@/utils/pageUtil";
|
||||
import { hideLoading } from "@/utils/uniapp";
|
||||
|
||||
const { getCurXs, getUser } = useUserStore();
|
||||
const { getCurXs, getUser, initWs, setWsCallback } = useUserStore();
|
||||
const { setData, getData } = useDataStore();
|
||||
const { sign_file } = getData;
|
||||
|
||||
@ -53,6 +61,9 @@ const curXs = computed(() => getCurXs);
|
||||
const curXk = ref<any>({});
|
||||
const selectedXkkcIds = ref<any>([]);
|
||||
|
||||
// 替换 isSubmitting 状态为 useDebounce
|
||||
const { isProcessing: isSubmitting, debounce } = useDebounce(2000);
|
||||
|
||||
const xsFlag = ref(true);
|
||||
|
||||
// 检查选课是否已结束
|
||||
@ -102,8 +113,15 @@ const changeXkkc = (ids: any) => {
|
||||
selectedXkkcIds.value = ids;
|
||||
}
|
||||
|
||||
// 回到首页
|
||||
const goBack = () => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/base/home/index'
|
||||
});
|
||||
}
|
||||
|
||||
// 提交选课
|
||||
const submit = async () => {
|
||||
const submit = debounce(async () => {
|
||||
// 判断是否已选课
|
||||
if (selectedXkkcIds.value.length === 0) {
|
||||
uni.showToast({
|
||||
@ -126,24 +144,18 @@ const submit = async () => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uni.showLoading({
|
||||
title: "抢课中...",
|
||||
});
|
||||
uni.showLoading({ title: "开始抢课..." });
|
||||
try {
|
||||
const params = {
|
||||
xsId: curXs.value.id,
|
||||
xm: curXs.value.xm,
|
||||
njmc: curXs.value.njmc,
|
||||
njmcId: curXs.value.njmcId,
|
||||
njId: curXs.value.njId,
|
||||
bc: (curXs.value.njbc || '') + (curXs.value.bjmc || ''),
|
||||
xkId: curXk.value.id,
|
||||
xkkcIds: selectedXkkcIds.value,
|
||||
jzId: getUser.jzId,
|
||||
qmFile: sign_file ? sign_file.value : "",
|
||||
};
|
||||
|
||||
const res = await jzXkQkjApi(params);
|
||||
uni.hideLoading();
|
||||
|
||||
if (res.resultCode === 1) {
|
||||
selectedXkkcIds.value = [];
|
||||
uni.setStorageSync("selectedXkkcIds", []);
|
||||
@ -152,24 +164,25 @@ const submit = async () => {
|
||||
setTimeout(() => {
|
||||
xsFlag.value = false;
|
||||
}, 1000);
|
||||
if (curXk.value.sfjf === 1) {
|
||||
// 跳转到支付页面
|
||||
uni.navigateTo({
|
||||
url: "/pages/base/xk/pay/index",
|
||||
});
|
||||
} else {
|
||||
// 不需要支付,直接跳转到支付成功页面
|
||||
uni.navigateTo({
|
||||
url: "/pages/base/xk/pay/success?xklxId=" + xklxId.value,
|
||||
});
|
||||
}
|
||||
hideLoading();
|
||||
// 提示已经加入抢课队列,抢课中,请稍后,然后一直转圈等待
|
||||
uni.showLoading({ title: "抢课中,请稍后..." });
|
||||
} else {
|
||||
hideLoading();
|
||||
uni.showToast({
|
||||
title: res.message,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
hideLoading();
|
||||
console.error('报名失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || "报名失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onLoad((options:any) => {
|
||||
xklxId.value = options.xklxId || '';
|
||||
@ -178,8 +191,35 @@ onLoad((options:any) => {
|
||||
case '816059832': { title.value = '俱乐部信息'; } break;
|
||||
default: {
|
||||
uni.reLaunch({ url: '/pages/base/home/index' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
initWs();
|
||||
// 设置回调处理
|
||||
setWsCallback((type: string, res: any) => {
|
||||
// 将data从字符串转为对象
|
||||
const dataObj = JSON.parse(res.data);
|
||||
if (dataObj.action === 'qk') {
|
||||
uni.hideLoading();
|
||||
if (dataObj.code === 1 && dataObj.data === "qk") {
|
||||
if (curXk.value.sfjf === 1) {
|
||||
PageUtils.toHome(xklxId.value);
|
||||
} else {
|
||||
// 不需要支付,直接跳转到支付成功页面
|
||||
uni.navigateTo({
|
||||
url: "/pages/base/xk/pay/success?xklxId=" + xklxId.value,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: dataObj.message,
|
||||
icon: "none",
|
||||
duration: 3000
|
||||
});
|
||||
goBack();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -303,6 +343,14 @@ onLoad((options:any) => {
|
||||
border-radius: 25px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
|
||||
// 添加禁用状态样式
|
||||
&.register-btn--disabled {
|
||||
background-color: #a0cfff;
|
||||
color: #ffffff;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<!-- 显示课程列表 -->
|
||||
<XkkcList :xk="curXk" :can-selected="true" :multiple="true" @change="changeXkkc" />
|
||||
<XkkcList :xk="curXk" :can-selected="true" @change="changeXkkc" />
|
||||
</view>
|
||||
|
||||
<!-- 底部报名按钮 - 固定部分 -->
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<!-- 显示课程列表 -->
|
||||
<XkkcList :xk="curXk" :can-selected="true" :multiple="false" @change="changeXkkc" />
|
||||
<XkkcList :xk="curXk" :can-selected="true" @change="changeXkkc" />
|
||||
</view>
|
||||
|
||||
<!-- 底部报名按钮 - 固定部分 -->
|
||||
|
||||
@ -106,19 +106,22 @@ export const useUserStore = defineStore({
|
||||
this.wsCallback = callback;
|
||||
},
|
||||
initWs() {
|
||||
if (this.ws) {
|
||||
if (typeof this.ws.closeConnect === 'function') {
|
||||
this.ws.closeConnect();
|
||||
}
|
||||
this.ws = null;
|
||||
}
|
||||
this.exitWs();
|
||||
this.ws = useWebSocket(`/zhxy/webSocket/${this.userdata.userId}`, (type: string, res: any) => {
|
||||
// 判断this.wsCallback是函数,调用
|
||||
if (typeof this.wsCallback === "function") {
|
||||
this.wsCallback(type, res);
|
||||
}
|
||||
});
|
||||
this.ws.reconnect();
|
||||
this.ws.reconnect(this.token);
|
||||
},
|
||||
exitWs() {
|
||||
if (this.ws) {
|
||||
if (typeof this.ws.closeConnect === 'function') {
|
||||
this.ws.closeConnect();
|
||||
}
|
||||
this.ws = null;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description: 验证码登录
|
||||
@ -218,10 +221,7 @@ export const useUserStore = defineStore({
|
||||
this.setCurXs({})
|
||||
this.setAuth([])
|
||||
this.setXsPickerInitialized(false); // 注销时重置学生选择器状态
|
||||
if (this.ws) {
|
||||
this.ws.closeConnect();
|
||||
this.ws = null;
|
||||
}
|
||||
this.exitWs();
|
||||
this.wsCallback = defWsCallback;
|
||||
useDicStore().setData({});
|
||||
useCommonStore().setData({});
|
||||
|
||||
107
src/utils/debounce.ts
Normal file
107
src/utils/debounce.ts
Normal file
@ -0,0 +1,107 @@
|
||||
// src/utils/debounce.ts
|
||||
import { ref } from 'vue';
|
||||
|
||||
/**
|
||||
* 通用防抖函数
|
||||
* @param func 需要防抖的函数
|
||||
* @param delay 延迟时间(毫秒)
|
||||
* @param immediate 是否立即执行
|
||||
* @returns 防抖后的函数
|
||||
*/
|
||||
export function debounce(func: Function, wait: number, immediate: boolean = false) {
|
||||
let timeout: NodeJS.Timeout | null;
|
||||
|
||||
return function (this: any, ...args: any[]) {
|
||||
const context = this;
|
||||
const later = function () {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
const callNow = immediate && !timeout;
|
||||
if (timeout) clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 防抖状态管理类
|
||||
* 用于管理多个防抖状态
|
||||
*/
|
||||
export class DebounceManager {
|
||||
private states: Map<string, boolean> = new Map();
|
||||
|
||||
/**
|
||||
* 设置防抖状态
|
||||
* @param key 状态标识
|
||||
* @param value 状态值
|
||||
* @param duration 状态持续时间(毫秒)
|
||||
*/
|
||||
setState(key: string, value: boolean, duration?: number): void {
|
||||
this.states.set(key, value);
|
||||
|
||||
if (value && duration) {
|
||||
setTimeout(() => {
|
||||
this.states.set(key, false);
|
||||
}, duration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取防抖状态
|
||||
* @param key 状态标识
|
||||
* @returns 状态值
|
||||
*/
|
||||
getState(key: string): boolean {
|
||||
return this.states.get(key) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置所有状态
|
||||
*/
|
||||
reset(): void {
|
||||
this.states.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vue组合式API防抖函数
|
||||
* @param delay 延迟时间(毫秒)
|
||||
* @returns 包含防抖状态和控制函数的对象
|
||||
*/
|
||||
export function useDebounce(delay: number = 1000) {
|
||||
const isProcessing = ref(false);
|
||||
|
||||
const debounce = <T extends (...args: any[]) => Promise<any>>(
|
||||
func: T
|
||||
): ((...args: Parameters<T>) => Promise<ReturnType<T> | void>) => {
|
||||
return async (...args: Parameters<T>): Promise<ReturnType<T> | void> => {
|
||||
// 如果正在处理中,则阻止新的调用
|
||||
if (isProcessing.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
isProcessing.value = true;
|
||||
|
||||
try {
|
||||
const result = await func(...args);
|
||||
return result;
|
||||
} finally {
|
||||
// 延迟重置状态,防止快速重复点击
|
||||
setTimeout(() => {
|
||||
isProcessing.value = false;
|
||||
}, delay);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
isProcessing.value = false;
|
||||
};
|
||||
|
||||
return {
|
||||
isProcessing,
|
||||
debounce,
|
||||
reset
|
||||
};
|
||||
}
|
||||
@ -14,7 +14,7 @@ export const PageUtils = {
|
||||
* 跳转逻辑
|
||||
* @param lxId 类型( JC: 就餐,816059832: 俱乐部,962488654: 兴趣课)
|
||||
*/
|
||||
async toHome(lxId: string) {
|
||||
async toHome(lxId?: string) {
|
||||
// 没有类型,则跳转首页
|
||||
if (!lxId) {
|
||||
uni.reLaunch({
|
||||
@ -84,13 +84,19 @@ export const PageUtils = {
|
||||
});
|
||||
} break;
|
||||
case 'QKZ': { // QKZ抢课中
|
||||
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/qk/index?xklxId=" + xklxId,
|
||||
});
|
||||
} break;
|
||||
case 'YQK': { // YQK已选课
|
||||
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/pay/index?xklxId=" + xklxId,
|
||||
});
|
||||
} break;
|
||||
case 'DZF': { // DZF待支付
|
||||
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/xk/pay/index?xklxId=" + xklxId,
|
||||
});
|
||||
} break;
|
||||
case 'YZF': { // YZF已支付
|
||||
uni.reLaunch({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user