2025-09-12 11:20:21 +08:00

708 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="interest-course">
<!-- 选课信息头部 - 固定部分 -->
<view class="selection-header">
<view class="header-content">
<view class="title-section" @click="clickShowXkSelector">
<view class="title">
<text v-if="xkData && xkData.xkmc">{{ xkData.xkmc }}</text>
<text v-else>巡查选课</text>
</view>
<view class="switch-btn" v-if="xkList.length > 1">切换</view>
</view>
</view>
</view>
<!-- 可滚动的内容区域 -->
<view class="scrollable-content">
<!-- 课程网格列表 -->
<view class="course-list" v-if="xkkcList && xkkcList.length > 0">
<view
v-for="(xkkc, index) in xkkcList"
:key="xkkc.id || index"
class="course-item"
>
<view class="course-name">{{ xkkc.kcmc }}</view>
<view class="course-info-item">
<view class="info-label">年级</view>
<view class="info-data">{{ xkkc.gradeName || '暂无' }}</view>
</view>
<view class="course-info-item" v-if="xkkc.bjmc">
<view class="info-label">班级</view>
<view class="info-data">{{ xkkc.bjmc || '暂无' }}</view>
</view>
<view class="separator-line"></view>
<view class="course-btn-group">
<view class="xc-btn" @click.stop="goXc(xkkc)">巡查</view>
<view class="record-btn" @click.stop="goRecord(xkkc)">巡查记录</view>
</view>
</view>
</view>
<!-- 暂无数据提示 -->
<view v-else class="empty-course-list">
<view class="empty-icon">
<u-icon name="list" size="50" color="#C8C9CC"></u-icon>
</view>
<view class="empty-text">暂无课程数据</view>
</view>
</view>
<view>
<!-- 选课选择弹窗 -->
<u-popup
:show="showXkFlag"
@close="showXkFlag = false"
mode="bottom"
round="10"
>
<view class="xk-selector">
<view class="selector-header">
<text class="selector-title">选择俱乐部</text>
<u-icon name="close" size="20" @click="showXkFlag = false"></u-icon>
</view>
<view class="xk-list">
<view
v-for="(xk, index) in xkList"
:key="index"
class="xk-item"
:class="{
'xk-item-active': xkData.id === xk.id,
}"
@click="switchXk(xk)"
>
<view class="xk-info">
<text class="xk-name">{{ xk.xkmc }}</text>
<text class="xk-type">{{ xk.xkmc }}</text>
</view>
<u-icon
v-if="xkData.id === xk.id"
name="checkmark"
color="#409EFF"
size="20"
></u-icon>
</view>
</view>
</view>
</u-popup>
</view>
</view>
</template>
<script setup lang="ts">
import { getKyXcCourseListApi } from "@/api/base/xkPbApi";
import { useDataStore } from "@/store/modules/data";
import { useUserStore } from "@/store/modules/user";
import { onBeforeUnmount, onMounted, ref } from "vue";
const { getJs } = useUserStore();
const dataStore = useDataStore();
// 控制选择器显示状态
const showXkFlag = ref(false);
const xkList = ref<any>([]);
const xkData = ref();
// 课程列表数据
const xkkcList = ref<any[]>([]);
const xcBeforeMinute = ref<number>(0);
// 星期名称列表
const wdNameList = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
onMounted(async () => {
uni.showLoading({
title: "加载中...",
});
// 优先从global获取排班数据如果没有则从data获取
let pbData = dataStore.getGlobal;
if (!pbData || !pbData.xcbt || !pbData.xcbt.includes('课业辅导巡计划')) {
pbData = dataStore.getData;
}
// 检查数据是否有效
if (!pbData || !pbData.xcbt || pbData.xcbt.includes('课业辅导巡计划') === false) {
uni.showToast({
title: '数据异常,请重新选择排班',
icon: 'none'
});
uni.navigateBack();
return;
}
// 检查是否是课程数据包含kcmc字段
if (pbData.kcmc) {
// 这是课程数据,需要重建排班数据
// 从课程数据中提取排班相关字段
const reconstructedPbData = {
id: pbData.pbId, // 使用pbId作为排班ID
status: 'A',
njIds: pbData.njIds || '',
bjIds: pbData.bjIds || '',
xcbt: pbData.xcbt,
xclx: pbData.xclx,
xqId: pbData.xqId,
xqmc: pbData.xqmc,
xcstime: pbData.xcstime,
xcjstime: pbData.xcjstime,
pk: pbData.pk
};
dataStore.setGlobal(reconstructedPbData);
pbData = reconstructedPbData;
} else {
// 这是排班数据,直接保存
dataStore.setGlobal(pbData);
}
await loadXcCourseList(pbData);
uni.hideLoading();
});
// 加载巡查课程列表
const loadXcCourseList = async (pbData: any) => {
try {
// 检查pbData是否有效
if (!pbData || !pbData.id) {
uni.showToast({
title: '排班数据无效,请重新选择',
icon: 'none'
});
return;
}
const res = await getKyXcCourseListApi({
jsId: getJs.id,
pbId: pbData.id
});
if (res && res.resultCode == 1) {
const list = res.result || [];
xkkcList.value = list.map((item: any) => ({
id: item.id, // 课程记录ID
pbId: item.pbId || pbData.id, // 排班ID
kcmc: item.kmmc || '课业辅导',
gradeName: item.bc && item.njmc ? `${item.bc}(${item.njmc})` : (item.njmc || '暂无'),
bjmc: item.bjmc || '暂无',
// 添加年级和班级ID字段
njId: item.njId || '',
njmcId: item.njmcId || '',
bjId: item.bjId || ''
}));
} else {
xkkcList.value = [];
uni.showToast({
title: (res as any).resultMessage || '获取课业辅导巡查失败',
icon: 'none'
});
return;
}
} catch (error) {
console.error('加载巡查课程失败:', error);
xkkcList.value = [];
uni.showToast({
title: '加载巡查课程失败',
icon: 'none'
});
}
};
// 显示选课选择器
function clickShowXkSelector() {
if (xkList.value.length > 1) {
showXkFlag.value = true;
}
}
// 切换选课
function switchXk(xk: any) {
xkData.value = xk;
xkkcList.value = xk.xkkcs;
showXkFlag.value = false;
for (let i = 0; i < xk.xkkcs.length; i++) {
let xkkc = xk.xkkcs[i];
// 判断周期
switch (xkkc.skzqlx) {
case "每天":
xkkc.skzqmc = "每天";
break;
case "每周":
const daysOfWeek = xkkc.skzq.split(",").map(Number);
xkkc.skzqmc = daysOfWeek
.map((day: number) => wdNameList[day - 1])
.join(",");
break;
case "每月":
const daysOfMonth = xkkc.skzq.split(",").map(Number);
xkkc.skzqmc = daysOfMonth.map((day: number) => day + "号").join(",");
break;
}
}
// 显示切换成功提示
uni.showToast({
title: `已切换到${xk.xkmc}`,
icon: "none",
});
}
// 跳转到巡查
const goXc = (xkkc: any) => {
// 直接从global获取排班数据
const pbData = dataStore.getGlobal;
// 检查排班数据是否有效
if (!pbData || !pbData.xcbt || !pbData.xcbt.includes('课业辅导巡计划')) {
uni.showToast({
title: '数据异常,请重新选择排班',
icon: 'none'
});
return;
}
// 合并排班数据和课程数据
const combinedData = {
...xkkc,
id: xkkc.id, // 课程记录ID
pbId: pbData.id, // 排班ID - 确保使用正确的排班ID
xclx: pbData.xclx,
xcbt: pbData.xcbt,
xqmc: pbData.xqmc,
// 确保传递年级和班级ID
njId: xkkc.njId || '',
njmcId: xkkc.njmcId || '',
bjId: xkkc.bjId || ''
};
// 使用不同的存储键来避免覆盖排班数据
dataStore.setData(combinedData); // 存储课程数据
// 确保保存到global的是原始排班数据而不是课程数据
// 从combinedData中提取排班相关字段
const originalPbData = {
id: pbData.id, // 排班ID
status: pbData.status,
njIds: pbData.njIds,
bjIds: pbData.bjIds,
xcbt: pbData.xcbt,
xclx: pbData.xclx,
xqId: pbData.xqId,
xqmc: pbData.xqmc,
xcstime: pbData.xcstime,
xcjstime: pbData.xcjstime,
pk: pbData.pk
};
dataStore.setGlobal(originalPbData); // 保存原始排班数据到global
uni.navigateTo({
url: `/pages/view/routine/kefuxuncha/kyXkkcDetail`,
});
};
// 跳转到巡查记录
const goRecord = (xkkc: any) => {
// 直接从global获取排班数据
const pbData = dataStore.getGlobal;
// 检查排班数据是否有效
if (!pbData || !pbData.xcbt || !pbData.xcbt.includes('课业辅导巡计划')) {
uni.showToast({
title: '数据异常,请重新选择排班',
icon: 'none'
});
return;
}
// 合并排班数据和课程数据
const combinedData = {
...xkkc,
id: xkkc.id, // 课程记录ID
pbId: pbData.id, // 排班ID - 确保使用正确的排班ID
xclx: pbData.xclx,
xcbt: pbData.xcbt,
xqmc: pbData.xqmc,
// 确保传递年级和班级ID
njId: xkkc.njId || '',
njmcId: xkkc.njmcId || '',
bjId: xkkc.bjId || ''
};
dataStore.setData(combinedData);
uni.navigateTo({
url: `/pages/view/routine/kefuxuncha/xcRecord`,
});
};
// 页面卸载前清除定时器
onBeforeUnmount(() => {});
</script>
<style lang="scss" scoped>
.interest-course {
min-height: 100%;
background: linear-gradient(180deg, #f8fafc 0%, #f1f5f9 100%);
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
.selection-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 25px 20px;
color: #fff;
border-radius: 0 0 20px 20px;
box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);
position: sticky;
top: 0;
left: 0;
right: 0;
z-index: 10;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1) 0%, transparent 50%, rgba(255, 255, 255, 0.05) 100%);
pointer-events: none;
}
.header-content {
display: flex;
flex-direction: column;
gap: 15px;
position: relative;
z-index: 1;
.title-section {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
.title {
font-size: 20px;
font-weight: 700;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
letter-spacing: 0.5px;
}
.switch-btn {
padding: 8px 16px;
background-color: rgba(255, 255, 255, 0.2);
color: #fff;
border-radius: 20px;
font-size: 14px;
font-weight: 500;
transition: all 0.3s ease;
&:hover {
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(-1px);
}
}
}
}
}
// 可滚动内容区域样式
.scrollable-content {
flex: 1;
overflow-y: auto;
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
}
.course-list {
padding: 15px 15px 0 15px;
.course-item {
position: relative;
width: 100%;
margin-bottom: 20px;
background-color: #fff;
border-radius: 12px;
padding: 20px;
box-sizing: border-box;
border: 1px solid #f0f0f0;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
animation: fadeInUp 0.6s ease-out;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
border-color: #e8e8e8;
}
&.selected {
border: 2px solid #3fbf72;
background-color: rgba(63, 191, 114, 0.02);
box-shadow: 0 4px 20px rgba(63, 191, 114, 0.15);
}
.course-name {
font-size: 17px;
font-weight: 600;
color: #1a1a1a;
margin-bottom: 15px;
line-height: 1.4;
animation: fadeInLeft 0.5s ease-out 0.1s both;
}
.course-btn-group {
display: flex;
justify-content: flex-end;
gap: 10px; // Added gap for spacing between buttons
.xc-btn {
display: inline-block;
color: #ff6b35;
font-size: 14px;
font-weight: 600;
padding: 8px 18px;
border-radius: 8px;
background: linear-gradient(135deg, rgba(255, 107, 53, 0.1), rgba(255, 107, 53, 0.05));
border: 1px solid #ff6b35;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.15);
animation: fadeInUp 0.5s ease-out 0.3s both;
&:hover {
background: linear-gradient(135deg, rgba(255, 107, 53, 0.15), rgba(255, 107, 53, 0.1));
transform: translateY(-1px);
box-shadow: 0 4px 15px rgba(255, 107, 53, 0.25);
}
&:active {
background: linear-gradient(135deg, rgba(255, 107, 53, 0.2), rgba(255, 107, 53, 0.15));
transform: translateY(0);
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.2);
}
}
.record-btn {
display: inline-block;
color: #409EFF;
font-size: 14px;
font-weight: 600;
padding: 8px 18px;
border-radius: 8px;
background: linear-gradient(135deg, rgba(64, 158, 255, 0.1), rgba(64, 158, 255, 0.05));
border: 1px solid #409EFF;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
animation: fadeInUp 0.5s ease-out 0.3s both;
&:hover {
background: linear-gradient(135deg, rgba(64, 158, 255, 0.15), rgba(64, 158, 255, 0.1));
transform: translateY(-1px);
box-shadow: 0 4px 15px rgba(64, 158, 255, 0.25);
}
&:active {
background: linear-gradient(135deg, rgba(64, 158, 255, 0.2), rgba(64, 158, 255, 0.15));
transform: translateY(0);
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
}
}
}
.course-info-item {
display: flex;
margin-bottom: 14px;
font-size: 13px;
align-items: center;
animation: fadeInUp 0.5s ease-out 0.15s both;
.info-label {
color: #666;
flex: 0 0 100px;
font-weight: 500;
}
.info-data {
flex: 1 0 1px;
color: #333;
font-weight: 400;
}
}
.separator-line {
height: 1px;
background: linear-gradient(90deg, transparent, #e8e8e8, transparent);
margin: 18px 0;
opacity: 0.8;
animation: fadeIn 0.5s ease-out 0.25s both;
}
}
}
// 添加动画关键帧
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInLeft {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes fadeInRight {
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/* 全局图片样式 */
.w-full {
width: 100%;
}
.h-full {
height: 100%;
}
// 暂无数据样式
.empty-course-list {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80px 20px;
text-align: center;
.empty-icon {
margin-bottom: 25px;
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
width: 90px;
height: 90px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
border: 2px solid rgba(255, 255, 255, 0.8);
}
.empty-text {
font-size: 18px;
font-weight: 600;
color: #475569;
margin-bottom: 8px;
letter-spacing: 0.3px;
}
.empty-desc {
font-size: 14px;
color: #64748b;
max-width: 80%;
line-height: 1.6;
}
}
/* 选课选择弹窗样式 */
.xk-selector {
background-color: #ffffff;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
padding-bottom: 20px;
.selector-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
border-bottom: 1px solid #f2f2f2;
.selector-title {
font-size: 16px;
font-weight: 500;
color: #303133;
}
}
.xk-list {
padding: 0 15px;
.xk-item {
display: flex;
align-items: center;
padding: 15px 0;
border-bottom: 1px solid #f2f2f2;
transition: all 0.3s ease;
&:last-child {
border-bottom: none;
}
&-active {
background-color: rgba(64, 158, 255, 0.05);
}
&:hover {
background-color: rgba(64, 158, 255, 0.02);
}
.xk-info {
flex: 1;
margin-left: 12px;
.xk-name {
font-size: 15px;
font-weight: 500;
color: #303133;
margin-bottom: 4px;
}
.xk-type {
font-size: 13px;
color: #303133;
margin-bottom: 4px;
}
.xk-class {
font-size: 13px;
color: #606266;
}
}
}
}
}
</style>