880 lines
24 KiB
Vue
880 lines
24 KiB
Vue
<template>
|
||
<div class="course-list-page">
|
||
<h2 class="page-title">我添加的课程</h2>
|
||
|
||
<!-- 加载状态 -->
|
||
<div v-if="!isLoaded" class="loading-message">
|
||
加载中,请稍后...
|
||
</div>
|
||
|
||
<!-- 无课程记录时的提示 -->
|
||
<div v-else-if="submissions.length === 0" class="empty-message">
|
||
您还没有添加任何课程。
|
||
</div>
|
||
|
||
<!-- 课程卡片列表 -->
|
||
<div v-else class="course-cards">
|
||
<div v-for="submission in paginatedSubmissions" :key="submission.submit_id" class="course-card" @click="handleCardClick(submission)">
|
||
<div class="card-header">
|
||
<h3 class="course-name-title">{{ submission.course_name }}</h3>
|
||
<div class="status-tag" :class="getStatusClass(submission.status)">
|
||
{{ submission.status }}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card-body">
|
||
<div class="info-row">
|
||
<span class="info-label">分类</span>
|
||
<span class="info-val">{{ getCategoryName(submission.category_id) }}</span>
|
||
</div>
|
||
<div class="info-row">
|
||
<span class="info-label">教师</span>
|
||
<span class="info-val truncate">{{ submission.teachers }}</span>
|
||
</div>
|
||
<div class="info-row">
|
||
<span class="info-label">院系</span>
|
||
<span class="info-val truncate">{{ getCollegeName(submission.college) }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card-footer">
|
||
<div class="time-info">
|
||
<div class="time-row">
|
||
<span class="time-label">提交:</span>
|
||
<span class="time-val">{{ formatTimeShort(submission.create_time) }}</span>
|
||
</div>
|
||
<div class="time-row">
|
||
<span class="time-label">更新:</span>
|
||
<span class="time-val">{{ formatTimeShort(submission.status_update_time) }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 页码栏 -->
|
||
<div class="pagination-bar" v-if="totalPages > 1">
|
||
<button @click="goToPage(1)" :class="{ active: currentPage === 1 }" :disabled="currentPage === 1">首页</button>
|
||
|
||
<button
|
||
v-for="page in getPaginationPages()"
|
||
:key="page"
|
||
@click="goToPage(page)"
|
||
:class="{ active: currentPage === page }"
|
||
>
|
||
{{ page }}
|
||
</button>
|
||
|
||
<button
|
||
@click="goToPage(totalPages)"
|
||
:class="{ active: currentPage === totalPages }"
|
||
:disabled="currentPage === totalPages"
|
||
>
|
||
尾页
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 添加课程区域 -->
|
||
<div class="add-course-section card-style">
|
||
<div class="section-header">
|
||
<h2>我要添加课程</h2>
|
||
<button class="help-btn" @click="showHelp = true">
|
||
<span class="help-icon">?</span>
|
||
帮助
|
||
</button>
|
||
</div>
|
||
|
||
<div class="input-grid">
|
||
<div class="input-group">
|
||
<label>课程名称</label>
|
||
<input v-model="newCourseName" type="text" placeholder="请输入课程名称" class="modern-input" />
|
||
</div>
|
||
|
||
<div class="input-group">
|
||
<label>课程类别</label>
|
||
<select v-model="newCategoryId" class="modern-select">
|
||
<option value="" disabled>请选择课程类别</option>
|
||
<option value="1">选修课-通识选修类</option>
|
||
<option value="2">选修课-人文选修类</option>
|
||
<option value="3">选修课-专业方向类</option>
|
||
<option value="4">选修课-体育类</option>
|
||
<option value="5">选修课-学科基础类</option>
|
||
<option value="6">选修课-暑期国际课</option>
|
||
<option value="7">选修课-数学与自然科学类</option>
|
||
<option value="8">选修课-重修专栏</option>
|
||
<option value="9">必修课-数学与自然科学类</option>
|
||
<option value="10">必修课-人文社会科学类</option>
|
||
<option value="11">必修课-学科基础类</option>
|
||
<option value="12">必修课-学科基础类</option>
|
||
<option value="13">必修课-实践类</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="input-group">
|
||
<label>开课院系</label>
|
||
<select v-model="newCollege" class="modern-select">
|
||
<option value="" disabled>请选择开课院系</option>
|
||
<option v-for="(name, id) in filteredColleges" :key="id" :value="id">
|
||
{{ name }}
|
||
</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="input-group">
|
||
<label>任课教师</label>
|
||
<input v-model="newTeachers" type="text" placeholder="多个教师用英文逗号隔开,如A,B" class="modern-input" />
|
||
</div>
|
||
|
||
<div class="button-group">
|
||
<button @click="submitCourse" class="submit-btn">提交课程</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 添加帮助模态框 -->
|
||
<div v-if="showHelp" class="help-modal">
|
||
<div class="help-modal-content">
|
||
<div class="help-modal-header">
|
||
<h3>关于本系统课程信息的说明</h3>
|
||
<button class="close-btn" @click="showHelp = false">×</button>
|
||
</div>
|
||
<div class="help-modal-body">
|
||
<h3>一些说明</h3>
|
||
<div class="help-section">
|
||
<p>
|
||
<strong>本系统中,课程分为两大类:选修课和必修课。</strong>选修课有8个小类:通识选修、人文选修、专业方向、体育、学科基础、暑期国际课、数学与自然科学、重修专栏。<strong>人文选修类包括采用“抢选”方式进行选课的所有选修课,以及“改革开放史”和“社会主义发展史”两门人文社会科学类的选修课。</strong>体育课单独作为一类,不属于人文选修类。<strong>重修课程的选课归为选修课的“重修专栏”类别,不属于必修课范畴。</strong>重修专栏可以分享<strong>任何类别课程</strong>,但<strong>仅限分享重修体验</strong>。
|
||
</p>
|
||
<p>
|
||
必修课有5个小类:数学与自然科学、人文社会科学、学科基础、专业方向、实践。<strong>如上所述,本系统中重修的必修课程也属于选修课范畴。</strong>特别说明:<strong>军训课程属于实践类,系辅导员给分,在创建课程时课程教师请填写辅导员。</strong>
|
||
</p>
|
||
<p>
|
||
在创建课程时,请先了解课程的类别,以及课程的<strong>开课院系(详见下文)</strong>。<strong>如果同一课程的任课教师不同,用户可以创建多个同名课程,例如“A老师-篮球”和“B老师-篮球”将被视为两个不同的课程。</strong>创建的课程卡片<strong>需经过管理员审核</strong>,审核进度可在“我的课程”中实时查看。
|
||
</p>
|
||
</div>
|
||
|
||
<h3>如何查看课程类别和开课院系?</h3>
|
||
<div class="help-section">
|
||
<h4>1. 本人课程</h4>
|
||
<p>在教务系统选择“我的考试”,选择对应的学期后,即可查看当前学期的课程类别和开课院系。</p>
|
||
<img src="https://download.东北大学.com/course_system/coursehelp.png" width="98%">
|
||
</div>
|
||
<div class="help-section">
|
||
<h4>2. 非本人课程</h4>
|
||
<p>在教务系统选择“公共课表查询”,课表类型选择“班级课表”,再选好要查询的学期,并填写要查询的班级名称,点击查询按钮。</p>
|
||
<img src="https://download.东北大学.com/course_system/other1.png" width="98%">
|
||
<p>进入班级课表后,即可对应课程的开课院系。然后记下老师的姓名。</p>
|
||
<img src="https://download.东北大学.com/course_system/other2.png" width="98%">
|
||
<p>然后回到公共课表查询页面,课表类型选择“教师课表”,同样选好要查询的学期,并填写要查询的教师姓名,点击查询按钮。</p>
|
||
<img src="https://download.东北大学.com/course_system/other3.png" width="98%">
|
||
<p>进入教师课表后,找到此课程,即可查看课程类别。</p>
|
||
<img src="https://download.东北大学.com/course_system/other4.png" width="98%">
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
components: {
|
||
},
|
||
data() {
|
||
return {
|
||
submissions: [], // 存储用户提交的课程数据
|
||
newCourseName: '', // 新提交的课程名
|
||
newCategoryId: '', // 新提交的课程分类
|
||
newTeachers: '', // 新提交的任课教师
|
||
newCollege: '', // 新提交的课程院系,默认空字符串
|
||
currentPage: 1, // 当前页
|
||
itemsPerPage: 10, // 每页显示的条目数
|
||
totalPages: 1, // 总页数
|
||
isLoaded: false, // 控制页面加载状态
|
||
cachedEmail: null, // 缓存的邮箱信息
|
||
showHelp: false, // 添加这一行来控制帮助模态框的显示
|
||
maxVisiblePages: 10, // 最大显示页码数
|
||
collegeMap: {
|
||
59: '未填写',
|
||
1: '材料科学与工程学院',
|
||
2: '创新创业学院',
|
||
3: '档案馆',
|
||
4: '党委宣传部',
|
||
5: '党委组织部',
|
||
6: '发展规划与学科建设处',
|
||
7: '佛山研究生创新学院',
|
||
8: '工程训练中心',
|
||
9: '工会',
|
||
10: '工商管理学院',
|
||
11: '国防教育学院',
|
||
12: '国际教育学院',
|
||
13: '后勤服务中心',
|
||
14: '后勤管理处',
|
||
15: '浑南管委会',
|
||
16: '江河建筑学院',
|
||
17: '尖子班',
|
||
18: '教务处',
|
||
19: '基础学院',
|
||
20: '计划财经处',
|
||
21: '机器人科学与工程学院',
|
||
22: '计算机科学与工程学院',
|
||
23: '计算中心',
|
||
24: '纪委',
|
||
25: '机械工程与自动化学院',
|
||
26: '继续教育学院',
|
||
27: '科技产业集团',
|
||
28: '科学技术研究院',
|
||
29: '理学院',
|
||
30: '马克思主义学院',
|
||
31: '民族教育学院',
|
||
33: '人事处',
|
||
34: '人文选修课群',
|
||
35: '软件学院',
|
||
36: '生命科学与健康学院',
|
||
37: '体育部',
|
||
38: '体育场馆管理中心',
|
||
39: '团委',
|
||
40: '图书馆',
|
||
41: '外国语学院',
|
||
42: '外联处',
|
||
43: '网络教育学院',
|
||
44: '未来技术学院',
|
||
45: '文法学院',
|
||
46: '校长办公室',
|
||
47: '信息科学与工程学院',
|
||
48: '新知识课群',
|
||
49: '学生处',
|
||
50: '学生创新中心',
|
||
51: '学生指导服务中心',
|
||
52: '研究生院',
|
||
53: '冶金学院',
|
||
54: '艺术学院',
|
||
55: '医学与生物信息工程学院',
|
||
56: '医院',
|
||
57: '资产与实验室管理处',
|
||
58: '资源与土木工程学院'
|
||
}
|
||
};
|
||
},
|
||
computed: {
|
||
// 计算当前页展示的投稿数据
|
||
paginatedSubmissions() {
|
||
const start = (this.currentPage - 1) * this.itemsPerPage;
|
||
const end = start + this.itemsPerPage;
|
||
return this.submissions.slice(start, end);
|
||
},
|
||
|
||
// 过滤掉 "不限院系" 的选项
|
||
filteredColleges() {
|
||
return Object.fromEntries(Object.entries(this.collegeMap).filter(([id]) => id !== '59'));
|
||
}
|
||
},
|
||
mounted() {
|
||
this.checkMobile();
|
||
window.addEventListener('resize', this.checkMobile);
|
||
|
||
// 页面加载时,延迟0.3秒加载数据
|
||
setTimeout(async () => {
|
||
this.isLoaded = true;
|
||
// 获取投稿记录
|
||
this.fetchSubmissions();
|
||
}, 300);
|
||
|
||
// 检查 URL 参数,如果 m=true 则打开帮助模态框
|
||
if (this.$route.query.m === 'true') {
|
||
this.showHelp = true;
|
||
}
|
||
|
||
// 处理 query.c 参数跳转 (保留逻辑但改为直接跳转)
|
||
const encodedParam = this.$route.query.c;
|
||
if (encodedParam) {
|
||
try {
|
||
const decodedString = atob(encodedParam);
|
||
if (this.isPositiveInteger(decodedString)) {
|
||
this.$router.push(`/detail/${decodedString}`);
|
||
}
|
||
} catch (error) {
|
||
// ignore error
|
||
}
|
||
}
|
||
},
|
||
beforeUnmount() {
|
||
window.removeEventListener('resize', this.checkMobile);
|
||
},
|
||
methods: {
|
||
checkMobile() {
|
||
this.maxVisiblePages = window.innerWidth <= 768 ? 5 : 10;
|
||
},
|
||
|
||
// 检查是否为正整数
|
||
isPositiveInteger(value) {
|
||
const num = Number(value);
|
||
return Number.isInteger(num) && num > 0;
|
||
},
|
||
|
||
// 获取用户投稿
|
||
async fetchSubmissions() {
|
||
const token = this.getCookie('token');
|
||
if (!token) {
|
||
// alert('无法获取JWT,请重新登录。');
|
||
// 用户体验优化:如果只是查看,可能不需要alert,但这里是"我添加的课程",必须登录
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`https://coursesystem.xn--xhq44jb2fzpc.com/user/user-submissions`, {
|
||
method: 'GET',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': token
|
||
}
|
||
});
|
||
|
||
if (response.status !== 200) {
|
||
const result = await response.json();
|
||
alert(result.error || '查询投稿记录失败');
|
||
return;
|
||
}
|
||
|
||
const result = await response.json();
|
||
this.submissions = result;
|
||
this.totalPages = Math.ceil(this.submissions.length / this.itemsPerPage);
|
||
} catch (e) {
|
||
console.error("Fetch submissions error", e);
|
||
}
|
||
},
|
||
|
||
getCookie(name) {
|
||
const cookies = document.cookie.split(';');
|
||
for (let cookie of cookies) {
|
||
const [key, value] = cookie.trim().split('=');
|
||
if (key === name) {
|
||
return value;
|
||
}
|
||
}
|
||
return null;
|
||
},
|
||
|
||
goToPage(page) {
|
||
if (page < 1 || page > this.totalPages) return;
|
||
this.currentPage = page;
|
||
},
|
||
|
||
getPaginationPages() {
|
||
const pages = [];
|
||
const total = this.totalPages;
|
||
const current = this.currentPage;
|
||
const maxVisible = this.maxVisiblePages;
|
||
|
||
if (total <= maxVisible) {
|
||
for (let i = 1; i <= total; i++) {
|
||
pages.push(i);
|
||
}
|
||
} else {
|
||
let startPage = current - Math.floor(maxVisible / 2);
|
||
startPage = Math.max(startPage, 1);
|
||
let endPage = startPage + maxVisible - 1;
|
||
|
||
if (endPage > total) {
|
||
endPage = total;
|
||
startPage = Math.max(endPage - maxVisible + 1, 1);
|
||
}
|
||
|
||
for (let i = startPage; i <= endPage; i++) {
|
||
pages.push(i);
|
||
}
|
||
}
|
||
return pages;
|
||
},
|
||
|
||
// 提交新课程
|
||
async submitCourse() {
|
||
if (!this.newCourseName || !this.newCategoryId || !this.newTeachers || !this.newCollege) {
|
||
alert('请填写所有字段后提交!');
|
||
return;
|
||
}
|
||
|
||
if (confirm('确认提交审核吗?')) {
|
||
const token = this.getCookie('token');
|
||
if (!token) {
|
||
alert('无法获取JWT,请重新登录。');
|
||
return;
|
||
}
|
||
|
||
const newSubmission = {
|
||
course_name: this.newCourseName,
|
||
category_id: this.newCategoryId,
|
||
teachers: this.newTeachers,
|
||
college: this.newCollege
|
||
};
|
||
|
||
await fetch('https://coursesystem.xn--xhq44jb2fzpc.com/user/submit-course', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': token
|
||
},
|
||
body: JSON.stringify(newSubmission)
|
||
});
|
||
|
||
// 清空输入框并重新加载投稿记录
|
||
this.newCourseName = '';
|
||
this.newCategoryId = '';
|
||
this.newTeachers = '';
|
||
this.newCollege = '';
|
||
this.fetchSubmissions();
|
||
}
|
||
},
|
||
|
||
getCategoryName(categoryId) {
|
||
const categoryMap = {
|
||
1: '选修课-通识选修类',
|
||
2: '选修课-人文选修类',
|
||
3: '选修课-专业方向类',
|
||
4: '选修课-体育类',
|
||
5: '选修课-学科基础类',
|
||
6: '选修课-暑期国际课',
|
||
7: '选修课-数学与自然科学类',
|
||
8: '选修课-重修专栏',
|
||
9: '必修课-数学与自然科学类',
|
||
10: '必修课-人文社会科学类',
|
||
11: '必修课-学科基础类',
|
||
12: '必修课-学科基础类',
|
||
13: '必修课-实践类'
|
||
};
|
||
return categoryMap[categoryId] || '未知分类';
|
||
},
|
||
|
||
formatTime(time) {
|
||
const date = new Date(time);
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
const hours = String(date.getHours()).padStart(2, '0');
|
||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||
},
|
||
|
||
formatTimeShort(time) {
|
||
if (!time) return '-';
|
||
const date = new Date(time);
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
return `${month}-${day}`;
|
||
},
|
||
|
||
handleCardClick(submission) {
|
||
// 如果 course_id 为 0,说明还在审核中或者没有关联到正式课程,暂时不可点击或点击无反应
|
||
if (submission.course_id === 0) {
|
||
return;
|
||
}
|
||
this.$router.push(`/detail/${submission.course_id}`);
|
||
},
|
||
|
||
getStatusClass(status) {
|
||
if (status === '已通过') return 'status-approved';
|
||
if (status === '待审核') return 'status-pending';
|
||
if (status === '已拒绝') return 'status-rejected';
|
||
return '';
|
||
},
|
||
|
||
getCollegeName(collegeId) {
|
||
return this.collegeMap[collegeId] || '未知院系';
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.course-list-page {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 20px;
|
||
min-height: 100vh;
|
||
background-color: #f8f9fa;
|
||
}
|
||
|
||
.page-title {
|
||
margin-bottom: 20px;
|
||
font-size: 24px;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.loading-message, .empty-message {
|
||
font-size: 16px;
|
||
color: #666;
|
||
text-align: center;
|
||
margin-top: 40px;
|
||
}
|
||
|
||
/* Course Cards Grid */
|
||
.course-cards {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 20px;
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.course-card {
|
||
background: white;
|
||
border-radius: 12px;
|
||
border: 1px solid #f0f0f0;
|
||
overflow: hidden;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
position: relative;
|
||
}
|
||
|
||
.course-card:hover {
|
||
transform: translateY(-5px);
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
|
||
border-color: #e0e0e0;
|
||
}
|
||
|
||
.card-header {
|
||
padding: 16px;
|
||
border-bottom: 1px solid #f9f9f9;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
gap: 10px;
|
||
}
|
||
|
||
.course-name-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin: 0;
|
||
line-height: 1.4;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
flex: 1;
|
||
}
|
||
|
||
.status-tag {
|
||
font-size: 12px;
|
||
padding: 2px 8px;
|
||
border-radius: 10px;
|
||
white-space: nowrap;
|
||
background: #eee;
|
||
color: #666;
|
||
}
|
||
|
||
.status-approved {
|
||
background: #e6f7ff;
|
||
color: #1890ff;
|
||
border: 1px solid #91d5ff;
|
||
}
|
||
|
||
.status-pending {
|
||
background: #fffbe6;
|
||
color: #faad14;
|
||
border: 1px solid #ffe58f;
|
||
}
|
||
|
||
.status-rejected {
|
||
background: #fff1f0;
|
||
color: #f5222d;
|
||
border: 1px solid #ffa39e;
|
||
}
|
||
|
||
.card-body {
|
||
padding: 16px;
|
||
flex: 1;
|
||
}
|
||
|
||
.info-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 8px;
|
||
font-size: 13px;
|
||
color: #666;
|
||
}
|
||
|
||
.info-label {
|
||
color: #999;
|
||
margin-right: 8px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.info-val {
|
||
text-align: right;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.truncate {
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
max-width: 70%;
|
||
}
|
||
|
||
.card-footer {
|
||
padding: 12px 16px;
|
||
background: #fafafa;
|
||
border-top: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.time-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
|
||
.time-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 12px;
|
||
color: #999;
|
||
}
|
||
|
||
/* Pagination */
|
||
.pagination-bar {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
margin-bottom: 40px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.pagination-bar button {
|
||
min-width: 36px;
|
||
height: 36px;
|
||
padding: 0 10px;
|
||
border: 1px solid #e0e0e0;
|
||
background: white;
|
||
color: #606266;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.pagination-bar button:hover:not(:disabled) {
|
||
color: #409eff;
|
||
border-color: #409eff;
|
||
}
|
||
|
||
.pagination-bar button.active {
|
||
background-color: #409eff;
|
||
border-color: #409eff;
|
||
color: white;
|
||
}
|
||
|
||
.pagination-bar button:disabled {
|
||
background: #f5f7fa;
|
||
color: #c0c4cc;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
/* Add Course Section */
|
||
.add-course-section {
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 24px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||
margin-top: 40px;
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.section-header h2 {
|
||
margin: 0;
|
||
font-size: 20px;
|
||
color: #333;
|
||
}
|
||
|
||
.help-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
padding: 5px 10px;
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
color: #495057;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.help-btn:hover {
|
||
background: #e9ecef;
|
||
}
|
||
|
||
.help-icon {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 50%;
|
||
background: #6c757d;
|
||
color: white;
|
||
font-size: 12px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.input-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 30px;
|
||
}
|
||
|
||
.input-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
|
||
.input-group label {
|
||
font-size: 14px;
|
||
color: #606266;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.modern-input, .modern-select {
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
padding: 10px;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 8px;
|
||
font-size: 14px;
|
||
transition: all 0.3s;
|
||
background: white;
|
||
}
|
||
|
||
.modern-input:focus, .modern-select:focus {
|
||
border-color: #409eff;
|
||
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
||
outline: none;
|
||
}
|
||
|
||
.button-group {
|
||
grid-column: 1 / -1;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.submit-btn {
|
||
padding: 10px 30px;
|
||
background-color: #409eff;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 8px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.submit-btn:hover {
|
||
background-color: #66b1ff;
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
/* Help Modal */
|
||
.help-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.help-modal-content {
|
||
background: white;
|
||
border-radius: 12px;
|
||
width: 90%;
|
||
max-width: 600px;
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
padding: 20px;
|
||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.help-modal-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
padding-bottom: 10px;
|
||
border-bottom: 1px solid #dee2e6;
|
||
}
|
||
|
||
.close-btn {
|
||
background: none;
|
||
border: none;
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
color: #6c757d;
|
||
}
|
||
|
||
.help-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.help-modal-header h3 {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
margin: 0;
|
||
}
|
||
|
||
.help-section h4 {
|
||
color: #0056b3;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.help-section p {
|
||
color: #495057;
|
||
line-height: 1.6;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
/* Responsive */
|
||
@media (max-width: 768px) {
|
||
.course-cards {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 12px;
|
||
}
|
||
|
||
.input-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.course-name-title {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.status-tag {
|
||
font-size: 10px;
|
||
padding: 1px 5px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
.course-cards {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
</style>
|
||
|