sytle: 教师端尺寸
This commit is contained in:
parent
c4e96ea899
commit
e75ffdf1e8
2687
pnpm-lock.yaml
generated
Normal file
2687
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -31,14 +31,14 @@
|
||||
<div class="options-menu">
|
||||
<template v-if="course.status === '发布中'">
|
||||
<a href="#" class="option-item"><img src="/images/teacher/下架.png" alt="">下架</a>
|
||||
<a href="#" class="option-item" @click.prevent="editCourse(course.id)"><img
|
||||
<a href="javascript:void(0)" class="option-item"><img
|
||||
src="/images/teacher/小编辑.png" alt="">编辑</a>
|
||||
<a href="#" class="option-item"><img src="/images/teacher/移动.png" alt="">移动</a>
|
||||
<a href="#" class="option-item"><img src="/images/teacher/删除.png" alt="">删除</a>
|
||||
</template>
|
||||
<template v-else-if="course.status === '下架中'">
|
||||
<a href="#" class="option-item"><img src="/images/teacher/加号.png" alt="">发布</a>
|
||||
<a href="#" class="option-item" @click.prevent="editCourse(course.id)"><img
|
||||
<a href="javascript:void(0)" class="option-item"><img
|
||||
src="/images/teacher/小编辑.png" alt="">编辑</a>
|
||||
<a href="#" class="option-item"><img src="/images/teacher/移动.png" alt="">移动</a>
|
||||
<a href="#" class="option-item"><img src="/images/teacher/删除.png" alt="">删除</a>
|
||||
@ -46,9 +46,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="course-info">
|
||||
<div class="course-info" @click="router.push(`/teacher/course-editor/${course.id}`)" style="cursor: pointer;">
|
||||
<img :src="course.image" alt="">
|
||||
<a href="#" class="course-name">{{ course.name }}</a>
|
||||
<a href="javascript:void(0)" class="course-name">{{ course.name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -99,10 +99,6 @@ const courseList = ref([
|
||||
{ id: 12, name: 'Flutter 跨平台开发', status: '发布中', image: 'https://picsum.photos/200/200?random=12' },
|
||||
]);
|
||||
|
||||
// 编辑课程
|
||||
const editCourse = (courseId: number) => {
|
||||
router.push(`/teacher/course-editor/${courseId}`);
|
||||
};
|
||||
|
||||
// 跳转到创建课程页面
|
||||
const navigateToCreateCourse = () => {
|
||||
@ -229,8 +225,9 @@ const navigateToCreateCourse = () => {
|
||||
}
|
||||
|
||||
.course-card {
|
||||
width: 190px;
|
||||
height: 201px;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
aspect-ratio: 190 / 201;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #D8D8D8;
|
||||
box-sizing: border-box;
|
||||
@ -316,8 +313,9 @@ const navigateToCreateCourse = () => {
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
||||
display: none;
|
||||
z-index: 10;
|
||||
width: 59px;
|
||||
height: 98px;
|
||||
width: auto;
|
||||
min-width: 59px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.more-options:hover .options-menu {
|
||||
@ -371,8 +369,9 @@ const navigateToCreateCourse = () => {
|
||||
padding: 0;
|
||||
}
|
||||
.course-info img{
|
||||
width: 150px;
|
||||
height: 105px;
|
||||
width: 80%;
|
||||
height: auto;
|
||||
aspect-ratio: 150 / 105;
|
||||
/* 居中 */
|
||||
display: block;
|
||||
margin: 5px auto 10px;
|
||||
@ -380,7 +379,7 @@ const navigateToCreateCourse = () => {
|
||||
top: -10px;
|
||||
}
|
||||
.course-name{
|
||||
width: 138px;
|
||||
width: 80%;
|
||||
height: 20px;
|
||||
font-family: AppleSystemUIFont;
|
||||
font-size: 14px;
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="course-create-page">
|
||||
<div class="course-form-container flex-col">
|
||||
<!-- 第一行:课程名称和课程分类 -->
|
||||
<div class="form-row-name-category flex-row">
|
||||
<div class="label-required">
|
||||
<span class="text_17">*</span>
|
||||
<span class="text_18">课程名称:</span>
|
||||
<div class="course-basic-info-row flex-row">
|
||||
<div class="course-name-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">课程名称:</span>
|
||||
</div>
|
||||
<div class="course-name-input-wrapper flex-col">
|
||||
<n-input
|
||||
@ -15,10 +15,10 @@
|
||||
:bordered="false"
|
||||
/>
|
||||
</div>
|
||||
<div class="category-section flex-col">
|
||||
<div class="label-category">
|
||||
<span class="text_20">*</span>
|
||||
<span class="text_21">课程分类:</span>
|
||||
<div class="course-category-section flex-col">
|
||||
<div class="course-category-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">课程分类:</span>
|
||||
</div>
|
||||
<div class="course-category-select-wrapper flex-col">
|
||||
<n-select
|
||||
@ -33,12 +33,12 @@
|
||||
</div>
|
||||
|
||||
<!-- 第二行:主讲老师和排序 -->
|
||||
<div class="form-row-instructor flex-row">
|
||||
<div class="label-instructor">
|
||||
<span class="text_23">*</span>
|
||||
<span class="text_24">主讲老师:</span>
|
||||
<div class="instructor-sort-row flex-row">
|
||||
<div class="instructor-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">主讲老师:</span>
|
||||
</div>
|
||||
<div class="form-select-wrapper flex-row">
|
||||
<div class="instructor-select-wrapper flex-row">
|
||||
<n-select
|
||||
v-model:value="formData.instructors"
|
||||
multiple
|
||||
@ -49,16 +49,16 @@
|
||||
:render-tag="renderInstructorTag"
|
||||
/>
|
||||
</div>
|
||||
<div class="sort-section flex-col">
|
||||
<div class="label-sort">
|
||||
<span class="text_28">*</span>
|
||||
<span class="text_29">排序:</span>
|
||||
<div class="course-sort-section flex-col">
|
||||
<div class="course-sort-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">排序:</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 排序输入框 -->
|
||||
<div class="form-input-wrapper">
|
||||
<div class="course-sort-input-wrapper">
|
||||
<n-input
|
||||
v-model:value="formData.sort"
|
||||
placeholder="数字越小越排序靠前"
|
||||
@ -68,12 +68,12 @@
|
||||
</div>
|
||||
|
||||
<!-- 第三行:课程开始时间和结束时间 -->
|
||||
<div class="form-row-date flex-row">
|
||||
<div class="label-date">
|
||||
<span class="text_30">*</span>
|
||||
<span class="text_31">课程开始时间:</span>
|
||||
<div class="course-time-row flex-row">
|
||||
<div class="start-time-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">课程开始时间:</span>
|
||||
</div>
|
||||
<div class="start-date-wrapper flex-row">
|
||||
<div class="start-time-picker-wrapper flex-row">
|
||||
<n-date-picker
|
||||
v-model:value="formData.startTime"
|
||||
type="datetime"
|
||||
@ -82,11 +82,11 @@
|
||||
:bordered="false"
|
||||
/>
|
||||
</div>
|
||||
<div class="label-end-date">
|
||||
<span class="text_33">*</span>
|
||||
<span class="text_34">课程结束时间:</span>
|
||||
<div class="end-time-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">课程结束时间:</span>
|
||||
</div>
|
||||
<div class="end-date-wrapper flex-row">
|
||||
<div class="end-time-picker-wrapper flex-row">
|
||||
<n-date-picker
|
||||
v-model:value="formData.endTime"
|
||||
type="datetime"
|
||||
@ -98,30 +98,30 @@
|
||||
</div>
|
||||
|
||||
<!-- 第四行:参与学员 -->
|
||||
<div class="form-row-students flex-row">
|
||||
<div class="label-students">
|
||||
<span class="text_36">*</span>
|
||||
<span class="text_37">参与学员:</span>
|
||||
<div class="student-selection-row flex-row">
|
||||
<div class="student-selection-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">参与学员:</span>
|
||||
</div>
|
||||
<div class="radio-group flex-row">
|
||||
<div class="student-type-radio-group flex-row">
|
||||
<label class="radio-option" @click="formData.studentType = 'all'">
|
||||
<div class="radio-circle" :class="{ active: formData.studentType === 'all' }">
|
||||
<div class="radio-dot" v-if="formData.studentType === 'all'"></div>
|
||||
</div>
|
||||
<span class="text_38">全部学员</span>
|
||||
<span class="radio-text">全部学员</span>
|
||||
</label>
|
||||
<label class="radio-option" @click="formData.studentType = 'partial'">
|
||||
<div class="radio-circle" :class="{ active: formData.studentType === 'partial' }">
|
||||
<div class="radio-dot" v-if="formData.studentType === 'partial'"></div>
|
||||
</div>
|
||||
<span class="text_39">仅部分学员</span>
|
||||
<span class="radio-text">仅部分学员</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 第五行:选择班级(仅在选择部分学员时显示) -->
|
||||
<div class="form-row-class" v-if="formData.studentType === 'partial'">
|
||||
<div class="form-select-wrapper flex-row">
|
||||
<div class="class-selection-row" v-if="formData.studentType === 'partial'">
|
||||
<div class="class-select-wrapper flex-row">
|
||||
<n-select
|
||||
v-model:value="formData.selectedClasses"
|
||||
multiple
|
||||
@ -134,19 +134,19 @@
|
||||
</div>
|
||||
|
||||
<!-- 第六行:课程封面 -->
|
||||
<div class="form-row-cover flex-row justify-between">
|
||||
<div class="label-cover">
|
||||
<span class="text_41">*</span>
|
||||
<span class="text_42">课程封面:</span>
|
||||
<div class="course-cover-row flex-row justify-between">
|
||||
<div class="course-cover-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">课程封面:</span>
|
||||
</div>
|
||||
<div class="cover-upload-box flex-row">
|
||||
<div class="image-text_6 flex-col justify-between" style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;">
|
||||
<div class="cover-upload-area flex-row">
|
||||
<div class="upload-container flex-col justify-between" style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;">
|
||||
<div class="native-upload">
|
||||
<input
|
||||
type="file"
|
||||
id="coverUpload"
|
||||
accept="image/*"
|
||||
@change="handleNativeFileChange"
|
||||
<input
|
||||
type="file"
|
||||
id="coverUpload"
|
||||
accept="image/*"
|
||||
@change="handleNativeFileChange"
|
||||
style="display: none;"
|
||||
/>
|
||||
<label for="coverUpload" class="upload-content" style="cursor: pointer; width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;">
|
||||
@ -156,9 +156,9 @@
|
||||
</template>
|
||||
<div v-if="previewUrl" style="position: relative; width: 100%; height: 100%;">
|
||||
<img :src="previewUrl" style="max-width: 100%; max-height: 100%; object-fit: contain;" />
|
||||
<div
|
||||
class="delete-icon"
|
||||
@click.stop="clearUpload"
|
||||
<div
|
||||
class="image-delete-icon"
|
||||
@click.stop="clearUpload"
|
||||
style="position: absolute; top: 5px; right: 5px; background-color: rgba(0,0,0,0.5); color: white; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer;"
|
||||
>
|
||||
×
|
||||
@ -171,16 +171,16 @@
|
||||
</div>
|
||||
|
||||
<!-- 课程简介标题和工具栏 -->
|
||||
<div class="form-row-description flex-row">
|
||||
<div class="label-description">
|
||||
<span class="text_43">*</span>
|
||||
<span class="text_44">课程简介:</span>
|
||||
<div class="course-description-header flex-row">
|
||||
<div class="course-description-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">课程简介:</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 富文本编辑器区域 -->
|
||||
<div class="editor-container flex-col">
|
||||
<div class="description-editor-container flex-col">
|
||||
<QuillEditor
|
||||
v-model="formData.courseDescription"
|
||||
:height="'280px'"
|
||||
@ -190,51 +190,51 @@
|
||||
</div>
|
||||
|
||||
<!-- 设置选项区域 -->
|
||||
<div class="form-settings">
|
||||
<div class="course-settings-section">
|
||||
<!-- 离开页面停止播放 -->
|
||||
<div class="form-row-settings flex-row">
|
||||
<div class="settings-label flex-row justify-between">
|
||||
<div class="label-settings">
|
||||
<span class="text_47">*</span>
|
||||
<span class="text_48">离开页面停止播放:</span>
|
||||
<div class="stop-on-leave-setting flex-row">
|
||||
<div class="setting-control flex-row">
|
||||
<div class="setting-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">离开页面停止播放:</span>
|
||||
</div>
|
||||
<button
|
||||
@click="formData.stopOnLeave = !formData.stopOnLeave"
|
||||
class="toggle-button"
|
||||
<button
|
||||
@click="formData.stopOnLeave = !formData.stopOnLeave"
|
||||
class="toggle-button"
|
||||
:class="{ 'toggle-button-active': formData.stopOnLeave }"
|
||||
>
|
||||
{{ formData.stopOnLeave ? '开启' : '关闭' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 视频倍数播放 -->
|
||||
<div class="form-row-setting1 flex-row">
|
||||
<div class="setting1-label flex-row justify-between">
|
||||
<div class="label-setting1">
|
||||
<span class="text_49">*</span>
|
||||
<span class="text_50">视频倍数播放:</span>
|
||||
<div class="video-speed-setting flex-row">
|
||||
<div class="setting-control flex-row">
|
||||
<div class="setting-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">视频倍数播放:</span>
|
||||
</div>
|
||||
<button
|
||||
@click="formData.videoSpeedControl = !formData.videoSpeedControl"
|
||||
class="toggle-button"
|
||||
<button
|
||||
@click="formData.videoSpeedControl = !formData.videoSpeedControl"
|
||||
class="toggle-button"
|
||||
:class="{ 'toggle-button-active': formData.videoSpeedControl }"
|
||||
>
|
||||
{{ formData.videoSpeedControl ? '开启' : '关闭' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 显示视频文本 -->
|
||||
<div class="form-row-setting2 flex-row">
|
||||
<div class="setting2-label flex-row justify-between">
|
||||
<div class="label-setting2">
|
||||
<span class="text_51">*</span>
|
||||
<span class="text_52">显示视频文本:</span>
|
||||
<div class="video-text-setting flex-row">
|
||||
<div class="setting-control flex-row">
|
||||
<div class="setting-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">显示视频文本:</span>
|
||||
</div>
|
||||
<button
|
||||
@click="formData.showVideoText = !formData.showVideoText"
|
||||
class="toggle-button"
|
||||
<button
|
||||
@click="formData.showVideoText = !formData.showVideoText"
|
||||
class="toggle-button"
|
||||
:class="{ 'toggle-button-active': formData.showVideoText }"
|
||||
>
|
||||
{{ formData.showVideoText ? '开启' : '关闭' }}
|
||||
@ -243,53 +243,53 @@
|
||||
</div>
|
||||
|
||||
<!-- 积分设置 -->
|
||||
<div class="form-row-points flex-row">
|
||||
<div class="points-label flex-row justify-between">
|
||||
<div class="label-points">
|
||||
<span class="text_53">*</span>
|
||||
<span class="text_54">积分设置:</span>
|
||||
<div class="points-setting-row flex-row">
|
||||
<div class="points-setting-control flex-row justify-between">
|
||||
<div class="setting-label">
|
||||
<span class="required-asterisk">*</span>
|
||||
<span class="label-text">积分设置:</span>
|
||||
</div>
|
||||
<button
|
||||
@click="formData.pointsEnabled = !formData.pointsEnabled"
|
||||
class="toggle-button"
|
||||
<button
|
||||
@click="formData.pointsEnabled = !formData.pointsEnabled"
|
||||
class="toggle-button"
|
||||
:class="{ 'toggle-button-active': formData.pointsEnabled }"
|
||||
>
|
||||
{{ formData.pointsEnabled ? '开启' : '关闭' }}
|
||||
</button>
|
||||
</div>
|
||||
<span class="text_55">学完可获得</span>
|
||||
<div class="form-input-container">
|
||||
<span class="points-description-text">学完可获得</span>
|
||||
<div class="earn-points-input-container">
|
||||
<input
|
||||
type="number"
|
||||
v-model="formData.earnPoints"
|
||||
min="0"
|
||||
max="1000"
|
||||
class="native-input"
|
||||
class="points-input"
|
||||
/>
|
||||
</div>
|
||||
<span class="text_57">积分</span>
|
||||
<span class="text_58">本课程需</span>
|
||||
<div class="points-input-wrapper">
|
||||
<span class="points-description-text">积分</span>
|
||||
<span class="points-description-text">本课程需</span>
|
||||
<div class="required-points-input-container">
|
||||
<input
|
||||
type="number"
|
||||
v-model="formData.requiredPoints"
|
||||
min="0"
|
||||
max="1000"
|
||||
class="native-input"
|
||||
class="points-input"
|
||||
/>
|
||||
</div>
|
||||
<span class="text_60">积分兑换</span>
|
||||
<span class="points-description-text">积分兑换</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 底部按钮区域 -->
|
||||
<div class="form-actions flex-row">
|
||||
<div class="action-button-group flex-col"></div>
|
||||
<div class="btn-cancel flex-col" @click="handleCancel">
|
||||
<span class="text_67">取消</span>
|
||||
<div class="form-action-buttons flex-row">
|
||||
<div class="button-spacer flex-col"></div>
|
||||
<div class="cancel-button flex-col" @click="handleCancel">
|
||||
<span class="button-text">取消</span>
|
||||
</div>
|
||||
<div class="btn-submit flex-col" @click="handleSubmit">
|
||||
<span class="text_68">保存</span>
|
||||
<div class="submit-button flex-col" @click="handleSubmit">
|
||||
<span class="button-text">保存</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,15 @@
|
||||
<span class="icon icon-status icon-delete"></span>
|
||||
</div>
|
||||
</router-link>
|
||||
<router-link to="/teacher/course-management/course-analysis" class="nav-item sub-nav-item"
|
||||
:class="{ active: $route.path === '/teacher/course-management/course-analysis' }">
|
||||
<span>资料分类</span>
|
||||
<div class="icon-container">
|
||||
<span class="icon icon-status icon-add"></span>
|
||||
<span class="icon icon-status icon-edit"></span>
|
||||
<span class="icon icon-status icon-delete"></span>
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -91,6 +100,11 @@ import CourseCategory from './CourseComponents/CourseCategory.vue'
|
||||
background-color: #e6f7ff;
|
||||
}
|
||||
|
||||
/* 鼠标悬停在导航项上时显示图标 */
|
||||
.nav-container .nav-item:hover .icon.icon-status {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* 选中状态样式 */
|
||||
.nav-container .nav-item.active {
|
||||
background-color: #F5F8FB;
|
||||
@ -129,7 +143,7 @@ import CourseCategory from './CourseComponents/CourseCategory.vue'
|
||||
background-position: center;
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
opacity: 0.6;
|
||||
opacity: 0; /* 默认不显示图标 */
|
||||
transition: opacity 0.3s ease, background-image 0.3s ease;
|
||||
}
|
||||
|
||||
@ -148,36 +162,44 @@ import CourseCategory from './CourseComponents/CourseCategory.vue'
|
||||
background-image: url('/images/teacher/删除.png');
|
||||
}
|
||||
|
||||
/* 鼠标悬停时显示有颜色的图标 */
|
||||
.nav-item:hover .icon.icon-add {
|
||||
background-image: url('/images/teacher/加号(选中).png');
|
||||
opacity: 1;
|
||||
/* 鼠标悬停在导航项上时显示灰色图标(更暗) */
|
||||
.nav-container .nav-item:hover .icon.icon-status {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.nav-item:hover .icon.icon-edit {
|
||||
background-image: url('/images/teacher/编辑(选中).png');
|
||||
opacity: 1;
|
||||
/* 鼠标直接悬停在图标上时显示蓝色图标(优先级更高) */
|
||||
.icon.icon-add:hover {
|
||||
background-image: url('/images/teacher/加号(选中).png') !important;
|
||||
opacity: 1 !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.nav-item:hover .icon.icon-delete {
|
||||
background-image: url('/images/teacher/删除(选中).png');
|
||||
opacity: 1;
|
||||
.icon.icon-edit:hover {
|
||||
background-image: url('/images/teacher/编辑(选中).png') !important;
|
||||
opacity: 1 !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon.icon-delete:hover {
|
||||
background-image: url('/images/teacher/删除(选中).png') !important;
|
||||
opacity: 1 !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 选中状态下显示有颜色的图标 */
|
||||
.nav-item.active .icon.icon-add {
|
||||
background-image: url('/images/teacher/加号(选中).png');
|
||||
opacity: 1;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.nav-item.active .icon.icon-edit {
|
||||
background-image: url('/images/teacher/编辑(选中).png');
|
||||
opacity: 1;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.nav-item.active .icon.icon-delete {
|
||||
background-image: url('/images/teacher/删除(选中).png');
|
||||
opacity: 1;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
|
@ -127,12 +127,25 @@ const updateActiveNavItem = () => {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 响应式调整 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.top-image-container {
|
||||
height: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
.top-image-container {
|
||||
height: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.top-image {
|
||||
width: 1920px;
|
||||
height: 130px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
/* top: 20px; */
|
||||
top: 0px;
|
||||
opacity: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
@ -141,13 +154,43 @@ const updateActiveNavItem = () => {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.main-content {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.router-view-container {
|
||||
height: auto;
|
||||
min-height: calc(100vh - var(--top-height, 100px) - 300px);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
width: 294px;
|
||||
height: calc(100vh - 130px);
|
||||
height: calc(100vh - var(--top-height, 130px));
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.sidebar-container {
|
||||
--top-height: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
.sidebar-container {
|
||||
--top-height: 80px;
|
||||
width: 240px;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
height: 230px;
|
||||
position: relative;
|
||||
@ -187,6 +230,40 @@ const updateActiveNavItem = () => {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.avatar-container {
|
||||
height: 180px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-container img {
|
||||
margin: 0 0 15px 0;
|
||||
}
|
||||
|
||||
.avatar-text {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
.avatar-container {
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.avatar-container img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.avatar-text {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-container {
|
||||
margin-top: 30px;
|
||||
/* 鼠标变小手 */
|
||||
@ -204,6 +281,33 @@ const updateActiveNavItem = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: all 0.3s ease;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.nav-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.nav-container .nav-item {
|
||||
width: 200px;
|
||||
margin: 0 10px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
.nav-container .nav-item {
|
||||
width: 150px;
|
||||
height: 45px;
|
||||
margin: 0 5px 10px;
|
||||
}
|
||||
|
||||
.nav-container .nav-item img {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-container .nav-item:hover {
|
||||
@ -220,7 +324,6 @@ const updateActiveNavItem = () => {
|
||||
}
|
||||
|
||||
.nav-container .nav-item img {
|
||||
width: 17px;
|
||||
height: 20px;
|
||||
margin-left: 50px;
|
||||
margin-top: 0;
|
||||
@ -243,10 +346,24 @@ const updateActiveNavItem = () => {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
background: #F5F7FA;
|
||||
height: calc(100vh - 130px);
|
||||
height: calc(100vh - var(--top-height, 130px));
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.router-view-container {
|
||||
--top-height: 100px;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
.router-view-container {
|
||||
--top-height: 80px;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
502
src/views/teacher/course/AddCoursewareModal.vue
Normal file
502
src/views/teacher/course/AddCoursewareModal.vue
Normal file
@ -0,0 +1,502 @@
|
||||
<template>
|
||||
<div class="modal-container flex-col">
|
||||
<span class="modal-title">添加课件</span>
|
||||
<div class="upload-section flex-row">
|
||||
<div class="label-group flex-col justify-between">
|
||||
<span class="upload-path-label">上传路径:</span>
|
||||
<span class="upload-file-label">上传文件:</span>
|
||||
</div>
|
||||
<div class="button-group flex-col justify-between">
|
||||
<div class="select-path-button flex-col">
|
||||
<input
|
||||
type="file"
|
||||
id="pathUpload"
|
||||
@change="handleLocalFileUpload"
|
||||
style="display: none;"
|
||||
accept=".doc,.docx,.pdf,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4"
|
||||
/>
|
||||
<label for="pathUpload" class="button-text file-input-label">选择路径</label>
|
||||
</div>
|
||||
<div class="select-file-button flex-col" style="position: relative;">
|
||||
<div class="button-text file-input-label" @click="toggleResourceDropdown">选择文件</div>
|
||||
<div v-show="showResourceDropdown" class="upload-type flex-col">
|
||||
<label class="upload-type-text">
|
||||
<input
|
||||
type="file"
|
||||
@change="handleDropdownLocalUpload"
|
||||
style="display: none;"
|
||||
accept=".doc,.docx,.pdf,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4"
|
||||
/>
|
||||
本地上传
|
||||
</label>
|
||||
<label class="upload-type-text">
|
||||
<input
|
||||
type="file"
|
||||
@change="handleDropdownResourceUpload"
|
||||
style="display: none;"
|
||||
accept=".doc,.docx,.pdf,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4"
|
||||
/>
|
||||
资源上传
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="folder-display flex-col justify-between">
|
||||
<span class="folder-name">文件夹一</span>
|
||||
<div class="existing-folders flex-col">
|
||||
<span class="folder-item">已由文件夹名称一</span>
|
||||
<span class="folder-item">已由文件夹名称二</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="supported-formats flex-row">
|
||||
<span class="formats-label">支持格式:</span>
|
||||
<span class="document-formats">文本文:.doc、.docx、.pdf表格文件:.xls、.xlsx<br />演示文稿:.ppt、.pptx</span>
|
||||
<span class="media-formats">音频文件:.mp3<br />视频文件:.mp4<br /></span>
|
||||
</div>
|
||||
<div class="upload-limit flex-row justify-between">
|
||||
<span class="limit-label">上传限制:</span>
|
||||
<span class="limit-description">word、excel、ppt文件需小于100MB,其他文件需小于2GB.mp4格式编码<br />说明(上传mp4格式文件请查看编码说明)</span>
|
||||
</div>
|
||||
<div class="action-buttons flex-row justify-between">
|
||||
<div class="cancel-button-container flex-col">
|
||||
<div class="cancel-button flex-col" @click="handleCancel">
|
||||
<span class="button-text button-text1">取消</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="confirm-button flex-col" @click="handleConfirm">
|
||||
<span class="button-text button-text2">确定</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
// 控制资源上传下拉菜单的显示
|
||||
const showResourceDropdown = ref(false)
|
||||
|
||||
// 处理本地上传文件选择
|
||||
const handleLocalFileUpload = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
const files = target.files
|
||||
if (files && files.length > 0) {
|
||||
console.log('本地上传文件:', files[0])
|
||||
// 这里处理本地文件上传逻辑
|
||||
}
|
||||
}
|
||||
|
||||
// 处理资源上传文件选择
|
||||
const handleResourceFileUpload = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
const files = target.files
|
||||
if (files && files.length > 0) {
|
||||
console.log('资源上传文件:', files[0])
|
||||
// 这里处理资源文件上传逻辑
|
||||
}
|
||||
}
|
||||
|
||||
// 切换资源上传下拉菜单
|
||||
const toggleResourceDropdown = () => {
|
||||
showResourceDropdown.value = !showResourceDropdown.value
|
||||
}
|
||||
|
||||
// 处理下拉选项中的本地上传
|
||||
const handleDropdownLocalUpload = (event: Event) => {
|
||||
handleLocalFileUpload(event)
|
||||
showResourceDropdown.value = false
|
||||
}
|
||||
|
||||
// 处理下拉选项中的资源上传
|
||||
const handleDropdownResourceUpload = (event: Event) => {
|
||||
handleResourceFileUpload(event)
|
||||
showResourceDropdown.value = false
|
||||
}
|
||||
|
||||
// 定义事件发射器
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
// 处理取消按钮
|
||||
const handleCancel = () => {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// 处理确定按钮
|
||||
const handleConfirm = () => {
|
||||
// 这里可以添加确定逻辑,比如验证文件等
|
||||
console.log('确定上传')
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-container {
|
||||
position: relative;
|
||||
width: 1076px;
|
||||
height: 623px;
|
||||
background: #FFFFFF ;
|
||||
background-size: 100% 100%;
|
||||
margin: 0 auto;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
width: 77px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 20px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin: 21px 0 0 24px;
|
||||
}
|
||||
|
||||
.upload-section {
|
||||
width: 1028px;
|
||||
height: 160px;
|
||||
background: #FCFCFC ;
|
||||
background-size: 100% 100%;
|
||||
margin: 46px 0 0 22px;
|
||||
}
|
||||
|
||||
.label-group {
|
||||
width: 90px;
|
||||
height: 82px;
|
||||
margin: 39px 0 0 35px;
|
||||
}
|
||||
|
||||
.upload-path-label {
|
||||
width: 90px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.upload-file-label {
|
||||
width: 90px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin-top: 38px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
width: 123px;
|
||||
height: 98px;
|
||||
margin: 30px 0 0 3px;
|
||||
}
|
||||
|
||||
.select-path-button {
|
||||
height: 38px;
|
||||
background: #0288D1;
|
||||
background-size: 100% 100%;
|
||||
width: 123px;
|
||||
}
|
||||
|
||||
.button-text {
|
||||
width: 100%;
|
||||
height: 21px;
|
||||
overflow-wrap: break-word;
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: 21px;
|
||||
margin: 6px 0 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.button-text1{
|
||||
color: #0288D1 ;
|
||||
}
|
||||
.button-text2{
|
||||
color: #FFFFFF ;
|
||||
}
|
||||
|
||||
.select-file-button {
|
||||
height: 38px;
|
||||
background: #0288D1 ;
|
||||
background-size: 100% 100%;
|
||||
margin-top: 22px;
|
||||
width: 123px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.folder-display {
|
||||
width: 171px;
|
||||
height: 106px;
|
||||
margin: 39px 604px 0 2px;
|
||||
}
|
||||
|
||||
.folder-name {
|
||||
width: 72px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.existing-folders {
|
||||
width: 171px;
|
||||
height: 80px;
|
||||
background: #FFFFFF;
|
||||
background-size: 289px 198px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.folder-item {
|
||||
width: 112px;
|
||||
height: 17px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 14px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 17px;
|
||||
margin: 13px 0 0 29px;
|
||||
}
|
||||
|
||||
.folder-item {
|
||||
width: 112px;
|
||||
height: 17px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 14px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 17px;
|
||||
margin: 14px 0 19px 29px;
|
||||
}
|
||||
|
||||
.supported-formats {
|
||||
width: 532px;
|
||||
height: 93px;
|
||||
margin: 37px 0 0 57px;
|
||||
}
|
||||
|
||||
.formats-label {
|
||||
width: 90px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.document-formats {
|
||||
width: 230px;
|
||||
height: 90px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(102, 102, 102, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
line-height: 30px;
|
||||
margin-left: 18px;
|
||||
}
|
||||
|
||||
.media-formats {
|
||||
width: 131px;
|
||||
height: 90px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(102, 102, 102, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
line-height: 30px;
|
||||
margin: 3px 0 0 63px;
|
||||
}
|
||||
|
||||
.upload-limit {
|
||||
width: 698px;
|
||||
height: 60px;
|
||||
margin: 26px 0 0 57px;
|
||||
}
|
||||
|
||||
.limit-label {
|
||||
width: 90px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.limit-description {
|
||||
width: 590px;
|
||||
height: 60px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(102, 102, 102, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
width: 147px;
|
||||
height: 32px;
|
||||
margin: 103px 0 23px 905px;
|
||||
}
|
||||
|
||||
.cancel-button-container {
|
||||
height: 32px;
|
||||
width: 66px;
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
height: 32px;
|
||||
background: #E2F5FF;
|
||||
background-size: 68px 34px;
|
||||
width: 66px;
|
||||
color: #0288D1;
|
||||
/* 字体居中 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* 小手 */
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.cancel-button:hover {
|
||||
background: #D1EFFF;
|
||||
}
|
||||
|
||||
.button-text {
|
||||
width: 32px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
font-size: 16px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin: 0;
|
||||
}
|
||||
.flex-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.justify-between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.confirm-button {
|
||||
height: 32px;
|
||||
background: #0288D1;
|
||||
background-size: 100% 100%;
|
||||
width: 66px;
|
||||
/* 字体居中 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* 小手 */
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.confirm-button:hover {
|
||||
background: #0277BD;
|
||||
}
|
||||
|
||||
.upload-type {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 100%;
|
||||
width: 123px;
|
||||
height: 76px;
|
||||
background: #FFFFFF;
|
||||
background-size: 241px 194px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
}
|
||||
.upload-type-text {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 14px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: 30px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.upload-type-text:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 文件输入框标签样式 */
|
||||
.file-input-label {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.cancel-button{
|
||||
color: #0288D1 ;
|
||||
}
|
||||
</style>
|
1116
src/views/teacher/course/ChapterEditor.vue
Normal file
1116
src/views/teacher/course/ChapterEditor.vue
Normal file
File diff suppressed because it is too large
Load Diff
@ -63,6 +63,10 @@
|
||||
import { ref, computed, h } from 'vue'
|
||||
import { NButton, useMessage, NDataTable, NConfigProvider, zhCN, dateZhCN } from 'naive-ui'
|
||||
import type { DataTableColumns } from 'naive-ui'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
|
||||
const message = useMessage()
|
||||
|
||||
@ -331,7 +335,7 @@ const toggleChapter = (chapter: Chapter) => {
|
||||
|
||||
// 章节操作方法
|
||||
const addChapter = () => {
|
||||
message.info('添加章节功能')
|
||||
router.push('/teacher/chapter-editor')
|
||||
}
|
||||
|
||||
const importChapters = () => {
|
||||
@ -488,7 +492,7 @@ const columns: DataTableColumns<Chapter> = [
|
||||
|
||||
<style scoped>
|
||||
.chapter-management {
|
||||
width: 1293px;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
|
@ -1,16 +1,11 @@
|
||||
<template>
|
||||
<div class="course-editor">
|
||||
<!-- 左侧导航菜单 -->
|
||||
<div class="sidebar" v-if="showSidebar">
|
||||
<router-link
|
||||
:to="`/teacher/course-editor/${courseId}/courseware`"
|
||||
class="menu-item"
|
||||
:class="{ active: $route.path.includes('courseware') }"
|
||||
>
|
||||
<img
|
||||
:src="$route.path.includes('courseware') ? '/images/teacher/课件-选中.png' : '/images/teacher/课件.png'"
|
||||
alt="课件"
|
||||
/>
|
||||
<div class="sidebar">
|
||||
<router-link :to="`/teacher/course-editor/${courseId}/courseware`" class="menu-item"
|
||||
:class="{ active: $route.path.includes('courseware') }">
|
||||
<img :src="$route.path.includes('courseware') ? '/images/teacher/课件-选中.png' : '/images/teacher/课件.png'"
|
||||
alt="课件" />
|
||||
<span>课件</span>
|
||||
</router-link>
|
||||
<router-link :to="`/teacher/course-editor/${courseId}/chapters`" class="menu-item"
|
||||
@ -19,63 +14,41 @@
|
||||
alt="章节" />
|
||||
<span>章节</span>
|
||||
</router-link>
|
||||
<router-link
|
||||
:to="`/teacher/course-editor/${courseId}/homework`"
|
||||
class="menu-item"
|
||||
:class="{ active: $route.path.includes('homework') }"
|
||||
>
|
||||
<img
|
||||
:src="$route.path.includes('homework') ? '/images/teacher/作业-选中.png' : '/images/teacher/作业.png'"
|
||||
alt="作业"
|
||||
/>
|
||||
<span>作业</span>
|
||||
</router-link>
|
||||
|
||||
<!-- 练考通父菜单 -->
|
||||
<div
|
||||
class="menu-item"
|
||||
:class="{ active: $route.path.includes('practice') }"
|
||||
@click="togglePracticeMenu"
|
||||
>
|
||||
<img
|
||||
:src="($route.path.includes('practice')) ? '/images/teacher/练考通-选中.png' : '/images/teacher/练考通.png'"
|
||||
alt="练考通"
|
||||
/>
|
||||
<span>练考通</span>
|
||||
<div class="expand-icon" :class="{ expanded: practiceMenuExpanded }">
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
|
||||
<path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<!-- 作业二级导航 -->
|
||||
<div class="menu-group">
|
||||
<div class="menu-header" @click="toggleHomework">
|
||||
<img :src="$route.path.includes('homework') ? '/images/teacher/作业-选中.png' : '/images/teacher/作业.png'"
|
||||
alt="作业" />
|
||||
<span>作业</span>
|
||||
<i class="n-base-icon" :class="{ 'expanded': homeworkExpanded }">
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5.64645 3.14645C5.45118 3.34171 5.45118 3.65829 5.64645 3.85355L9.79289 8L5.64645 12.1464C5.45118 12.3417 5.45118 12.6583 5.64645 12.8536C5.84171 13.0488 6.15829 13.0488 6.35355 12.8536L10.8536 8.35355C11.0488 8.15829 11.0488 7.84171 10.8536 7.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645Z"
|
||||
fill="#C2C2C2"></path>
|
||||
</svg>
|
||||
</i>
|
||||
</div>
|
||||
<div class="submenu" v-show="homeworkExpanded">
|
||||
<router-link :to="`/teacher/course-editor/${courseId}/homework/library`" class="submenu-item"
|
||||
:class="{ active: $route.path.includes('homework/library') }">
|
||||
<span>作业库</span>
|
||||
</router-link>
|
||||
<router-link :to="`/teacher/course-editor/${courseId}/homework/review`" class="submenu-item"
|
||||
:class="{ active: $route.path.includes('homework/review') }">
|
||||
<span>批阅作业</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 练考通子菜单 -->
|
||||
<div class="submenu" :class="{ expanded: practiceMenuExpanded }">
|
||||
<router-link
|
||||
:to="`/teacher/course-editor/${courseId}/practice/exam-library`"
|
||||
class="submenu-item"
|
||||
:class="{ active: $route.path.includes('exam-library') }"
|
||||
>
|
||||
<span>试卷库</span>
|
||||
</router-link>
|
||||
<router-link
|
||||
:to="`/teacher/course-editor/${courseId}/practice/marking-center`"
|
||||
class="submenu-item"
|
||||
:class="{ active: $route.path.includes('marking-center') }"
|
||||
>
|
||||
<span>阅卷中心</span>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<router-link
|
||||
:to="`/teacher/course-editor/${courseId}/question-bank`"
|
||||
class="menu-item"
|
||||
:class="{ active: $route.path.includes('question-bank') }"
|
||||
>
|
||||
<img
|
||||
:src="$route.path.includes('question-bank') ? '/images/teacher/题库-选中.png' : '/images/teacher/题库.png'"
|
||||
alt="题库"
|
||||
/>
|
||||
<router-link :to="`/teacher/course-editor/${courseId}/practice`" class="menu-item"
|
||||
:class="{ active: $route.path.includes('practice') }">
|
||||
<img :src="$route.path.includes('practice') ? '/images/teacher/练考通-选中.png' : '/images/teacher/练考通.png'"
|
||||
alt="练考通" />
|
||||
<span>练考通</span>
|
||||
</router-link>
|
||||
<router-link :to="`/teacher/course-editor/${courseId}/question-bank`" class="menu-item"
|
||||
:class="{ active: $route.path.includes('question-bank') }">
|
||||
<img :src="$route.path.includes('question-bank') ? '/images/teacher/题库-选中.png' : '/images/teacher/题库.png'"
|
||||
alt="题库" />
|
||||
<span>题库</span>
|
||||
</router-link>
|
||||
<router-link :to="`/teacher/course-editor/${courseId}/certificate`" class="menu-item"
|
||||
@ -118,34 +91,21 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// 获取课程ID
|
||||
const courseId = route.params.id
|
||||
|
||||
// 控制练考通菜单的展开状态
|
||||
const practiceMenuExpanded = ref(false)
|
||||
// 作业菜单展开状态
|
||||
const homeworkExpanded = ref(false)
|
||||
|
||||
// 切换练考通菜单展开状态
|
||||
const togglePracticeMenu = () => {
|
||||
practiceMenuExpanded.value = !practiceMenuExpanded.value
|
||||
// 切换作业菜单展开/收起
|
||||
const toggleHomework = () => {
|
||||
homeworkExpanded.value = !homeworkExpanded.value
|
||||
}
|
||||
|
||||
// 监听路由变化,如果当前路由是子菜单,自动展开父菜单
|
||||
watch(() => route.path, (newPath) => {
|
||||
if (newPath.includes('exam-library') || newPath.includes('marking-center')) {
|
||||
practiceMenuExpanded.value = true
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
|
||||
// 判断是否显示侧边菜单栏
|
||||
const showSidebar = computed(() => {
|
||||
return route.meta.hideSidebar !== true
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -297,60 +257,7 @@ const showSidebar = computed(() => {
|
||||
.submenu-item span {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
transition: transform 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.expand-icon.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* 子菜单样式 */
|
||||
.submenu {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease;
|
||||
margin-left: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.submenu.expanded {
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.submenu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 20px 12px 60px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-decoration: none;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
border-radius: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.submenu-item:hover {
|
||||
background: #e9ecef;
|
||||
}
|
||||
|
||||
.submenu-item.active {
|
||||
background: #E3F2FD;
|
||||
color: #0288D1;
|
||||
}
|
||||
|
||||
.submenu-item span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 右侧内容区域 */
|
||||
.content-area {
|
||||
flex: 1;
|
||||
|
@ -60,7 +60,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, h } from 'vue'
|
||||
import { ref, computed, h, onMounted, onUnmounted } from 'vue'
|
||||
import { NButton, NDropdown, NTag, useMessage, NDataTable, NConfigProvider, zhCN, dateZhCN } from 'naive-ui'
|
||||
import type { DataTableColumns, DropdownOption } from 'naive-ui'
|
||||
|
||||
@ -75,6 +75,8 @@ interface FileItem {
|
||||
creator: string
|
||||
createTime: string
|
||||
isTop: boolean
|
||||
children?: FileItem[]
|
||||
expanded?: boolean
|
||||
}
|
||||
|
||||
// 搜索关键词
|
||||
@ -92,63 +94,88 @@ const fileList = ref<FileItem[]>([
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'excel',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'excel',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'word',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'pdf',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'video',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
isTop: true,
|
||||
expanded: false,
|
||||
children: [
|
||||
{
|
||||
id: 2,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'excel',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'excel',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'word',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'pdf',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '这是一个表格文件.xlsx',
|
||||
type: 'video',
|
||||
size: '1MB',
|
||||
creator: '王建国',
|
||||
createTime: '2025.07.25 09:20',
|
||||
isTop: false
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
// 过滤后的文件列表
|
||||
// 将树形结构展平为列表
|
||||
const flattenFiles = (files: FileItem[]): FileItem[] => {
|
||||
const result: FileItem[] = []
|
||||
files.forEach((file: FileItem) => {
|
||||
result.push(file)
|
||||
if (file.children && file.expanded) {
|
||||
result.push(...flattenFiles(file.children))
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
// 过滤后的文件列表(优化版,置顶文件优先显示)
|
||||
const filteredFiles = computed(() => {
|
||||
if (!searchKeyword.value) {
|
||||
return fileList.value
|
||||
const allFiles = flattenFiles(fileList.value)
|
||||
let filtered = allFiles
|
||||
|
||||
// 如果有搜索关键词,先过滤
|
||||
if (searchKeyword.value) {
|
||||
filtered = allFiles.filter((file: FileItem) =>
|
||||
file.name.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
||||
)
|
||||
}
|
||||
return fileList.value.filter((file: FileItem) =>
|
||||
file.name.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
||||
)
|
||||
|
||||
// 对过滤后的文件进行排序:置顶文件在前,其他文件按原顺序
|
||||
return filtered.sort((a: FileItem, b: FileItem) => {
|
||||
if (a.isTop && !b.isTop) return -1
|
||||
if (!a.isTop && b.isTop) return 1
|
||||
return 0
|
||||
})
|
||||
})
|
||||
|
||||
// 获取文件图标
|
||||
@ -298,23 +325,157 @@ const handleMoreAction = (key: string, row: FileItem) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式列宽计算
|
||||
// const getResponsiveColumns = () => {
|
||||
// const screenWidth = window.innerWidth
|
||||
|
||||
// // 基础列宽配置
|
||||
// const baseColumns = {
|
||||
// selection: 40,
|
||||
// index: 80,
|
||||
// name: 270,
|
||||
// size: 100,
|
||||
// creator: 120,
|
||||
// createTime: 180,
|
||||
// actions: 320
|
||||
// }
|
||||
|
||||
// // 根据屏幕宽度调整列宽
|
||||
// if (screenWidth < 1200) {
|
||||
// // 小屏幕:减少各列宽度
|
||||
// return {
|
||||
// selection: 35,
|
||||
// index: 60,
|
||||
// name: Math.max(200, screenWidth * 0.25),
|
||||
// size: 80,
|
||||
// creator: 100,
|
||||
// createTime: 140,
|
||||
// actions: Math.max(280, screenWidth * 0.3)
|
||||
// }
|
||||
// } else if (screenWidth < 1600) {
|
||||
// // 中等屏幕:保持基础宽度
|
||||
// return baseColumns
|
||||
// } else {
|
||||
// // 大屏幕:适当增加宽度
|
||||
// return {
|
||||
// selection: 45,
|
||||
// index: 90,
|
||||
// name: 320,
|
||||
// size: 110,
|
||||
// creator: 130,
|
||||
// createTime: 200,
|
||||
// actions: 360
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// 屏幕宽度响应式数据
|
||||
const screenWidth = ref(window.innerWidth)
|
||||
|
||||
// 监听窗口大小变化
|
||||
const handleResize = () => {
|
||||
screenWidth.value = window.innerWidth
|
||||
}
|
||||
|
||||
// 响应式列配置计算属性
|
||||
const responsiveColumns = computed(() => {
|
||||
const width = screenWidth.value
|
||||
|
||||
// 基础列宽配置
|
||||
const baseColumns = {
|
||||
selection: 40,
|
||||
index: 80,
|
||||
name: 270,
|
||||
size: 100,
|
||||
creator: 120,
|
||||
createTime: 180,
|
||||
actions: 320
|
||||
}
|
||||
|
||||
// 根据屏幕宽度调整列宽
|
||||
if (width < 1200) {
|
||||
// 小屏幕:减少各列宽度
|
||||
return {
|
||||
selection: 35,
|
||||
index: 60,
|
||||
name: Math.max(200, width * 0.25),
|
||||
size: 80,
|
||||
creator: 100,
|
||||
createTime: 140,
|
||||
actions: Math.max(280, width * 0.3)
|
||||
}
|
||||
} else if (width < 1600) {
|
||||
// 中等屏幕:保持基础宽度
|
||||
return baseColumns
|
||||
} else {
|
||||
// 大屏幕:适当增加宽度
|
||||
return {
|
||||
selection: 45,
|
||||
index: 90,
|
||||
name: 320,
|
||||
size: 110,
|
||||
creator: 130,
|
||||
createTime: 200,
|
||||
actions: 360
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 在组件挂载时添加事件监听器
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
// 在组件卸载时移除事件监听器
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
// 表格列配置
|
||||
const columns: DataTableColumns<FileItem> = [
|
||||
const columns = computed((): DataTableColumns<FileItem> => [
|
||||
{
|
||||
type: 'selection'
|
||||
type: 'selection',
|
||||
width: responsiveColumns.value.selection
|
||||
},
|
||||
{
|
||||
title: '序号',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
width: responsiveColumns.value.index,
|
||||
render: (_row: FileItem, index: number) => index + 1
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
key: 'name',
|
||||
minWidth: 200,
|
||||
width: responsiveColumns.value.name,
|
||||
ellipsis: {
|
||||
tooltip: true
|
||||
},
|
||||
render: (row: FileItem) => {
|
||||
return h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } }, [
|
||||
return h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', justifyContent: 'center' } }, [
|
||||
// 如果是文件夹,添加展开/收起按钮
|
||||
row.type === 'folder' ? h('svg', {
|
||||
viewBox: '0 0 16 16',
|
||||
fill: 'none',
|
||||
xmlns: 'http://www.w3.org/2000/svg',
|
||||
style: {
|
||||
cursor: 'pointer',
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
color: '#666',
|
||||
marginRight: '4px',
|
||||
transition: 'transform 0.3s ease',
|
||||
transform: row.expanded ? 'rotate(90deg)' : 'rotate(0deg)'
|
||||
},
|
||||
onClick: (e: Event) => {
|
||||
e.stopPropagation()
|
||||
toggleFolder(row)
|
||||
}
|
||||
}, [
|
||||
h('path', {
|
||||
d: 'M5.64645 3.14645C5.45118 3.34171 5.45118 3.65829 5.64645 3.85355L9.79289 8L5.64645 12.1464C5.45118 12.3417 5.45118 12.6583 5.64645 12.8536C5.84171 13.0488 6.15829 13.0488 6.35355 12.8536L10.8536 8.35355C11.0488 8.15829 11.0488 7.84171 10.8536 7.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645Z',
|
||||
fill: 'currentColor'
|
||||
})
|
||||
]) : null,
|
||||
h('img', {
|
||||
src: getFileIcon(row.type),
|
||||
alt: row.type,
|
||||
@ -330,30 +491,39 @@ const columns: DataTableColumns<FileItem> = [
|
||||
{
|
||||
title: '大小',
|
||||
key: 'size',
|
||||
width: 100
|
||||
width: responsiveColumns.value.size
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
key: 'creator',
|
||||
width: 120
|
||||
width: responsiveColumns.value.creator
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime',
|
||||
width: 180
|
||||
width: responsiveColumns.value.createTime
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
width: 320,
|
||||
width: responsiveColumns.value.actions,
|
||||
render: (row: FileItem) => {
|
||||
return h('div', { style: { display: 'flex', gap: '8px', alignItems: 'center', flexWrap: 'wrap' } }, [
|
||||
h(NButton, {
|
||||
size: 'small',
|
||||
type: 'info',
|
||||
secondary: true,
|
||||
onClick: () => uploadFile(row)
|
||||
}, { default: () => '上传文件' }),
|
||||
const buttons = []
|
||||
|
||||
// 只有文件夹类型才显示上传文件按钮
|
||||
if (row.type === 'folder') {
|
||||
buttons.push(
|
||||
h(NButton, {
|
||||
size: 'small',
|
||||
type: 'info',
|
||||
secondary: true,
|
||||
onClick: () => uploadFile(row)
|
||||
}, { default: () => '上传文件' })
|
||||
)
|
||||
}
|
||||
|
||||
// 其他按钮始终显示
|
||||
buttons.push(
|
||||
h(NButton, {
|
||||
size: 'small',
|
||||
type: 'primary',
|
||||
@ -372,10 +542,12 @@ const columns: DataTableColumns<FileItem> = [
|
||||
}, {
|
||||
default: () => h(NButton, { size: 'small', secondary: true }, { default: () => '更多' })
|
||||
})
|
||||
])
|
||||
)
|
||||
|
||||
return h('div', { style: { display: 'flex', gap: '8px', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'center' } }, buttons)
|
||||
}
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
// 文件操作方法
|
||||
const addCourseware = () => {
|
||||
@ -435,9 +607,61 @@ const renameFile = (file: FileItem) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 递归查找文件在树形结构中的位置
|
||||
const findFileInTree = (files: FileItem[], targetId: number): { parent: FileItem | null, index: number } | null => {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i]
|
||||
if (file.id === targetId) {
|
||||
return { parent: null, index: i }
|
||||
}
|
||||
if (file.children) {
|
||||
for (let j = 0; j < file.children.length; j++) {
|
||||
if (file.children[j].id === targetId) {
|
||||
return { parent: file, index: j }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 优化后的置顶功能,支持文件夹内部置顶
|
||||
const toggleTop = (file: FileItem) => {
|
||||
file.isTop = !file.isTop
|
||||
message.success(file.isTop ? '已置顶' : '已取消置顶')
|
||||
|
||||
if (file.isTop) {
|
||||
// 置顶:在当前位置进行置顶
|
||||
const result = findFileInTree(fileList.value, file.id)
|
||||
if (result) {
|
||||
if (result.parent) {
|
||||
// 如果是子文件,在父文件夹内部置顶
|
||||
const children = result.parent.children!
|
||||
const [topFile] = children.splice(result.index, 1)
|
||||
children.unshift(topFile)
|
||||
} else {
|
||||
// 如果是根级别文件,在根级别置顶
|
||||
const [topFile] = fileList.value.splice(result.index, 1)
|
||||
fileList.value.unshift(topFile)
|
||||
}
|
||||
}
|
||||
message.success('已置顶')
|
||||
} else {
|
||||
// 取消置顶:在当前位置取消置顶
|
||||
const result = findFileInTree(fileList.value, file.id)
|
||||
if (result) {
|
||||
if (result.parent) {
|
||||
// 如果是子文件,在父文件夹内部取消置顶
|
||||
const children = result.parent.children!
|
||||
const [unTopFile] = children.splice(result.index, 1)
|
||||
children.push(unTopFile)
|
||||
} else {
|
||||
// 如果是根级别文件,在根级别取消置顶
|
||||
const [unTopFile] = fileList.value.splice(result.index, 1)
|
||||
fileList.value.push(unTopFile)
|
||||
}
|
||||
}
|
||||
message.success('已取消置顶')
|
||||
}
|
||||
}
|
||||
|
||||
const setPermissions = (file: FileItem) => {
|
||||
@ -447,11 +671,18 @@ const setPermissions = (file: FileItem) => {
|
||||
const downloadFile = (file: FileItem) => {
|
||||
message.info('下载文件: ' + file.name)
|
||||
}
|
||||
|
||||
// 切换文件夹展开/收起状态
|
||||
const toggleFolder = (folder: FileItem) => {
|
||||
if (folder.type === 'folder' && folder.children) {
|
||||
folder.expanded = !folder.expanded
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.courseware-management {
|
||||
width: 1293px;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
@ -486,7 +717,7 @@ const downloadFile = (file: FileItem) => {
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@ -534,8 +765,8 @@ const downloadFile = (file: FileItem) => {
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #F1F3F4;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@ -563,7 +794,7 @@ const downloadFile = (file: FileItem) => {
|
||||
.table-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 1181px;
|
||||
height: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
@ -601,11 +832,11 @@ const downloadFile = (file: FileItem) => {
|
||||
|
||||
/* 名称列左对齐 */
|
||||
:deep(.file-data-table .n-data-table-td[data-col-key="name"]) {
|
||||
text-align: left;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep(.file-data-table .n-data-table-th[data-col-key="name"]) {
|
||||
text-align: left;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep(.file-data-table .n-data-table-tr:hover) {
|
||||
@ -726,6 +957,11 @@ const downloadFile = (file: FileItem) => {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* 隐藏序号列中的展开图标 */
|
||||
:deep(.file-data-table .n-data-table-expand-trigger) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* 操作按钮样式 - 只有边框和文字颜色,无背景色 */
|
||||
:deep(.file-data-table .n-button--info-type.n-button--secondary) {
|
||||
background-color: transparent !important;
|
||||
@ -867,4 +1103,146 @@ const downloadFile = (file: FileItem) => {
|
||||
.nav-button:hover:not(.disabled) {
|
||||
color: #0088D1;
|
||||
}
|
||||
|
||||
/* 响应式样式 */
|
||||
@media (max-width: 1200px) {
|
||||
.toolbar {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.toolbar-actions {
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
/* 表格在小屏幕下的优化 */
|
||||
:deep(.file-data-table) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 操作按钮在小屏幕下换行 */
|
||||
:deep(.file-data-table .n-data-table-td:last-child .n-button) {
|
||||
margin: 2px;
|
||||
font-size: 11px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.toolbar {
|
||||
padding: 20px 15px;
|
||||
}
|
||||
|
||||
.toolbar h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 120px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 表格在移动端的优化 */
|
||||
:deep(.file-data-table) {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* 隐藏某些列在移动端 */
|
||||
:deep(.file-data-table .n-data-table-th[data-col-key="creator"]),
|
||||
:deep(.file-data-table .n-data-table-td[data-col-key="creator"]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 操作按钮在移动端垂直排列 */
|
||||
:deep(.file-data-table .n-data-table-td:last-child > div) {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
:deep(.file-data-table .n-data-table-td:last-child .n-button) {
|
||||
width: 100%;
|
||||
margin: 1px 0;
|
||||
}
|
||||
|
||||
/* 分页器在移动端的优化 */
|
||||
.page-numbers {
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.page-number {
|
||||
min-width: 32px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
font-size: 12px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.toolbar-actions {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 进一步隐藏列 */
|
||||
:deep(.file-data-table .n-data-table-th[data-col-key="createTime"]),
|
||||
:deep(.file-data-table .n-data-table-td[data-col-key="createTime"]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 表格内容在超小屏幕下的优化 */
|
||||
:deep(.file-data-table .n-data-table-td) {
|
||||
padding: 8px 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.file-data-table .n-data-table-th) {
|
||||
padding: 8px 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 表格横向滚动优化 */
|
||||
:deep(.file-data-table .n-data-table-wrapper) {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
:deep(.file-data-table .n-data-table-base-table) {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
/* 确保表格内容不会溢出 */
|
||||
:deep(.file-data-table .n-data-table-td) {
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* 名称列文本溢出处理 */
|
||||
:deep(.file-data-table .n-data-table-td[data-col-key="name"] span) {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
@ -17,9 +17,9 @@
|
||||
<div class="content-area">
|
||||
<div class="table-container">
|
||||
<n-config-provider :locale="zhCN" :date-locale="dateZhCN">
|
||||
<n-data-table :columns="columns" :data="homeworkList" :row-key="rowKey" :checked-row-keys="selectedHomework"
|
||||
@update:checked-row-keys="handleCheck" :bordered="false" :single-line="false" size="medium"
|
||||
class="homework-data-table" />
|
||||
<n-data-table :columns="columns" :data="sortedHomeworkList" :row-key="rowKey"
|
||||
:checked-row-keys="selectedHomework" @update:checked-row-keys="handleCheck" :bordered="false"
|
||||
:single-line="false" size="medium" class="homework-data-table" />
|
||||
</n-config-provider>
|
||||
</div>
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, h, computed } from 'vue'
|
||||
import { ref, h, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { NButton, NDropdown, NDataTable, NConfigProvider, zhCN, dateZhCN } from 'naive-ui'
|
||||
import type { DataTableColumns } from 'naive-ui'
|
||||
|
||||
@ -85,6 +85,71 @@ const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const totalCount = ref(6)
|
||||
|
||||
// 屏幕宽度响应式数据
|
||||
const screenWidth = ref(window.innerWidth)
|
||||
|
||||
// 监听窗口大小变化
|
||||
const handleResize = () => {
|
||||
screenWidth.value = window.innerWidth
|
||||
}
|
||||
|
||||
// 响应式列配置计算属性
|
||||
const responsiveColumns = computed(() => {
|
||||
const width = screenWidth.value
|
||||
|
||||
// 基础列宽配置
|
||||
const baseColumns = {
|
||||
selection: 50,
|
||||
index: 80,
|
||||
name: 200,
|
||||
chapter: 180,
|
||||
class: 150,
|
||||
creator: 120,
|
||||
createTime: 180,
|
||||
actions: 200
|
||||
}
|
||||
|
||||
// 根据屏幕宽度调整列宽
|
||||
if (width < 1200) {
|
||||
// 小屏幕:减少各列宽度
|
||||
return {
|
||||
selection: 40,
|
||||
index: 60,
|
||||
name: Math.max(150, width * 0.2),
|
||||
chapter: Math.max(120, width * 0.15),
|
||||
class: Math.max(100, width * 0.12),
|
||||
creator: 80,
|
||||
createTime: 140,
|
||||
actions: Math.max(160, width * 0.2)
|
||||
}
|
||||
} else if (width < 1600) {
|
||||
// 中等屏幕:保持基础宽度
|
||||
return baseColumns
|
||||
} else {
|
||||
// 大屏幕:适当增加宽度
|
||||
return {
|
||||
selection: 55,
|
||||
index: 90,
|
||||
name: 250,
|
||||
chapter: 220,
|
||||
class: 180,
|
||||
creator: 140,
|
||||
createTime: 200,
|
||||
actions: 240
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 在组件挂载时添加事件监听器
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
// 在组件卸载时移除事件监听器
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
// 计算总页数
|
||||
const totalPages = computed(() => Math.ceil(totalCount.value / pageSize.value))
|
||||
|
||||
@ -190,6 +255,15 @@ const homeworkList = ref<HomeworkItem[]>([
|
||||
}
|
||||
])
|
||||
|
||||
// 排序后的作业列表(置顶作业优先显示)
|
||||
const sortedHomeworkList = computed(() => {
|
||||
return homeworkList.value.sort((a: HomeworkItem, b: HomeworkItem) => {
|
||||
if (a.isTop && !b.isTop) return -1
|
||||
if (!a.isTop && b.isTop) return 1
|
||||
return 0
|
||||
})
|
||||
})
|
||||
|
||||
// 行键
|
||||
const rowKey = (row: HomeworkItem) => row.id
|
||||
|
||||
@ -199,20 +273,24 @@ const handleCheck = (keys: number[]) => {
|
||||
}
|
||||
|
||||
// 表格列定义
|
||||
const columns: DataTableColumns<HomeworkItem> = [
|
||||
const columns = computed((): DataTableColumns<HomeworkItem> => [
|
||||
{
|
||||
type: 'selection',
|
||||
width: 50
|
||||
width: responsiveColumns.value.selection
|
||||
},
|
||||
{
|
||||
title: '序号',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
width: responsiveColumns.value.index,
|
||||
render: (_, index) => index + 1
|
||||
},
|
||||
{
|
||||
title: '作业名称',
|
||||
key: 'name',
|
||||
width: responsiveColumns.value.name,
|
||||
ellipsis: {
|
||||
tooltip: true
|
||||
},
|
||||
render: (row) => {
|
||||
return h('div', { style: 'display: flex; align-items: center; gap: 8px;' }, [
|
||||
h('span', { class: 'homework-name' }, row.name),
|
||||
@ -222,24 +300,34 @@ const columns: DataTableColumns<HomeworkItem> = [
|
||||
},
|
||||
{
|
||||
title: '所属章节',
|
||||
key: 'chapter'
|
||||
key: 'chapter',
|
||||
width: responsiveColumns.value.chapter,
|
||||
ellipsis: {
|
||||
tooltip: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '绑定班级',
|
||||
key: 'class'
|
||||
key: 'class',
|
||||
width: responsiveColumns.value.class,
|
||||
ellipsis: {
|
||||
tooltip: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
key: 'creator'
|
||||
key: 'creator',
|
||||
width: responsiveColumns.value.creator
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime'
|
||||
key: 'createTime',
|
||||
width: responsiveColumns.value.createTime
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
width: 200,
|
||||
width: responsiveColumns.value.actions,
|
||||
render: (row) => {
|
||||
return h('div', { style: 'display: flex; gap: 8px; align-items: center;' }, [
|
||||
h(NButton, {
|
||||
@ -289,7 +377,7 @@ const columns: DataTableColumns<HomeworkItem> = [
|
||||
])
|
||||
}
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
// 编辑作业
|
||||
const editHomework = (id: number) => {
|
||||
@ -301,15 +389,51 @@ const deleteHomework = (id: number) => {
|
||||
console.log('删除作业:', id)
|
||||
}
|
||||
|
||||
// 处理下拉菜单操作
|
||||
// 处理更多操作
|
||||
const handleAction = (key: string, row: HomeworkItem) => {
|
||||
console.log('操作:', key, row)
|
||||
switch (key) {
|
||||
case 'rename':
|
||||
console.log('重命名作业:', row.id)
|
||||
break
|
||||
case 'toggleTop':
|
||||
toggleTop(row)
|
||||
break
|
||||
case 'permissions':
|
||||
console.log('权限设置:', row.id)
|
||||
break
|
||||
case 'download':
|
||||
console.log('下载作业:', row.id)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 置顶/取消置顶功能(真实置顶版本)
|
||||
const toggleTop = (homework: HomeworkItem) => {
|
||||
homework.isTop = !homework.isTop
|
||||
|
||||
if (homework.isTop) {
|
||||
// 置顶:将作业移动到数组最前面
|
||||
const index = homeworkList.value.findIndex((h: HomeworkItem) => h.id === homework.id)
|
||||
if (index > -1) {
|
||||
const [topHomework] = homeworkList.value.splice(index, 1)
|
||||
homeworkList.value.unshift(topHomework)
|
||||
}
|
||||
console.log('已置顶作业:', homework.id)
|
||||
} else {
|
||||
// 取消置顶:将作业移动到数组末尾
|
||||
const index = homeworkList.value.findIndex((h: HomeworkItem) => h.id === homework.id)
|
||||
if (index > -1) {
|
||||
const [unTopHomework] = homeworkList.value.splice(index, 1)
|
||||
homeworkList.value.push(unTopHomework)
|
||||
}
|
||||
console.log('已取消置顶作业:', homework.id)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.homework-library {
|
||||
width: 1293px;
|
||||
width: 100%;
|
||||
padding: 10px 20px 20px 0;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
@ -717,4 +841,154 @@ const handleAction = (key: string, row: HomeworkItem) => {
|
||||
border-color: #9ac1d6 !important;
|
||||
font-size: 10px !important;
|
||||
}
|
||||
|
||||
/* 响应式样式 */
|
||||
@media (max-width: 1200px) {
|
||||
.toolbar {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.toolbar-actions {
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
/* 表格在小屏幕下的优化 */
|
||||
:deep(.homework-data-table) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 操作按钮在小屏幕下换行 */
|
||||
:deep(.homework-data-table .n-data-table-td:last-child .n-button) {
|
||||
margin: 2px;
|
||||
font-size: 11px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.toolbar {
|
||||
padding: 20px 15px;
|
||||
}
|
||||
|
||||
.toolbar h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 120px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 表格在移动端的优化 */
|
||||
:deep(.homework-data-table) {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* 隐藏某些列在移动端 */
|
||||
:deep(.homework-data-table .n-data-table-th[data-col-key="creator"]),
|
||||
:deep(.homework-data-table .n-data-table-td[data-col-key="creator"]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 操作按钮在移动端垂直排列 */
|
||||
:deep(.homework-data-table .n-data-table-td:last-child > div) {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
:deep(.homework-data-table .n-data-table-td:last-child .n-button) {
|
||||
width: 100%;
|
||||
margin: 1px 0;
|
||||
}
|
||||
|
||||
/* 分页器在移动端的优化 */
|
||||
.page-numbers {
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.page-number {
|
||||
min-width: 32px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
font-size: 12px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.toolbar-actions {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 进一步隐藏列 */
|
||||
:deep(.homework-data-table .n-data-table-th[data-col-key="createTime"]),
|
||||
:deep(.homework-data-table .n-data-table-td[data-col-key="createTime"]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 表格内容在超小屏幕下的优化 */
|
||||
:deep(.homework-data-table .n-data-table-td) {
|
||||
padding: 8px 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.homework-data-table .n-data-table-th) {
|
||||
padding: 8px 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 表格横向滚动优化 */
|
||||
:deep(.homework-data-table .n-data-table-wrapper) {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
:deep(.homework-data-table .n-data-table-base-table) {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
/* 确保表格内容不会溢出 */
|
||||
:deep(.homework-data-table .n-data-table-td) {
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* 作业名称列文本溢出处理 */
|
||||
:deep(.homework-data-table .n-data-table-td[data-col-key="name"] .homework-name) {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* 置顶标签在小屏幕下的优化 */
|
||||
@media (max-width: 768px) {
|
||||
.tag-pinned {
|
||||
padding: 2px 6px;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -96,7 +96,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
interface HomeworkItem {
|
||||
id: number
|
||||
@ -112,6 +112,24 @@ interface HomeworkItem {
|
||||
|
||||
const activeTab = ref<'all' | 'publishing' | 'ended'>('all')
|
||||
|
||||
// 屏幕宽度响应式数据
|
||||
const screenWidth = ref(window.innerWidth)
|
||||
|
||||
// 监听窗口大小变化
|
||||
const handleResize = () => {
|
||||
screenWidth.value = window.innerWidth
|
||||
}
|
||||
|
||||
// 在组件挂载时添加事件监听器
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
// 在组件卸载时移除事件监听器
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
const homeworks = ref<HomeworkItem[]>([
|
||||
{
|
||||
id: 1,
|
||||
@ -145,7 +163,7 @@ const filteredHomeworks = computed(() => {
|
||||
if (activeTab.value === 'all') {
|
||||
return homeworks.value
|
||||
}
|
||||
return homeworks.value.filter(homework => homework.status === activeTab.value)
|
||||
return homeworks.value.filter((homework: HomeworkItem) => homework.status === activeTab.value)
|
||||
})
|
||||
|
||||
const reviewHomework = (id: number) => {
|
||||
@ -163,7 +181,7 @@ const deleteHomework = (id: number) => {
|
||||
|
||||
<style scoped>
|
||||
.homework-review {
|
||||
width: 1293px;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
@ -406,4 +424,168 @@ const deleteHomework = (id: number) => {
|
||||
.homework-card.publishing .stats-area {
|
||||
margin-top: 20px;
|
||||
}
|
||||
/* 响应式样式 */
|
||||
@media (max-width: 1200px) {
|
||||
.top-section {
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
align-items: flex-start;
|
||||
padding: 20px 0 0 20px;
|
||||
}
|
||||
|
||||
.filter-tabs {
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 作业卡片在小屏幕下的优化 */
|
||||
.homework-card {
|
||||
margin: 15px 20px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.content-right {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.top-section {
|
||||
padding: 15px 0 0 15px;
|
||||
}
|
||||
|
||||
.filter-tabs {
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
font-size: 14px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.dropdown-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 作业卡片在移动端的优化 */
|
||||
.homework-card {
|
||||
margin: 10px 15px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.homework-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.homework-desc {
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.info-item .text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.stats-area {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.big-number {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.top-section {
|
||||
padding: 10px 0 0 10px;
|
||||
}
|
||||
|
||||
.filter-tabs {
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
font-size: 13px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
/* 作业卡片在超小屏幕下的优化 */
|
||||
.homework-card {
|
||||
margin: 8px 10px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.homework-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.homework-desc {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.info-item .text {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.big-number {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.delete-link {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 确保内容不会溢出 */
|
||||
.homework-card {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.homework-title {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.homework-desc {
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
</style>
|
@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div class="practice-management">
|
||||
<router-view></router-view>
|
||||
<div class="content-placeholder">
|
||||
<h2>练考通管理</h2>
|
||||
<p>练考通管理功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -14,4 +17,20 @@
|
||||
background: #fff;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content-placeholder {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
}
|
||||
|
||||
.content-placeholder h2 {
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.content-placeholder p {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
|
400
src/views/teacher/course/UploadFileModal.vue
Normal file
400
src/views/teacher/course/UploadFileModal.vue
Normal file
@ -0,0 +1,400 @@
|
||||
<template>
|
||||
<div class="modal-container flex-col" @click.stop>
|
||||
<span class="modal-title">上传文件</span>
|
||||
<div class="upload-area flex-row">
|
||||
<span class="upload-label">上传文件:</span>
|
||||
<div class="select-file-btn flex-col" @click="toggleDropdown" style="position: relative;">
|
||||
<span class="btn-text">选择文件</span>
|
||||
<!-- 下拉选项 -->
|
||||
<div v-show="showDropdown" class="upload-methods flex-col">
|
||||
<label class="local-upload">
|
||||
<input
|
||||
type="file"
|
||||
@change="handleLocalUpload"
|
||||
style="display: none;"
|
||||
accept=".doc,.docx,.pdf,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4"
|
||||
/>
|
||||
本地上传
|
||||
</label>
|
||||
<label class="resource-upload">
|
||||
<input
|
||||
type="file"
|
||||
@change="handleResourceUpload"
|
||||
style="display: none;"
|
||||
accept=".doc,.docx,.pdf,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4"
|
||||
/>
|
||||
资源上传
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="supported-formats flex-row">
|
||||
<span class="formats-label">支持格式:</span>
|
||||
<span class="document-formats">文本文:.doc、.docx、.pdf表格文件:.xls、.xlsx<br />演示文稿:.ppt、.pptx</span>
|
||||
<span class="media-formats">音频文件:.mp3<br />视频文件:.mp4<br /></span>
|
||||
</div>
|
||||
<div class="upload-limits flex-row justify-between">
|
||||
<span class="limits-label">上传限制:</span>
|
||||
<span class="limits-description">word、excel、ppt文件需小于100MB,其他文件需小于2GB.mp4格式编码<br />说明(上传mp4格式文件请查看编码说明)</span>
|
||||
</div>
|
||||
<div class="action-buttons flex-row justify-between">
|
||||
<div class="cancel-btn-container flex-col">
|
||||
<div class="cancel-btn flex-col" @click="handleCancel">
|
||||
<span class="cancel-btn-text">取消</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="confirm-btn flex-col" @click="handleConfirm">
|
||||
<span class="confirm-btn-text">确定</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
// 控制下拉菜单显示
|
||||
const showDropdown = ref(false)
|
||||
|
||||
// 切换下拉菜单
|
||||
const toggleDropdown = () => {
|
||||
showDropdown.value = !showDropdown.value
|
||||
}
|
||||
|
||||
// 处理本地上传
|
||||
const handleLocalUpload = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
const files = target.files
|
||||
if (files && files.length > 0) {
|
||||
console.log('本地上传文件:', files[0])
|
||||
// 这里处理本地文件上传逻辑
|
||||
showDropdown.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理资源上传
|
||||
const handleResourceUpload = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
const files = target.files
|
||||
if (files && files.length > 0) {
|
||||
console.log('资源上传文件:', files[0])
|
||||
// 这里处理资源文件上传逻辑
|
||||
showDropdown.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 定义事件发射器
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
// 处理取消按钮
|
||||
const handleCancel = () => {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
// 处理确定按钮
|
||||
const handleConfirm = () => {
|
||||
// 这里可以添加确定逻辑,比如验证文件等
|
||||
console.log('确定上传')
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-container {
|
||||
width: 1076px;
|
||||
height: 623px;
|
||||
background: #FFFFFF;
|
||||
background-size: 100% 100%;
|
||||
margin: 0 auto;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
width: 77px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 20px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin: 21px 0 0 24px;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
width: 1028px;
|
||||
height: 160px;
|
||||
background: #FCFCFC;
|
||||
background-size: 100% 100%;
|
||||
margin: 46px 0 0 22px;
|
||||
border: 1px solid rgba(204, 204, 204, 1);
|
||||
|
||||
}
|
||||
|
||||
.upload-label {
|
||||
width: 90px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin: 65px 0 0 35px;
|
||||
}
|
||||
|
||||
.select-file-btn {
|
||||
height: 38px;
|
||||
background: #0288D1;
|
||||
background-size: 100% 100%;
|
||||
width: 123px;
|
||||
margin: 56px 777px 0 3px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
width: 100%;
|
||||
height: 21px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: 21px;
|
||||
margin: 6px 0 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.upload-methods {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
width: 123px;
|
||||
height: 76px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.local-upload {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 14px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: 30px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px 0;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.local-upload:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.resource-upload {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 14px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
line-height: 30px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 5px 0;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.resource-upload:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.supported-formats {
|
||||
width: 532px;
|
||||
height: 93px;
|
||||
margin: 27px 0 0 57px;
|
||||
}
|
||||
|
||||
.formats-label {
|
||||
width: 90px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.document-formats {
|
||||
width: 230px;
|
||||
height: 90px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(102, 102, 102, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
line-height: 30px;
|
||||
margin-left: 18px;
|
||||
}
|
||||
|
||||
.media-formats {
|
||||
width: 131px;
|
||||
height: 90px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(102, 102, 102, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
line-height: 30px;
|
||||
margin: 3px 0 0 63px;
|
||||
}
|
||||
|
||||
.upload-limits {
|
||||
width: 698px;
|
||||
height: 60px;
|
||||
margin: 26px 0 0 57px;
|
||||
}
|
||||
|
||||
.limits-label {
|
||||
width: 90px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(6, 35, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.limits-description {
|
||||
width: 590px;
|
||||
height: 60px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(102, 102, 102, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
width: 147px;
|
||||
height: 32px;
|
||||
margin: 103px 0 23px 905px;
|
||||
}
|
||||
|
||||
.cancel-btn-container {
|
||||
height: 32px;
|
||||
width: 66px;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
height: 32px;
|
||||
background: #E2F5FF;
|
||||
background-size: 68px 34px;
|
||||
width: 66px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.cancel-btn:hover {
|
||||
background: #D1EFFF;
|
||||
}
|
||||
|
||||
.cancel-btn-text {
|
||||
width: 32px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(2, 136, 209, 1);
|
||||
font-size: 16px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin: 5px 0 0 17px;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
height: 32px;
|
||||
background: #0288D1;
|
||||
background-size: 100% 100%;
|
||||
width: 66px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.confirm-btn:hover {
|
||||
background: #0277BD;
|
||||
}
|
||||
|
||||
.confirm-btn-text {
|
||||
width: 32px;
|
||||
height: 22px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
font-size: 16px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 22px;
|
||||
margin: 5px 0 0 17px;
|
||||
}
|
||||
|
||||
/* 添加按钮悬停效果 */
|
||||
.select-file-btn:hover {
|
||||
background: #0277BD;
|
||||
}
|
||||
|
||||
/* 确保下拉菜单在按钮上方显示 */
|
||||
.select-file-btn .upload-methods {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* 隐藏文件输入框 */
|
||||
.local-upload input[type="file"],
|
||||
.resource-upload input[type="file"] {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user