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