This commit is contained in:
CakeCN
2025-12-29 20:52:54 +08:00
8 changed files with 181 additions and 31 deletions

View File

@@ -60,6 +60,7 @@
border-radius: 8px; border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
cursor: pointer; cursor: pointer;
position: relative; /* 添加相对定位 */
} }
.course-image { .course-image {
@@ -81,6 +82,27 @@
.course-description { .course-description {
font-size: 14px; font-size: 14px;
color: #555; color: #555;
margin-bottom: 10px;
display: -webkit-box; /* 使用-webkit-box实现文本截断 */
-webkit-line-clamp: 3; /* 限制显示3行 */
-webkit-box-orient: vertical; /* 垂直排列 */
overflow: hidden; /* 隐藏溢出内容 */
text-overflow: ellipsis; /* 用省略号表示截断 */
}
/* 课程日期信息 */
.course-date {
position: absolute; /* 绝对定位到底部 */
bottom: 10px; /* 距离底部10px */
left: 0; /* 左对齐 */
right: 0; /* 右对齐 */
padding: 10px; /* 内边距 */
background-color: white; /* 白色背景 */
border-radius: 5px; /* 圆角 */
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影 */
font-size: 12px; /* 字体大小 */
color: #666; /* 字体颜色 */
line-height: 1.5; /* 行高 */
} }
/* 课程目录弹出框 */ /* 课程目录弹出框 */
@@ -159,11 +181,14 @@
/* 浮窗内容 */ /* 浮窗内容 */
.modal-content { .modal-content {
background-color: #fff; background-color: #fff;
margin: 15% auto; margin: 10% auto; /* 修改为10%以缩小顶部距离 */
padding: 20px; padding: 20px;
border-radius: 10px; border-radius: 10px;
width: 40%; width: 80%; /* 修改为80%以适应小屏幕 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); max-width: 600px; /* 设置最大宽度 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0 1);
overflow-y: auto; /* 添加垂直滚动条 */
max-height: 80vh; /* 设置最大高度 */
} }
/* 按钮样式 */ /* 按钮样式 */
@@ -205,7 +230,34 @@ label {
margin-top: 20px; /* 上方间距 */ margin-top: 20px; /* 上方间距 */
} }
/* 选择课程或新建课程的下拉框 */
.course-selection-container {
margin: 10px 0;
font-size: 16px;
}
#course-selection {
width: 100%; /* 占满一行 */
padding: 12px; /* 增加内边距 */
font-size: 16px; /* 调整字体大小 */
margin: 10px 0; /* 上下留间距 */
border: 2px solid #ccc; /* 边框 */
border-radius: 8px; /* 圆角边框 */
background-color: #f9f9f9; /* 背景色 */
transition: border 0.3s ease, box-shadow 0.3s ease; /* 添加过渡效果 */
}
/* 鼠标悬停时下拉框的效果 */
#course-selection:hover {
border-color: #4CAF50; /* 悬停时的边框颜色 */
box-shadow: 0 0 10px rgba(76, 175, 80, 0.5); /* 悬停时的阴影效果 */
}
/* 下拉框选中项的样式 */
#course-selection option {
padding: 10px;
font-size: 16px;
}
/* 添加课程按钮样式 */ /* 添加课程按钮样式 */
.add-course-button { .add-course-button {
@@ -433,6 +485,20 @@ label[for="course-description"] {
cursor: pointer; cursor: pointer;
} }
.delete-course-btn {
background-color: #e74c3c;
color: white;
padding: 10px;
border-radius: 5px;
cursor: pointer;
width: 100%;
margin-top: 10px;
}
.delete-course-btn:hover {
background-color: #c0392b;
}
/* 编辑弹窗 */ /* 编辑弹窗 */
.edit-modal { .edit-modal {
display: none; display: none;

View File

@@ -292,13 +292,50 @@ function closeAddCourseModal() {
document.getElementById('add-course-modal').style.display = 'none'; document.getElementById('add-course-modal').style.display = 'none';
} }
// 显示删除课程确认弹窗
function showDeleteCourseConfirmation() {
if (!material_id) {
alert('无法删除课程未找到课程ID');
return;
}
if (confirm('确定要删除这个课程吗?此操作无法撤销!')) {
deleteCourse(material_id);
}
}
// 删除课程
function deleteCourse(courseId) {
fetch(`/materials/${courseId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.message) {
alert(data.message);
if (data.success) {
// 关闭侧边栏并刷新页面
closeCourseDetails();
location.reload();
}
}
})
.catch(error => {
console.error('删除课程时出错:', error);
alert('删除课程失败,请稍后再试!');
});
}
function onTeacherboardPageLoad(){ function onTeacherboardPageLoad(){
// 提交表单处理 // 提交表单处理
document.getElementById('add-course-form').addEventListener('submit', function(event) { document.getElementById('add-course-form').addEventListener('submit', function(event) {
event.preventDefault(); event.preventDefault();
const courseName = document.getElementById('course-name').value; const courseName = document.getElementById('course-name').value;
const courseSelection = document.getElementById('course-selection').value; const courseSelection = document.getElementById('course-selection').value; // 获取选择值
const coverImage = document.getElementById('cover-preview').src; const coverImage = document.getElementById('cover-preview').src;
const courseDescription = document.getElementById('course-description').value; const courseDescription = document.getElementById('course-description').value;
// 构建发送的数据 // 构建发送的数据
@@ -312,7 +349,7 @@ document.getElementById('add-course-form').addEventListener('submit', function(e
// 如果选择了已有课程,可以通过 courseSelection 传递课程ID根据需要修改 // 如果选择了已有课程,可以通过 courseSelection 传递课程ID根据需要修改
if (courseSelection !== 'new') { if (courseSelection !== 'new') {
// 如果是修改已有课程,设置相关的章节信息或其他数据 // 如果是修改已有课程,设置相关的章节信息或其他数据
data.chapters = ["Chapter 1", "Chapter 2"]; // 示例章节信息 data.chapters = ["Chapter 1", "Chapter 2"];
} }
// 发送 POST 请求到 /create_material // 发送 POST 请求到 /create_material

View File

@@ -46,7 +46,7 @@
</div> </div>
</div> </div>
</div> </div>
{% include 'foot.html' %} {% include 'footer-brief.html' %}
</body> </body>
<script> <script>
var course_id = "{{course_id}}"; var course_id = "{{course_id}}";

View File

@@ -13,7 +13,6 @@
</head> </head>
<body> <body>
{% include 'navbar.html' %} <!-- 引入navbar.html --> {% include 'navbar.html' %} <!-- 引入navbar.html -->
{% include 'learning-path.html' %} <!-- 引入learning-path.html -->
<section class="search-section"> <section class="search-section">
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
@@ -81,7 +80,7 @@
</div> </div>
</div> </div>
{% include 'foot.html' %} {% include 'footer-brief.html' %}
<script src="/static/js/dashboard.js"></script> <script src="/static/js/dashboard.js"></script>
<script> <script>

View File

@@ -0,0 +1,11 @@
<link rel="stylesheet" href="/static/css/footer.css">
<footer class="hs-footer">
<div class="footer-main">
<div class="footer-bottom">
<div class="footer-bottom-right">
<span>© 2025 华实学伴. 保留所有权利</span>
<a href="https://beian.miit.gov.cn" target="_blank">沪ICP备2025142149号</a>
</div>
</div>
</footer>

View File

@@ -80,7 +80,7 @@
</main> </main>
{% include 'foot.html' %} {% include 'footer-brief.html' %}
</body> </body>
<script> <script>
window.appData = { window.appData = {

View File

@@ -65,7 +65,7 @@
</div> </div>
</ul> </ul>
<button class="add-chapter-btn" onclick="showInputForNewChapter()">新增章节</button> <button class="add-chapter-btn" onclick="showInputForNewChapter()">新增章节</button>
<button class="delete-course-btn" onclick="showDeleteCourseConfirmation()">删除课程</button>
</div> </div>
<!-- 编辑章节或课时弹窗 --> <!-- 编辑章节或课时弹窗 -->
@@ -100,8 +100,8 @@
<label for="course-selection">从课程创建或新建课程:</label> <label for="course-selection">从课程创建或新建课程:</label>
<select id="course-selection"> <select id="course-selection">
<option value="new">新建课程</option> <option value="new">新建课程</option>
{% for course in courses %} {% for course in materials %}
<option value="{{ course.id }}">{{ course.name }}</option> <option value="{{ course._id }}">{{ course.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
<br><br> <br><br>
@@ -121,6 +121,6 @@
<script src="/static/js/course_current.js"></script> <script src="/static/js/course_current.js"></script>
<script src="/static/js/teacherboard.js"></script> <script src="/static/js/teacherboard.js"></script>
<script src="/static/js/teacher_course_setting.js"></script> <script src="/static/js/teacher_course_setting.js"></script>
{% include 'foot.html' %} {% include 'footer-brief.html' %}
</body> </body>
</html> </html>

View File

@@ -1,4 +1,5 @@
from flask import Blueprint, request, jsonify, current_app, session, render_template, session from flask import Blueprint, request, jsonify, current_app, session, render_template, session
from bson import ObjectId
from ..services.course_service import create_material, update_material, get_materials_by_teacher, load_material, get_materials_by_teacher_dict, add_material_chapter, add_material_chapter_lesson, delete_material_chapter_lesson, reorder_material_structure, rename_material_structure from ..services.course_service import create_material, update_material, get_materials_by_teacher, load_material, get_materials_by_teacher_dict, add_material_chapter, add_material_chapter_lesson, delete_material_chapter_lesson, reorder_material_structure, rename_material_structure
from ..auth.decorators import require_role from ..auth.decorators import require_role
from ..services.cos_service import upload_file from ..services.cos_service import upload_file
@@ -37,24 +38,60 @@ def create_new_material():
material_id = create_material(teacher_id, material_name, description, chapters, image_url) material_id = create_material(teacher_id, material_name, description, chapters, image_url)
return jsonify({"message": "教材创建成功", "material_id": material_id}), 201 return jsonify({"message": "教材创建成功", "material_id": material_id}), 201
@bp.route('/materials/<material_id>', methods=['GET']) @bp.route('/materials/<material_id>', methods=['GET', 'PUT', 'DELETE'])
@require_role(roles="teacher") @require_role(roles="teacher")
def get_material(material_id): def handle_material(material_id):
if request.method == 'GET':
if material_id is None: if material_id is None:
return jsonify({"message": "教材名称不能为空"}), 400 return jsonify({"message": "教材名称不能为空"}), 400
material = load_material(material_id) material = load_material(material_id)
print(material) print(material)
return jsonify(material.model_dump()), 200 return jsonify(material.model_dump()), 200
elif request.method == 'PUT':
@bp.route('/materials/<material_id>', methods=['PUT'])
@require_role(roles="teacher")
def update_existing_material(material_id):
data = request.get_json() data = request.get_json()
chapters = data.get('chapters') chapters = data.get('chapters')
if update_material(material_id, chapters): if update_material(material_id, chapters):
return jsonify({"message": "教材更新成功"}), 200 return jsonify({"message": "教材更新成功"}), 200
return jsonify({"message": "教材未找到"}), 404 else:
return jsonify({"message": "教材更新失败"}), 500
elif request.method == 'DELETE':
# 获取当前教师信息
teacher_uuid = session.get("user_uuid")
teacher_id = current_app.extensions["uuid2username"][teacher_uuid]
# 检查材料是否存在,并且是否为当前教师创建
mongo = current_app.extensions["mongo"]
print(f"尝试删除课程ID: {material_id}, 当前教师ID: {teacher_id}")
try:
material = mongo.db.materials.find_one({'_id': ObjectId(material_id)})
print(f"找到的材料: {material}")
if not material:
return jsonify({"message": "课程不存在", "success": False}), 404
# 验证是否为当前教师创建的课程
if material.get('teacher_id') != teacher_id:
return jsonify({"message": "权限不足,无法删除他人课程", "success": False}), 403
except Exception as e:
print(f"查询材料时出错: {e}")
return jsonify({"message": f"查询课程时出错: {str(e)}", "success": False}), 500
# 执行删除操作
try:
result = mongo.db.materials.delete_one({'_id': ObjectId(material_id), 'teacher_id': teacher_id})
print(f"删除操作结果: {result.deleted_count}")
except Exception as e:
print(f"删除材料时出错: {e}")
return jsonify({"message": f"删除课程时出错: {str(e)}", "success": False}), 500
if result.deleted_count > 0:
return jsonify({"message": "课程删除成功", "success": True}), 200
else:
return jsonify({"message": "删除失败", "success": False}), 500
@bp.route('/materials/addchapter/<material_id>', methods=['POST']) @bp.route('/materials/addchapter/<material_id>', methods=['POST'])
@require_role(roles="teacher") @require_role(roles="teacher")