sytle: 教师端尺寸

This commit is contained in:
guoan 2025-08-22 19:52:05 +08:00
parent c4e96ea899
commit e75ffdf1e8
15 changed files with 6144 additions and 910 deletions

2687
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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;

View 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">wordexcelppt文件需小于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>

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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;

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View 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">wordexcelppt文件需小于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>