style: 课件部分弹窗

This commit is contained in:
Wxp 2025-08-24 18:20:16 +08:00
parent 16ee40e020
commit 7be3eca61e
21 changed files with 3355 additions and 1078 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 980 B

After

Width:  |  Height:  |  Size: 980 B

View File

Before

Width:  |  Height:  |  Size: 963 B

After

Width:  |  Height:  |  Size: 963 B

View File

Before

Width:  |  Height:  |  Size: 705 B

After

Width:  |  Height:  |  Size: 705 B

View File

@ -100,7 +100,7 @@ const courseList = ref([
// //
const navigateToCreateCourse = () => { const navigateToCreateCourse = () => {
router.push('/teacher/course-create'); // router.push('/teacher/course-create');
}; };
</script> </script>

View File

@ -71,13 +71,13 @@
.course-create-page { .course-create-page {
background-color: rgba(255, 255, 255, 1); background-color: rgba(255, 255, 255, 1);
position: relative; position: relative;
min-height: 1712px; min-height: 1200px; /* 从1712px减少到1200px */
height: auto; height: auto;
overflow: visible; overflow: visible;
} }
.course-form-container { .course-form-container {
min-height: 1211px; min-height: 900px; /* 从1211px减少到900px */
height: auto; height: auto;
background-size: 100% 100%; background-size: 100% 100%;
/* width: 1565px; */ /* width: 1565px; */
@ -86,52 +86,52 @@
/* 第一行:课程名称和分类 */ /* 第一行:课程名称和分类 */
.course-basic-info-row { .course-basic-info-row {
width: 1307px; width: 1000px; /* 从1307px减少到1000px */
height: 43px; height: 32px; /* 从43px减少到32px */
margin: 30px 0 0 102px; margin: 20px 0 0 80px; /* 从30px 0 0 102px减少到20px 0 0 80px */
} }
.course-name-label { .course-name-label {
width: 89px; width: 70px; /* 从89px减少到70px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
margin-top: 9px; margin-top: 6px; /* 从9px减少到6px */
} }
.required-asterisk { .required-asterisk {
color: rgba(255, 77, 79, 1); color: rgba(255, 77, 79, 1);
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: left; text-align: left;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
} }
.label-text { .label-text {
color: rgba(51, 51, 51, 1); color: rgba(51, 51, 51, 1);
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: left; text-align: left;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
} }
.course-name-input-wrapper { .course-name-input-wrapper {
height: 42px; height: 32px; /* 从42px减少到32px */
background-size: 562px 44px; background-size: 400px 32px; /* 从562px 44px减少到400px 32px */
margin-left: 2px; margin-left: 2px;
width: 560px; width: 400px; /* 从560px减少到400px */
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
padding: 0 12px; padding: 0 10px; /* 从0 12px减少到0 10px */
display: flex; display: flex;
align-items: center; align-items: center;
} }
@ -141,45 +141,45 @@
height: 100%; height: 100%;
border: none; border: none;
background: transparent; background: transparent;
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
color: #333; color: #333;
} }
.course-input::placeholder { .course-input::placeholder {
color: rgba(153, 153, 153, 1); color: rgba(153, 153, 153, 1);
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
} }
.course-category-section { .course-category-section {
height: 42px; height: 32px; /* 从42px减少到32px */
width: 522px; width: 400px; /* 从522px减少到400px */
position: relative; position: relative;
margin: 1px 0 0 134px; margin: 1px 0 0 100px; /* 从1px 0 0 134px减少到1px 0 0 100px */
} }
.course-category-label { .course-category-label {
width: 89px; width: 70px; /* 从89px减少到70px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
margin-top: 9px; margin-top: 6px; /* 从9px减少到6px */
} }
.course-category-select-wrapper { .course-category-select-wrapper {
height: 42px; height: 32px; /* 从42px减少到32px */
background-size: 562px 44px; background-size: 400px 32px; /* 从562px 44px减少到400px 32px */
width: 560px; width: 400px; /* 从560px减少到400px */
position: absolute; position: absolute;
left: 87px; left: 70px; /* 从87px减少到70px */
top: 0; top: 0;
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
padding: 0 12px; padding: 0 10px; /* 从0 12px减少到0 10px */
display: flex; display: flex;
align-items: center; align-items: center;
} }
@ -193,32 +193,32 @@
/* 第二行:主讲老师 */ /* 第二行:主讲老师 */
.instructor-sort-row { .instructor-sort-row {
width: 1340px; width: 1000px; /* 从1340px减少到1000px */
height: 42px; height: 32px; /* 从42px减少到32px */
margin: 29px 0 0 102px; margin: 20px 0 0 80px; /* 从29px 0 0 102px减少到20px 0 0 80px */
} }
.instructor-label { .instructor-label {
width: 89px; width: 70px; /* 从89px减少到70px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
margin-top: 9px; margin-top: 6px; /* 从9px减少到6px */
} }
.instructor-select-wrapper { .instructor-select-wrapper {
width: 560px; width: 400px; /* 从560px减少到400px */
height: 42px; height: 32px; /* 从42px减少到32px */
background-size: 562px 44px; background-size: 400px 32px; /* 从562px 44px减少到400px 32px */
margin-left: 2px; margin-left: 2px;
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
padding: 0 12px; padding: 0 10px; /* 从0 12px减少到0 10px */
display: flex; display: flex;
align-items: center; align-items: center;
} }
@ -233,24 +233,24 @@
/* 主讲老师选择区域样式已整合到 .instructor-select 中 */ /* 主讲老师选择区域样式已整合到 .instructor-select 中 */
.course-sort-section { .course-sort-section {
height: 42px; height: 32px; /* 从42px减少到32px */
margin-left: 159px; margin-left: 120px; /* 从159px减少到120px */
width: 630px; width: 480px; /* 从630px减少到480px */
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px; /* 从10px减少到8px */
} }
.course-sort-label { .course-sort-label {
width: 57px; width: 45px; /* 从57px减少到45px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
flex-shrink: 0; flex-shrink: 0;
} }
@ -259,12 +259,12 @@
position: relative; position: relative;
left: 0; left: 0;
top: 0; top: 0;
width: 560px; width: 400px; /* 从560px减少到400px */
height: 42px; height: 32px; /* 从42px减少到32px */
background-size: 562px 44px; background-size: 400px 32px; /* 从562px 44px减少到400px 32px */
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
padding: 0 12px; padding: 0 10px; /* 从0 12px减少到0 10px */
display: flex; display: flex;
align-items: center; align-items: center;
flex-shrink: 0; flex-shrink: 0;
@ -275,49 +275,50 @@
height: 100%; height: 100%;
border: none; border: none;
background: transparent; background: transparent;
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
color: #333; color: #333;
} }
.sort-input::placeholder { .sort-input::placeholder {
color: rgba(153, 153, 153, 1); color: rgba(153, 153, 153, 1);
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
} }
/* 第三行:时间选择 */ /* 第三行:时间选择 */
.course-time-row { .course-time-row {
width: 1463px; width: 1100px; /* 从1463px减少到1100px */
height: 49px; height: 36px; /* 从49px减少到36px */
margin: 30px 0 0 71px; margin: 20px 0 0 60px; /* 从30px 0 0 71px减少到20px 0 0 60px */
} }
.start-time-label { .start-time-label {
width: 121px; width: 90px; /* 从121px减少到90px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
margin-top: 9px; margin-top: 6px; /* 从9px减少到6px */
} }
.start-time-picker-wrapper, .end-time-picker-wrapper { .start-time-picker-wrapper,
width: 560px; .end-time-picker-wrapper {
height: 42px; width: 400px; /* 从560px减少到400px */
background-size: 562px 44px; height: 32px; /* 从42px减少到32px */
background-size: 400px 32px; /* 从562px 44px减少到400px 32px */
margin-left: 1px; margin-left: 1px;
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
padding: 0 12px; padding: 0 10px; /* 从0 12px减少到0 10px */
display: flex; display: flex;
align-items: center; align-items: center;
} }
.group_12 { .group_12 {
margin: 7px 0 0 6px; margin: 5px 0 0 4px; /* 从7px 0 0 6px减少到5px 0 0 4px */
} }
.form-datepicker { .form-datepicker {
@ -328,35 +329,35 @@
} }
.end-time-label { .end-time-label {
width: 121px; width: 90px; /* 从121px减少到90px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
margin: 16px 0 0 94px; margin: 12px 0 0 70px; /* 从16px 0 0 94px减少到12px 0 0 70px */
} }
/* 参与学员 */ /* 参与学员 */
.student-selection-row { .student-selection-row {
width: 312px; width: 250px; /* 从312px减少到250px */
height: 18px; height: 16px; /* 从18px减少到16px */
margin: 23px 0 0 103px; margin: 16px 0 0 80px; /* 从23px 0 0 103px减少到16px 0 0 80px */
} }
.student-selection-label { .student-selection-label {
width: 89px; width: 70px; /* 从89px减少到70px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
} }
.student-type-radio-group { .student-type-radio-group {
@ -368,16 +369,16 @@
display: flex; display: flex;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
margin-right: 38px; margin-right: 30px; /* 从38px减少到30px */
} }
.radio-circle { .radio-circle {
width: 16px; width: 14px; /* 从16px减少到14px */
height: 16px; height: 14px; /* 从16px减少到14px */
border: 2px solid #d9d9d9; border: 2px solid #d9d9d9;
border-radius: 50%; border-radius: 50%;
background: white; background: white;
margin-right: 8px; margin-right: 6px; /* 从8px减少到6px */
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -389,37 +390,37 @@
} }
.radio-dot { .radio-dot {
width: 8px; width: 6px; /* 从8px减少到6px */
height: 8px; height: 6px; /* 从8px减少到6px */
background: #1890ff; background: #1890ff;
border-radius: 50%; border-radius: 50%;
} }
.radio-text { .radio-text {
color: rgba(51, 51, 51, 1); color: rgba(51, 51, 51, 1);
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: left; text-align: left;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
margin-left: 7px; margin-left: 5px; /* 从7px减少到5px */
} }
/* 班级选择 */ /* 班级选择 */
.class-selection-row { .class-selection-row {
width: 560px; width: 400px; /* 从560px减少到400px */
height: 44px; height: 32px; /* 从44px减少到32px */
margin: 16px 0 0 192px; margin: 12px 0 0 150px; /* 从16px 0 0 192px减少到12px 0 0 150px */
} }
.class-select-wrapper { .class-select-wrapper {
width: 560px; width: 400px; /* 从560px减少到400px */
height: 44px; height: 32px; /* 从44px减少到32px */
background-size: 100% 100%; background-size: 100% 100%;
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
padding: 0 18px; padding: 0 14px; /* 从0 18px减少到0 14px */
display: flex; display: flex;
align-items: center; align-items: center;
} }
@ -433,27 +434,27 @@
/* 课程封面 */ /* 课程封面 */
.course-cover-row { .course-cover-row {
width: 312px; width: 250px; /* 从312px减少到250px */
height: 128px; height: 96px; /* 从128px减少到96px */
margin: 30px 0 0 41px; margin: 20px 0 0 30px; /* 从30px 0 0 41px减少到20px 0 0 30px */
} }
.course-cover-label { .course-cover-label {
width: 89px; width: 70px; /* 从89px减少到70px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
margin-top: 9px; margin-top: 6px; /* 从9px减少到6px */
} }
.cover-upload-area { .cover-upload-area {
width: 160px; width: 120px; /* 从160px减少到120px */
height: 128px; height: 96px; /* 从128px减少到96px */
border: 2px dashed #d9d9d9; border: 2px dashed #d9d9d9;
border-radius: 6px; border-radius: 6px;
display: flex; display: flex;
@ -495,9 +496,9 @@
} }
.upload-plus-icon { .upload-plus-icon {
font-size: 28px; font-size: 24px; /* 从28px减少到24px */
color: #999; color: #999;
margin-bottom: 8px; margin-bottom: 6px; /* 从8px减少到6px */
font-weight: normal; font-weight: normal;
line-height: 1; line-height: 1;
display: block; display: block;
@ -506,62 +507,60 @@
.upload-text { .upload-text {
color: rgba(102, 102, 102, 1); color: rgba(102, 102, 102, 1);
display: block; display: block;
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: center; text-align: center;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
} }
.upload-text-label { .upload-text-label {
width: 32px; width: 28px; /* 从32px减少到28px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
color: rgba(102, 102, 102, 1); color: rgba(102, 102, 102, 1);
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: center; text-align: center;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
} }
/* 课程简介整体区域 */ /* 课程简介整体区域 */
.course-description-section { .course-description-section {
width: 1452px; width: 1100px; /* 从1452px减少到1100px */
margin: 42px 0 0 41px; margin: 30px 0 0 30px; /* 从42px 0 0 41px减少到30px 0 0 30px */
} }
/* 课程简介标题 */ /* 课程简介标题 */
.course-description-header { .course-description-header {
position: relative; position: relative;
width: 100%; width: 100%;
height: 20px; height: 18px; /* 从20px减少到18px */
margin-bottom: -30px; margin-bottom: -20px; /* 从-30px减少到-20px */
} }
.course-description-label { .course-description-label {
width: 89px; width: 70px; /* 从89px减少到70px */
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: right; text-align: right;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
} }
.toolbar-icon-btn { .toolbar-icon-btn {
background: #f5f5f5; background: #f5f5f5;
border: 1px solid #d9d9d9; border: 1px solid #d9d9d9;
border-radius: 4px; border-radius: 4px;
padding: 4px 8px; padding: 3px 6px; /* 从4px 8px减少到3px 6px */
cursor: pointer; cursor: pointer;
font-size: 14px; font-size: 12px; /* 从14px减少到12px */
transition: all 0.3s; transition: all 0.3s;
} }
@ -572,27 +571,25 @@
/* 富文本编辑器区域 */ /* 富文本编辑器区域 */
.description-editor-container { .description-editor-container {
height: 336px; height: 250px; /* 从336px减少到250px */
background-size: 100% 100%; background-size: 100% 100%;
width: 1340px; width: 1000px; /* 从1340px减少到1000px */
position: relative; position: relative;
left: 0; left: 0;
top: 0; top: 0;
margin-left: 129px; margin-left: 100px; /* 从129px减少到100px */
border-radius: 8px; border-radius: 8px;
padding: 13px 19px; padding: 10px 15px; /* 从13px 19px减少到10px 15px */
background: white; background: white;
} }
.toolbar-btn { .toolbar-btn {
background: #f5f5f5; background: #f5f5f5;
border: 1px solid #d9d9d9; border: 1px solid #d9d9d9;
border-radius: 4px; border-radius: 4px;
padding: 3px 8px; padding: 2px 6px; /* 从3px 8px减少到2px 6px */
cursor: pointer; cursor: pointer;
font-size: 14px; font-size: 12px; /* 从14px减少到12px */
font-weight: bold; font-weight: bold;
transition: all 0.3s; transition: all 0.3s;
} }
@ -602,7 +599,6 @@
border-color: #1890ff; border-color: #1890ff;
} }
.rich-text-editor { .rich-text-editor {
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -630,14 +626,14 @@
/* 设置选项区域 */ /* 设置选项区域 */
.course-settings-section { .course-settings-section {
margin: 30px 0 0 41px; margin: 20px 0 0 30px; /* 从30px 0 0 41px减少到20px 0 0 30px */
width: 1400px; width: 1000px; /* 从1400px减少到1000px */
} }
.stop-on-leave-setting { .stop-on-leave-setting {
width: 350px; width: 280px; /* 从350px减少到280px */
height: 24px; height: 20px; /* 从24px减少到20px */
margin: 20px 0 0 31px; margin: 15px 0 0 25px; /* 从20px 0 0 31px减少到15px 0 0 25px */
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@ -645,40 +641,40 @@
.setting-control { .setting-control {
width: 100%; width: 100%;
height: 24px; height: 20px; /* 从24px减少到20px */
display: flex; display: flex;
align-items: center; align-items: center;
} }
.setting-label { .setting-label {
width: auto; width: auto;
height: 18px; height: 16px; /* 从18px减少到16px */
overflow-wrap: break-word; overflow-wrap: break-word;
font-size: 0; font-size: 0;
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: left; text-align: left;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
margin-top: 1px; margin-top: 1px;
display: flex; display: flex;
align-items: center; align-items: center;
margin-right: 5px; margin-right: 4px; /* 从5px减少到4px */
} }
.video-speed-setting { .video-speed-setting {
width: 350px; width: 280px; /* 从350px减少到280px */
height: 24px; height: 20px; /* 从24px减少到20px */
margin: 20px 0 0 63px; margin: 15px 0 0 50px; /* 从20px 0 0 63px减少到15px 0 0 50px */
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.video-text-setting { .video-text-setting {
width: 350px; width: 280px; /* 从350px减少到280px */
height: 24px; height: 20px; /* 从24px减少到20px */
margin: 20px 0 0 63px; margin: 15px 0 0 50px; /* 从20px 0 0 63px减少到15px 0 0 50px */
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@ -686,42 +682,43 @@
/* 积分设置 */ /* 积分设置 */
.points-setting-row { .points-setting-row {
width: 800px; width: 600px; /* 从800px减少到600px */
height: 40px; height: 32px; /* 从40px减少到32px */
margin: 21px 0 40px 95px; margin: 15px 0 30px 70px; /* 从21px 0 40px 95px减少到15px 0 30px 70px */
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px; /* 从10px减少到8px */
} }
.points-setting-control { .points-setting-control {
width: auto; width: auto;
height: 24px; height: 20px; /* 从24px减少到20px */
margin-top: 9px; margin-top: 6px; /* 从9px减少到6px */
display: flex; display: flex;
align-items: center; align-items: center;
margin-right: 20px; margin-right: 15px; /* 从20px减少到15px */
} }
.points-setting-control .setting-label { .points-setting-control .setting-label {
width: 89px; width: 70px; /* 从89px减少到70px */
margin-right: 0; margin-right: 0;
} }
.points-description-text { .points-description-text {
color: rgba(51, 51, 51, 1); color: rgba(51, 51, 51, 1);
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: left; text-align: left;
white-space: nowrap; white-space: nowrap;
line-height: 18px; line-height: 16px; /* 从18px减少到16px */
margin: 0 8px; margin: 0 6px; /* 从0 8px减少到0 6px */
} }
.earn-points-input-container, .required-points-input-container { .earn-points-input-container,
width: 80px; .required-points-input-container {
height: 32px; width: 60px; /* 从80px减少到60px */
height: 24px; /* 从32px减少到24px */
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -750,9 +747,9 @@
/* 原生开关按钮样式 */ /* 原生开关按钮样式 */
.toggle-button { .toggle-button {
position: relative; position: relative;
width: 44px; width: 36px; /* 从44px减少到36px */
height: 22px; height: 18px; /* 从22px减少到18px */
border-radius: 11px; border-radius: 9px; /* 从11px减少到9px */
background-color: #e0e0e0; background-color: #e0e0e0;
cursor: pointer; cursor: pointer;
transition: all 0.3s; transition: all 0.3s;
@ -765,12 +762,12 @@
} }
.toggle-button::after { .toggle-button::after {
content: ''; content: "";
position: absolute; position: absolute;
top: 2px; top: 2px;
left: 2px; left: 2px;
width: 18px; width: 14px; /* 从18px减少到14px */
height: 18px; height: 14px; /* 从18px减少到14px */
border-radius: 50%; border-radius: 50%;
background-color: white; background-color: white;
transition: all 0.3s; transition: all 0.3s;
@ -783,7 +780,7 @@
} }
.toggle-button-active::after { .toggle-button-active::after {
left: calc(100% - 20px); left: calc(100% - 16px); /* 从calc(100% - 20px)减少到calc(100% - 16px) */
} }
/* 积分输入框样式 */ /* 积分输入框样式 */
@ -792,7 +789,7 @@
height: 100%; height: 100%;
border: none; border: none;
background: transparent; background: transparent;
font-size: 14px; font-size: 12px; /* 从14px减少到12px */
color: #333; color: #333;
text-align: center; text-align: center;
outline: none; outline: none;
@ -802,32 +799,30 @@
background: rgba(240, 248, 255, 0.3); background: rgba(240, 248, 255, 0.3);
} }
/* 底部按钮区域 */ /* 底部按钮区域 */
.form-action-buttons { .form-action-buttons {
position: relative; position: relative;
left: 0; left: 0;
top: 0; top: 0;
width: 100%; width: 100%;
height: 91px; height: 70px; /* 从91px减少到70px */
background-size: 1920px 139px; background-size: 1920px 139px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
padding-right: 100px; padding-right: 80px; /* 从100px减少到80px */
gap: 15px; gap: 12px; /* 从15px减少到12px */
margin-top: 60px; margin-top: 40px; /* 从60px减少到40px */
} }
.button-spacer { .button-spacer {
width: 66px; width: 50px; /* 从66px减少到50px */
height: 32px; height: 28px; /* 从32px减少到28px */
} }
.cancel-button { .cancel-button {
height: 32px; height: 28px; /* 从32px减少到28px */
width: 80px; width: 70px; /* 从80px减少到70px */
border: 1px solid #d9d9d9; border: 1px solid #d9d9d9;
border-radius: 4px; border-radius: 4px;
display: flex; display: flex;
@ -844,8 +839,8 @@
} }
.submit-button { .submit-button {
height: 32px; height: 28px; /* 从32px减少到28px */
width: 80px; width: 70px; /* 从80px减少到70px */
background-color: #1890ff; background-color: #1890ff;
border: 1px solid #1890ff; border: 1px solid #1890ff;
border-radius: 4px; border-radius: 4px;
@ -863,133 +858,15 @@
.button-text { .button-text {
color: rgba(255, 255, 255, 1); color: rgba(255, 255, 255, 1);
font-size: 16px; font-size: 14px; /* 从16px减少到14px */
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif; font-family: Helvetica, "Microsoft YaHei", Arial, sans-serif;
font-weight: normal; font-weight: normal;
text-align: center; text-align: center;
white-space: nowrap; white-space: nowrap;
line-height: 22px; line-height: 18px; /* 从22px减少到18px */
} }
.cancel-button .button-text { .cancel-button .button-text {
color: rgba(0, 0, 0, 0.65); color: rgba(0, 0, 0, 0.65);
font-size: 14px; font-size: 12px; /* 从14px减少到12px */
}
/* 响应式设计 - 保持原有布局不变,只在特定屏幕尺寸下优化 */
/* 大屏幕优化 (≥1920px) - 让表单居中显示 */
@media (min-width: 1920px) {
.course-create-page {
display: flex;
justify-content: center;
align-items: flex-start;
background-color: #f5f5f5;
}
.course-form-container {
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
padding: 40px;
margin: 0 auto;
}
}
/* 中等屏幕 (1400px-1919px) - 保持原有布局 */
@media (max-width: 1919px) and (min-width: 1400px) {
.course-create-page {
width: 100%;
min-width: 1400px;
}
}
/* 小屏幕适配 (1200px-1399px) */
@media (max-width: 1399px) and (min-width: 1200px) {
.course-create-page {
width: 100%;
overflow-x: auto;
}
.course-form-container {
min-width: 1200px;
}
/* 稍微缩小一些元素的宽度 */
.course-basic-info-row {
width: 1100px;
margin-left: 50px;
}
.instructor-sort-row {
width: 1150px;
margin-left: 50px;
}
.course-time-row {
width: 1250px;
margin-left: 50px;
}
.course-description-section {
width: 1250px;
margin-left: 50px;
}
.description-editor-container {
width: 1150px;
margin-left: 80px;
}
}
/* 平板适配 (768px-1199px) */
@media (max-width: 1199px) and (min-width: 768px) {
.course-create-page {
width: 100%;
overflow-x: auto;
padding: 20px;
}
.course-form-container {
min-width: 800px;
position: relative;
transform: scale(0.8);
transform-origin: top left;
}
}
/* 移动端适配 (≤767px) */
@media (max-width: 767px) {
.course-create-page {
width: 100%;
overflow-x: auto;
padding: 10px;
}
.course-form-container {
min-width: 600px;
position: relative;
transform: scale(0.6);
transform-origin: top left;
}
/* 调整一些关键元素以适应移动端 */
.form-action-buttons {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: white;
border-top: 1px solid #e0e0e0;
z-index: 1000;
transform: none;
width: 100%;
justify-content: center;
padding: 15px;
}
.cancel-button,
.submit-button {
transform: scale(1.2);
}
} }

View File

@ -0,0 +1,232 @@
<template>
<div v-if="visible" class="common-modal">
<div class="modal-overlay" @click="closeModal"></div>
<div class="modal-content">
<!-- 模态框标题 -->
<div class="modal-header">
<h3 class="modal-title">{{ title }}</h3>
</div>
<!-- 模态框内容区域 -->
<div class="modal-body">
<slot name="content" :get-value="getValueFromContent"></slot>
</div>
<!-- 模态框底部按钮 -->
<div class="modal-footer">
<button class="btn btn-cancel" @click="closeModal">{{ cancelText }}</button>
<button
class="btn btn-confirm"
@click="confirmAction"
:disabled="disabled"
>
{{ confirmText }}
</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, nextTick, onMounted } from 'vue'
// Props
const props = defineProps({
visible: {
type: Boolean,
default: false
},
title: {
type: String,
required: true
},
cancelText: {
type: String,
default: '取消'
},
confirmText: {
type: String,
default: '确定'
},
disabled: {
type: Boolean,
default: false
}
})
// Emits
const emit = defineEmits(['close', 'confirm'])
//
const contentValue = ref(null)
//
const getValueFromContent = (value: any) => {
console.log('CommonModal.getValueFromContent 接收到值:', value)
contentValue.value = value
}
//
const closeModal = () => {
emit('close')
}
//
const confirmAction = async () => {
if (!props.disabled) {
console.log('CommonModal.confirmAction 准备发送值:', contentValue.value)
//
emit('confirm', contentValue.value)
}
}
</script>
<style scoped>
.common-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.modal-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
position: relative;
background: white;
border-radius: 2px;
width: 580px;
min-width: 580px;
min-height: 380px;
max-width: 90vw;
overflow: hidden;
display: flex;
flex-direction: column;
padding: 20px;
}
.modal-header {
padding-bottom: 10px;
border-bottom: 1.5px solid #E6E6E6;
}
.modal-title {
margin: 0;
font-size: 16px;
font-weight: 500;
color: #000;
text-align: left;
}
.modal-body {
padding: 24px 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: left;
}
.modal-footer {
padding-bottom: 10px;
display: flex;
justify-content: flex-end;
gap: 12px;
}
.btn {
padding: 8px 16px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
min-width: 80px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
}
.btn-cancel {
background-color: white;
border: 1px solid #d9d9d9;
color: #666;
}
.btn-cancel:hover {
border-color: #0288D1;
color: #0288D1;
}
.btn-confirm {
background-color: #0288D1;
border: 1px solid #0288D1;
color: white;
}
.btn-confirm:hover {
background-color: #0277BD;
border-color: #0277BD;
}
.btn-confirm:disabled {
background-color: #f5f5f5;
border-color: #d9d9d9;
color: #bfbfbf;
cursor: not-allowed;
}
/* 响应式设计 */
@media (max-width: 768px) {
.modal-content {
width: 90vw;
min-width: 320px;
min-height: 300px;
margin: 20px;
}
.modal-header,
.modal-body,
.modal-footer {
padding: 16px 20px;
}
.btn {
min-width: 70px;
height: 32px;
font-size: 13px;
}
}
@media (max-width: 480px) {
.modal-content {
width: 95vw;
min-width: 280px;
min-height: 280px;
margin: 10px;
}
.modal-header,
.modal-body,
.modal-footer {
padding: 12px 16px;
}
.btn {
min-width: 60px;
height: 30px;
font-size: 12px;
}
}
</style>

View File

@ -0,0 +1,129 @@
<template>
<div class="create-folder-content">
<div class="form-group">
<label class="form-label">
<span class="required-asterisk">*</span>
文件夹名称:
</label>
<input
type="text"
v-model="folderName"
class="form-input"
placeholder="请输入文件夹名称"
@keyup.enter="handleConfirm"
ref="folderNameInput"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, nextTick } from 'vue'
// Props
const props = defineProps({
visible: {
type: Boolean,
default: false
},
getValue: {
type: Function,
required: true
}
})
// Emits
const emit = defineEmits(['confirm'])
//
const folderName = ref('')
const folderNameInput = ref<HTMLInputElement>()
//
watch(() => props.visible, (newVal) => {
if (newVal) {
folderName.value = ''
nextTick(() => {
folderNameInput.value?.focus()
})
}
})
//
watch(folderName, (newVal) => {
if (props.getValue) {
props.getValue(newVal.trim())
}
})
//
const handleConfirm = () => {
const trimmedName = folderName.value.trim()
if (trimmedName) {
emit('confirm', trimmedName)
}
}
//
defineExpose({
getFolderName: () => {
const name = folderName.value.trim()
console.log('CreateFolderContent.getFolderName() 返回:', name)
return name
},
clearFolderName: () => {
folderName.value = ''
}
})
</script>
<style scoped>
.create-folder-content {
width: 100%;
}
.form-group {
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
width: 100%;
}
.form-label {
font-size: 14px;
color: #333;
font-weight: 500;
white-space: nowrap;
flex-shrink: 0;
}
.required-asterisk {
color: #ff4d4f;
margin-right: 4px;
}
.form-input {
flex: 1;
height: 36px;
padding: 0 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
color: #333;
background: white;
transition: all 0.3s ease;
box-sizing: border-box;
min-width: 0;
}
.form-input:focus {
outline: none;
border-color: #0288D1;
box-shadow: 0 0 0 2px rgba(2, 136, 209, 0.2);
}
.form-input::placeholder {
color: #bfbfbf;
}
</style>

View File

@ -0,0 +1,216 @@
<template>
<div class="move-file-content">
<div class="form-group">
<label class="form-label">
<span class="required-asterisk">*</span>
选择文件:
</label>
<div class="select-wrapper">
<select
v-model="selectedFolder"
class="form-select"
@change="handleFolderChange"
>
<option value="" disabled>请选择文件夹</option>
<option
v-for="folder in availableFolders"
:key="folder.id"
:value="folder.id"
>
{{ folder.name }}
</option>
</select>
<div class="select-arrow">
<img src="/images/teacher/箭头-灰.png" alt="下拉箭头" class="arrow-icon">
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
// Props
const props = defineProps({
visible: {
type: Boolean,
default: false
},
availableFolders: {
type: Array as () => Array<{id: number, name: string}>,
default: () => []
},
getValue: {
type: Function,
required: true
}
})
// Emits
const emit = defineEmits(['confirm'])
//
const selectedFolder = ref('')
//
watch(() => props.visible, (newVal) => {
if (newVal) {
selectedFolder.value = ''
}
})
//
watch(selectedFolder, (newVal) => {
if (props.getValue && newVal) {
const folder = props.availableFolders.find(f => f.id === newVal)
if (folder) {
props.getValue(folder)
}
}
})
//
const handleFolderChange = () => {
if (selectedFolder.value) {
const folder = props.availableFolders.find(f => f.id === selectedFolder.value)
if (folder) {
emit('confirm', folder)
}
}
}
//
defineExpose({
getSelectedFolder: () => selectedFolder.value,
clearSelection: () => {
selectedFolder.value = ''
}
})
</script>
<style scoped>
.move-file-content {
width: 100%;
}
.form-group {
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
width: 100%;
}
.form-label {
font-size: 14px;
color: #333;
font-weight: 500;
white-space: nowrap;
flex-shrink: 0;
}
.required-asterisk {
color: #ff4d4f;
margin-right: 4px;
}
.select-wrapper {
position: relative;
flex: 1;
min-width: 0;
}
.form-select {
width: 100%;
height: 36px;
padding: 0 12px;
padding-right: 32px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
color: #333;
background: white;
transition: all 0.3s ease;
box-sizing: border-box;
appearance: none;
cursor: pointer;
background-image: none;
}
.form-select:focus {
outline: none;
border-color: #0288D1;
box-shadow: 0 0 0 2px rgba(2, 136, 209, 0.2);
}
.form-select:disabled {
background-color: #f5f5f5;
color: #bfbfbf;
cursor: not-allowed;
}
/* 下拉框选项样式 */
.form-select option {
padding: 8px 12px;
font-size: 14px;
color: #333;
background: white;
border: none;
}
.form-select option:hover {
background-color: #f5f5f5;
}
.form-select option:checked {
background-color: #e6f7ff;
color: #0288D1;
}
.form-select option:disabled {
color: #bfbfbf;
background-color: #f5f5f5;
font-style: italic;
}
/* 默认提示选项样式 */
.form-select option[value=""] {
color: #bfbfbf;
background-color: #fafafa;
font-style: italic;
}
/* 下拉框悬停效果 */
.form-select:hover:not(:disabled) {
border-color: #40a9ff;
}
/* 确保下拉框在不同浏览器中显示一致 */
.form-select::-ms-expand {
display: none;
}
.select-arrow {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
transition: opacity 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.arrow-icon {
width: 12px;
height: 12px;
object-fit: contain;
transition: opacity 0.3s ease;
}
.form-select:focus + .select-arrow .arrow-icon {
opacity: 0.8;
}
</style>

View File

@ -120,7 +120,7 @@ const routes: RouteRecordRaw[] = [
path: 'course-editor/:id', path: 'course-editor/:id',
name: 'CourseEditor', name: 'CourseEditor',
component: CourseEditor, component: CourseEditor,
meta: { title: '编辑课程' }, meta: { title: '课程管理' },
redirect: (to) => `/teacher/course-editor/${to.params.id}/courseware`, redirect: (to) => `/teacher/course-editor/${to.params.id}/courseware`,
children: [ children: [
{ {
@ -157,9 +157,23 @@ const routes: RouteRecordRaw[] = [
}, },
{ {
path: 'practice', path: 'practice',
name: 'PracticeManagement', name: 'Practice',
component: PracticeManagement, redirect: (to) => `/teacher/course-editor/${to.params.id}/practice/exam`,
meta: { title: '考试管理' }, meta: { title: '练考通' },
children: [
{
path: 'exam',
name: 'PracticeExam',
component: () => import('../views/teacher/course/PracticeExam.vue'),
meta: { title: '试卷' }
},
{
path: 'review',
name: 'PracticeReview',
component: () => import('../views/teacher/course/PracticeReview.vue'),
meta: { title: '阅卷中心' }
}
]
}, },
{ {
path: 'question-bank', path: 'question-bank',
@ -167,6 +181,12 @@ const routes: RouteRecordRaw[] = [
component: QuestionBankManagement, component: QuestionBankManagement,
meta: { title: '题库管理' } meta: { title: '题库管理' }
}, },
{
path: 'add-question',
name: 'AddQuestion',
component: () => import('../views/teacher/course/AddQuestion.vue'),
meta: { title: '新增试题' }
},
{ {
path: 'certificate', path: 'certificate',
name: 'CertificateManagement', name: 'CertificateManagement',

View File

@ -83,13 +83,30 @@ const breadcrumbItems = computed(() => {
// matched // matched
const matchedRoutes = route.matched; const matchedRoutes = route.matched;
// matchedRoutes'' //
return matchedRoutes let breadcrumbs = matchedRoutes
.filter(item => item.meta.title !== '管理后台') .filter(item => item.meta.title !== '管理后台')
.map(item => ({ .map(item => ({
title: item.meta.title || '未知页面', title: item.meta.title || '未知页面',
path: item.path path: item.path
})); }));
// ""
const currentPath = route.path;
if (currentPath.includes('/add-question')) {
//
const courseIndex = breadcrumbs.findIndex(item => item.title === '课程管理');
if (courseIndex !== -1) {
//
const courseId = route.params.id;
breadcrumbs.splice(courseIndex + 1, 0, {
title: '题库',
path: `/teacher/course-editor/${courseId}/question-bank`
});
}
}
return breadcrumbs;
}); });
// //
@ -120,6 +137,10 @@ const updateActiveNavItem = () => {
</script> </script>
<style scoped> <style scoped>
.admin-dashboard {
padding-top: 64px;
min-height: 100vh;
}
.top-image-container { .top-image-container {
position: relative; position: relative;
width: 100%; width: 100%;

View File

@ -0,0 +1,955 @@
<template>
<div class="add-question">
<!-- 主要内容区域 -->
<div class="main-content">
<!-- 左侧表单区域 -->
<div class="form-section">
<form class="question-form">
<!-- 题目类型 -->
<div class="form-group">
<label class="form-label required">题目类型</label>
<div class="question-type-tabs">
<button
v-for="type in questionTypes"
:key="type.value"
type="button"
class="type-tab"
:class="{ active: selectedType === type.value }"
@click="selectedType = type.value"
>
{{ type.label }}
</button>
</div>
</div>
<!-- 题目内容 -->
<div class="form-group">
<label class="form-label required">题目内容</label>
<div class="rich-editor">
<div class="editor-toolbar">
<select class="font-size-select">
<option value="12">12</option>
<option value="14">14</option>
<option value="16">16</option>
<option value="18">18</option>
</select>
<button type="button" class="toolbar-btn" title="加粗">B</button>
<button type="button" class="toolbar-btn" title="文字样式">Aa</button>
<button type="button" class="toolbar-btn" title="对齐">A</button>
<button type="button" class="toolbar-btn" title="列表"></button>
<button type="button" class="toolbar-btn" title="插入图片"></button>
</div>
<textarea
v-model="questionContent"
class="question-content-input"
placeholder="请输入题目内容"
rows="6"
></textarea>
</div>
</div>
<!-- 选择答案 -->
<div class="form-group" v-if="selectedType === 'single' || selectedType === 'multiple'">
<label class="form-label required">选择答案</label>
<div class="answer-options">
<div
v-for="(option, index) in answerOptions"
:key="index"
class="answer-option"
>
<input
:type="selectedType === 'single' ? 'radio' : 'checkbox'"
:name="selectedType === 'single' ? 'correctAnswer' : 'correctAnswers'"
:value="option.letter"
:checked="selectedType === 'single' ? singleAnswer === option.letter : multipleAnswers.includes(option.letter)"
@change="handleOptionChange(option.letter)"
:id="`option-${option.letter}`"
/>
<label :for="`option-${option.letter}`" class="option-label">{{ option.letter }}.</label>
<input
v-model="option.content"
type="text"
class="option-input"
placeholder="请输入内容"
/>
</div>
<button type="button" class="add-option-btn" @click="addOption">
+添加选项
</button>
</div>
</div>
<!-- 判断题答案 -->
<div class="form-group" v-if="selectedType === 'judge'">
<label class="form-label required">正确答案</label>
<div class="judge-answer">
<label class="radio-label">
<input type="radio" v-model="judgeAnswer" value="true" />
<span>正确</span>
</label>
<label class="radio-label">
<input type="radio" v-model="judgeAnswer" value="false" />
<span>错误</span>
</label>
</div>
</div>
<!-- 填空题答案 -->
<div class="form-group" v-if="selectedType === 'fill'">
<label class="form-label required">正确答案</label>
<div class="fill-answers">
<div
v-for="(answer, index) in fillAnswers"
:key="index"
class="fill-answer-item"
>
<span class="blank-number">{{ index + 1 }}</span>
<input
v-model="answer.content"
type="text"
class="fill-answer-input"
placeholder="请输入答案"
/>
<button
type="button"
class="remove-blank-btn"
@click="removeBlank(index)"
v-if="fillAnswers.length > 1"
>
×
</button>
</div>
<button type="button" class="add-blank-btn" @click="addBlank">
+添加空格
</button>
</div>
</div>
<!-- 简答题答案 -->
<div class="form-group" v-if="selectedType === 'short'">
<label class="form-label required">参考答案</label>
<textarea
v-model="shortAnswer"
class="short-answer-input"
placeholder="请输入参考答案"
rows="4"
></textarea>
</div>
<!-- 答案解析 -->
<div class="form-group">
<label class="form-label">答案解析</label>
<textarea
v-model="answerAnalysis"
class="analysis-input"
placeholder="请输入答案解析"
rows="4"
></textarea>
</div>
<!-- 分类难度分值 -->
<div class="form-row">
<div class="form-group">
<label class="form-label required">分类</label>
<select v-model="selectedCategory" class="form-select">
<option value="">请选择分类</option>
<option value="folder1">文件夹一</option>
<option value="folder2">文件夹二</option>
<option value="folder3">文件夹三</option>
</select>
</div>
<div class="form-group">
<label class="form-label required">难度</label>
<select v-model="selectedDifficulty" class="form-select">
<option value="">请选择难度</option>
<option value="easy"></option>
<option value="medium"></option>
<option value="hard"></option>
</select>
</div>
<div class="form-group">
<label class="form-label required">分值</label>
<select v-model="selectedScore" class="form-select">
<option value="">请选择分值</option>
<option value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
<option value="20">20</option>
</select>
</div>
</div>
<!-- 操作按钮 -->
<div class="form-actions">
<button type="button" class="btn btn-cancel" @click="cancel">取消</button>
<button type="button" class="btn btn-save" @click="saveQuestion">保存</button>
</div>
</form>
</div>
<!-- 右侧预览区域 -->
<div class="preview-section">
<h3 class="preview-title">题目预览</h3>
<div class="question-preview">
<!-- 题目内容预览 -->
<div class="preview-question">
<span class="question-number">1.</span>
<span class="question-text">{{ questionContent || '请输入题目内容' }}</span>
</div>
<!-- 答案选项预览 -->
<div v-if="selectedType === 'single' || selectedType === 'multiple'" class="preview-options">
<div
v-for="option in answerOptions"
:key="option.letter"
class="preview-option"
:class="{
'correct': isOptionCorrect(option.letter),
'selected': isOptionCorrect(option.letter)
}"
>
<span class="option-letter">{{ option.letter }}.</span>
<span class="option-content">{{ option.content || '请输入内容' }}</span>
</div>
</div>
<!-- 判断题预览 -->
<div v-if="selectedType === 'judge'" class="preview-judge">
<div class="preview-option" :class="{ 'correct': judgeAnswer === 'true' }">
<span class="option-letter">A.</span>
<span class="option-content">正确</span>
</div>
<div class="preview-option" :class="{ 'correct': judgeAnswer === 'false' }">
<span class="option-letter">B.</span>
<span class="option-content">错误</span>
</div>
</div>
<!-- 填空题预览 -->
<div v-if="selectedType === 'fill'" class="preview-fill">
<div class="preview-question">
<span class="question-number">1.</span>
<span class="question-text">
{{ getFillQuestionText() }}
</span>
</div>
<div class="fill-answers-preview">
<div
v-for="(answer, index) in fillAnswers"
:key="index"
class="fill-answer-preview"
>
<span class="blank-label">{{ index + 1 }}</span>
<span class="blank-answer">{{ answer.content || '_____' }}</span>
</div>
</div>
</div>
<!-- 简答题预览 -->
<div v-if="selectedType === 'short'" class="preview-short">
<div class="short-answer-preview">
<strong>参考答案</strong>
<p>{{ shortAnswer || '请输入参考答案' }}</p>
</div>
</div>
<!-- 答案解析预览 -->
<div v-if="answerAnalysis" class="preview-analysis">
<strong>答案解析</strong>
<p>{{ answerAnalysis }}</p>
</div>
<!-- 元数据预览 -->
<div class="preview-metadata">
<div class="metadata-item">
<span class="metadata-label">分类</span>
<span class="metadata-value">{{ getCategoryText(selectedCategory) }}</span>
</div>
<div class="metadata-item">
<span class="metadata-label">难度</span>
<span class="metadata-value">{{ getDifficultyText(selectedDifficulty) }}</span>
</div>
<div class="metadata-item">
<span class="metadata-label">分值</span>
<span class="metadata-value">{{ selectedScore ? selectedScore + '分' : '' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
//
const questionTypes = [
{ value: 'single', label: '单选题' },
{ value: 'multiple', label: '多选题' },
{ value: 'judge', label: '判断题' },
{ value: 'fill', label: '填空题' },
{ value: 'short', label: '简答题' },
{ value: 'composite', label: '复合题' }
]
//
const selectedType = ref('single')
const questionContent = ref('')
const answerOptions = ref([
{ letter: 'A', content: '' },
{ letter: 'B', content: '' },
{ letter: 'C', content: '' },
{ letter: 'D', content: '' }
])
const singleAnswer = ref('')
const multipleAnswers = ref<string[]>([])
const judgeAnswer = ref('')
const fillAnswers = ref([{ content: '' }])
const shortAnswer = ref('')
const answerAnalysis = ref('')
const selectedCategory = ref('')
const selectedDifficulty = ref('')
const selectedScore = ref('')
//
const isOptionCorrect = (letter: string) => {
if (selectedType.value === 'single') {
return singleAnswer.value === letter
} else if (selectedType.value === 'multiple') {
return multipleAnswers.value.includes(letter)
}
return false
}
//
const addOption = () => {
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
const nextLetter = letters[answerOptions.value.length]
if (nextLetter) {
answerOptions.value.push({ letter: nextLetter, content: '' })
}
}
const handleOptionChange = (letter: string) => {
if (selectedType.value === 'single') {
singleAnswer.value = letter
} else if (selectedType.value === 'multiple') {
if (multipleAnswers.value.includes(letter)) {
multipleAnswers.value = multipleAnswers.value.filter((l: string) => l !== letter)
} else {
multipleAnswers.value.push(letter)
}
}
}
const addBlank = () => {
fillAnswers.value.push({ content: '' })
}
const removeBlank = (index: number) => {
if (fillAnswers.value.length > 1) {
fillAnswers.value.splice(index, 1)
}
}
const getFillQuestionText = () => {
if (!questionContent.value) return '请输入题目内容'
return questionContent.value.replace(/\{\}/g, '_____')
}
const getCategoryText = (value: string) => {
const categoryMap: Record<string, string> = {
'folder1': '文件夹一',
'folder2': '文件夹二',
'folder3': '文件夹三'
}
return categoryMap[value] || ''
}
const getDifficultyText = (value: string) => {
const difficultyMap: Record<string, string> = {
'easy': '易',
'medium': '中',
'hard': '难'
}
return difficultyMap[value] || ''
}
const cancel = () => {
//
history.back()
}
const saveQuestion = () => {
//
if (!questionContent.value.trim()) {
alert('请输入题目内容')
return
}
if (selectedType.value === 'single' && !singleAnswer.value) {
alert('请选择正确答案')
return
}
if (selectedType.value === 'multiple' && multipleAnswers.value.length === 0) {
alert('请选择正确答案')
return
}
if (selectedType.value === 'judge' && !judgeAnswer.value) {
alert('请选择正确答案')
return
}
if (selectedType.value === 'fill' && fillAnswers.value.some((a: { content: string }) => !a.content.trim())) {
alert('请填写所有空格的答案')
return
}
if (selectedType.value === 'short' && !shortAnswer.value.trim()) {
alert('请输入参考答案')
return
}
if (!selectedCategory.value) {
alert('请选择分类')
return
}
if (!selectedDifficulty.value) {
alert('请选择难度')
return
}
if (!selectedScore.value) {
alert('请选择分值')
return
}
//
console.log('保存题目:', {
type: selectedType.value,
content: questionContent.value,
answer: selectedType.value === 'single' ? singleAnswer.value :
selectedType.value === 'multiple' ? multipleAnswers.value :
selectedType.value === 'judge' ? judgeAnswer.value :
selectedType.value === 'fill' ? fillAnswers.value :
shortAnswer.value,
analysis: answerAnalysis.value,
category: selectedCategory.value,
difficulty: selectedDifficulty.value,
score: selectedScore.value
})
alert('题目保存成功!')
}
</script>
<style scoped>
.add-question {
background: #F6F6F6;
min-height: 100vh;
padding: 0;
}
/* 主要内容区域 */
.main-content {
display: flex;
gap: 20px;
min-height: calc(100vh - 80px);
padding-bottom: 80px;
}
/* 左侧表单区域 */
.form-section {
flex: 3;
background: white;
padding: 24px;
}
.question-form {
display: flex;
flex-direction: column;
gap: 24px;
}
.form-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.form-row {
display: flex;
gap: 24px;
}
.form-row .form-group {
flex: 1;
}
.form-label {
font-size: 14px;
font-weight: 500;
color: #333;
display: flex;
align-items: center;
}
.form-label.required::after {
content: '*';
color: #ff4d4f;
margin-left: 4px;
}
/* 题目类型标签 */
.question-type-tabs {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.type-tab {
padding: 8px 16px;
border: 1px solid #d9d9d9;
background: white;
color: #666;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
font-size: 14px;
}
.type-tab:hover {
border-color: #0288D1;
color: #0288D1;
}
.type-tab.active {
background: #0288D1;
color: white;
border-color: #0288D1;
}
/* 富文本编辑器 */
.rich-editor {
border: 1px solid #d9d9d9;
border-radius: 4px;
overflow: hidden;
}
.editor-toolbar {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: #fafafa;
border-bottom: 1px solid #e8e8e8;
}
.font-size-select {
padding: 4px 8px;
border: 1px solid #d9d9d9;
border-radius: 2px;
font-size: 12px;
}
.toolbar-btn {
width: 24px;
height: 24px;
border: 1px solid #d9d9d9;
background: white;
border-radius: 2px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
transition: all 0.3s ease;
}
.toolbar-btn:hover {
border-color: #0288D1;
color: #0288D1;
}
.question-content-input {
width: 100%;
padding: 12px;
border: none;
outline: none;
resize: vertical;
font-size: 14px;
line-height: 1.6;
min-height: 120px;
}
/* 答案选项 */
.answer-options {
display: flex;
flex-direction: column;
gap: 12px;
}
.answer-option {
display: flex;
align-items: center;
gap: 8px;
}
.option-label {
font-size: 14px;
color: #333;
min-width: 20px;
}
.option-input {
flex: 1;
padding: 8px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
}
.option-input:focus {
outline: none;
border-color: #0288D1;
box-shadow: 0 0 0 2px rgba(2, 136, 209, 0.2);
}
.add-option-btn {
color: #0288D1;
background: none;
border: none;
cursor: pointer;
font-size: 14px;
padding: 8px 0;
text-align: left;
}
.add-option-btn:hover {
text-decoration: underline;
}
/* 判断题答案 */
.judge-answer {
display: flex;
gap: 24px;
}
.radio-label {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
}
/* 填空题答案 */
.fill-answers {
display: flex;
flex-direction: column;
gap: 12px;
}
.fill-answer-item {
display: flex;
align-items: center;
gap: 8px;
}
.blank-number {
font-size: 14px;
color: #333;
min-width: 60px;
}
.fill-answer-input {
flex: 1;
padding: 8px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
}
.remove-blank-btn {
width: 24px;
height: 24px;
border: 1px solid #ff4d4f;
background: white;
color: #ff4d4f;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
.add-blank-btn {
color: #0288D1;
background: none;
border: none;
cursor: pointer;
font-size: 14px;
padding: 8px 0;
text-align: left;
}
/* 简答题答案 */
.short-answer-input {
width: 100%;
padding: 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
resize: vertical;
min-height: 80px;
}
/* 答案解析 */
.analysis-input {
width: 100%;
padding: 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
resize: vertical;
min-height: 80px;
}
/* 表单选择器 */
.form-select {
width: 100%;
padding: 8px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
background: white;
}
.form-select:focus {
outline: none;
border-color: #0288D1;
box-shadow: 0 0 0 2px rgba(2, 136, 209, 0.2);
}
/* 操作按钮 */
.form-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: flex-end;
gap: 12px;
padding: 16px 24px;
background: white;
z-index: 1000;
}
.btn {
padding: 12px 12px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
border: none;
min-width: 100px;
font-weight: 500;
}
.btn-cancel {
background: white;
color: #0288D1;
border: 1px solid #0288D1;
}
.btn-cancel:hover {
background: #f0f8ff;
}
.btn-save {
background: #0288D1;
color: white;
}
.btn-save:hover {
background: #0277BD;
}
/* 右侧预览区域 */
.preview-section {
flex: 1;
background: white;
padding: 24px;
height: fit-content;
}
.preview-title {
font-size: 18px;
font-weight: 600;
color: #333;
margin: 0 0 20px 0;
padding-bottom: 12px;
border-bottom: 1px solid #e8e8e8;
}
.question-preview {
display: flex;
flex-direction: column;
gap: 20px;
}
.preview-question {
display: flex;
gap: 8px;
line-height: 1.6;
}
.question-number {
font-weight: 500;
color: #333;
}
.question-text {
color: #333;
flex: 1;
}
.preview-options {
display: flex;
flex-direction: column;
gap: 8px;
}
.preview-option {
display: flex;
gap: 8px;
padding: 8px 12px;
border-radius: 4px;
transition: all 0.3s ease;
}
.preview-option.correct {
background: #e6f7ff;
color: #0288D1;
}
.preview-option.selected {
background: #0288D1;
color: white;
}
.option-letter {
font-weight: 500;
min-width: 20px;
}
.option-content {
flex: 1;
}
.preview-judge {
display: flex;
flex-direction: column;
gap: 8px;
}
.preview-fill {
display: flex;
flex-direction: column;
gap: 16px;
}
.fill-answers-preview {
display: flex;
flex-direction: column;
gap: 8px;
}
.fill-answer-preview {
display: flex;
gap: 8px;
align-items: center;
}
.blank-label {
font-size: 14px;
color: #666;
min-width: 60px;
}
.blank-answer {
color: #0288D1;
font-weight: 500;
}
.short-answer-preview {
line-height: 1.6;
}
.short-answer-preview p {
margin: 8px 0 0 0;
color: #333;
}
.preview-analysis {
line-height: 1.6;
}
.preview-analysis p {
margin: 8px 0 0 0;
color: #333;
}
.preview-metadata {
display: flex;
flex-direction: column;
gap: 8px;
padding-top: 16px;
border-top: 1px solid #e8e8e8;
}
.metadata-item {
display: flex;
gap: 8px;
}
.metadata-label {
font-size: 14px;
color: #666;
min-width: 40px;
}
.metadata-value {
font-size: 14px;
color: #333;
font-weight: 500;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.main-content {
flex-direction: column;
}
.form-section,
.preview-section {
flex: none;
}
}
@media (max-width: 768px) {
.form-row {
flex-direction: column;
gap: 16px;
}
.question-type-tabs {
justify-content: center;
}
}
</style>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="course-editor"> <div class="course-editor">
<!-- 左侧导航菜单 --> <!-- 左侧导航菜单 -->
<div class="sidebar"> <div class="sidebar" v-if="!hideSidebar">
<router-link :to="`/teacher/course-editor/${courseId}/courseware`" class="menu-item" <router-link :to="`/teacher/course-editor/${courseId}/courseware`" class="menu-item"
:class="{ active: $route.path.includes('courseware') }"> :class="{ active: $route.path.includes('courseware') }">
<img :src="$route.path.includes('courseware') ? '/images/teacher/课件-选中.png' : '/images/teacher/课件.png'" <img :src="$route.path.includes('courseware') ? '/images/teacher/课件-选中.png' : '/images/teacher/课件.png'"
@ -17,34 +17,52 @@
<!-- 作业二级导航 --> <!-- 作业二级导航 -->
<div class="menu-group"> <div class="menu-group">
<div class="menu-header" @click="toggleHomework"> <div class="menu-header" @click="toggleHomework">
<img :src="$route.path.includes('homework') ? '/images/teacher/作业-选中.png' : '/images/teacher/作业.png'" <img src="/images/teacher/作业.png" alt="作业" />
alt="作业" />
<span>作业</span> <span>作业</span>
<i class="n-base-icon" :class="{ 'expanded': homeworkExpanded }"> <i class="n-base-icon" :class="{ expanded: homeworkExpanded }">
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <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" 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> fill="#C2C2C2" />
</svg> </svg>
</i> </i>
</div> </div>
<div class="submenu" v-show="homeworkExpanded"> <div class="submenu" v-show="homeworkExpanded">
<router-link :to="`/teacher/course-editor/${courseId}/homework/library`" class="submenu-item" <router-link :to="`/teacher/course-editor/${courseId}/homework/library`" class="submenu-item"
:class="{ active: $route.path.includes('homework/library') }"> :class="{ active: $route.path.includes('/homework/library') }">
<span>作业库</span> <span>作业库</span>
</router-link> </router-link>
<router-link :to="`/teacher/course-editor/${courseId}/homework/review`" class="submenu-item" <router-link :to="`/teacher/course-editor/${courseId}/homework/review`" class="submenu-item"
:class="{ active: $route.path.includes('homework/review') }"> :class="{ active: $route.path.includes('/homework/review') }">
<span>批阅作业</span> <span>批阅作业</span>
</router-link> </router-link>
</div> </div>
</div> </div>
<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'" <div class="menu-group">
alt="练考通" /> <div class="menu-header" @click="togglePractice">
<img src="/images/teacher/练考通.png" alt="练考通" />
<span>练考通</span> <span>练考通</span>
<i class="n-base-icon" :class="{ expanded: practiceExpanded }">
<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" />
</svg>
</i>
</div>
<div class="submenu" v-show="practiceExpanded">
<router-link :to="`/teacher/course-editor/${courseId}/practice/exam`" class="submenu-item"
:class="{ active: $route.path.includes('/practice/exam') }">
<span>试卷</span>
</router-link> </router-link>
<router-link :to="`/teacher/course-editor/${courseId}/practice/review`" class="submenu-item"
:class="{ active: $route.path.includes('/practice/review') }">
<span>阅卷中心</span>
</router-link>
</div>
</div>
<router-link :to="`/teacher/course-editor/${courseId}/question-bank`" class="menu-item" <router-link :to="`/teacher/course-editor/${courseId}/question-bank`" class="menu-item"
:class="{ active: $route.path.includes('question-bank') }"> :class="{ active: $route.path.includes('question-bank') }">
<img :src="$route.path.includes('question-bank') ? '/images/teacher/题库-选中.png' : '/images/teacher/题库.png'" <img :src="$route.path.includes('question-bank') ? '/images/teacher/题库-选中.png' : '/images/teacher/题库.png'"
@ -84,7 +102,7 @@
</div> </div>
<!-- 右侧内容区域 --> <!-- 右侧内容区域 -->
<div class="content-area"> <div class="content-area" :class="{ 'full-width': hideSidebar }">
<router-view /> <router-view />
</div> </div>
</div> </div>
@ -92,7 +110,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { ref } from 'vue' import { ref, computed } from 'vue'
const route = useRoute() const route = useRoute()
@ -106,6 +124,30 @@ const homeworkExpanded = ref(false)
const toggleHomework = () => { const toggleHomework = () => {
homeworkExpanded.value = !homeworkExpanded.value homeworkExpanded.value = !homeworkExpanded.value
} }
//
const practiceExpanded = ref(false)
// /
const togglePractice = () => {
practiceExpanded.value = !practiceExpanded.value
}
//
const hideSidebar = computed(() => {
const currentPath = route.path
//
const hideSidebarPaths = [
'add-question', //
'edit-question', //
'question-preview', //
'bulk-import', //
'question-analysis' //
]
//
return hideSidebarPaths.some(path => currentPath.includes(path))
})
</script> </script>
<style scoped> <style scoped>
@ -125,6 +167,18 @@ const toggleHomework = () => {
margin-right: 5px; margin-right: 5px;
} }
/* 右侧内容区域 */
.content-area {
flex: 1;
overflow: auto;
}
/* 全宽显示(隐藏侧边栏的页面) */
.content-area.full-width {
width: 100%;
margin-left: 0;
}
.menu-item { .menu-item {
display: flex; display: flex;
align-items: center; align-items: center;
@ -175,13 +229,13 @@ const toggleHomework = () => {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 12px 15px; padding: 12px 15px;
margin-bottom: 5px;
cursor: pointer; cursor: pointer;
transition: all 0.3s ease; transition: all 0.3s ease;
border-left: 3px solid transparent; border-left: 3px solid transparent;
font-size: 16px; font-size: 16px;
color: #666; color: #666;
border-radius: 5px; border-radius: 5px;
position: relative;
} }
.menu-header:hover { .menu-header:hover {
@ -199,70 +253,51 @@ const toggleHomework = () => {
.menu-header span { .menu-header span {
font-size: 16px; font-size: 16px;
color: #666; color: #666;
flex: 1;
} }
.menu-header .n-base-icon { .menu-header .n-base-icon {
margin-left: auto;
transition: transform 0.3s ease;
width: 16px; width: 16px;
height: 16px; height: 16px;
transition: transform 0.2s ease; display: flex;
margin-right: 10px; align-items: center;
justify-content: center;
} }
.menu-header .n-base-icon.expanded { .menu-header .n-base-icon svg {
width: 16px;
height: 16px;
transition: transform 0.3s ease;
}
.menu-header .n-base-icon.expanded svg {
transform: rotate(90deg); transform: rotate(90deg);
} }
.submenu { .submenu {
margin-left: 0; margin-left: 30px;
margin-bottom: 5px;
} }
.submenu-item { .submenu-item {
display: flex; display: block;
align-items: center; padding: 8px 15px;
padding: 10px 15px; margin-bottom: 3px;
margin-bottom: 2px;
cursor: pointer;
transition: all 0.3s ease;
border-left: 3px solid transparent;
text-decoration: none; text-decoration: none;
color: inherit;
font-size: 14px;
color: #666; color: #666;
border-radius: 5px; font-size: 14px;
} border-radius: 3px;
transition: all 0.3s ease;
.submenu-item::before {
content: '';
width: 16px;
height: 16px;
margin-left: 30px;
margin-right: 8px;
flex-shrink: 0;
} }
.submenu-item:hover { .submenu-item:hover {
background: #f5f5f5; background: #f0f8ff;
color: #0288D1;
} }
.submenu-item.active { .submenu-item.active {
background: #F5F8FB; background: #e6f7ff;
color: #0288D1; color: #0288D1;
} }
.submenu-item.active span {
color: #0288D1;
}
.submenu-item span {
font-size: 14px;
color: #666;
}
/* 右侧内容区域 */
.content-area {
flex: 1;
background-color: #fff;
overflow: auto;
}
</style> </style>

View File

@ -6,7 +6,8 @@
<div class="toolbar-actions"> <div class="toolbar-actions">
<button class="btn btn-primary" @click="addCourseware">添加课件</button> <button class="btn btn-primary" @click="addCourseware">添加课件</button>
<button class="btn btn-new" @click="createFolder">新建文件夹</button> <button class="btn btn-new" @click="createFolder">新建文件夹</button>
<button class="btn btn-default" @click="moveFiles" :disabled="selectedFiles.length === 0">移动</button> <button class="btn btn-default" @click="moveFiles" :disabled="selectedFiles.length === 0"
:class="{ 'btn-default--active': selectedFiles.length > 0 }">移动</button>
<button class="btn btn-danger" @click="deleteSelected" :disabled="selectedFiles.length === 0">删除</button> <button class="btn btn-danger" @click="deleteSelected" :disabled="selectedFiles.length === 0">删除</button>
<div class="search-box"> <div class="search-box">
@ -71,6 +72,22 @@
<!-- 删除确认模态框 --> <!-- 删除确认模态框 -->
<DeleteFolderConfirmModal v-if="showDeleteConfirmModal" :show="showDeleteConfirmModal" @confirm="confirmDelete" <DeleteFolderConfirmModal v-if="showDeleteConfirmModal" :show="showDeleteConfirmModal" @confirm="confirmDelete"
@cancel="cancelDelete" /> @cancel="cancelDelete" />
<!-- 新建文件夹模态框 -->
<CommonModal :visible="showCreateFolderModal" title="新建文件夹" @close="closeCreateFolderModal"
@confirm="handleCreateFolder">
<template #content="{ getValue }">
<CreateFolderContent :visible="showCreateFolderModal" :get-value="getValue" />
</template>
</CommonModal>
<!-- 移动文件模态框 -->
<CommonModal :visible="showMoveFileModal" title="移动文件" @close="closeMoveFileModal" @confirm="handleMoveFiles">
<template #content="{ getValue }">
<MoveFileContent :visible="showMoveFileModal" :available-folders="fileList.filter(f => f.type === 'folder')"
:get-value="getValue" />
</template>
</CommonModal>
</div> </div>
</template> </template>
@ -81,6 +98,9 @@ import type { DataTableColumns, DropdownOption } from 'naive-ui'
import AddCoursewareModal from './AddCoursewareModal.vue' import AddCoursewareModal from './AddCoursewareModal.vue'
import UploadFileModal from './UploadFileModal.vue' import UploadFileModal from './UploadFileModal.vue'
import DeleteFolderConfirmModal from '@/components/common/DeleteFolderConfirmModal.vue' import DeleteFolderConfirmModal from '@/components/common/DeleteFolderConfirmModal.vue'
import CommonModal from '@/components/common/CommonModal.vue'
import CreateFolderContent from '@/components/common/CreateFolderContent.vue'
import MoveFileContent from '@/components/common/MoveFileContent.vue'
const message = useMessage() const message = useMessage()
@ -107,6 +127,8 @@ const selectedFiles = ref<number[]>([])
const showAddCoursewareModal = ref(false) const showAddCoursewareModal = ref(false)
const showUploadFileModal = ref(false) const showUploadFileModal = ref(false)
const showDeleteConfirmModal = ref(false) const showDeleteConfirmModal = ref(false)
const showCreateFolderModal = ref(false)
const showMoveFileModal = ref(false)
// //
const itemsToDelete = ref<{ type: 'single' | 'multiple', data: any }>({ type: 'single', data: null }) const itemsToDelete = ref<{ type: 'single' | 'multiple', data: any }>({ type: 'single', data: null })
@ -589,12 +611,67 @@ const closeAddCoursewareModal = () => {
} }
const createFolder = () => { const createFolder = () => {
message.info('新建文件夹功能') showCreateFolderModal.value = true
} }
const moveFiles = () => { const moveFiles = () => {
if (selectedFiles.value.length === 0) return if (selectedFiles.value.length === 0) return
message.info(`移动 ${selectedFiles.value.length} 个文件`) showMoveFileModal.value = true
}
//
const closeCreateFolderModal = () => {
showCreateFolderModal.value = false
}
//
const closeMoveFileModal = () => {
showMoveFileModal.value = false
}
//
const handleCreateFolder = (folderName: string) => {
console.log('handleCreateFolder 接收到参数:', folderName)
//
const newFolder: FileItem = {
id: Date.now(),
name: folderName,
type: 'folder',
size: '0B',
creator: '王建国', //
createTime: new Date().toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
}).replace(/\//g, '.'),
isTop: false,
expanded: false,
children: []
}
console.log('创建的新文件夹对象:', newFolder)
//
fileList.value.push(newFolder)
//
message.success(`文件夹 "${folderName}" 创建成功`)
//
showCreateFolderModal.value = false
}
//
const handleMoveFiles = (targetFolder: any) => {
//
message.success(`成功移动 ${selectedFiles.value.length} 个文件到 "${targetFolder.name}"`)
selectedFiles.value = [] //
//
showMoveFileModal.value = false
} }
const deleteSelected = () => { const deleteSelected = () => {
@ -814,6 +891,10 @@ const toggleFolder = (folder: FileItem) => {
color: #1890ff; color: #1890ff;
} }
.btn-default--active {
border-color: #1890ff !important;
color: #1890ff !important;
}
.btn-danger { .btn-danger {
background: white; background: white;
color: #FF4D4F; color: #FF4D4F;

View File

@ -0,0 +1,655 @@
<template>
<div class="local-upload-modal" v-if="visible">
<div class="modal-overlay" @click="closeModal"></div>
<div class="modal-content">
<!-- 弹框标题 -->
<div class="modal-header">
<h3 class="modal-title">本地上传</h3>
<!-- <button class="close-btn" @click="closeModal">&times;</button> -->
</div>
<!-- 文件上传列表 -->
<div class="file-list">
<table class="file-table">
<thead>
<tr>
<th>文件名</th>
<th>大小</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr v-for="file in fileList" :key="file.id">
<td>
<div class="file-info">
<img :src="getFileImage(file.name)" :alt="getFileExtension(file.name) + ' icon'" class="file-type-icon-img">
<span>{{ file.name }}</span>
</div>
</td>
<td>{{ formatFileSize(file.size) }}</td>
<td>
<div class="progress-bar">
<div class="progress-fill"
:class="file.status === 'success' ? 'success' : file.status === 'failed' ? 'failed' : ''"
:style="{ width: file.progress + '%' }"></div>
</div>
<span class="status-text" :class="file.status">
{{ getStatusText(file.status, file.progress) }}
</span>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 隐藏的文件输入框 -->
<input
type="file"
ref="fileInput"
@change="handleFileSelect"
multiple
accept=".doc,.docx,.pdf,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4"
style="display: none;"
/>
<!-- 上传结果通知 - 在模态框中央显示 -->
<div v-if="notifications.length > 0" class="upload-notifications-overlay">
<div class="notification-center">
<n-alert
v-for="notification in notifications"
:key="notification.id"
type="default"
:show-icon="true"
class="custom-notification-alert"
:class="notification.type"
>
<template #icon>
<img
:src="notification.type === 'success' ? '/images/teacher/upload-succeed.png' : '/images/teacher/upload-fail.png'"
:alt="notification.type === 'success' ? '上传成功' : '上传失败'"
class="notification-icon-img"
/>
</template>
{{ notification.message }}
</n-alert>
</div>
</div>
<!-- 底部操作按钮 -->
<div class="modal-footer">
<button class="btn btn-secondary" @click="closeModal">完成</button>
<button class="btn btn-primary" @click="triggerFileSelect">上传更多</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { NAlert } from 'naive-ui'
// Props
const props = defineProps({
visible: {
type: Boolean,
default: false
}
})
// Emits
const emit = defineEmits(['close', 'upload-more'])
//
const fileList = ref([
{
id: 1,
name: '这是一个表格文件.xlsx',
size: 18022, // 17.6k
status: 'success',
progress: 100
},
{
id: 2,
name: '这是一个表格文件.xlsx',
size: 18022, // 17.6k
status: 'failed',
progress: 0
}
])
const notifications = ref([]) //
//
const fileInput = ref<HTMLInputElement>()
//
const hasFailedFiles = computed(() => {
return fileList.value.some(file => file.status === 'failed')
})
//
const closeModal = () => {
emit('close')
}
//
const triggerFileSelect = () => {
fileInput.value?.click()
}
//
const handleFileSelect = (event: Event) => {
const target = event.target as HTMLInputElement
const files = target.files
if (files && files.length > 0) {
//
notifications.value = []
//
Array.from(files).forEach((file, index) => {
const newFile = {
id: Date.now() + index,
name: file.name,
size: file.size,
status: 'uploading' as const,
progress: 0
}
fileList.value.push(newFile)
//
simulateUpload(newFile)
})
//
target.value = ''
}
}
//
const simulateUpload = (file: any) => {
let progress = 0
const interval = setInterval(() => {
progress += Math.random() * 20
if (progress >= 100) {
progress = 100
file.status = 'success'
file.progress = progress
//
const notificationId = Date.now()
notifications.value.push({
id: notificationId,
type: 'success',
message: `${file.name} 上传成功`
})
// 3
setTimeout(() => {
const index = notifications.value.findIndex(n => n.id === notificationId)
if (index > -1) {
notifications.value.splice(index, 1)
}
}, 3000)
clearInterval(interval)
} else {
file.progress = Math.floor(progress)
}
}, 200)
}
//
const getFileExtension = (fileName: string) => {
return fileName.split('.').pop()?.toLowerCase() || 'default'
}
//
const getFileImage = (fileName: string) => {
const extension = getFileExtension(fileName)
const iconMap: { [key: string]: string } = {
'doc': 'doc.png',
'docx': 'doc.png',
'pdf': 'pdf.png',
'xls': 'xls.png',
'xlsx': 'xls.png',
'ppt': 'ppt.png',
'pptx': 'ppt.png',
'mp3': 'mp3.png',
'mp4': 'mp4.png',
'default': 'default-file.png' //
}
const imageName = iconMap[extension] || iconMap['default']
return `/images/profile/${imageName}`
}
const getFileIcon = (fileName: string) => {
const extension = fileName.split('.').pop()?.toLowerCase()
switch (extension) {
case 'doc':
case 'docx':
return 'icon-doc'
case 'pdf':
return 'icon-pdf'
case 'xls':
case 'xlsx':
return 'icon-xls'
case 'ppt':
case 'pptx':
return 'icon-ppt'
case 'mp3':
return 'icon-mp3'
case 'mp4':
return 'icon-mp4'
default:
return 'icon-file'
}
}
const formatFileSize = (bytes: number) => {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + sizes[i]
}
const getStatusText = (status: string, progress: number) => {
switch (status) {
case 'success':
return `上传成功${progress}%`
case 'failed':
return `上传失败${progress}%`
case 'uploading':
return `上传中${progress}%`
default:
return `等待上传${progress}%`
}
}
</script>
<style scoped>
.local-upload-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.modal-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
/* 文件上传区域样式 */
.file-upload-area {
display: none; /* 隐藏文件上传区域 */
}
.upload-btn {
display: none; /* 隐藏上传按钮 */
}
.upload-hint {
display: none; /* 隐藏上传提示 */
}
/* 通知容器样式 - 在模态框中央显示 */
.upload-notifications-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
z-index: 1001; /* 确保在最上层 */
pointer-events: none; /* 不阻挡其他交互 */
}
.notification-center {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
pointer-events: auto; /* 恢复通知的交互 */
}
/* 通知容器样式 */
.upload-notifications {
padding: 16px 24px;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
border-top: 1px solid #e8e8e8;
}
/* 确保模态框内容使用flexbox布局 */
.modal-content {
position: relative;
background: white;
border-radius: 2px;
width: 1000px;
min-height: 700px;
max-height: 80vh;
overflow: hidden;
padding: 20px 20px 40px 20px;
display: flex;
flex-direction: column;
}
/* 文件列表区域 */
.file-list {
padding: 20px 0;
flex: 1; /* 占据剩余空间 */
}
/* 底部操作按钮 - 确保在最底部 */
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: auto; /* 推到底部 */
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 10px;
border-bottom: 1.5px solid #E6E6E6;
}
.modal-title {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #000;
}
.close-btn {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #999;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.close-btn:hover {
color: #666;
}
.file-table {
width: 100%;
border-collapse: collapse;
border: 1px solid #e8e8e8;
}
.file-table th {
background-color: #fafafa;
font-weight: 600;
color: #062333;
font-size: 14px;
padding: 12px;
text-align: center;
border-bottom: 1px solid #e8e8e8;
border-right: 1px solid #e8e8e8;
}
.file-table th:last-child {
border-right: none;
}
.file-table td {
padding: 12px;
border-bottom: 1px solid #f5f5f5;
border-right: 1px solid #f5f5f5;
vertical-align: middle;
height: 50px;
font-size: 14px;
color: #062333;
}
.file-table td:last-child {
border-right: none;
}
.file-table tr:last-child td {
border-bottom: none;
}
.file-info {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.file-info img {
width: 18px;
height: 18px;
object-fit: contain;
flex-shrink: 0;
}
.file-info i {
display: none; /* 隐藏旧的图标 */
}
.file-info span {
font-size: 14px;
color: #062333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-table td:nth-child(2) {
text-align: center;
}
.file-table td:nth-child(3) {
text-align: center;
}
.progress-bar {
width: 60px;
height: 6px;
background-color: #F0F0F0;
border-radius: 3px;
overflow: hidden;
display: inline-block;
margin-right: 8px;
vertical-align: middle;
}
.progress-fill {
height: 100%;
background-color: #0288D1;
transition: width 0.3s ease;
}
.progress-fill.success {
background-color: #0288D1;
}
.progress-fill.failed {
background-color: #ED1C1C;
}
.status-text {
min-width: 95px;
font-size: 14px;
color: #062333;
display: inline-block;
vertical-align: middle;
}
.status-text.success {
color: #062333;
}
.status-text.failed {
color: #ED1C1C;
}
/* 通知容器样式 */
.upload-notifications {
padding: 16px 24px;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center; /* 左对齐 */
}
/* Naive UI Alert组件的自定义样式 */
.custom-notification-alert {
--n-color: #424242 !important; /* 深灰色背景 */
--n-content-text-color: #E0E0E0 !important; /* 浅色文字 */
--n-title-text-color: #E0E0E0 !important;
--n-border-radius: 8px !important; /* 圆角 */
margin-bottom: 8px; /* 通知之间的间距 */
padding: 8px 12px !important; /* 紧凑的内边距 */
border: none !important; /* 移除默认边框 */
box-shadow: none !important; /* 移除默认阴影 */
width: fit-content !important; /* 宽度自适应内容 */
max-width: 100% !important; /* 最大宽度不超过容器 */
display: flex !important; /* 使用flexbox布局 */
align-items: center !important; /* 垂直居中 */
gap: 8px !important; /* 图标和文字之间的间距 */
}
/* 强制覆盖Naive UI的默认图标样式 */
.custom-notification-alert .n-alert__icon {
display: flex !important;
align-items: center !important;
justify-content: center !important;
margin: 0 !important; /* 重置默认边距 */
order: -1 !important; /* 确保图标在最前面 */
width: 24px !important; /* 固定图标容器宽度 */
height: 24px !important; /* 固定图标容器高度 */
flex-shrink: 0 !important;
position: relative !important; /* 相对定位 */
}
:deep(.n-alert .n-alert__icon) {
top: 14%;
left: 10px;
}
.notification-icon-img {
width: auto !important;
height: 16px !important;
object-fit: contain !important;
flex-shrink: 0 !important;
display: block !important; /* 确保图片正确显示 */
position: absolute !important; /* 绝对定位 */
top: 50% !important; /* 垂直居中 */
left: 50% !important; /* 水平居中 */
transform: translate(-50%, -50%) !important; /* 完美居中 */
}
/* 确保文字内容正确显示 */
.custom-notification-alert .n-alert-body {
flex: 1 !important; /* 让文字区域占据剩余空间 */
}
/* 移除旧的图标样式 */
.custom-notification-alert .n-alert__icon i {
display: none;
}
/* 移除旧的图标颜色样式 */
.custom-notification-alert.success .n-alert__icon i,
.custom-notification-alert.failed .n-alert__icon i {
display: none;
}
/* 定义自定义图标内容 */
.icon-success::before {
content: "✓";
}
.icon-failed::before {
content: "✗";
}
.btn {
padding: 6px 16px;
border: 1px solid;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: all 0.3s;
min-width: 100px;
}
.btn-secondary {
background-color: #E2F5FF;
border-color: #0288D1;
color: #0288D1;
}
.btn-secondary:hover {
border-color: #0288D1;
color: #0288D1;
}
.btn-primary {
background-color: #0288D1;
border-color: #0288D1;
color: white;
}
.btn-primary:hover {
background-color: #0288D1;
border-color: #0288D1;
}
/* 文件类型图标样式 */
.icon-doc::before {
content: "📄";
}
.icon-pdf::before {
content: "📕";
}
.icon-xls::before {
content: "📊";
}
.icon-ppt::before {
content: "📑";
}
.icon-mp3::before {
content: "🎵";
}
.icon-mp4::before {
content: "🎬";
}
.icon-file::before {
content: "📁";
}
</style>

View File

@ -0,0 +1,15 @@
<template>
<div class="practice-exam">
<h2>试卷管理</h2>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>

View File

@ -0,0 +1,15 @@
<template>
<div class="practice-review">
<h2>阅卷中心</h2>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>

View File

@ -51,8 +51,11 @@ import {
dateZhCN dateZhCN
} from 'naive-ui' } from 'naive-ui'
import type { DataTableColumns } from 'naive-ui' import type { DataTableColumns } from 'naive-ui'
import { useRoute, useRouter } from 'vue-router'
const message = useMessage() const message = useMessage()
const route = useRoute()
const router = useRouter()
// //
interface Question { interface Question {
@ -440,7 +443,8 @@ const searchQuestions = () => {
} }
const addQuestion = () => { const addQuestion = () => {
message.info('添加试题功能') const courseId = route.params.id
router.push(`/teacher/course-editor/${courseId}/add-question`)
} }
const importQuestions = () => { const importQuestions = () => {

View File

@ -356,7 +356,6 @@ watch(() => props.show, (newVal) => {
justify-content: flex-end; justify-content: flex-end;
gap: 12px; gap: 12px;
padding-top: 16px; padding-top: 16px;
border-top: 1px solid #e0e0e0;
} }
/* 响应式设计 */ /* 响应式设计 */

View File

@ -7,9 +7,9 @@
<span class="btn-text">选择文件</span> <span class="btn-text">选择文件</span>
<!-- 下拉选项 --> <!-- 下拉选项 -->
<div v-show="showDropdown" class="upload-methods flex-col"> <div v-show="showDropdown" class="upload-methods flex-col">
<label class="local-upload"> <label class="local-upload" @click="openLocalUpload">
<input type="file" @change="handleLocalUpload" style="display: none;" <!-- <input type="file" @change="handleLocalUpload" style="display: none;"
accept=".doc,.docx,.pdf,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4" /> accept=".doc,.docx,.pdf,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4" /> -->
本地上传 本地上传
</label> </label>
<label class="resource-upload" @click="openResourceModal"> <label class="resource-upload" @click="openResourceModal">
@ -42,31 +42,38 @@
<!-- 资源选择模态框 --> <!-- 资源选择模态框 -->
<ResourceSelectionModal v-model:show="showResourceModal" @select="handleResourceSelection" /> <ResourceSelectionModal v-model:show="showResourceModal" @select="handleResourceSelection" />
<!-- 本地上传模态框 -->
<LocalUploadModal :visible="showLocalUploadModal" @close="closeLocalUploadModal" @upload-more="handleUploadMore" />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
import ResourceSelectionModal from './ResourceSelectionModal.vue' import ResourceSelectionModal from './ResourceSelectionModal.vue'
import LocalUploadModal from './LocalUploadModal.vue'
// //
const showDropdown = ref(false) const showDropdown = ref(false)
//
const showLocalUploadModal = ref(false)
// //
const toggleDropdown = () => { const toggleDropdown = () => {
showDropdown.value = !showDropdown.value showDropdown.value = !showDropdown.value
} }
// //
const handleLocalUpload = (event: Event) => { // const handleLocalUpload = (event: Event) => {
const target = event.target as HTMLInputElement // const target = event.target as HTMLInputElement
const files = target.files // const files = target.files
if (files && files.length > 0) { // if (files && files.length > 0) {
console.log('本地上传文件:', files[0]) // console.log(':', files[0])
// // //
showDropdown.value = false // showDropdown.value = false
} // }
} // }
// //
// const handleResourceUpload = (event: Event) => { // const handleResourceUpload = (event: Event) => {
@ -79,6 +86,24 @@ const handleLocalUpload = (event: Event) => {
// } // }
// } // }
//
const openLocalUpload = () => {
showLocalUploadModal.value = true
showDropdown.value = false
}
//
const closeLocalUploadModal = () => {
showLocalUploadModal.value = false
}
//
const handleUploadMore = () => {
closeLocalUploadModal()
//
console.log('用户选择上传更多文件')
}
// //
const openResourceModal = () => { const openResourceModal = () => {
console.log('打开资源选择模态框') console.log('打开资源选择模态框')
@ -173,7 +198,6 @@ const handleConfirm = () => {
.btn-text { .btn-text {
width: 100%; width: 100%;
height: 21px;
overflow-wrap: break-word; overflow-wrap: break-word;
color: rgba(255, 255, 255, 1); color: rgba(255, 255, 255, 1);
font-size: 18px; font-size: 18px;
@ -181,7 +205,6 @@ const handleConfirm = () => {
font-weight: normal; font-weight: normal;
text-align: center; text-align: center;
white-space: nowrap; white-space: nowrap;
line-height: 21px;
margin: 6px 0 0 0; margin: 6px 0 0 0;
display: flex; display: flex;
align-items: center; align-items: center;