提现
This commit is contained in:
parent
d22acd005c
commit
eefe1e37f6
@ -19,3 +19,12 @@ export const xkXkqdApi = async (params: any) => {
|
||||
export const kcjhFindKcjhByKcIdApi = async (params: any) => {
|
||||
return await get("/api/kcjh/findKcjhByKcId", params);
|
||||
};
|
||||
export const xkgzsApi = async (params: any) => {
|
||||
return await get("/api/gzs/findPage", params);
|
||||
};
|
||||
export const xkxkbmInfoApi = async (params: any) => {
|
||||
return await get("/mobile/xk/xkbmInfo", params);
|
||||
};
|
||||
export const xkqddeleteApi = async (params: any) => {
|
||||
return await post("/api/xkqd/delete?ids=" + params.ids);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// const ip: string = "119.29.194.155:8893";
|
||||
const ip: string = "yufangzc.com";
|
||||
const ip: string = "119.29.194.155:8893";
|
||||
// const ip: string = "yufangzc.com";
|
||||
const fwqip: string = "yufangzc.com";
|
||||
//打包服务器接口代理标识
|
||||
const SERVERAGENT: string = "/jzd-api";
|
||||
@ -7,11 +7,11 @@ const SERVERAGENT: string = "/jzd-api";
|
||||
export const HOMEAGENT: string = "";
|
||||
// 接口地址
|
||||
export const BASE_URL: string =
|
||||
process.env.NODE_ENV == "development" ? `https://${ip}/zhxy` : SERVERAGENT;
|
||||
process.env.NODE_ENV == "development" ? `http://${ip}/zhxy` : SERVERAGENT;
|
||||
// WebSocket地址
|
||||
export const BASE_WS_URL: string = `wss://${ip}`;
|
||||
//图片地址
|
||||
export const BASE_IMAGE_URL: string = process.env.NODE_ENV == "development" ? `https://${ip}` : `https://${fwqip}`;
|
||||
export const BASE_IMAGE_URL: string = process.env.NODE_ENV == "development" ? `http://${ip}` : `http://${fwqip}`;
|
||||
//存token的key
|
||||
export const AUTH_KEY: string = "satoken";
|
||||
//token过期返回状态码
|
||||
|
||||
@ -215,6 +215,11 @@
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"navigationBarBackgroundColor": "#fff",
|
||||
"backgroundColor": "#F8F8F8",
|
||||
"orientation": "portrait"
|
||||
"orientation": "portrait",
|
||||
"navigationStyle": "custom",
|
||||
"app-plus": {
|
||||
"background": "#efeff4",
|
||||
"titleView": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1026
src/pages/base/course-selection/club-selection copy.vue
Normal file
1026
src/pages/base/course-selection/club-selection copy.vue
Normal file
File diff suppressed because it is too large
Load Diff
@ -97,10 +97,12 @@
|
||||
|
||||
<!-- 底部报名按钮 - 固定部分 -->
|
||||
<view class="register-btn-container">
|
||||
<view class="selected-count-info" v-if="getSelectedCount > 0">
|
||||
已选 {{ getSelectedCount }} 门课程
|
||||
<view class="register-btn" @click="submitRegistration">
|
||||
<text v-if="selectedCoursesCount > 0">
|
||||
点击报名 (已选{{ selectedCoursesCount }}门)
|
||||
</text>
|
||||
<text v-else>点击报名</text>
|
||||
</view>
|
||||
<view class="register-btn" @click="submitRegistration">点击报名</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
@ -157,15 +159,26 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { navigateTo } from "@/utils/uniapp";
|
||||
import { ref, computed, reactive, onBeforeUnmount, watch } from "vue";
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
reactive,
|
||||
onBeforeUnmount,
|
||||
watch,
|
||||
onMounted,
|
||||
} from "vue";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { xkAddXkqdApi, xkListApi, xkXkqdApi } from "@/api/base/server";
|
||||
import {
|
||||
xkAddXkqdApi,
|
||||
xkListApi,
|
||||
xkxkbmInfoApi,
|
||||
xkXkqdApi,
|
||||
} from "@/api/base/server";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const { getUser } = useUserStore();
|
||||
const { getData, setKcData } = useDataStore();
|
||||
const { getData, setKcData, setData } = useDataStore();
|
||||
const { sign_file } = getData;
|
||||
|
||||
// 倒计时相关
|
||||
@ -204,6 +217,11 @@ const kcStatus = ref(false);
|
||||
// 添加选课是否已结束的标记
|
||||
const isEnrollmentEnded = ref(false);
|
||||
|
||||
// 添加轮询定时器变量
|
||||
let pollTimer: number | null = null;
|
||||
|
||||
const courseInfo = ref({});
|
||||
|
||||
// 封装检查学生报名状态的通用方法
|
||||
function checkStudentEnrollmentApi(student: any): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -213,16 +231,32 @@ function checkStudentEnrollmentApi(student: any): Promise<boolean> {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查kcData是否已加载
|
||||
if (!kcData.value || !kcData.value.id) {
|
||||
console.error("课程数据未加载:", kcData.value);
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用选课签到接口检查学生是否已报名
|
||||
xkXkqdApi({
|
||||
njId: student.njId,
|
||||
xsId: student.id,
|
||||
xklxId: "962488654", // 课程类型ID
|
||||
xklxId: "816059832", // 课程类型ID
|
||||
xkId: kcData.value.id,
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(1122, res);
|
||||
|
||||
// 根据接口返回的result判断是否已报名
|
||||
if (res && res.resultCode === 1) {
|
||||
resolve(!!res.result); // 转换为布尔值返回
|
||||
setData({
|
||||
...getData,
|
||||
kcData,
|
||||
studentInfo: student,
|
||||
enrolledCourse: res.result,
|
||||
});
|
||||
resolve(res.result.length > 0); // 转换为布尔值返回
|
||||
} else {
|
||||
// 接口调用成功但返回错误
|
||||
console.warn("检查报名状态接口返回错误:", res);
|
||||
@ -237,14 +271,76 @@ function checkStudentEnrollmentApi(student: any): Promise<boolean> {
|
||||
});
|
||||
}
|
||||
|
||||
// 轮询获取课程报名人数
|
||||
const pollEnrollmentCount = () => {
|
||||
xkxkbmInfoApi({ xkId: kcData.value.id })
|
||||
.then((res) => {
|
||||
if (res && res.resultCode === 1 && Array.isArray(res.result)) {
|
||||
updateEnrollmentCount(res.result);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("获取报名人数失败:", error);
|
||||
});
|
||||
};
|
||||
|
||||
// 更新课程报名人数
|
||||
const updateEnrollmentCount = (
|
||||
data: Array<{ xkkcId: string; bmrs: number }>
|
||||
) => {
|
||||
if (!Array.isArray(courseListData.value) || courseListData.value.length === 0)
|
||||
return;
|
||||
|
||||
let hasUpdates = false;
|
||||
|
||||
courseListData.value.forEach((course) => {
|
||||
const newCount = data.find((item) => item.xkkcId === course.id);
|
||||
if (newCount && course.ybmr !== newCount.bmrs) {
|
||||
course.ybmr = newCount.bmrs;
|
||||
hasUpdates = true;
|
||||
}
|
||||
});
|
||||
|
||||
// 如果有更新,强制重新渲染列表
|
||||
if (hasUpdates) {
|
||||
courseListData.value = [...courseListData.value];
|
||||
}
|
||||
};
|
||||
|
||||
// 启动轮询
|
||||
const startPolling = (interval = 5000) => {
|
||||
// 清除可能存在的旧定时器
|
||||
stopPolling();
|
||||
|
||||
// 立即执行一次
|
||||
pollEnrollmentCount();
|
||||
|
||||
// 设置定时器定期执行
|
||||
pollTimer = setInterval(pollEnrollmentCount, interval) as unknown as number;
|
||||
};
|
||||
|
||||
// 停止轮询
|
||||
const stopPolling = () => {
|
||||
if (pollTimer) {
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 在组件挂载时开始轮询
|
||||
onMounted(() => {
|
||||
// 当课程列表加载完成后启动轮询
|
||||
watch(courseListData, (newVal) => {
|
||||
if (newVal.length > 0 && !pollTimer) {
|
||||
startPolling();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 页面初始化时检查当前学生是否已报名
|
||||
const checkInitialEnrollment = (currentStudent: any) => {
|
||||
if (!currentStudent) return;
|
||||
|
||||
uni.showLoading({
|
||||
title: "加载中...",
|
||||
});
|
||||
|
||||
// 使用封装的API函数检查学生报名状态
|
||||
checkStudentEnrollmentApi(currentStudent)
|
||||
.then((isEnrolled) => {
|
||||
@ -253,22 +349,14 @@ const checkInitialEnrollment = (currentStudent: any) => {
|
||||
uni.reLaunch({
|
||||
url: `/pages/base/course-selection/enrolled`,
|
||||
});
|
||||
} else {
|
||||
loadCourseList(currentStudent);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
uni.hideLoading();
|
||||
loadCourseList(currentStudent);
|
||||
// 检查失败时不做特殊处理,继续正常流程
|
||||
console.log("检查学生报名状态失败,继续正常流程");
|
||||
});
|
||||
};
|
||||
|
||||
if (studentList.value.length > 0 && studentList.value.length === 1) {
|
||||
currentStudent.value = studentList.value[0];
|
||||
// 检查当前学生是否已报名
|
||||
checkInitialEnrollment(currentStudent.value);
|
||||
}
|
||||
|
||||
// 加载课程列表
|
||||
const loadCourseList = (currentStudent: any) => {
|
||||
if (!currentStudent) {
|
||||
@ -278,10 +366,9 @@ const loadCourseList = (currentStudent: any) => {
|
||||
|
||||
xkListApi({
|
||||
njId: currentStudent.njId,
|
||||
xklxId: "962488654",
|
||||
xklxId: "816059832",
|
||||
})
|
||||
.then((res) => {
|
||||
uni.hideLoading();
|
||||
if (res.resultCode == 1) {
|
||||
if (res.result) {
|
||||
kcData.value = res.result;
|
||||
@ -308,11 +395,15 @@ const loadCourseList = (currentStudent: any) => {
|
||||
kcStatus.value = true;
|
||||
startCountdown(xkjstime);
|
||||
}
|
||||
|
||||
// 课程数据加载完成后,检查学生报名状态
|
||||
checkInitialEnrollment(currentStudent);
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/course-selection/notopen",
|
||||
});
|
||||
}
|
||||
uni.hideLoading();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@ -320,6 +411,15 @@ const loadCourseList = (currentStudent: any) => {
|
||||
});
|
||||
};
|
||||
|
||||
if (studentList.value.length > 0 && studentList.value.length === 1) {
|
||||
currentStudent.value = studentList.value[0];
|
||||
// 先加载课程列表,不立即检查报名状态
|
||||
uni.showLoading({
|
||||
title: "加载中...",
|
||||
});
|
||||
loadCourseList(currentStudent.value);
|
||||
}
|
||||
|
||||
// 显示学生选择器
|
||||
function showStudentSelector() {
|
||||
if (studentList.value.length > 1) {
|
||||
@ -337,38 +437,14 @@ function switchStudent(student: any) {
|
||||
title: "加载中...",
|
||||
});
|
||||
|
||||
// 使用封装的API函数检查学生是否已报名
|
||||
checkStudentEnrollmentApi(student)
|
||||
.then((isEnrolled) => {
|
||||
uni.hideLoading();
|
||||
// 显示切换成功提示
|
||||
uni.showToast({
|
||||
title: `已切换到${student.xm}`,
|
||||
icon: "none",
|
||||
});
|
||||
|
||||
if (isEnrolled) {
|
||||
// 如果已报名,跳转到已报名页面
|
||||
uni.navigateTo({
|
||||
url: `/pages/base/course-selection/enrolled?studentId=${student.id}`,
|
||||
});
|
||||
} else {
|
||||
// 未报名,显示切换成功提示并刷新课程列表
|
||||
uni.showToast({
|
||||
title: `已切换到${student.xm}`,
|
||||
icon: "none",
|
||||
});
|
||||
|
||||
// 加载当前学生的课程列表
|
||||
loadCourseList(student);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: `已切换到${student.xm}`,
|
||||
icon: "none",
|
||||
});
|
||||
console.error("检查学生报名状态出错:", error);
|
||||
|
||||
// 出错时也加载课程列表
|
||||
loadCourseList(student);
|
||||
});
|
||||
// 先加载当前学生的课程列表,课程数据加载完成后会自动检查报名状态
|
||||
loadCourseList(student);
|
||||
}
|
||||
|
||||
// 启动倒计时
|
||||
@ -461,11 +537,25 @@ const displayCourseList = computed(() => {
|
||||
// 可修改的课程列表数据
|
||||
const courseListData = ref<any[]>([]);
|
||||
|
||||
// 计算已选择的课程数量
|
||||
const selectedCoursesCount = computed(() => {
|
||||
return courseListData.value.filter((course: any) => course.isSelected).length;
|
||||
});
|
||||
|
||||
// 监听计算属性变化,更新可修改的数据
|
||||
watch(
|
||||
displayCourseList,
|
||||
(newVal) => {
|
||||
courseListData.value = JSON.parse(JSON.stringify(newVal));
|
||||
|
||||
// 初始化时,将已选课程的全部信息存入courseInfo
|
||||
const selectedCourseIds = uni.getStorageSync("selectedCourseIds") || [];
|
||||
if (selectedCourseIds.length > 0) {
|
||||
const selectedCourses = newVal.filter((course: any) =>
|
||||
selectedCourseIds.includes(course.id)
|
||||
);
|
||||
courseInfo.value = selectedCourses;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
@ -490,23 +580,33 @@ const toggleSelection = (course: any) => {
|
||||
courseListData.value[courseIndex].isSelected =
|
||||
!courseListData.value[courseIndex].isSelected;
|
||||
|
||||
// 获取本地存储的已选课程ID数组
|
||||
let selectedCourseIds = uni.getStorageSync("selectedCourseIds") || [];
|
||||
// 获取所有选中的课程ID
|
||||
const selectedCourseIds = courseListData.value
|
||||
.filter((item: any) => item.isSelected)
|
||||
.map((item: any) => item.id);
|
||||
|
||||
if (courseListData.value[courseIndex].isSelected) {
|
||||
// 添加到已选数组
|
||||
if (!selectedCourseIds.includes(course.id)) {
|
||||
selectedCourseIds.push(course.id);
|
||||
}
|
||||
} else {
|
||||
// 从已选数组中移除
|
||||
selectedCourseIds = selectedCourseIds.filter(
|
||||
(id: string) => id !== course.id
|
||||
);
|
||||
}
|
||||
|
||||
// 更新本地存储
|
||||
// 存储选中的课程ID数组
|
||||
uni.setStorageSync("selectedCourseIds", selectedCourseIds);
|
||||
|
||||
// 更新courseInfo为所有选中的课程
|
||||
courseInfo.value = courseListData.value.filter(
|
||||
(item: any) => item.isSelected
|
||||
);
|
||||
|
||||
// 显示提示
|
||||
if (courseListData.value[courseIndex].isSelected) {
|
||||
uni.showToast({
|
||||
title: `已选择 ${course.kcmc}`,
|
||||
icon: "none",
|
||||
duration: 1500,
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: `已取消选择 ${course.kcmc}`,
|
||||
icon: "none",
|
||||
duration: 1500,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 查看课程详情
|
||||
@ -561,73 +661,58 @@ const submitRegistration = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查所有选中的课程是否有已满的
|
||||
// 检查选中的课程是否有已满的
|
||||
const fullCourses = selectedCourses.filter(
|
||||
(course) => course.ybmr >= course.maxNum
|
||||
);
|
||||
if (fullCourses.length > 0) {
|
||||
uni.showToast({
|
||||
title: `"${fullCourses[0].kcmc}"名额已满,请重新选择!`,
|
||||
title: `课程"${fullCourses[0].kcmc}"名额已满,请重新选择!`,
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建课程名称列表用于显示
|
||||
const courseNames = selectedCourses
|
||||
.map((course) => `"${course.kcmc}"`)
|
||||
.join("、");
|
||||
// 构建课程名称列表用于确认弹窗
|
||||
const courseNames = selectedCourses.map((course) => course.kcmc).join("、");
|
||||
|
||||
uni.showModal({
|
||||
title: "确认报名",
|
||||
content: `您确定要为${currentStudent.value.xm}报名以下课程吗?\n${courseNames}`,
|
||||
content: `您确定要为${currentStudent.value.xm}报名以下课程吗?\n\n${courseNames}`,
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showLoading({
|
||||
title: "报名中...",
|
||||
});
|
||||
|
||||
try {
|
||||
// 依次提交每个选中的课程
|
||||
for (const course of selectedCourses) {
|
||||
const result = await xkAddXkqdApi({
|
||||
njId: currentStudent.value.njId,
|
||||
xsId: currentStudent.value.id,
|
||||
xklxId: course.id,
|
||||
sign_file,
|
||||
});
|
||||
// 将选中的课程ID用逗号隔开
|
||||
const selectedCourseIds = selectedCourses
|
||||
.map((course) => course.id)
|
||||
.join(",");
|
||||
|
||||
if (result.resultCode !== 1) {
|
||||
throw new Error(
|
||||
`课程"${course.kcmc}"报名失败: ${result.message || "未知错误"}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 全部成功报名
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: "报名成功!",
|
||||
icon: "success",
|
||||
duration: 2000,
|
||||
const res = await xkAddXkqdApi({
|
||||
xsId: currentStudent.value.id,
|
||||
xkkcId: selectedCourseIds,
|
||||
qmFile: sign_file,
|
||||
xklxId: "816059832",
|
||||
});
|
||||
uni.hideLoading();
|
||||
if (res.resultCode == 1) {
|
||||
setData({
|
||||
...getData,
|
||||
kcData,
|
||||
studentInfo: currentStudent.value,
|
||||
enrolledCourse: res.result,
|
||||
});
|
||||
uni.showToast({
|
||||
title: "报名成功",
|
||||
icon: "none",
|
||||
});
|
||||
|
||||
// 清除选课记录
|
||||
uni.removeStorageSync("selectedCourseIds");
|
||||
|
||||
// 延迟后跳转到已报名页面
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: `/pages/base/course-selection/enrolled`,
|
||||
});
|
||||
}, 2000);
|
||||
} catch (error: any) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: error.message || "报名失败,请稍后重试",
|
||||
icon: "none",
|
||||
duration: 3000,
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -640,11 +725,8 @@ onBeforeUnmount(() => {
|
||||
clearInterval(countdownTimer);
|
||||
countdownTimer = null;
|
||||
}
|
||||
});
|
||||
|
||||
// 计算已选课程数量
|
||||
const getSelectedCount = computed(() => {
|
||||
return courseListData.value.filter((course) => course.isSelected).length;
|
||||
stopPolling();
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -875,12 +957,6 @@ const getSelectedCount = computed(() => {
|
||||
z-index: 10;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.selected-count-info {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.register-btn {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
@ -891,12 +967,6 @@ const getSelectedCount = computed(() => {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.multi-select-tip {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 学生选择器弹窗样式 */
|
||||
|
||||
@ -31,73 +31,111 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已报名课程信息 -->
|
||||
<!-- 已报名课程列表 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">已报名课程</view>
|
||||
<view class="card-title"
|
||||
>已报名课程 ({{ enrolledCourse.length }}门)</view
|
||||
>
|
||||
<view class="divider"></view>
|
||||
|
||||
<view class="course-info">
|
||||
<image
|
||||
class="course-image"
|
||||
:src="enrolledCourse.image || '/static/base/home/2211.png'"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
<view class="course-details">
|
||||
<view class="course-name">{{ enrolledCourse.title }}</view>
|
||||
<view class="course-teacher"
|
||||
>开课老师:{{ enrolledCourse.teacher }}</view
|
||||
>
|
||||
<view class="course-time">上课时间:{{ enrolledCourse.time }}</view>
|
||||
<view class="course-location"
|
||||
>上课地点:{{ enrolledCourse.location }}</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 课程列表 -->
|
||||
<view class="course-list">
|
||||
<view
|
||||
v-for="(item, index) in enrolledCourse"
|
||||
:key="item.id"
|
||||
class="course-item"
|
||||
:class="{ 'last-item': index === enrolledCourse.length - 1 }"
|
||||
>
|
||||
<view class="course-header">
|
||||
<view class="course-name">{{ item.title }}</view>
|
||||
<view class="course-fee">¥{{ item.fee }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 报名信息 -->
|
||||
<view class="enrollment-info">
|
||||
<view class="info-item">
|
||||
<text class="info-label">报名时间:</text>
|
||||
<text class="info-value">{{ enrolledCourse.enrollDate }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">课程费用:</text>
|
||||
<text class="info-value highlight">¥{{ enrolledCourse.fee }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">支付状态:</text>
|
||||
<text
|
||||
class="info-value"
|
||||
:class="enrolledCourse.isPaid ? 'paid' : 'unpaid'"
|
||||
>
|
||||
{{ enrolledCourse.isPaid ? "已支付" : "未支付" }}
|
||||
</text>
|
||||
<view class="course-details">
|
||||
<view class="detail-row">
|
||||
<view class="detail-item">
|
||||
<u-icon name="account" size="14" color="#666"></u-icon>
|
||||
<text>{{ item.teacher }}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<u-icon name="clock" size="14" color="#666"></u-icon>
|
||||
<text>{{ item.time }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="detail-row">
|
||||
<view class="detail-item">
|
||||
<u-icon name="map" size="14" color="#666"></u-icon>
|
||||
<text>{{ item.location }}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<u-icon name="calendar" size="14" color="#666"></u-icon>
|
||||
<text>{{ formatDate(item.enrollDate) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="course-actions" v-if="!isAllPaid">
|
||||
<u-button
|
||||
text="取消报名"
|
||||
size="mini"
|
||||
:plain="true"
|
||||
@click="cancelRegistration(item.id)"
|
||||
></u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 温馨提示 -->
|
||||
<!-- <view class="notice-card">
|
||||
<view class="notice-title">
|
||||
<u-icon name="info-circle" size="18" color="#2879FF"></u-icon>
|
||||
<text>温馨提示</text>
|
||||
<!-- 支付状态卡片 -->
|
||||
<view
|
||||
class="payment-status-card"
|
||||
:class="{ paid: isAllPaid, unpaid: !isAllPaid }"
|
||||
>
|
||||
<view class="status-header">
|
||||
<view class="status-icon">
|
||||
<u-icon
|
||||
:name="isAllPaid ? 'checkmark-circle' : 'clock'"
|
||||
size="24"
|
||||
:color="isAllPaid ? '#3FBF72' : '#FF9900'"
|
||||
></u-icon>
|
||||
</view>
|
||||
<view class="status-text">
|
||||
<text class="status-title">{{
|
||||
isAllPaid ? "支付完成" : "待支付"
|
||||
}}</text>
|
||||
<text class="status-desc">{{
|
||||
isAllPaid ? "所有课程费用已支付" : "请完成课程费用支付"
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="notice-content">
|
||||
<text>1. 课程一经报名成功,不可取消或更换;</text>
|
||||
<text>2. 如有特殊情况需要请假,请提前与老师联系;</text>
|
||||
<text>3. 请按时上课,迟到将影响学习效果。</text>
|
||||
|
||||
<view class="payment-details">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">课程总数</text>
|
||||
<text class="detail-value">{{ enrolledCourse.length }}门</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">总费用</text>
|
||||
<text class="detail-value amount">¥{{ totalAmount }}</text>
|
||||
</view>
|
||||
<view class="detail-item" v-if="!isAllPaid">
|
||||
<text class="detail-label">待支付</text>
|
||||
<text class="detail-value unpaid-amount">¥{{ totalAmount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<template #bottom>
|
||||
<view class="bottom-actions" v-if="!enrolledCourse.isPaid">
|
||||
<u-button text="继续支付" type="primary" @click="goPay"></u-button>
|
||||
<!-- <u-button
|
||||
text="返回选课"
|
||||
:plain="true"
|
||||
@click="goBack"
|
||||
></u-button> -->
|
||||
<view class="bottom-actions" v-if="!isAllPaid">
|
||||
<view class="payment-info">
|
||||
<text class="payment-label">待支付:</text>
|
||||
<text class="payment-amount">¥{{ totalAmount }}</text>
|
||||
</view>
|
||||
<view class="payment-button">
|
||||
<u-button text="立即支付" type="primary" @click="goPay"></u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</BasicLayout>
|
||||
@ -106,110 +144,100 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from "vue";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { xkqddeleteApi } from "@/api/base/server";
|
||||
import { map } from "lodash";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const { getUser } = useUserStore();
|
||||
|
||||
// 获取路由参数
|
||||
const studentId = ref("");
|
||||
onMounted(() => {
|
||||
const pages = getCurrentPages();
|
||||
const currentPage = pages[pages.length - 1];
|
||||
// @ts-ignore
|
||||
const options = currentPage.$page?.options;
|
||||
if (options && options.studentId) {
|
||||
studentId.value = options.studentId;
|
||||
}
|
||||
});
|
||||
onMounted(() => {});
|
||||
|
||||
const useData = useDataStore();
|
||||
const { getData } = storeToRefs(useData);
|
||||
|
||||
|
||||
// 当前学生信息
|
||||
const studentInfo = ref({
|
||||
id: "",
|
||||
xm: "加载中...",
|
||||
njmc: "",
|
||||
bjmc: "",
|
||||
avatar: "",
|
||||
id: getData.value.studentInfo.id,
|
||||
xm: getData.value.studentInfo.xm,
|
||||
njmc: getData.value.studentInfo.njmc,
|
||||
bjmc: getData.value.studentInfo.bjmc,
|
||||
avatar: getData.value.studentInfo.avatar,
|
||||
});
|
||||
|
||||
// 已报名课程信息
|
||||
const enrolledCourse = ref({
|
||||
id: "",
|
||||
title: "少儿声乐",
|
||||
image: "",
|
||||
teacher: "张老师",
|
||||
time: "每周一 16:00-17:30",
|
||||
location: "艺术楼 203教室",
|
||||
enrollDate: "2023-09-15 14:30:45",
|
||||
fee: 420,
|
||||
isPaid: false,
|
||||
const enrolledCourse = ref();
|
||||
|
||||
enrolledCourse.value = map(getData.value.enrolledCourse, (item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.xkmc,
|
||||
image: item.image,
|
||||
teacher: item.jsxm,
|
||||
time: item.studyTime,
|
||||
location: item.kcdd,
|
||||
enrollDate: item.createdTime,
|
||||
fee: item.jfje || 0,
|
||||
};
|
||||
});
|
||||
|
||||
// 获取学生信息
|
||||
const fetchStudentInfo = () => {
|
||||
// 在实际应用中,这里应该从学生列表中找到对应ID的学生
|
||||
// 或者调用接口获取详细信息
|
||||
const student = getUser.xsList.find((s: any) => s.id === studentId.value);
|
||||
if (student) {
|
||||
studentInfo.value = student;
|
||||
}
|
||||
// 整体支付状态(假设从后端获取或本地存储)
|
||||
const isAllPaid = ref(enrolledCourse.value[0].jfzt == "B"); // 这里可以根据实际业务逻辑设置
|
||||
|
||||
// TODO: 添加实际的接口调用
|
||||
// const url = '/api/student/detail';
|
||||
// const params = { studentId: studentId.value };
|
||||
// return new Promise((resolve) => {
|
||||
// // 模拟API调用
|
||||
// setTimeout(() => {
|
||||
// resolve();
|
||||
// }, 500);
|
||||
// });
|
||||
};
|
||||
// 计算费用汇总
|
||||
const totalAmount = computed(() => {
|
||||
return enrolledCourse.value.reduce(
|
||||
(sum: number, course: any) => sum + course.fee,
|
||||
0
|
||||
);
|
||||
});
|
||||
|
||||
// 获取已报名课程信息
|
||||
const fetchEnrolledCourse = () => {
|
||||
// TODO: 添加实际的接口调用
|
||||
// const url = '/api/course/enrolled';
|
||||
// const params = { studentId: studentId.value };
|
||||
// return new Promise((resolve) => {
|
||||
// // 模拟API调用
|
||||
// setTimeout(() => {
|
||||
// resolve();
|
||||
// }, 500);
|
||||
// });
|
||||
|
||||
// 模拟数据
|
||||
setTimeout(() => {
|
||||
enrolledCourse.value = {
|
||||
id: "course123",
|
||||
title: "少儿声乐",
|
||||
image: "/static/base/home/2211.png",
|
||||
teacher: "张老师",
|
||||
time: "每周一 16:00-17:30",
|
||||
location: "艺术楼 203教室",
|
||||
enrollDate: "2023-09-15 14:30:45",
|
||||
fee: 420,
|
||||
isPaid: Math.random() > 0.5, // 随机生成支付状态
|
||||
};
|
||||
}, 500);
|
||||
// 格式化日期
|
||||
const formatDate = (dateStr: string) => {
|
||||
if (!dateStr) return "未知";
|
||||
return dayjs(dateStr).format("YYYY-MM-DD HH:mm");
|
||||
};
|
||||
|
||||
// 去支付
|
||||
const goPay = () => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/base/course-selection/payment?courseId=${enrolledCourse.value.id}&studentId=${studentId.value}`,
|
||||
});
|
||||
};
|
||||
const goPay = () => {};
|
||||
|
||||
// 返回选课页面
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
const cancelRegistration = async (id: string) => {
|
||||
uni.showModal({
|
||||
title: "确认取消",
|
||||
content: "确定要取消该课程的报名吗?",
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showLoading({ title: "处理中..." });
|
||||
try {
|
||||
await xkqddeleteApi({
|
||||
ids: id,
|
||||
});
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: "取消成功",
|
||||
icon: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: `/pages/base/course-selection/index`,
|
||||
});
|
||||
}, 1500);
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: "取消失败",
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
uni.showLoading({ title: "加载中..." });
|
||||
|
||||
// 获取学生信息和已报名课程信息
|
||||
Promise.all([fetchStudentInfo(), fetchEnrolledCourse()]).finally(() => {
|
||||
uni.hideLoading();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -217,6 +245,7 @@ onMounted(() => {
|
||||
.enrolled-page {
|
||||
background-color: #f5f7fa;
|
||||
padding: 15px;
|
||||
padding-bottom: 80px; /* 为底部固定按钮留出空间 */
|
||||
}
|
||||
|
||||
.status-card {
|
||||
@ -310,72 +339,151 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.course-info {
|
||||
display: flex;
|
||||
margin-bottom: 15px;
|
||||
.course-list {
|
||||
.course-item {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.course-image {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 8px;
|
||||
margin-right: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.course-details {
|
||||
flex: 1;
|
||||
|
||||
.course-name {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
&.last-item {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.course-teacher,
|
||||
.course-time,
|
||||
.course-location {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
.course-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.course-name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.course-fee {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #ff6b01;
|
||||
}
|
||||
}
|
||||
|
||||
.course-details {
|
||||
margin-bottom: 12px;
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
text {
|
||||
margin-left: 5px;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.course-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
:deep(.u-button) {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.enrollment-info {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
.payment-status-card {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||
border-left: 4px solid #ddd;
|
||||
|
||||
.info-item {
|
||||
&.paid {
|
||||
border-left-color: #3fbf72;
|
||||
background: linear-gradient(135deg, #f0f9ff, #e6f7ff);
|
||||
}
|
||||
|
||||
&.unpaid {
|
||||
border-left-color: #ff9900;
|
||||
background: linear-gradient(135deg, #fff9f0, #fff2e6);
|
||||
}
|
||||
|
||||
.status-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
.status-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
.status-text {
|
||||
flex: 1;
|
||||
|
||||
.status-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.status-desc {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
.payment-details {
|
||||
.detail-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&.highlight {
|
||||
color: #ff6b01;
|
||||
font-weight: 500;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.paid {
|
||||
color: #3fbf72;
|
||||
.detail-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&.unpaid {
|
||||
color: #ff5252;
|
||||
.detail-value {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
|
||||
&.amount {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
&.unpaid-amount {
|
||||
color: #ff5252;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -415,14 +523,62 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.bottom-actions {
|
||||
padding: 15px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 12px 20px;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
||||
border-top: 1px solid #f0f0f0;
|
||||
z-index: 100;
|
||||
safe-area-inset-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.payment-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
.payment-label {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-bottom: 2px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.payment-amount {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #ff6b01;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
.payment-button {
|
||||
flex: 0 0 auto;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
:deep(.u-button) {
|
||||
flex: 1;
|
||||
margin: 0 5px;
|
||||
width: 120px !important;
|
||||
height: 40px !important;
|
||||
border-radius: 20px !important;
|
||||
font-size: 15px !important;
|
||||
font-weight: 500 !important;
|
||||
|
||||
.u-button__text {
|
||||
font-size: 15px !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
&.u-button--primary {
|
||||
background-color: #2879ff !important;
|
||||
border-color: #2879ff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -155,14 +155,26 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { navigateTo } from "@/utils/uniapp";
|
||||
import { ref, computed, reactive, onBeforeUnmount, watch, onMounted } from "vue";
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
reactive,
|
||||
onBeforeUnmount,
|
||||
watch,
|
||||
onMounted,
|
||||
} from "vue";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { xkAddXkqdApi, xkListApi, xkXkqdApi } from "@/api/base/server";
|
||||
import {
|
||||
xkAddXkqdApi,
|
||||
xkListApi,
|
||||
xkxkbmInfoApi,
|
||||
xkXkqdApi,
|
||||
} from "@/api/base/server";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const { getUser } = useUserStore();
|
||||
const { getData, setKcData } = useDataStore();
|
||||
const { getData, setKcData, setData } = useDataStore();
|
||||
const { sign_file } = getData;
|
||||
|
||||
// 倒计时相关
|
||||
@ -204,6 +216,8 @@ const isEnrollmentEnded = ref(false);
|
||||
// 添加轮询定时器变量
|
||||
let pollTimer: number | null = null;
|
||||
|
||||
const courseInfo = ref({});
|
||||
|
||||
// 封装检查学生报名状态的通用方法
|
||||
function checkStudentEnrollmentApi(student: any): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -213,16 +227,32 @@ function checkStudentEnrollmentApi(student: any): Promise<boolean> {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查kcData是否已加载
|
||||
if (!kcData.value || !kcData.value.id) {
|
||||
console.error("课程数据未加载:", kcData.value);
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用选课签到接口检查学生是否已报名
|
||||
xkXkqdApi({
|
||||
njId: student.njId,
|
||||
xsId: student.id,
|
||||
xklxId: "962488654", // 课程类型ID
|
||||
xkId: kcData.value.id,
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(1122,res);
|
||||
|
||||
// 根据接口返回的result判断是否已报名
|
||||
if (res && res.resultCode === 1) {
|
||||
resolve(!!res.result); // 转换为布尔值返回
|
||||
setData({
|
||||
...getData,
|
||||
kcData,
|
||||
studentInfo: student,
|
||||
enrolledCourse: res.result,
|
||||
});
|
||||
resolve(res.result.length > 0); // 转换为布尔值返回
|
||||
} else {
|
||||
// 接口调用成功但返回错误
|
||||
console.warn("检查报名状态接口返回错误:", res);
|
||||
@ -239,45 +269,34 @@ function checkStudentEnrollmentApi(student: any): Promise<boolean> {
|
||||
|
||||
// 轮询获取课程报名人数
|
||||
const pollEnrollmentCount = () => {
|
||||
// 预留接口调用
|
||||
// 假设接口名为 getEnrollmentCountApi
|
||||
/*
|
||||
getEnrollmentCountApi().then(res => {
|
||||
if (res && res.resultCode === 1 && Array.isArray(res.result)) {
|
||||
updateEnrollmentCount(res.result);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('获取报名人数失败:', error);
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: 接口对接后替换上面注释的代码
|
||||
// console.log('轮询更新报名人数');
|
||||
|
||||
// 模拟数据结构,接口实现后可删除
|
||||
const mockData = [
|
||||
{ id: '111B98397A08E8DA20D', ybmr: 10 },
|
||||
{ id: '74ECFE7249A54FE9B98397A08E8DA20D', ybmr: 15 }
|
||||
];
|
||||
|
||||
// 测试更新逻辑
|
||||
updateEnrollmentCount(mockData);
|
||||
xkxkbmInfoApi({ xkId: kcData.value.id })
|
||||
.then((res) => {
|
||||
if (res && res.resultCode === 1 && Array.isArray(res.result)) {
|
||||
updateEnrollmentCount(res.result);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("获取报名人数失败:", error);
|
||||
});
|
||||
};
|
||||
|
||||
// 更新课程报名人数
|
||||
const updateEnrollmentCount = (data: Array<{id: string, ybmr: number}>) => {
|
||||
if (!Array.isArray(courseListData.value) || courseListData.value.length === 0) return;
|
||||
|
||||
const updateEnrollmentCount = (
|
||||
data: Array<{ xkkcId: string; bmrs: number }>
|
||||
) => {
|
||||
if (!Array.isArray(courseListData.value) || courseListData.value.length === 0)
|
||||
return;
|
||||
|
||||
let hasUpdates = false;
|
||||
|
||||
courseListData.value.forEach(course => {
|
||||
const newCount = data.find(item => item.id === course.id);
|
||||
if (newCount && course.ybmr !== newCount.ybmr) {
|
||||
course.ybmr = newCount.ybmr;
|
||||
|
||||
courseListData.value.forEach((course) => {
|
||||
const newCount = data.find((item) => item.xkkcId === course.id);
|
||||
if (newCount && course.ybmr !== newCount.bmrs) {
|
||||
course.ybmr = newCount.bmrs;
|
||||
hasUpdates = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 如果有更新,强制重新渲染列表
|
||||
if (hasUpdates) {
|
||||
courseListData.value = [...courseListData.value];
|
||||
@ -288,10 +307,10 @@ const updateEnrollmentCount = (data: Array<{id: string, ybmr: number}>) => {
|
||||
const startPolling = (interval = 5000) => {
|
||||
// 清除可能存在的旧定时器
|
||||
stopPolling();
|
||||
|
||||
|
||||
// 立即执行一次
|
||||
pollEnrollmentCount();
|
||||
|
||||
|
||||
// 设置定时器定期执行
|
||||
pollTimer = setInterval(pollEnrollmentCount, interval) as unknown as number;
|
||||
};
|
||||
@ -318,10 +337,6 @@ onMounted(() => {
|
||||
const checkInitialEnrollment = (currentStudent: any) => {
|
||||
if (!currentStudent) return;
|
||||
|
||||
uni.showLoading({
|
||||
title: "加载中...",
|
||||
});
|
||||
|
||||
// 使用封装的API函数检查学生报名状态
|
||||
checkStudentEnrollmentApi(currentStudent)
|
||||
.then((isEnrolled) => {
|
||||
@ -330,22 +345,14 @@ const checkInitialEnrollment = (currentStudent: any) => {
|
||||
uni.reLaunch({
|
||||
url: `/pages/base/course-selection/enrolled`,
|
||||
});
|
||||
} else {
|
||||
loadCourseList(currentStudent);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
uni.hideLoading();
|
||||
loadCourseList(currentStudent);
|
||||
// 检查失败时不做特殊处理,继续正常流程
|
||||
console.log("检查学生报名状态失败,继续正常流程");
|
||||
});
|
||||
};
|
||||
|
||||
if (studentList.value.length > 0 && studentList.value.length === 1) {
|
||||
currentStudent.value = studentList.value[0];
|
||||
// 检查当前学生是否已报名
|
||||
checkInitialEnrollment(currentStudent.value);
|
||||
}
|
||||
|
||||
// 加载课程列表
|
||||
const loadCourseList = (currentStudent: any) => {
|
||||
if (!currentStudent) {
|
||||
@ -358,7 +365,6 @@ const loadCourseList = (currentStudent: any) => {
|
||||
xklxId: "962488654",
|
||||
})
|
||||
.then((res) => {
|
||||
uni.hideLoading();
|
||||
if (res.resultCode == 1) {
|
||||
if (res.result) {
|
||||
kcData.value = res.result;
|
||||
@ -385,11 +391,15 @@ const loadCourseList = (currentStudent: any) => {
|
||||
kcStatus.value = true;
|
||||
startCountdown(xkjstime);
|
||||
}
|
||||
|
||||
// 课程数据加载完成后,检查学生报名状态
|
||||
checkInitialEnrollment(currentStudent);
|
||||
} else {
|
||||
uni.reLaunch({
|
||||
url: "/pages/base/course-selection/notopen",
|
||||
});
|
||||
}
|
||||
uni.hideLoading();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@ -397,6 +407,15 @@ const loadCourseList = (currentStudent: any) => {
|
||||
});
|
||||
};
|
||||
|
||||
if (studentList.value.length > 0 && studentList.value.length === 1) {
|
||||
currentStudent.value = studentList.value[0];
|
||||
// 先加载课程列表,不立即检查报名状态
|
||||
uni.showLoading({
|
||||
title: "加载中...",
|
||||
});
|
||||
loadCourseList(currentStudent.value);
|
||||
}
|
||||
|
||||
// 显示学生选择器
|
||||
function showStudentSelector() {
|
||||
if (studentList.value.length > 1) {
|
||||
@ -414,38 +433,14 @@ function switchStudent(student: any) {
|
||||
title: "加载中...",
|
||||
});
|
||||
|
||||
// 使用封装的API函数检查学生是否已报名
|
||||
checkStudentEnrollmentApi(student)
|
||||
.then((isEnrolled) => {
|
||||
uni.hideLoading();
|
||||
// 显示切换成功提示
|
||||
uni.showToast({
|
||||
title: `已切换到${student.xm}`,
|
||||
icon: "none",
|
||||
});
|
||||
|
||||
if (isEnrolled) {
|
||||
// 如果已报名,跳转到已报名页面
|
||||
uni.navigateTo({
|
||||
url: `/pages/base/course-selection/enrolled?studentId=${student.id}`,
|
||||
});
|
||||
} else {
|
||||
// 未报名,显示切换成功提示并刷新课程列表
|
||||
uni.showToast({
|
||||
title: `已切换到${student.xm}`,
|
||||
icon: "none",
|
||||
});
|
||||
|
||||
// 加载当前学生的课程列表
|
||||
loadCourseList(student);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: `已切换到${student.xm}`,
|
||||
icon: "none",
|
||||
});
|
||||
console.error("检查学生报名状态出错:", error);
|
||||
|
||||
// 出错时也加载课程列表
|
||||
loadCourseList(student);
|
||||
});
|
||||
// 先加载当前学生的课程列表,课程数据加载完成后会自动检查报名状态
|
||||
loadCourseList(student);
|
||||
}
|
||||
|
||||
// 启动倒计时
|
||||
@ -543,6 +538,17 @@ watch(
|
||||
displayCourseList,
|
||||
(newVal) => {
|
||||
courseListData.value = JSON.parse(JSON.stringify(newVal));
|
||||
|
||||
// 初始化时,将已选课程的全部信息存入courseInfo
|
||||
const selectedCourseId = uni.getStorageSync("selectedCourseId");
|
||||
if (selectedCourseId) {
|
||||
const selectedCourse = newVal.find(
|
||||
(course: any) => course.id === selectedCourseId
|
||||
);
|
||||
if (selectedCourse) {
|
||||
courseInfo.value = selectedCourse;
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
@ -575,6 +581,7 @@ const toggleSelection = (course: any) => {
|
||||
courseListData.value[courseIndex].isSelected = true;
|
||||
// 存储当前选中的课程ID
|
||||
uni.setStorageSync("selectedCourseId", course.id);
|
||||
courseInfo.value = course;
|
||||
} else {
|
||||
// 取消选择提示
|
||||
uni.showToast({
|
||||
@ -659,36 +666,29 @@ const submitRegistration = () => {
|
||||
title: "报名中...",
|
||||
});
|
||||
const res = await xkAddXkqdApi({
|
||||
njId: currentStudent.value.njId,
|
||||
xsId: currentStudent.value.id,
|
||||
xklxId: selectedCourse.id,
|
||||
sign_file
|
||||
xkkcId: selectedCourse.id,
|
||||
qmFile: sign_file,
|
||||
xklxId: "962488654",
|
||||
});
|
||||
// TODO: 替换为实际的报名接口
|
||||
// 下面是模拟报名请求
|
||||
// setTimeout(() => {
|
||||
// uni.hideLoading();
|
||||
|
||||
// // 存储选课信息到全局状态或本地存储
|
||||
// uni.setStorageSync(
|
||||
// "enrolledCourse",
|
||||
// JSON.stringify({
|
||||
// courseId: selectedCourse.id,
|
||||
// courseName: selectedCourse.kcmc,
|
||||
// studentId: currentStudent.value.id,
|
||||
// studentName: currentStudent.value.xm,
|
||||
// enrollTime: new Date().toISOString(),
|
||||
// // 其他需要传递的信息
|
||||
// fee: selectedCourse.kcje || 0,
|
||||
// location: selectedCourse.kcdd || "",
|
||||
// teacher: selectedCourse.jsName || "",
|
||||
// studyTime: selectedCourse.studyTime || "",
|
||||
// })
|
||||
// );
|
||||
|
||||
// // 跳转到支付页面
|
||||
// navigateTo("/pages/base/course-selection/payment");
|
||||
// }, 1500);
|
||||
uni.hideLoading();
|
||||
if (res.resultCode == 1) {
|
||||
setData({
|
||||
...getData,
|
||||
kcData,
|
||||
studentInfo: currentStudent.value,
|
||||
enrolledCourse: res.result,
|
||||
});
|
||||
uni.showToast({
|
||||
title: "报名成功",
|
||||
icon: "none",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: `/pages/base/course-selection/enrolled`,
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -700,7 +700,7 @@ onBeforeUnmount(() => {
|
||||
clearInterval(countdownTimer);
|
||||
countdownTimer = null;
|
||||
}
|
||||
|
||||
|
||||
stopPolling();
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<BasicLayout>
|
||||
<view class="p-15">
|
||||
<view class="white-bg-color p-15 r-md">
|
||||
<view class="white-bg-color p-15 r-md" v-if="notice">
|
||||
<view> 各位家长:</view>
|
||||
<view class="notice-text">
|
||||
随着素质教育的不断深入,学生各项素质、能力的培养越来越受到学校、家庭的重视。我校根据教育局的有关精神,继续举办兴趣班。请各位家长根据实际情况,遵照"孩子自主,家长自愿"的原则,选择兴趣班,请点击下一步确认知晓告知内容。
|
||||
{{ notice }}
|
||||
</view>
|
||||
</view>
|
||||
<BasicSign ref="signCompRef" title="签名"></BasicSign>
|
||||
@ -25,13 +25,23 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { xkListApi } from "@/api/base/server";
|
||||
import { xkgzsApi } from "@/api/base/server";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { showLoading } from "@/utils/uniapp";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
|
||||
const signCompRef = ref<any>(null);
|
||||
const sign_file = ref<any>(null);
|
||||
const { setData, getGlobal } = useDataStore();
|
||||
|
||||
const notice = ref("");
|
||||
onLoad(async () => {
|
||||
showLoading({ title: "加载中..." });
|
||||
const res = await xkgzsApi({ kcLx: "兴趣课" });
|
||||
notice.value = res.rows?.[0]?.content || "";
|
||||
uni.hideLoading();
|
||||
});
|
||||
|
||||
async function submit() {
|
||||
// 显示加载中
|
||||
const data = await signCompRef.value.getSyncSignature();
|
||||
|
||||
@ -6,10 +6,10 @@
|
||||
<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>
|
||||
|
||||
<!-- 学生信息卡片 -->
|
||||
@ -26,18 +26,11 @@
|
||||
</view>
|
||||
<view class="student-details">
|
||||
<view class="student-name">
|
||||
{{ student.name }}
|
||||
<view class="gender-icon">
|
||||
<u-icon
|
||||
v-if="student.gender === '男'"
|
||||
name="man"
|
||||
color="#2879ff"
|
||||
size="18"
|
||||
></u-icon>
|
||||
<u-icon v-else name="woman" color="#ff6b9d" size="18"></u-icon>
|
||||
</view>
|
||||
{{ student.xm }}
|
||||
</view>
|
||||
<view class="student-class">{{ student.class }}</view>
|
||||
<view class="student-class"
|
||||
>{{ student.njmc }}{{ student.bjmc }}</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -50,15 +43,15 @@
|
||||
<view class="course-info">
|
||||
<image
|
||||
class="course-image"
|
||||
:src="course.image"
|
||||
:src="imagUrl(course.xkkcImg)"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
<view class="course-details">
|
||||
<view class="course-name">{{ course.title }}</view>
|
||||
<view class="course-teacher">开课老师:{{ course.teacher }}</view>
|
||||
<view class="course-location">上课地点:{{ course.location }}</view>
|
||||
<view class="course-name">{{ course.kcmc }}</view>
|
||||
<view class="course-teacher">开课老师:{{ course.jsName }}</view>
|
||||
<view class="course-location">上课地点:{{ course.kcdd }}</view>
|
||||
<view class="course-price"
|
||||
>金额:<text class="price-value">¥{{ course.price }}</text></view
|
||||
>金额:<text class="price-value">¥{{ course.kcje }}</text></view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
@ -68,7 +61,7 @@
|
||||
<view class="payment-footer">
|
||||
<view class="total-amount">
|
||||
<text>总金额:</text>
|
||||
<text class="amount-value">¥{{ course.price }}</text>
|
||||
<text class="amount-value">¥{{ course.kcje }}</text>
|
||||
</view>
|
||||
|
||||
<view class="action-buttons">
|
||||
@ -80,52 +73,47 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { xkqddeleteApi } from "@/api/base/server";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { imagUrl } from "@/utils";
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
const useData = useDataStore();
|
||||
const { getData } = storeToRefs(useData);
|
||||
|
||||
// 倒计时
|
||||
const countdownTime = ref("1分20秒");
|
||||
let timer: any = null;
|
||||
let seconds = 1 * 60 + 20; // 1分20秒
|
||||
// const countdownTime = ref("1分20秒");
|
||||
// let timer: any = null;
|
||||
// let seconds = 1 * 60 + 20; // 1分20秒
|
||||
|
||||
// 学生信息
|
||||
const student = ref({
|
||||
name: "何明远",
|
||||
gender: "男",
|
||||
class: "三年级2班",
|
||||
});
|
||||
const student = ref(getData.value.studentInfo);
|
||||
|
||||
// 课程信息
|
||||
const course = ref({
|
||||
id: 2,
|
||||
title: "机器人创客",
|
||||
teacher: "叶老师",
|
||||
location: "第一教学楼302",
|
||||
price: 142,
|
||||
image: "/static/images/robot-course.jpg",
|
||||
});
|
||||
const course = ref(getData.value.enrolledCourse);
|
||||
console.log(course.value);
|
||||
|
||||
// 开始倒计时
|
||||
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: () => {
|
||||
// goBack();
|
||||
// },
|
||||
// });
|
||||
// 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 = () => {
|
||||
@ -137,8 +125,12 @@ const cancelRegistration = () => {
|
||||
uni.showModal({
|
||||
title: "取消报名",
|
||||
content: "确定要取消报名吗?",
|
||||
success: (res) => {
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
await xkqddeleteApi({
|
||||
id: course.value.id,
|
||||
});
|
||||
|
||||
uni.showToast({
|
||||
title: "已取消报名",
|
||||
icon: "success",
|
||||
@ -157,32 +149,27 @@ const payNow = () => {
|
||||
title: "支付中...",
|
||||
});
|
||||
|
||||
// 模拟支付过程
|
||||
setTimeout(() => {
|
||||
uni.hideLoading();
|
||||
// // 模拟支付过程
|
||||
// setTimeout(() => {
|
||||
// uni.hideLoading();
|
||||
|
||||
uni.redirectTo({
|
||||
url: "/pages/base/course-selection/payment-success",
|
||||
});
|
||||
// uni.redirectTo({
|
||||
// url: "/pages/base/course-selection/payment-fail",
|
||||
// });
|
||||
}, 2000);
|
||||
// uni.redirectTo({
|
||||
// url: "/pages/base/course-selection/payment-success",
|
||||
// });
|
||||
// // uni.redirectTo({
|
||||
// // url: "/pages/base/course-selection/payment-fail",
|
||||
// // });
|
||||
// }, 2000);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
startCountdown();
|
||||
|
||||
// 实际应用中,应从页面参数或缓存获取课程和学生信息
|
||||
// const courseId = uni.getStorageSync('selectedCourseId');
|
||||
// const studentId = uni.getStorageSync('currentStudentId');
|
||||
// fetchPaymentInfo(courseId, studentId);
|
||||
// startCountdown();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
// if (timer) {
|
||||
// clearInterval(timer);
|
||||
// }
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@ -1,61 +1,68 @@
|
||||
<template>
|
||||
<view class="home-page">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="custom-navbar">
|
||||
<text class="page-title">智慧校园</text>
|
||||
</view>
|
||||
|
||||
<view class="content-container">
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="user-info-card">
|
||||
<view class="user-avatar-placeholder">
|
||||
<image :src="currentStudent.avatar" class="w-full h-full"></image>
|
||||
</view>
|
||||
<!-- <view-->
|
||||
<!-- class="user-details"-->
|
||||
<!-- @click="navigateTo('/pages/system/login/login')"-->
|
||||
<!-- >-->
|
||||
<view
|
||||
class="user-details"
|
||||
>
|
||||
<text class="user-name">{{ currentStudent.name }}</text>
|
||||
<view class="user-class-container">
|
||||
<text class="user-class"
|
||||
>{{ currentStudent.grade }} {{ currentStudent.class }}</text
|
||||
>
|
||||
<u-icon name="edit-pen" size="14" color="#909399"></u-icon>
|
||||
<view class="user-content">
|
||||
<view class="user-avatar">
|
||||
<image :src="currentStudent.avatar || '/static/base/home/11222.png'" class="avatar-img"></image>
|
||||
<view class="avatar-ring"></view>
|
||||
</view>
|
||||
<view class="user-details">
|
||||
<text class="user-name">{{ currentStudent.name }}</text>
|
||||
<view class="user-class-container">
|
||||
<view class="class-tag">
|
||||
<text class="user-class">{{ currentStudent.grade }} {{ currentStudent.class }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="switch-btn" @click="showStudentSelector">
|
||||
<u-icon name="arrow-down" size="12" color="#fff"></u-icon>
|
||||
<text>切换</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="switch-btn" @click="showStudentSelector">切换</view>
|
||||
</view>
|
||||
|
||||
<!-- 学校横幅 -->
|
||||
<view class="school-banner">
|
||||
<view class="banner-placeholder">
|
||||
<image src="/static/base/home/2211.png" class="w-full h-full"></image>
|
||||
<view class="banner-content">
|
||||
<image src="/static/base/home/2211.png" class="banner-img"></image>
|
||||
<view class="banner-overlay">
|
||||
<view class="banner-text">
|
||||
<text class="banner-title">智慧校园</text>
|
||||
<text class="banner-subtitle">让教育更智能,让成长更精彩</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单 -->
|
||||
<view class="grid-menu">
|
||||
<view
|
||||
v-for="(item, index) in menuItems"
|
||||
:key="index"
|
||||
class="grid-item"
|
||||
@click="handleMenuClick(item)"
|
||||
>
|
||||
<view class="grid-icon-placeholder">
|
||||
<image :src="item.icon" class="w-full h-full"></image>
|
||||
<view class="menu-section">
|
||||
<view class="section-title">
|
||||
<text class="title-text">校园服务</text>
|
||||
<view class="title-line"></view>
|
||||
</view>
|
||||
<view class="grid-menu">
|
||||
<view
|
||||
v-for="(item, index) in menuItems"
|
||||
:key="index"
|
||||
class="grid-item"
|
||||
@click="handleMenuClick(item)"
|
||||
>
|
||||
<view class="grid-icon-container">
|
||||
<view class="icon-background"></view>
|
||||
<image :src="item.icon" class="grid-icon"></image>
|
||||
</view>
|
||||
<text class="grid-text">{{ item.title }}</text>
|
||||
</view>
|
||||
<text class="grid-text">{{ item.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 通知公告 -->
|
||||
<view class="notice-section">
|
||||
<view class="section-header">
|
||||
<view class="blue-dot"></view>
|
||||
<text class="section-title">通知公告</text>
|
||||
<view class="section-title">
|
||||
<text class="title-text">通知公告</text>
|
||||
<view class="title-line"></view>
|
||||
</view>
|
||||
|
||||
<view class="notice-list">
|
||||
@ -65,11 +72,18 @@
|
||||
class="notice-item"
|
||||
@click="navigateTo('/pages/base/home/detail')"
|
||||
>
|
||||
<view class="notice-img-placeholder"></view>
|
||||
<view class="notice-icon">
|
||||
<u-icon name="bell" size="20" color="#4A90E2"></u-icon>
|
||||
</view>
|
||||
<view class="notice-content">
|
||||
<text class="notice-title">{{ notice.title }}</text>
|
||||
<text class="notice-desc">{{ notice.description }}</text>
|
||||
<text class="notice-date">{{ notice.date }}</text>
|
||||
<view class="notice-footer">
|
||||
<text class="notice-date">{{ notice.date }}</text>
|
||||
<view class="notice-arrow">
|
||||
<u-icon name="arrow-right" size="12" color="#C8C9CC"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -81,12 +95,14 @@
|
||||
:show="showSelector"
|
||||
@close="showSelector = false"
|
||||
mode="bottom"
|
||||
round="10"
|
||||
round="20"
|
||||
>
|
||||
<view class="student-selector">
|
||||
<view class="selector-header">
|
||||
<text class="selector-title">选择学生</text>
|
||||
<u-icon name="close" size="20" @click="showSelector = false"></u-icon>
|
||||
<view class="close-btn" @click="showSelector = false">
|
||||
<u-icon name="close" size="18" color="#909399"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="student-list">
|
||||
<view
|
||||
@ -96,19 +112,16 @@
|
||||
:class="{ 'student-item-active': currentStudent.id === student.id }"
|
||||
@click="switchStudent(student)"
|
||||
>
|
||||
<view class="student-avatar-placeholder"></view>
|
||||
<view class="student-avatar">
|
||||
<image :src="student.avatar || '/static/base/home/11222.png'" class="avatar-img"></image>
|
||||
</view>
|
||||
<view class="student-info">
|
||||
<text class="student-name">{{ student.name }}</text>
|
||||
<text class="student-class"
|
||||
>{{ student.grade }} {{ student.class }}</text
|
||||
>
|
||||
<text class="student-class">{{ student.grade }} {{ student.class }}</text>
|
||||
</view>
|
||||
<view class="check-icon" v-if="currentStudent.id === student.id">
|
||||
<u-icon name="checkmark" color="#4A90E2" size="18"></u-icon>
|
||||
</view>
|
||||
<u-icon
|
||||
v-if="currentStudent.id === student.id"
|
||||
name="checkmark"
|
||||
color="#409EFF"
|
||||
size="20"
|
||||
></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -117,8 +130,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {navigateTo} from "@/utils/uniapp";
|
||||
import {ref} from "vue";
|
||||
import { navigateTo } from "@/utils/uniapp";
|
||||
import { ref } from "vue";
|
||||
// 菜单项数据
|
||||
const menuItems = ref([
|
||||
{
|
||||
@ -236,213 +249,398 @@ function switchStudent(student: any) {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.home-page {
|
||||
background-color: #f8f8f8;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* 自定义导航栏 */
|
||||
.custom-navbar {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
padding: 0 15px;
|
||||
padding-top: var(--status-bar-height);
|
||||
background-color: #ffffff;
|
||||
|
||||
.page-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.navbar-right {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
padding: 15px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 用户信息卡片 */
|
||||
.user-info-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
border-radius: 12px;
|
||||
padding: 12px 15px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.user-avatar-placeholder {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
border: 1px dashed #d0d0d0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
flex: 1;
|
||||
margin-left: 12px;
|
||||
|
||||
.user-name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.user-class-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.user-class {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
margin-right: 5px;
|
||||
position: relative;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
|
||||
border-radius: 20px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 20px;
|
||||
box-shadow: 0 12px 40px rgba(74, 144, 226, 0.25);
|
||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||
overflow: hidden;
|
||||
|
||||
.user-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
.user-avatar {
|
||||
position: relative;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 16px rgba(74, 144, 226, 0.3);
|
||||
border: 3px solid #ffffff;
|
||||
flex-shrink: 0;
|
||||
|
||||
.avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.avatar-ring {
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
left: -3px;
|
||||
width: calc(100% + 6px);
|
||||
height: calc(100% + 6px);
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(74, 144, 226, 0.3);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.user-details {
|
||||
flex: 1;
|
||||
margin-left: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
.user-name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.user-class-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.class-tag {
|
||||
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
|
||||
color: #ffffff;
|
||||
padding: 4px 12px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.3);
|
||||
|
||||
.user-class {
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.switch-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
padding: 8px 16px;
|
||||
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
|
||||
color: #ffffff;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 4px 12px rgba(74, 144, 226, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
flex-shrink: 0;
|
||||
min-width: 60px;
|
||||
height: 16px;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
text {
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.switch-btn {
|
||||
padding: 4px 12px;
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
color: #409eff;
|
||||
border: 1px solid #409eff;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 学校横幅 */
|
||||
.school-banner {
|
||||
margin-bottom: 15px;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 25px;
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
|
||||
.banner-placeholder {
|
||||
box-shadow: 0 10px 32px rgba(0, 0, 0, 0.15);
|
||||
|
||||
.banner-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
border: 1px dashed #d0d0d0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 160px;
|
||||
|
||||
.banner-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.banner-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, rgba(74, 144, 226, 0.8) 0%, rgba(53, 122, 189, 0.9) 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.banner-text {
|
||||
text-align: center;
|
||||
|
||||
.banner-title {
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
margin-bottom: 8px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 功能菜单 */
|
||||
.grid-menu {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background-color: #ffffff;
|
||||
border-radius: 12px;
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.grid-item {
|
||||
width: 33.33%;
|
||||
.menu-section {
|
||||
margin-bottom: 25px;
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 15px 0;
|
||||
|
||||
.grid-icon-placeholder {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.grid-text {
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
padding: 0 5px;
|
||||
|
||||
.title-text {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
position: relative;
|
||||
padding-left: 12px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.title-line {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, #e0e6ed 0%, transparent 100%);
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.grid-menu {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 32px rgba(74, 144, 226, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||
|
||||
.grid-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px 10px;
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 12px;
|
||||
position: relative;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
background-color: rgba(74, 144, 226, 0.05);
|
||||
}
|
||||
|
||||
.grid-icon-container {
|
||||
position: relative;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #f0f4ff 0%, #e6f0ff 100%);
|
||||
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.15);
|
||||
}
|
||||
|
||||
.grid-icon {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.grid-text {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 通知公告 */
|
||||
.notice-section {
|
||||
.section-header {
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.blue-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background-color: #1976d2;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20px;
|
||||
padding: 0 5px;
|
||||
|
||||
.title-text {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
position: relative;
|
||||
padding-left: 12px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.title-line {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, #e0e6ed 0%, transparent 100%);
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.notice-list {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
|
||||
.notice-item {
|
||||
display: flex;
|
||||
background-color: #ffffff;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 12px;
|
||||
|
||||
.notice-img-placeholder {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background-color: #f0f0f0;
|
||||
border: 1px dashed #d0d0d0;
|
||||
border-radius: 8px;
|
||||
margin-right: 12px;
|
||||
align-items: flex-start;
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
|
||||
padding: 18px;
|
||||
margin-bottom: 12px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 24px rgba(74, 144, 226, 0.18);
|
||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 12px 36px rgba(74, 144, 226, 0.25);
|
||||
}
|
||||
|
||||
|
||||
.notice-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: linear-gradient(135deg, #f0f4ff 0%, #e6f0ff 100%);
|
||||
border-radius: 12px;
|
||||
margin-right: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.15);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notice-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
min-width: 0;
|
||||
|
||||
.notice-title {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 6px;
|
||||
margin-bottom: 8px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
|
||||
.notice-desc {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
margin-bottom: 10px;
|
||||
color: #606266;
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
flex: 1;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.notice-date {
|
||||
font-size: 12px;
|
||||
color: #c0c4cc;
|
||||
|
||||
.notice-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.notice-date {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.notice-arrow {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -451,68 +649,160 @@ function switchStudent(student: any) {
|
||||
|
||||
/* 学生选择器弹窗样式 */
|
||||
.student-selector {
|
||||
background-color: #ffffff;
|
||||
border-top-left-radius: 12px;
|
||||
border-top-right-radius: 12px;
|
||||
padding-bottom: 20px;
|
||||
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
|
||||
border-top-left-radius: 20px;
|
||||
border-top-right-radius: 20px;
|
||||
padding-bottom: 30px;
|
||||
|
||||
.selector-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
|
||||
.selector-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.9);
|
||||
background-color: #e6e8eb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.student-list {
|
||||
padding: 0 15px;
|
||||
|
||||
padding: 0 20px;
|
||||
|
||||
.student-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
|
||||
padding: 16px 0;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
||||
&-active {
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
background: linear-gradient(135deg, rgba(74, 144, 226, 0.08) 0%, rgba(53, 122, 189, 0.05) 100%);
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
.student-avatar-placeholder {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
|
||||
.student-avatar {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
background-color: #f0f0f0;
|
||||
border: 1px dashed #d0d0d0;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.15);
|
||||
border: 2px solid #ffffff;
|
||||
|
||||
.avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.student-info {
|
||||
flex: 1;
|
||||
margin-left: 12px;
|
||||
|
||||
margin-left: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
|
||||
.student-name {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 4px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
|
||||
.student-class {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 8px rgba(74, 144, 226, 0.3);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 动画效果 */
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
opacity: 0.7;
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式优化 */
|
||||
@media (max-width: 375px) {
|
||||
.content-container {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.user-info-card .user-content .user-avatar {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.grid-menu .grid-item {
|
||||
padding: 15px 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
<template>
|
||||
<view class="interest-class-page">
|
||||
<u-navbar title="兴趣课" :autoBack="true"></u-navbar>
|
||||
|
||||
<view class="content-container">
|
||||
<!-- 顶部蓝色背景横幅 -->
|
||||
|
||||
@ -34,7 +34,6 @@ function toHome(data: any) {
|
||||
}
|
||||
|
||||
onLoad(async (data: any) => {
|
||||
console.log(data);
|
||||
setGlobal(data);
|
||||
if (data && data.openId) {
|
||||
checkOpenId({ openId: data.openId, appCode: "JZ" })
|
||||
|
||||
@ -112,7 +112,7 @@ import { useDataStore } from "@/store/modules/data";
|
||||
const [register, { getValue }] = useForm({
|
||||
formsProps: { labelWidth: 100 },
|
||||
schema: [
|
||||
{ title: "监督人信息" },
|
||||
{ title: "监护人信息" },
|
||||
{
|
||||
field: "jzxsgxId",
|
||||
label: "与学生关系",
|
||||
|
||||
@ -1,133 +1,189 @@
|
||||
import {AUTH_KEY, BASE_URL, HOMEAGENT, RESULT_CODE_NOT_LOGIN} from "@/config";
|
||||
import {useUserStore} from "@/store/modules/user";
|
||||
import {getLogin} from "../permission";
|
||||
import {request} from "@/utils/request/request";
|
||||
import {showToast} from "@/utils/uniapp";
|
||||
import { AUTH_KEY, BASE_URL, HOMEAGENT, RESULT_CODE_NOT_LOGIN } from "@/config";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { getLogin } from "../permission";
|
||||
import { request } from "@/utils/request/request";
|
||||
import { showToast } from "@/utils/uniapp";
|
||||
|
||||
let count: boolean = false;
|
||||
|
||||
function _loginExpiredModal() {
|
||||
const store = useUserStore();
|
||||
store.logout()
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '登录过期,请重新登录',
|
||||
showCancel: false,
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
count = false
|
||||
getLogin()
|
||||
} else if (res.cancel) {
|
||||
count = false
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
fail: (err) => {
|
||||
console.log(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
const store = useUserStore();
|
||||
store.logout();
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "登录过期,请重新登录",
|
||||
showCancel: false,
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
count = false;
|
||||
getLogin();
|
||||
} else if (res.cancel) {
|
||||
count = false;
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
fail: (err) => {
|
||||
console.log(err);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const config = {
|
||||
baseUrl: process.env.NODE_ENV == 'development' ? HOMEAGENT ? '/base' : BASE_URL : BASE_URL,
|
||||
header: {}
|
||||
}
|
||||
baseUrl:
|
||||
process.env.NODE_ENV == "development"
|
||||
? HOMEAGENT
|
||||
? "/base"
|
||||
: BASE_URL
|
||||
: BASE_URL,
|
||||
header: {},
|
||||
};
|
||||
export const interceptor = {
|
||||
request: (config: UniNamespace.UploadFileOption | UniNamespace.RequestOptions) => {
|
||||
const store = useUserStore();
|
||||
if (store.getToken) {
|
||||
config.header = {
|
||||
[AUTH_KEY]: store.getToken
|
||||
};
|
||||
}
|
||||
},
|
||||
response: (response: any) => {
|
||||
if (response.data && RESULT_CODE_NOT_LOGIN == response.data.resultCode) {
|
||||
if (!count) {
|
||||
_loginExpiredModal()
|
||||
}
|
||||
count = true;
|
||||
return;
|
||||
}
|
||||
if (response.config.name === "files") {
|
||||
return JSON.parse(response.data);
|
||||
}
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
} else {
|
||||
console.log('接口无返回值', response)
|
||||
}
|
||||
request: (
|
||||
config: UniNamespace.UploadFileOption | UniNamespace.RequestOptions
|
||||
) => {
|
||||
const store = useUserStore();
|
||||
if (store.getToken) {
|
||||
config.header = {
|
||||
[AUTH_KEY]: store.getToken,
|
||||
};
|
||||
}
|
||||
},
|
||||
response: (response: any) => {
|
||||
if (response.data && RESULT_CODE_NOT_LOGIN == response.data.resultCode) {
|
||||
if (!count) {
|
||||
_loginExpiredModal();
|
||||
}
|
||||
count = true;
|
||||
return;
|
||||
}
|
||||
if (response.config.name === "files") {
|
||||
return JSON.parse(response.data);
|
||||
}
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
} else {
|
||||
console.log("接口无返回值", response);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export function get<T = any>(
|
||||
url: string,
|
||||
data?: any,
|
||||
options?: UniNamespace.RequestOptions
|
||||
): Promise<Requests<T>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
url,
|
||||
data,
|
||||
method: "GET",
|
||||
dataType: "json",
|
||||
responseType: "text",
|
||||
},
|
||||
options
|
||||
)
|
||||
).then((res) => {
|
||||
if (res.resultCode == 1) {
|
||||
resolve(res);
|
||||
} else {
|
||||
if (res.resultCode) {
|
||||
if (res.resultCode != RESULT_CODE_NOT_LOGIN) {
|
||||
showToast(res.message || "接口异常");
|
||||
reject(res);
|
||||
}
|
||||
} else {
|
||||
if (res.rows) {
|
||||
resolve(res);
|
||||
} else {
|
||||
showToast(res.message || "接口异常");
|
||||
reject(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function get<T = any>(url: string, data?: any, options?: UniNamespace.RequestOptions): Promise<Requests<T>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(Object.assign({}, {
|
||||
url,
|
||||
data,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
responseType: 'text',
|
||||
}, options)).then(res => {
|
||||
if (res.resultCode == 1) {
|
||||
resolve(res)
|
||||
} else {
|
||||
if (res.resultCode) {
|
||||
if (res.resultCode != RESULT_CODE_NOT_LOGIN) {
|
||||
showToast(res.message || '接口异常')
|
||||
reject(res)
|
||||
}
|
||||
} else {
|
||||
if (res.rows) {
|
||||
resolve(res)
|
||||
} else {
|
||||
showToast(res.message || '接口异常')
|
||||
reject(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
export function post<T = any>(
|
||||
url: string,
|
||||
data?: any,
|
||||
options?: UniNamespace.RequestOptions
|
||||
): Promise<Requests<T>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
url,
|
||||
data,
|
||||
method: "POST",
|
||||
dataType: "json",
|
||||
responseType: "text",
|
||||
},
|
||||
options
|
||||
)
|
||||
).then((res) => {
|
||||
if (res.resultCode == 1) {
|
||||
resolve(res);
|
||||
} else {
|
||||
if (res.resultCode) {
|
||||
if (res.resultCode != RESULT_CODE_NOT_LOGIN) {
|
||||
showToast(res.message || "接口异常");
|
||||
reject(res);
|
||||
}
|
||||
} else {
|
||||
if (res.rows) {
|
||||
resolve(res);
|
||||
} else {
|
||||
showToast(res.message || "接口异常");
|
||||
reject(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function post<T = any>(url: string, data?: any, options?: UniNamespace.RequestOptions): Promise<Requests<T>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(Object.assign({}, {
|
||||
url,
|
||||
data,
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
responseType: 'text',
|
||||
}, options)).then(res => {
|
||||
if (res.resultCode == 1) {
|
||||
resolve(res)
|
||||
} else {
|
||||
if (res.resultCode) {
|
||||
if (res.resultCode != RESULT_CODE_NOT_LOGIN) {
|
||||
showToast(res.message || '接口异常')
|
||||
reject(res)
|
||||
}
|
||||
} else {
|
||||
if (res.rows) {
|
||||
resolve(res)
|
||||
} else {
|
||||
showToast(res.message || '接口异常')
|
||||
reject(res)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
export function file(
|
||||
url: string,
|
||||
data: Blob,
|
||||
options?: UniNamespace.UploadFileOption
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request(
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
url,
|
||||
filePath: data,
|
||||
name: "files",
|
||||
},
|
||||
options
|
||||
),
|
||||
true
|
||||
).then((res) => {
|
||||
if (res.resultCode == 1) {
|
||||
resolve(res);
|
||||
} else {
|
||||
if (res.resultCode) {
|
||||
if (res.resultCode != RESULT_CODE_NOT_LOGIN) {
|
||||
showToast(res.message || "接口异常");
|
||||
reject(res);
|
||||
}
|
||||
} else {
|
||||
if (res.rows) {
|
||||
resolve(res);
|
||||
} else {
|
||||
showToast(res.message || "接口异常");
|
||||
reject(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function file(url: string, data: Blob, options?: UniNamespace.UploadFileOption) {
|
||||
return request(Object.assign({}, {
|
||||
url,
|
||||
filePath: data,
|
||||
name: 'files',
|
||||
}, options), true)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user