diff --git a/src/pages/base/xk/components/XkPayXkqd/index.vue b/src/pages/base/xk/components/XkPayXkqd/index.vue index 801e9a9..a2aceb3 100644 --- a/src/pages/base/xk/components/XkPayXkqd/index.vue +++ b/src/pages/base/xk/components/XkPayXkqd/index.vue @@ -12,11 +12,11 @@ mode="aspectFill" > - {{ xkqd.xkmc }} - 开课老师:{{ xkqd.jsxm }} + {{ xkqd.xkmc || xkqd.kcmc }} + 开课老师:{{ xkqd.jsxm || xkqd.jsName }} 上课地点:{{ xkqd.kcdd }} 金额:¥{{ xkqd.jfje }}金额:¥{{ xkqd.kcje || xkqd.jfje }} @@ -27,10 +27,10 @@ diff --git a/src/pages/base/xk/components/XkPicker/index.vue b/src/pages/base/xk/components/XkPicker/index.vue index 3e573f9..7d471bf 100644 --- a/src/pages/base/xk/components/XkPicker/index.vue +++ b/src/pages/base/xk/components/XkPicker/index.vue @@ -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) { diff --git a/src/pages/base/xk/components/XkkcList/index.vue b/src/pages/base/xk/components/XkkcList/index.vue index d7955ef..d424c3e 100644 --- a/src/pages/base/xk/components/XkkcList/index.vue +++ b/src/pages/base/xk/components/XkkcList/index.vue @@ -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--; + selectedXkkcIds = selectedXkkcIds.filter( + (id: string) => id !== xkkc.id + ); } 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); @@ -142,12 +139,13 @@ const toggleSelection = (xkkc: any) => { const goToDetail = (xkkc: any) => { setKcData(xkkc); uni.navigateTo({ - url: `/pages/base/xk/detail`, + url: `/pages/base/xk/detail`, }); }; 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); } diff --git a/src/pages/base/xk/pay/index.vue b/src/pages/base/xk/pay/index.vue index 1b25413..733675d 100644 --- a/src/pages/base/xk/pay/index.vue +++ b/src/pages/base/xk/pay/index.vue @@ -30,9 +30,11 @@ - 取消报名 - - {{ isSubmitting ? '支付中...' : '立即支付' }} + + 取消报名 + + + {{ isPaySubmitting ? '支付中...' : '立即支付' }} @@ -42,37 +44,29 @@ @@ -303,7 +343,15 @@ 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; + } } } - + \ No newline at end of file diff --git a/src/pages/base/xk/qk/jlb.vue b/src/pages/base/xk/qk/jlb.vue index 34548b4..94ecb7e 100644 --- a/src/pages/base/xk/qk/jlb.vue +++ b/src/pages/base/xk/qk/jlb.vue @@ -18,7 +18,7 @@ - + diff --git a/src/pages/base/xk/qk/xqk.vue b/src/pages/base/xk/qk/xqk.vue index 755fe30..6b5f43a 100644 --- a/src/pages/base/xk/qk/xqk.vue +++ b/src/pages/base/xk/qk/xqk.vue @@ -18,7 +18,7 @@ - + diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index c6ad6db..3078852 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -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({}); diff --git a/src/utils/debounce.ts b/src/utils/debounce.ts new file mode 100644 index 0000000..c3a2905 --- /dev/null +++ b/src/utils/debounce.ts @@ -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 = 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 = Promise>( + func: T + ): ((...args: Parameters) => Promise | void>) => { + return async (...args: Parameters): Promise | 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 + }; +} \ No newline at end of file diff --git a/src/utils/pageUtil.ts b/src/utils/pageUtil.ts index 4b29735..6e3ded9 100644 --- a/src/utils/pageUtil.ts +++ b/src/utils/pageUtil.ts @@ -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({