diff --git a/src/api/system/login/index.ts b/src/api/system/login/index.ts index 704e17c..c6e7164 100644 --- a/src/api/system/login/index.ts +++ b/src/api/system/login/index.ts @@ -63,6 +63,14 @@ export const checkOpenId = async (param: { export const updateUserApi = async (param: any) => { return await post("/open/login/js/updateUser", param); }; + +export const updateSignFileApi = async (param: { userId: number; signFile: string }) => { + return await post("/api/user/updateSignFile", { + id: param.userId, + signFile: param.signFile + }); +}; + export const findJsByPhoneApi = async (param: any) => { return await get("/api/js/findJsByPhone", param); }; diff --git a/src/pages.json b/src/pages.json index dcc8157..100bf55 100644 --- a/src/pages.json +++ b/src/pages.json @@ -57,6 +57,15 @@ } } }, + { + "path": "pages/system/subscribe/index", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "关注服务号", + "enablePullDownRefresh": false, + "backgroundColor": "#f4f5f7" + } + }, { "path": "pages/system/webView/webView", "style": { @@ -242,6 +251,13 @@ "enablePullDownRefresh": false } }, + { + "path": "pages/base/course-selection/noticeclub", + "style": { + "navigationBarTitleText": "告知书", + "enablePullDownRefresh": false + } + }, { "path": "pages/base/course-selection/enrolled", "style": { @@ -254,6 +270,14 @@ "navigationBarTitleText": "未开放", "enablePullDownRefresh": false } + }, + { + "path": "pages/base/course-selection/enrollment-ended", + "style": { + "navigationBarTitleText": "选课已结束", + "enablePullDownRefresh": false, + "navigationStyle": "custom" + } } ], "globalStyle": { diff --git a/src/pages/base/components/XkCountdown/index.vue b/src/pages/base/components/XkCountdown/index.vue index 0ec2630..03f50a0 100644 --- a/src/pages/base/components/XkCountdown/index.vue +++ b/src/pages/base/components/XkCountdown/index.vue @@ -1,7 +1,6 @@ @@ -48,17 +58,20 @@ const countdownTime = reactive({ const kcStatus = ref(false); -// 倒计时标题文本 -const countdownTitle = computed(() => { - return kcStatus.value ? "距离选课结束还剩" : "距离选课开始还剩"; -}); - // 当前选中的学生 let countdownTimer: number | null = null; const remainTime = ref("00:00:00"); // 添加选课是否已结束的标记 const isEnrollmentEnded = ref(false); +// 添加选课是否已结束的标记(区分选课开始和选课结束) +const isCourseEnded = ref(false); + +// 格式化结束时间 +const formatEndTime = computed(() => { + if (!props.xk || !props.xk.xkjstime) return ''; + return dayjs(props.xk.xkjstime).format('YYYY-MM-DD'); +}); // 启动倒计时 const startCountdown = (endTimeStamp: number) => { @@ -82,26 +95,10 @@ const startCountdown = (endTimeStamp: number) => { countdownTimer = null; } - // 判断当前倒计时是选课开始还是选课结束 - if (!kcStatus.value) { - // 如果是选课开始倒计时结束,则切换到选课结束倒计时 - kcStatus.value = true; // 更新状态为选课已开始 - uni.showToast({ - title: "选课已开始", - icon: "none", - }); - // 开始选课结束倒计时 - const xkjstime = dayjs(props.xk.xkjstime).valueOf(); - startCountdown(xkjstime); - } else { - // 如果是选课结束倒计时结束 - isEnrollmentEnded.value = true; // 标记选课已结束 - emit("over"); - uni.showToast({ - title: "选课已结束", - icon: "none", - }); - } + // 选课开始倒计时结束 + isEnrollmentEnded.value = true; // 标记选课已开始,隐藏倒计时 + isCourseEnded.value = false; // 标记选课未结束 + emit("over"); return; } @@ -134,22 +131,29 @@ const changeXk = (xk: any) => { //获取选课结束时间 const xkjstime = dayjs(xk.xkjstime).valueOf(); - // 检查是否已经超过选课结束时间 - if (now > xkjstime) { - kcStatus.value = true; + // 如果当前时间 >= 选课结束时间,则显示选课已结束 + if (now >= xkjstime) { isEnrollmentEnded.value = true; + isCourseEnded.value = true; countdownTime.hours = "00"; countdownTime.minutes = "00"; countdownTime.seconds = "00"; + return; } - //判断选课是否开始 - else if (now < xkkstime) { - kcStatus.value = false; - startCountdown(xkkstime); - } else { - kcStatus.value = true; - startCountdown(xkjstime); + + // 如果当前时间 >= 选课开始时间 且 < 选课结束时间,显示报名提示 + if (now >= xkkstime && now < xkjstime) { + isEnrollmentEnded.value = true; + isCourseEnded.value = false; + countdownTime.hours = "00"; + countdownTime.minutes = "00"; + countdownTime.seconds = "00"; + return; } + + // 只有当前时间 < 选课开始时间时才显示倒计时 + kcStatus.value = false; + startCountdown(xkkstime); } // 页面卸载前清除定时器 @@ -174,38 +178,37 @@ if (props.xk && props.xk.id) { \ No newline at end of file diff --git a/src/pages/base/components/XkPicker/index.vue b/src/pages/base/components/XkPicker/index.vue index 94063ea..ad09b08 100644 --- a/src/pages/base/components/XkPicker/index.vue +++ b/src/pages/base/components/XkPicker/index.vue @@ -117,13 +117,6 @@ const loadXkList = async () => { const switchXk = (xk: any) => { curXk.value = xk; showFlag.value = false; - if (xk && xk.id) { - // 显示切换成功提示 - uni.showToast({ - title: `已切换到${xk.xkmc}`, - icon: "none", - }); - } emit("change", xk); } diff --git a/src/pages/base/components/XkkcList/index.vue b/src/pages/base/components/XkkcList/index.vue index 1ff678e..b9ab1d9 100644 --- a/src/pages/base/components/XkkcList/index.vue +++ b/src/pages/base/components/XkkcList/index.vue @@ -9,15 +9,17 @@ :class="{ selected: xkkc.isSelected }" @click="toggleSelection(xkkc)" > - {{ xkkc.kcmc }} + + {{ xkkc.kcmc }} + + + + 报名情况: {{ xkkc.hasNum || 0 }} | {{ xkkc.maxNum || 0 }} - 详情 { setCurXs(xs); showFlag.value = false; emit('change', xs); - // 这里可以添加切换学生后的其他操作,如刷新页面数据等 - uni.showToast({ - title: `已切换到${xs.xm}`, - icon: "none", - }); +} + +// 设置当前学生(无提示) +const setCurrentStudent = (xs: any) => { + setCurXs(xs); + emit('change', xs); } // 如果是bar形式,则默认打开选择器 -if (props.isBar -//&& (getCurXs === null || !getCurXs.id) -) { +if (props.isBar) { if (getUser.xsList.length > 1 ) { showPicker(); } else { - switchXs(getUser.xsList[0]); + // 只有一个学生时,直接设置但不显示提示 + setCurrentStudent(getUser.xsList[0]); } } diff --git a/src/pages/base/course-selection/club-selection.vue b/src/pages/base/course-selection/club-selection.vue index c9743bc..f074242 100644 --- a/src/pages/base/course-selection/club-selection.vue +++ b/src/pages/base/course-selection/club-selection.vue @@ -3,12 +3,15 @@ - - - - - - + + + + + + + + + @@ -35,6 +38,7 @@ import XkkcList from "@/pages/base/components/XkkcList/index.vue" import { jzXkQkjApi } from "@/api/base/server"; import { useUserStore } from "@/store/modules/user"; import { useDataStore } from "@/store/modules/data"; +import dayjs from "dayjs"; const { getCurXs, getUser } = useUserStore(); const { setData, getData } = useDataStore(); @@ -46,9 +50,31 @@ const selectedXkkcIds = ref([]); const xsFlag = ref(true); +// 检查选课是否已结束 +const checkEnrollmentStatus = (xk: any) => { + if (!xk || !xk.xkjstime) return; + + const now = new Date().getTime(); + const endTime = new Date(xk.xkjstime).getTime(); + + if (now > endTime) { + // 选课已结束,跳转到结束页面 + const courseInfo = encodeURIComponent(JSON.stringify(xk)); + uni.navigateTo({ + url: `/pages/base/course-selection/enrollment-ended?courseInfo=${courseInfo}` + }); + return true; + } + return false; +}; + // 切换选课 const switchXk = (xk: any) => { curXk.value = xk; + // 检查选课状态 + if (checkEnrollmentStatus(xk)) { + return; + } } const switchXs = (xs: any) => { @@ -57,7 +83,9 @@ const switchXs = (xs: any) => { // 选课时间结束 const xkTimeOver = (val: any) => { - console.log(val); + console.log('选课时间结束:', val); + // 选课开始时不再跳转,让用户继续选课 + // 只有在选课结束时才跳转到选课结束页面 } // 选中课程 @@ -75,6 +103,21 @@ const submit = async () => { }); return; } + + // 检查选课时间 + if (curXk.value && curXk.value.xkkstime) { + const now = dayjs().valueOf(); + const startTime = dayjs(curXk.value.xkkstime).valueOf(); + + if (now < startTime) { + uni.showToast({ + title: "选课还未开始,请耐心等待!", + icon: "none", + }); + return; + } + } + uni.showLoading({ title: "抢课中...", }); @@ -173,6 +216,36 @@ const submit = async () => { flex-direction: column; gap: 15px; + .top-row { + display: flex; + align-items: center; + + :deep(.title-section) { + width: 100%; + } + } + + .bottom-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 15px; + + // 学生选择器样式 + :deep(.xs-bar) { + flex: 1; + min-width: 0; + } + + // 倒计时组件样式 + :deep(.countdown-section) { + flex-shrink: 0; + background: rgba(255, 255, 255, 0.1); + border-radius: 6px; + padding: 6px 10px; + backdrop-filter: blur(10px); + } + } } } diff --git a/src/pages/base/course-selection/detail.vue b/src/pages/base/course-selection/detail.vue index 5895df4..2377bce 100644 --- a/src/pages/base/course-selection/detail.vue +++ b/src/pages/base/course-selection/detail.vue @@ -161,7 +161,7 @@ const courseDetail = computed(() => { location: data.kcdd || "暂无地点信息", price: data.kcje || 0, studyTime: data.studyTime || "暂无上课时间", - xkkcImg: data.xkkcImg || "/static/images/robot-course.jpg", // 默认图片 + xkkcImg: imagUrl(data.xkkcImg), // 使用imagUrl处理图片路径 }; }); diff --git a/src/pages/base/course-selection/enrollment-ended.vue b/src/pages/base/course-selection/enrollment-ended.vue new file mode 100644 index 0000000..9fd5088 --- /dev/null +++ b/src/pages/base/course-selection/enrollment-ended.vue @@ -0,0 +1,291 @@ + + + + + \ No newline at end of file diff --git a/src/pages/base/course-selection/index.vue b/src/pages/base/course-selection/index.vue index 32e04a8..1b4abaa 100644 --- a/src/pages/base/course-selection/index.vue +++ b/src/pages/base/course-selection/index.vue @@ -5,10 +5,11 @@ - - - - + + + + + @@ -35,6 +36,7 @@ import XkkcList from "@/pages/base/components/XkkcList/index.vue" import { jzXkQkjApi } from "@/api/base/server"; import { useUserStore } from "@/store/modules/user"; import { useDataStore } from "@/store/modules/data"; +import dayjs from "dayjs"; const { getCurXs, getUser } = useUserStore(); const { setData, getData } = useDataStore(); @@ -47,9 +49,31 @@ const selectedXkkcIds = ref([]); const xsFlag = ref(true); +// 检查选课是否已结束 +const checkEnrollmentStatus = (xk: any) => { + if (!xk || !xk.xkjstime) return; + + const now = new Date().getTime(); + const endTime = new Date(xk.xkjstime).getTime(); + + if (now > endTime) { + // 选课已结束,跳转到结束页面 + const courseInfo = encodeURIComponent(JSON.stringify(xk)); + uni.navigateTo({ + url: `/pages/base/course-selection/enrollment-ended?courseInfo=${courseInfo}` + }); + return true; + } + return false; +}; + // 切换选课 const switchXk = (xk: any) => { curXk.value = xk; + // 检查选课状态 + if (checkEnrollmentStatus(xk)) { + return; + } } // 切换学生 @@ -59,7 +83,12 @@ const switchXs = (xs: any) => { // 选课时间结束 const xkTimeOver = (val: any) => { - console.log(val); + console.log('选课时间结束:', val); + // 跳转到选课结束页面 + const courseInfo = encodeURIComponent(JSON.stringify(curXk.value)); + uni.navigateTo({ + url: `/pages/base/course-selection/enrollment-ended?courseInfo=${courseInfo}` + }); } // 选中课程 @@ -77,6 +106,21 @@ const submit = async () => { }); return; } + + // 检查选课时间 + if (curXk.value && curXk.value.xkkstime) { + const now = dayjs().valueOf(); + const startTime = dayjs(curXk.value.xkkstime).valueOf(); + + if (now < startTime) { + uni.showToast({ + title: "选课还未开始,请耐心等待!", + icon: "none", + }); + return; + } + } + uni.showLoading({ title: "抢课中...", }); @@ -174,6 +218,27 @@ const submit = async () => { flex-direction: column; gap: 15px; + .bottom-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 15px; + + // 学生选择器样式 + :deep(.xs-bar) { + flex: 1; + min-width: 0; + } + + // 倒计时组件样式 + :deep(.countdown-section) { + flex-shrink: 0; + background: rgba(255, 255, 255, 0.1); + border-radius: 6px; + padding: 6px 10px; + backdrop-filter: blur(10px); + } + } } } diff --git a/src/pages/base/course-selection/notice.vue b/src/pages/base/course-selection/notice.vue index 30632ab..4d4cfb4 100644 --- a/src/pages/base/course-selection/notice.vue +++ b/src/pages/base/course-selection/notice.vue @@ -25,14 +25,19 @@ + + diff --git a/src/pages/base/home/index.vue b/src/pages/base/home/index.vue index 716f418..ceae315 100644 --- a/src/pages/base/home/index.vue +++ b/src/pages/base/home/index.vue @@ -90,7 +90,7 @@ const { setData, getAppCode } = useDataStore(); // 刷新相关变量 const { getLastRefreshTime, getRefreshInterval, setLastRefreshTime, updateStudentInfo, updateStudentList } = useUserStore(); -const REFRESH_INTERVAL = 10 * 60 * 1000; // 10分钟刷新一次(测试用) +const REFRESH_INTERVAL = 7 * 24 * 60 * 60 * 1000; // 1周刷新一次(7天) // 获取当前changeTime const getCurrentChangeTime = () => { @@ -209,6 +209,18 @@ const menuItems = ref([ path: "/pages/base/club/index", permissionKey: "school-jlb", // 俱乐部权限编码 }, + { + title: "兴趣课选课", + icon: "/static/base/home/file-text-line.png", + path: "/pages/base/course-selection/notice", + permissionKey: "school-xqkxk", // 兴趣课选课权限编码 + }, + { + title: "俱乐部选课", + icon: "/static/base/home/contacts-book-3-line.png", + path: "/pages/base/course-selection/noticeclub", + permissionKey: "school-jlbxk", // 俱乐部选课权限编码 + }, ]); // 通知公告数据 @@ -328,8 +340,43 @@ onMounted(async () => { } } } + + // 检查用户是否已关注服务号 + await checkSubscribeStatus(); }); +// 检查关注状态 +const checkSubscribeStatus = async () => { + const userStore = useUserStore(); + const userInfo = userStore.getUser; + + if (userInfo && !userInfo.subscribed) { + // 延迟显示关注提醒,避免与启动页面冲突 + setTimeout(() => { + showSubscribeReminder(); + }, 2000); + } +}; + +// 显示关注提醒 +const showSubscribeReminder = () => { + uni.showModal({ + title: '关注服务号', + content: '请先关注我们的服务号,以便接收重要通知', + showCancel: true, + cancelText: '稍后关注', + confirmText: '立即关注', + success: (res) => { + if (res.confirm) { + // 跳转到关注页面 + uni.navigateTo({ + url: '/pages/system/subscribe/index' + }); + } + } + }); +}; + // 页面显示时检查是否需要刷新 onShow(async () => { await checkAndRefreshStudentInfo(); diff --git a/src/pages/system/launchPage/launchPage.vue b/src/pages/system/launchPage/launchPage.vue index 3c6a767..8c79c74 100644 --- a/src/pages/system/launchPage/launchPage.vue +++ b/src/pages/system/launchPage/launchPage.vue @@ -54,6 +54,7 @@ onLoad(async (data: any) => { } } + // 直接跳转到首页,关注检查在首页进行 toHome(data); } else { uni.reLaunch({ diff --git a/src/pages/system/login/login.vue b/src/pages/system/login/login.vue index 34ecff5..3d6d832 100644 --- a/src/pages/system/login/login.vue +++ b/src/pages/system/login/login.vue @@ -265,7 +265,7 @@ function toHome() { }); } else if (getGlobal.type == 2) { uni.reLaunch({ - url: "/pages/base/course-selection/club-selection", + url: "/pages/base/course-selection/noticeclub", }); } else { uni.reLaunch({ diff --git a/src/pages/system/subscribe/index.vue b/src/pages/system/subscribe/index.vue new file mode 100644 index 0000000..81745ba --- /dev/null +++ b/src/pages/system/subscribe/index.vue @@ -0,0 +1,194 @@ + + + + + \ No newline at end of file diff --git a/src/static/base/home/details.svg b/src/static/base/home/details.svg new file mode 100644 index 0000000..e36784f --- /dev/null +++ b/src/static/base/home/details.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/static/base/home/rdcode.jpg b/src/static/base/home/rdcode.jpg new file mode 100644 index 0000000..9950092 Binary files /dev/null and b/src/static/base/home/rdcode.jpg differ