style: 章节模态框
This commit is contained in:
parent
2d0dd00fc4
commit
cc7c4ec23a
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
Before Width: | Height: | Size: 329 B After Width: | Height: | Size: 329 B |
179
src/components/CustomDropdown.vue
Normal file
179
src/components/CustomDropdown.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<div ref="dropdownRef" class="custom-dropdown" :class="{ 'open': isOpen }">
|
||||
<div class="dropdown-input" @click="toggleDropdown">
|
||||
<div class="input-content">
|
||||
{{ displayValue || placeholder }}
|
||||
</div>
|
||||
<div class="dropdown-icon" :class="{ 'rotated': isOpen }">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.14645 5.64645C3.34171 5.45118 3.65829 5.45118 3.85355 5.64645L8 9.79289L12.1464 5.64645C12.3417 5.45118 12.6583 5.45118 12.8536 5.64645C13.0488 5.84171 13.0488 6.15829 12.8536 6.35355L8.35355 10.8536C8.15829 11.0488 7.84171 11.0488 7.64645 10.8536L3.14645 6.35355C2.95118 6.15829 2.95118 5.84171 3.14645 5.64645Z" fill="currentColor"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="isOpen" class="dropdown-menu">
|
||||
<div
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
class="dropdown-option"
|
||||
:class="{ 'first-option': option.value === '从考试/练习选择' }"
|
||||
@click="selectOption(option)"
|
||||
>
|
||||
{{ option.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
interface DropdownOption {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
modelValue?: string
|
||||
options: DropdownOption[]
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
placeholder: '请选择',
|
||||
modelValue: ''
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
'change': [value: string]
|
||||
}>()
|
||||
|
||||
const isOpen = ref(false)
|
||||
const dropdownRef = ref<HTMLElement>()
|
||||
|
||||
const displayValue = computed(() => {
|
||||
if (!props.modelValue) return ''
|
||||
const option = props.options.find((opt: DropdownOption) => opt.value === props.modelValue)
|
||||
return option ? option.label : props.modelValue
|
||||
})
|
||||
|
||||
const toggleDropdown = () => {
|
||||
isOpen.value = !isOpen.value
|
||||
}
|
||||
|
||||
const selectOption = (option: DropdownOption) => {
|
||||
emit('update:modelValue', option.value)
|
||||
emit('change', option.value) // 发出 change 事件
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (dropdownRef.value && !dropdownRef.value.contains(event.target as Node)) {
|
||||
isOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('click', handleClickOutside)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.custom-dropdown {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.custom-dropdown:hover {
|
||||
border-color: #0288D1;
|
||||
}
|
||||
|
||||
.custom-dropdown.open {
|
||||
border-color: #0288D1;
|
||||
box-shadow: 0 0 0 2px rgba(2, 136, 209, 0.1);
|
||||
}
|
||||
|
||||
.dropdown-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.input-content {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
line-height: 40px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.input-content:empty::before {
|
||||
content: attr(data-placeholder);
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.dropdown-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: #8C9191;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.dropdown-icon.rotated {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #ffffff;
|
||||
border: 1.5px solid #D8D8D8;
|
||||
border-radius: 0 0 2px 2px;
|
||||
z-index: 1000;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.dropdown-option {
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dropdown-option:hover {
|
||||
background: rgba(2, 136, 209, 0.1);
|
||||
color: #0288D1;
|
||||
}
|
||||
|
||||
.dropdown-option.first-option {
|
||||
color: #0288D1;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.dropdown-option.first-option:hover {
|
||||
color: #0277BD;
|
||||
background: rgba(2, 136, 209, 0.15);
|
||||
}
|
||||
</style>
|
201
src/components/CustomPagination.vue
Normal file
201
src/components/CustomPagination.vue
Normal file
@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<div class="custom-pagination">
|
||||
<!-- 上一页按钮 -->
|
||||
<button
|
||||
class="pagination-btn prev-btn"
|
||||
:disabled="currentPage === 1"
|
||||
@click="handlePageChange(currentPage - 1)"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.2674 15.793C11.9675 16.0787 11.4927 16.0672 11.2071 15.7673L6.20572 10.5168C5.9298 10.2271 5.9298 9.7719 6.20572 9.48223L11.2071 4.23177C11.4927 3.93184 11.9675 3.92031 12.2674 4.206C12.5673 4.49169 12.5789 4.96642 12.2932 5.26634L7.78458 9.99952L12.2932 14.7327C12.5789 15.0326 12.5673 15.5074 12.2674 15.793Z" fill="currentColor"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- 页码按钮 -->
|
||||
<button
|
||||
class="pagination-btn page-btn active"
|
||||
@click="handlePageChange(1)"
|
||||
>
|
||||
1
|
||||
</button>
|
||||
|
||||
<!-- 下一页按钮 -->
|
||||
<button
|
||||
class="pagination-btn next-btn"
|
||||
:disabled="currentPage === totalPages"
|
||||
@click="handlePageChange(currentPage + 1)"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.73271 4.20694C8.03263 3.92125 8.50737 3.93279 8.79306 4.23271L13.7944 9.48318C14.0703 9.77285 14.0703 10.2281 13.7944 10.5178L8.79306 15.7682C8.50737 16.0681 8.03263 16.0797 7.73271 15.794C7.43279 15.5083 7.42125 15.0336 7.70694 14.7336L12.2155 10.0005L7.70694 5.26729C7.42125 4.96737 7.43279 4.49264 7.73271 4.20694Z" fill="currentColor"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="separator"></div>
|
||||
|
||||
<!-- 每页条数选择器 -->
|
||||
<div class="page-size-selector">
|
||||
<span class="page-size-text">每页{{ pageSize }}条</span>
|
||||
</div>
|
||||
|
||||
<!-- 跳转输入框 -->
|
||||
<div class="jump-to-section">
|
||||
<span class="jump-text">跳至</span>
|
||||
<input
|
||||
type="number"
|
||||
class="jump-input"
|
||||
v-model="jumpPage"
|
||||
min="1"
|
||||
:max="totalPages"
|
||||
@keyup.enter="handleJumpToPage"
|
||||
@blur="handleJumpToPage"
|
||||
/>
|
||||
<span class="page-unit">页</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
|
||||
interface Props {
|
||||
currentPage: number
|
||||
pageSize: number
|
||||
total: number
|
||||
pageSizes?: number[]
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
pageSizes: () => [10, 20, 50]
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:currentPage': [page: number]
|
||||
'update:pageSize': [size: number]
|
||||
}>()
|
||||
|
||||
const jumpPage = ref(props.currentPage)
|
||||
|
||||
// 计算总页数
|
||||
const totalPages = computed(() => Math.ceil(props.total / props.pageSize))
|
||||
|
||||
// 监听当前页变化
|
||||
watch(() => props.currentPage, (newPage) => {
|
||||
jumpPage.value = newPage
|
||||
})
|
||||
|
||||
// 处理页码变化
|
||||
const handlePageChange = (page: number) => {
|
||||
if (page >= 1 && page <= totalPages.value) {
|
||||
emit('update:currentPage', page)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理跳转
|
||||
const handleJumpToPage = () => {
|
||||
const page = parseInt(jumpPage.value.toString())
|
||||
if (page >= 1 && page <= totalPages.value) {
|
||||
emit('update:currentPage', page)
|
||||
} else {
|
||||
jumpPage.value = props.currentPage
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.custom-pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.pagination-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.pagination-btn:hover:not(:disabled) {
|
||||
border-color: #d0d0d0;
|
||||
background: #f5f5f5;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.pagination-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.pagination-btn.active {
|
||||
background: #0288D1;
|
||||
border-color: #0288D1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.pagination-btn.active:hover {
|
||||
background: #0277BD;
|
||||
border-color: #0277BD;
|
||||
}
|
||||
|
||||
.separator {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background: #e0e0e0;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.page-size-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.page-size-text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.jump-to-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.jump-text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.jump-input {
|
||||
width: 60px;
|
||||
height: 28px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 3px;
|
||||
padding: 0 8px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
outline: none;
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
.jump-input:focus {
|
||||
border-color: #0288D1;
|
||||
}
|
||||
|
||||
.page-unit {
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
589
src/components/ExamPaperLibraryModal.vue
Normal file
589
src/components/ExamPaperLibraryModal.vue
Normal file
@ -0,0 +1,589 @@
|
||||
<template>
|
||||
<n-modal :show="show" @update:show="handleUpdateShow" preset="card"
|
||||
style="width: 90%; max-width: 1200px; max-height: 80vh;" :mask-closable="false" :closable="false">
|
||||
<template #header>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title">试卷库</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="modal-content">
|
||||
<!-- 筛选和搜索区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">类型:</span>
|
||||
<n-select v-model:value="selectedType" :options="typeOptions" placeholder="全部" class="type-select" />
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<div class="custom-search-input">
|
||||
<input v-model="searchKeyword" type="text" placeholder="请输入文档名称" class="search-input-field" />
|
||||
<img src="/images/teacher/搜索.png" alt="搜索" class="search-icon" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
已全部加载,共{{ totalCount }}份考试/练习
|
||||
</div>
|
||||
<n-button type="primary" class="import-btn">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 5V19M5 12H19" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</n-icon>
|
||||
</template>
|
||||
导入试卷
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 试卷列表 -->
|
||||
<div class="exam-list">
|
||||
<div class="exam-grid">
|
||||
<div v-for="exam in filteredExams" :key="exam.id" class="exam-card"
|
||||
:class="{ 'selected': selectedExams.includes(exam.id) }">
|
||||
<div class="card-checkbox">
|
||||
<n-checkbox :checked="selectedExams.includes(exam.id)" @update:checked="toggleExamSelection(exam.id)" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="title-section">
|
||||
<n-tag :type="exam.status === '未开始' ? 'info' : 'success'" size="small" class="status-tag"
|
||||
:data-status="exam.status">
|
||||
{{ exam.status }}
|
||||
</n-tag>
|
||||
<h3 class="exam-title">{{ exam.title }}</h3>
|
||||
</div>
|
||||
<div class="exam-details">
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">开考时间:</span>
|
||||
<span class="detail-value">{{ exam.startTime }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">考试时长:</span>
|
||||
<span class="detail-value">{{ exam.duration }}</span>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="detail-label">考题数量:</span>
|
||||
<span class="detail-value">{{ exam.questionCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<span class="view-details" @click="viewExamDetails(exam)">查看详情 ></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-section">
|
||||
<CustomPagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:total="totalCount"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="modal-footer">
|
||||
<n-button @click="handleCancel">取消</n-button>
|
||||
<n-button type="primary" @click="handleConfirm" :disabled="selectedExams.length === 0">
|
||||
确定
|
||||
</n-button>
|
||||
</div>
|
||||
</template>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { NModal, NButton, NSelect, NCheckbox, NTag, NIcon } from 'naive-ui'
|
||||
import CustomPagination from './CustomPagination.vue'
|
||||
|
||||
interface ExamPaper {
|
||||
id: number
|
||||
title: string
|
||||
status: '未开始' | '进行中'
|
||||
startTime: string
|
||||
duration: string
|
||||
questionCount: string
|
||||
type: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
show: boolean
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:show': [value: boolean]
|
||||
'confirm': [selectedExams: ExamPaper[]]
|
||||
}>()
|
||||
|
||||
// 响应式数据
|
||||
const selectedType = ref('全部')
|
||||
const searchKeyword = ref('')
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const selectedExams = ref<number[]>([])
|
||||
|
||||
// 类型选项
|
||||
const typeOptions = [
|
||||
{ label: '全部', value: '全部' },
|
||||
{ label: '考试', value: '考试' },
|
||||
{ label: '练习', value: '练习' },
|
||||
{ label: '测验', value: '测验' }
|
||||
]
|
||||
|
||||
// 模拟试卷数据
|
||||
const examPapers = ref<ExamPaper[]>([
|
||||
{
|
||||
id: 1,
|
||||
title: 'C++语言程序设计基础考试',
|
||||
status: '未开始',
|
||||
startTime: '2025.07.18 10:00',
|
||||
duration: '120分钟',
|
||||
questionCount: '100题',
|
||||
type: '考试'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Java编程基础练习',
|
||||
status: '进行中',
|
||||
startTime: '2025.07.19 14:00',
|
||||
duration: '90分钟',
|
||||
questionCount: '80题',
|
||||
type: '练习'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Python数据分析测验',
|
||||
status: '未开始',
|
||||
startTime: '2025.07.20 09:00',
|
||||
duration: '60分钟',
|
||||
questionCount: '50题',
|
||||
type: '测验'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'Web前端开发考试',
|
||||
status: '未开始',
|
||||
startTime: '2025.07.21 15:00',
|
||||
duration: '150分钟',
|
||||
questionCount: '120题',
|
||||
type: '考试'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '数据库设计练习',
|
||||
status: '进行中',
|
||||
startTime: '2025.07.22 11:00',
|
||||
duration: '100分钟',
|
||||
questionCount: '70题',
|
||||
type: '练习'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: '算法与数据结构测验',
|
||||
status: '未开始',
|
||||
startTime: '2025.07.23 16:00',
|
||||
duration: '75分钟',
|
||||
questionCount: '60题',
|
||||
type: '测验'
|
||||
}
|
||||
])
|
||||
|
||||
// 计算属性
|
||||
const filteredExams = computed(() => {
|
||||
let filtered = examPapers.value
|
||||
|
||||
// 按类型筛选
|
||||
if (selectedType.value !== '全部') {
|
||||
filtered = filtered.filter(exam => exam.type === selectedType.value)
|
||||
}
|
||||
|
||||
// 按关键词搜索
|
||||
if (searchKeyword.value) {
|
||||
filtered = filtered.filter(exam =>
|
||||
exam.title.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
||||
)
|
||||
}
|
||||
|
||||
return filtered
|
||||
})
|
||||
|
||||
const totalCount = computed(() => filteredExams.value.length)
|
||||
|
||||
// 方法
|
||||
const handleUpdateShow = (value: boolean) => {
|
||||
emit('update:show', value)
|
||||
}
|
||||
|
||||
const toggleExamSelection = (examId: number) => {
|
||||
const index = selectedExams.value.indexOf(examId)
|
||||
if (index > -1) {
|
||||
selectedExams.value.splice(index, 1)
|
||||
} else {
|
||||
selectedExams.value.push(examId)
|
||||
}
|
||||
}
|
||||
|
||||
const viewExamDetails = (exam: ExamPaper) => {
|
||||
console.log('查看试卷详情:', exam)
|
||||
// 这里可以添加查看详情的逻辑
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
selectedExams.value = []
|
||||
emit('update:show', false)
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
const selectedExamPapers = examPapers.value.filter(exam =>
|
||||
selectedExams.value.includes(exam.id)
|
||||
)
|
||||
emit('confirm', selectedExamPapers)
|
||||
emit('update:show', false)
|
||||
}
|
||||
|
||||
// 监听显示状态变化
|
||||
watch(() => props.show, (newVal) => {
|
||||
if (!newVal) {
|
||||
selectedExams.value = []
|
||||
searchKeyword.value = ''
|
||||
selectedType.value = '全部'
|
||||
currentPage.value = 1
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
border-bottom: 1.5px solid #E6E6E6;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 18px;
|
||||
padding-bottom: 10px;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
/* 隐藏滚动条但保持滚动功能 */
|
||||
scrollbar-width: none;
|
||||
/* Firefox */
|
||||
-ms-overflow-style: none;
|
||||
/* IE and Edge */
|
||||
}
|
||||
|
||||
/* Webkit浏览器隐藏滚动条 */
|
||||
.modal-content::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.type-select {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.search-item {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.custom-search-input {
|
||||
position: relative;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.search-input-field {
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 8px 32px 8px 12px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 3px;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
.search-input-field:focus {
|
||||
border-color: #0288D1;
|
||||
}
|
||||
|
||||
.search-input-field::placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.info-text {
|
||||
font-size: 10px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.import-btn {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.exam-list {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.exam-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.exam-card {
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.card-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 状态标签基础样式 */
|
||||
.status-tag :deep(.n-tag) {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.status-tag :deep(.n-tag__border) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* 未开始状态 */
|
||||
.status-tag :deep(.n-tag) {
|
||||
background-color: #E2F5FF !important;
|
||||
}
|
||||
|
||||
.status-tag :deep(.n-tag__content) {
|
||||
color: #0288D1 !important;
|
||||
}
|
||||
|
||||
/* 进行中状态 - 使用更具体的选择器 */
|
||||
.exam-card:has(.status-tag[data-status="进行中"]) .status-tag :deep(.n-tag),
|
||||
.status-tag[data-status="进行中"] :deep(.n-tag) {
|
||||
background-color: #D3FFE5 !important;
|
||||
}
|
||||
|
||||
.exam-card:has(.status-tag[data-status="进行中"]) .status-tag :deep(.n-tag__content),
|
||||
.status-tag[data-status="进行中"] :deep(.n-tag__content) {
|
||||
color: #10D781 !important;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
border: 1.5px solid #D8D8D8;
|
||||
padding: 15px 15px 15px 15px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.title-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
border-bottom: 1.5px solid #D8D8D8;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.exam-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.exam-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
color: #999;
|
||||
min-width: 70px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
color: #999;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
right: 18px;
|
||||
}
|
||||
|
||||
.view-details {
|
||||
color: #0288D1;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.view-details:hover {
|
||||
color: #0277BD;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.pagination-section {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
/* 分页器样式 */
|
||||
.pagination-section :deep(.n-pagination) {
|
||||
--n-item-border-radius: 4px;
|
||||
--n-item-font-size: 14px;
|
||||
--n-item-height: 32px;
|
||||
--n-item-padding: 0 12px;
|
||||
--n-item-color: #fff;
|
||||
--n-item-color-hover: #f5f5f5;
|
||||
--n-item-color-pressed: #e8e8e8;
|
||||
--n-item-color-active: #0288D1;
|
||||
--n-item-text-color: #666;
|
||||
--n-item-text-color-hover: #333;
|
||||
--n-item-text-color-pressed: #333;
|
||||
--n-item-text-color-active: #fff;
|
||||
--n-item-border: 1px solid #e0e0e0;
|
||||
--n-item-border-hover: 1px solid #d0d0d0;
|
||||
--n-item-border-pressed: 1px solid #c0c0c0;
|
||||
--n-item-border-active: 1px solid #0288D1;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 自定义按钮样式 */
|
||||
.modal-footer :deep(.n-button) {
|
||||
height: 32px !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* 取消按钮样式 */
|
||||
.modal-footer :deep(.n-button--default-type) {
|
||||
background-color: #E2F5FF !important;
|
||||
border-color: #0288D1 !important;
|
||||
color: #0288D1 !important;
|
||||
}
|
||||
|
||||
.modal-footer :deep(.n-button--default-type:hover) {
|
||||
background-color: #D3E8F5 !important;
|
||||
border-color: #0277BD !important;
|
||||
color: #0277BD !important;
|
||||
}
|
||||
|
||||
/* 确定按钮样式 */
|
||||
.modal-footer :deep(.n-button--primary-type) {
|
||||
background-color: #0288D1 !important;
|
||||
border-color: #0288D1 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.modal-footer :deep(.n-button--primary-type:hover) {
|
||||
background-color: #0277BD !important;
|
||||
border-color: #0277BD !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.modal-footer :deep(.n-button--primary-type:disabled) {
|
||||
background-color: #0288D1 !important;
|
||||
border-color: #0288D1 !important;
|
||||
color: #fff !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.filter-row {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.exam-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.filter-item,
|
||||
.search-item,
|
||||
.info-text,
|
||||
.import-btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
173
src/components/HomeworkDropdown.vue
Normal file
173
src/components/HomeworkDropdown.vue
Normal file
@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<div class="homework-dropdown" @click="toggleDropdown">
|
||||
<div class="dropdown-display">
|
||||
<span class="dropdown-text">{{ selectedOption || placeholder }}</span>
|
||||
<div class="dropdown-icon">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7 10l5 5 5-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="isOpen" class="dropdown-options">
|
||||
<div
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
class="dropdown-option"
|
||||
:class="{ 'selected': selectedOption === option.value }"
|
||||
@click.stop="selectOption(option)"
|
||||
>
|
||||
{{ option.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
interface Option {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
modelValue?: string
|
||||
options: Option[]
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
placeholder: '请添加作业'
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
'change': [value: string]
|
||||
}>()
|
||||
|
||||
const isOpen = ref(false)
|
||||
const selectedOption = ref(props.modelValue)
|
||||
|
||||
// 监听外部点击关闭下拉框
|
||||
const handleClickOutside = (event: Event) => {
|
||||
const target = event.target as HTMLElement
|
||||
if (!target.closest('.homework-dropdown')) {
|
||||
isOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 监听modelValue变化
|
||||
watch(() => props.modelValue, (newValue) => {
|
||||
selectedOption.value = newValue
|
||||
})
|
||||
|
||||
// 监听isOpen变化,添加/移除点击外部监听器
|
||||
watch(isOpen, (newValue) => {
|
||||
if (newValue) {
|
||||
document.addEventListener('click', handleClickOutside)
|
||||
} else {
|
||||
document.removeEventListener('click', handleClickOutside)
|
||||
}
|
||||
})
|
||||
|
||||
const toggleDropdown = () => {
|
||||
isOpen.value = !isOpen.value
|
||||
}
|
||||
|
||||
const selectOption = (option: Option) => {
|
||||
selectedOption.value = option.value
|
||||
emit('update:modelValue', option.value)
|
||||
emit('change', option.value)
|
||||
isOpen.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.homework-dropdown {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.dropdown-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 3px;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.3s ease;
|
||||
min-height: 34px;
|
||||
}
|
||||
|
||||
.dropdown-display:hover {
|
||||
border-color: #d0d0d0;
|
||||
}
|
||||
|
||||
.dropdown-text {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dropdown-text:empty::before {
|
||||
content: attr(data-placeholder);
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.dropdown-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #8C9191;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.dropdown-icon svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.homework-dropdown:has(.dropdown-options) .dropdown-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.dropdown-options {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-top: none;
|
||||
border-radius: 0 0 3px 3px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.dropdown-option {
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.dropdown-option:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.dropdown-option.selected {
|
||||
background-color: #E2F5FF;
|
||||
color: #0288D1;
|
||||
}
|
||||
|
||||
.dropdown-option:first-child {
|
||||
color: #0288D1;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
487
src/components/HomeworkLibraryModal.vue
Normal file
487
src/components/HomeworkLibraryModal.vue
Normal file
@ -0,0 +1,487 @@
|
||||
<template>
|
||||
<n-modal :show="show" @update:show="handleUpdateShow" preset="card"
|
||||
style="width: 90%; max-width: 1000px; max-height: 80vh;" :mask-closable="false" :closable="false">
|
||||
<template #header>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title">作业库</h2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="modal-content">
|
||||
<!-- 筛选和搜索区域 -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">类型:</span>
|
||||
<n-select v-model:value="selectedType" :options="typeOptions" placeholder="全部" class="type-select" />
|
||||
</div>
|
||||
<div class="search-item">
|
||||
<span class="search-label">搜索:</span>
|
||||
<div class="custom-search-input">
|
||||
<input v-model="searchKeyword" type="text" placeholder="请输入文档名称" class="search-input-field" />
|
||||
<img src="/images/teacher/搜索.png" alt="搜索" class="search-icon" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
已全部加载,共{{ totalCount }}份作业
|
||||
</div>
|
||||
<n-button type="primary" class="import-btn">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 5V19M5 12H19" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</n-icon>
|
||||
</template>
|
||||
导入作业
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 作业列表 -->
|
||||
<div class="homework-list">
|
||||
<div class="homework-grid">
|
||||
<div v-for="homework in filteredHomework" :key="homework.id" class="homework-card"
|
||||
:class="{ 'selected': selectedHomework.includes(homework.id) }">
|
||||
<div class="card-checkbox">
|
||||
<n-checkbox :checked="selectedHomework.includes(homework.id)" @update:checked="toggleHomeworkSelection(homework.id)" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="title-row">
|
||||
<h3 class="homework-title">{{ homework.title }}</h3>
|
||||
<span class="view-details" @click="viewHomeworkDetails(homework)">查看详情 ></span>
|
||||
</div>
|
||||
<div class="homework-description">
|
||||
{{ homework.description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-section">
|
||||
<CustomPagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:total="totalCount"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="modal-footer">
|
||||
<n-button @click="handleCancel">取消</n-button>
|
||||
<n-button type="primary" @click="handleConfirm" :disabled="selectedHomework.length === 0">
|
||||
确定
|
||||
</n-button>
|
||||
</div>
|
||||
</template>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { NModal, NButton, NSelect, NCheckbox, NIcon } from 'naive-ui'
|
||||
import CustomPagination from './CustomPagination.vue'
|
||||
|
||||
interface Homework {
|
||||
id: number
|
||||
title: string
|
||||
description: string
|
||||
type: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
show: boolean
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:show': [value: boolean]
|
||||
'confirm': [selectedHomework: Homework[]]
|
||||
}>()
|
||||
|
||||
// 响应式数据
|
||||
const selectedType = ref('全部')
|
||||
const searchKeyword = ref('')
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const selectedHomework = ref<number[]>([])
|
||||
|
||||
// 类型选项
|
||||
const typeOptions = [
|
||||
{ label: '全部', value: '全部' },
|
||||
{ label: '编程作业', value: '编程作业' },
|
||||
{ label: '文档作业', value: '文档作业' },
|
||||
{ label: '实验作业', value: '实验作业' }
|
||||
]
|
||||
|
||||
// 模拟作业数据
|
||||
const homeworkList = ref<Homework[]>([
|
||||
{
|
||||
id: 1,
|
||||
title: '作业标题作业标题作业标题作业标题',
|
||||
description: '作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作.......',
|
||||
type: '编程作业'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '作业标题作业标题作业标题作业标题',
|
||||
description: '作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作.......',
|
||||
type: '实验作业'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '作业标题作业标题作业标题作业标题',
|
||||
description: '作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作.......',
|
||||
type: '文档作业'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '作业标题作业标题作业标题作业标题',
|
||||
description: '作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作.......',
|
||||
type: '编程作业'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '作业标题作业标题作业标题作业标题',
|
||||
description: '作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作.......',
|
||||
type: '实验作业'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: '作业标题作业标题作业标题作业标题',
|
||||
description: '作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作业内容作.......',
|
||||
type: '文档作业'
|
||||
}
|
||||
])
|
||||
|
||||
// 计算属性
|
||||
const filteredHomework = computed(() => {
|
||||
let filtered = homeworkList.value
|
||||
|
||||
// 按类型筛选
|
||||
if (selectedType.value !== '全部') {
|
||||
filtered = filtered.filter(homework => homework.type === selectedType.value)
|
||||
}
|
||||
|
||||
// 按关键词搜索
|
||||
if (searchKeyword.value) {
|
||||
filtered = filtered.filter(homework =>
|
||||
homework.title.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
||||
)
|
||||
}
|
||||
|
||||
return filtered
|
||||
})
|
||||
|
||||
const totalCount = computed(() => filteredHomework.value.length)
|
||||
|
||||
// 方法
|
||||
const handleUpdateShow = (value: boolean) => {
|
||||
emit('update:show', value)
|
||||
}
|
||||
|
||||
const toggleHomeworkSelection = (homeworkId: number) => {
|
||||
const index = selectedHomework.value.indexOf(homeworkId)
|
||||
if (index > -1) {
|
||||
selectedHomework.value.splice(index, 1)
|
||||
} else {
|
||||
selectedHomework.value.push(homeworkId)
|
||||
}
|
||||
}
|
||||
|
||||
const viewHomeworkDetails = (homework: Homework) => {
|
||||
console.log('查看作业详情:', homework)
|
||||
// 这里可以添加查看详情的逻辑
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
selectedHomework.value = []
|
||||
emit('update:show', false)
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
const selectedHomeworkItems = homeworkList.value.filter(homework =>
|
||||
selectedHomework.value.includes(homework.id)
|
||||
)
|
||||
emit('confirm', selectedHomeworkItems)
|
||||
emit('update:show', false)
|
||||
}
|
||||
|
||||
// 监听显示状态变化
|
||||
watch(() => props.show, (newVal) => {
|
||||
if (!newVal) {
|
||||
selectedHomework.value = []
|
||||
searchKeyword.value = ''
|
||||
selectedType.value = '全部'
|
||||
currentPage.value = 1
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
border-bottom: 1.5px solid #E6E6E6;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 18px;
|
||||
padding-bottom: 10px;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
/* 隐藏滚动条但保持滚动功能 */
|
||||
scrollbar-width: none;
|
||||
/* Firefox */
|
||||
-ms-overflow-style: none;
|
||||
/* IE and Edge */
|
||||
}
|
||||
|
||||
/* Webkit浏览器隐藏滚动条 */
|
||||
.modal-content::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.filter-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.type-select {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.search-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.search-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.custom-search-input {
|
||||
position: relative;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.search-input-field {
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
padding: 8px 32px 8px 12px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 3px;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
.search-input-field:focus {
|
||||
border-color: #0288D1;
|
||||
}
|
||||
|
||||
.search-input-field::placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.info-text {
|
||||
font-size: 10px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.import-btn {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.homework-list {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.homework-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.homework-card {
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.card-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
border: 1.5px solid #D8D8D8;
|
||||
padding: 15px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.title-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1.5px solid #D8D8D8;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.homework-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.homework-description {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.view-details {
|
||||
color: #0288D1;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s ease;
|
||||
white-space: nowrap;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.view-details:hover {
|
||||
color: #0277BD;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.pagination-section {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 自定义按钮样式 */
|
||||
.modal-footer :deep(.n-button) {
|
||||
height: 32px !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* 取消按钮样式 */
|
||||
.modal-footer :deep(.n-button--default-type) {
|
||||
background-color: #E2F5FF !important;
|
||||
border-color: #0288D1 !important;
|
||||
color: #0288D1 !important;
|
||||
}
|
||||
|
||||
.modal-footer :deep(.n-button--default-type:hover) {
|
||||
background-color: #D3E8F5 !important;
|
||||
border-color: #0277BD !important;
|
||||
color: #0277BD !important;
|
||||
}
|
||||
|
||||
/* 确定按钮样式 */
|
||||
.modal-footer :deep(.n-button--primary-type) {
|
||||
background-color: #0288D1 !important;
|
||||
border-color: #0288D1 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.modal-footer :deep(.n-button--primary-type:hover) {
|
||||
background-color: #0277BD !important;
|
||||
border-color: #0277BD !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.modal-footer :deep(.n-button--primary-type:disabled) {
|
||||
background-color: #0288D1 !important;
|
||||
border-color: #0288D1 !important;
|
||||
color: #fff !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.filter-row {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.homework-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.filter-item,
|
||||
.search-item,
|
||||
.info-text,
|
||||
.import-btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -33,31 +33,20 @@
|
||||
<ChevronDownOutline />
|
||||
</n-icon>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 考试管理子菜单 -->
|
||||
<div class="submenu-container" :class="{ expanded: examMenuExpanded }">
|
||||
<router-link
|
||||
to="/teacher/exam-management/question-management"
|
||||
class="submenu-item"
|
||||
<router-link to="/teacher/exam-management/question-management" class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'question-management' }"
|
||||
@click="setActiveSubNavItem('question-management')"
|
||||
>
|
||||
@click="setActiveSubNavItem('question-management')">
|
||||
<span>试题管理</span>
|
||||
</router-link>
|
||||
<router-link
|
||||
to="/teacher/exam-management/exam-library"
|
||||
class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'exam-library' }"
|
||||
@click="setActiveSubNavItem('exam-library')"
|
||||
>
|
||||
<router-link to="/teacher/exam-management/exam-library" class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'exam-library' }" @click="setActiveSubNavItem('exam-library')">
|
||||
<span>试卷管理</span>
|
||||
</router-link>
|
||||
<router-link
|
||||
to="/teacher/exam-management/marking-center"
|
||||
class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'marking-center' }"
|
||||
@click="setActiveSubNavItem('marking-center')"
|
||||
>
|
||||
<router-link to="/teacher/exam-management/marking-center" class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'marking-center' }" @click="setActiveSubNavItem('marking-center')">
|
||||
<span>阅卷中心</span>
|
||||
</router-link>
|
||||
</div>
|
||||
@ -88,12 +77,14 @@
|
||||
<!-- 面包屑 -->
|
||||
<div class="breadcrumb">
|
||||
<span class="breadcrumb-separator"></span>
|
||||
<n-breadcrumb>
|
||||
<n-breadcrumb-item v-for="(item, index) in breadcrumbItems" :key="index"
|
||||
@click="handleBreadcrumbClick(item.path)" :class="{ 'clickable': index < breadcrumbItems.length - 1 }">
|
||||
<div class="custom-breadcrumb">
|
||||
<span v-for="(item, index) in breadcrumbItems" :key="index" class="breadcrumb-item"
|
||||
:class="{ 'clickable': index < breadcrumbItems.length - 1, 'last-item': index === breadcrumbItems.length - 1 }"
|
||||
@click="index < breadcrumbItems.length - 1 ? handleBreadcrumbClick(item.path) : null">
|
||||
{{ item.title }}
|
||||
</n-breadcrumb-item>
|
||||
</n-breadcrumb>
|
||||
<span v-if="index < breadcrumbItems.length - 1" class="breadcrumb-separator"> > </span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
@ -132,7 +123,7 @@ const setActiveNavItem = (index: number) => {
|
||||
const toggleExamMenu = () => {
|
||||
examMenuExpanded.value = !examMenuExpanded.value;
|
||||
activeNavItem.value = 4;
|
||||
|
||||
|
||||
// 如果展开且没有选中子菜单,默认选中第一个
|
||||
if (examMenuExpanded.value && !activeSubNavItem.value) {
|
||||
activeSubNavItem.value = 'question-management';
|
||||
@ -155,8 +146,8 @@ const handleBreadcrumbClick = (path: string) => {
|
||||
// 判断是否隐藏左侧侧边栏
|
||||
const hideSidebar = computed(() => {
|
||||
const currentPath = route.path
|
||||
// 当进入课程管理相关页面时隐藏侧边栏
|
||||
return currentPath.includes('course-editor')
|
||||
// 当进入课程管理相关页面或章节编辑页面时隐藏侧边栏
|
||||
return currentPath.includes('course-editor') || currentPath.includes('chapter-editor-teacher')
|
||||
})
|
||||
|
||||
// 动态生成面包屑
|
||||
@ -165,6 +156,10 @@ const breadcrumbItems = computed(() => {
|
||||
|
||||
// 如果在课程编辑器相关页面,强制添加课程管理面包屑
|
||||
if (currentPath.includes('course-editor')) {
|
||||
// 从路径中提取课程ID
|
||||
const courseIdMatch = currentPath.match(/\/course-editor\/(\d+)/);
|
||||
const courseId = courseIdMatch ? courseIdMatch[1] : '未知';
|
||||
|
||||
let breadcrumbs = [
|
||||
{
|
||||
title: '课程管理',
|
||||
@ -174,72 +169,300 @@ const breadcrumbItems = computed(() => {
|
||||
|
||||
// 根据当前路径添加子页面标题
|
||||
if (currentPath.includes('courseware')) {
|
||||
breadcrumbs.push({
|
||||
title: '课件管理',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '课件管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '课件管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('question-bank')) {
|
||||
breadcrumbs.push({
|
||||
title: '题库管理',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '题库管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '题库管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('add-question')) {
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '题库管理',
|
||||
path: currentPath.replace('/add-question', '/question-bank')
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
},
|
||||
{
|
||||
title: '新增试题',
|
||||
path: currentPath
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('chapters')) {
|
||||
breadcrumbs.push({
|
||||
title: '章节管理',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '章节管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '章节管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('homework')) {
|
||||
breadcrumbs.push({
|
||||
title: '作业管理',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '作业管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '作业管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('practice')) {
|
||||
breadcrumbs.push({
|
||||
title: '练考通',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '练考通',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '练考通',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('certificate')) {
|
||||
breadcrumbs.push({
|
||||
title: '证书管理',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '证书管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '证书管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('discussion')) {
|
||||
breadcrumbs.push({
|
||||
title: '讨论管理',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '讨论管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '讨论管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('statistics')) {
|
||||
breadcrumbs.push({
|
||||
title: '统计管理',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '统计管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '统计管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('notification')) {
|
||||
breadcrumbs.push({
|
||||
title: '通知管理',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '通知管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '通知管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
} else if (currentPath.includes('management')) {
|
||||
breadcrumbs.push({
|
||||
title: '综合管理',
|
||||
path: currentPath
|
||||
});
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '综合管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
breadcrumbs.push(
|
||||
{
|
||||
title: '综合管理',
|
||||
path: currentPath
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
console.log('课程编辑器页面面包屑:', breadcrumbs);
|
||||
return breadcrumbs;
|
||||
}
|
||||
|
||||
// 如果在章节编辑页面,显示课程管理>课程管理>课程名称>章节>章节名称 格式
|
||||
if (currentPath.includes('chapter-editor-teacher')) {
|
||||
const courseId = route.params.courseId;
|
||||
let breadcrumbs = [
|
||||
{
|
||||
title: '课程管理',
|
||||
path: '/teacher/course-management'
|
||||
},
|
||||
{
|
||||
title: '课程管理',
|
||||
path: '/teacher/course-management'
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
},
|
||||
{
|
||||
title: '章节',
|
||||
path: `/teacher/course-editor/${courseId}/chapters`
|
||||
},
|
||||
{
|
||||
title: '章节名称',
|
||||
path: currentPath
|
||||
}
|
||||
];
|
||||
|
||||
console.log('章节编辑页面面包屑:', breadcrumbs);
|
||||
return breadcrumbs;
|
||||
}
|
||||
|
||||
// 如果在章节编辑页面,显示课程管理>课程管理>课程名称>章节>章节名称 格式
|
||||
if (currentPath.includes('chapter-editor-teacher')) {
|
||||
const courseId = route.params.courseId;
|
||||
let breadcrumbs = [
|
||||
{
|
||||
title: '课程管理',
|
||||
path: '/teacher/course-management'
|
||||
},
|
||||
{
|
||||
title: '课程管理',
|
||||
path: '/teacher/course-management'
|
||||
},
|
||||
{
|
||||
title: `课程${courseId}`,
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
},
|
||||
{
|
||||
title: '章节',
|
||||
path: `/teacher/course-editor/${courseId}/chapters`
|
||||
},
|
||||
{
|
||||
title: '章节名称',
|
||||
path: currentPath
|
||||
}
|
||||
];
|
||||
|
||||
console.log('章节编辑页面面包屑:', breadcrumbs);
|
||||
return breadcrumbs;
|
||||
}
|
||||
|
||||
// 其他页面的面包屑逻辑
|
||||
const matchedRoutes = route.matched;
|
||||
let breadcrumbs = matchedRoutes
|
||||
@ -512,7 +735,7 @@ const updateActiveNavItem = () => {
|
||||
margin: 0 10px 15px;
|
||||
}
|
||||
|
||||
.submenu-container{
|
||||
.submenu-container {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
@ -594,37 +817,60 @@ const updateActiveNavItem = () => {
|
||||
}
|
||||
|
||||
.breadcrumb-separator {
|
||||
width: 4px;
|
||||
height: 17px;
|
||||
margin-right: 10px;
|
||||
background-color: #0C99DA;
|
||||
}
|
||||
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
.submenu-container{
|
||||
width: 150px;
|
||||
}
|
||||
@media screen and (max-width: 480px) {
|
||||
.nav-container .nav-item {
|
||||
width: 150px;
|
||||
height: 45px;
|
||||
margin: 0 5px 10px;
|
||||
}
|
||||
|
||||
/* 可点击的面包屑项样式 */
|
||||
.breadcrumb :deep(.n-breadcrumb-item.clickable) {
|
||||
cursor: pointer;
|
||||
color: #0C99DA;
|
||||
.nav-container .nav-item img {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.submenu-container {
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb :deep(.n-breadcrumb-item.clickable:hover) {
|
||||
color: #0277BD;
|
||||
/* 面包屑样式 */
|
||||
.custom-breadcrumb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.breadcrumb-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.breadcrumb-item.clickable:hover {
|
||||
color: #0C99DA;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.breadcrumb-item.last-item {
|
||||
color: #999;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.breadcrumb-item.last-item:hover {
|
||||
color: #999;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.breadcrumb-separator {
|
||||
color: #666;
|
||||
margin: 0 4px;
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
|
@ -26,15 +26,16 @@
|
||||
<span class="section-title">添加章节</span>
|
||||
</n-button>
|
||||
|
||||
<div class="chapter-item flex-row">
|
||||
<img class="chapter-arrow-icon" referrerpolicy="no-referrer" src="/images/teacher/路径18.png" />
|
||||
<div class="chapter-item flex-row" @click="toggleChapterExpansion" :class="{ 'collapsed': !isChapterExpanded }">
|
||||
<img class="chapter-arrow-icon" :class="{ 'rotated': !isChapterExpanded }" referrerpolicy="no-referrer"
|
||||
:src="isChapterExpanded ? '/images/teacher/路径18.png' : '/images/teacher/collapse.png'" />
|
||||
<span class="chapter-title">第一章 课前准备</span>
|
||||
<n-dropdown :options="chapterMenuOptions" @select="handleChapterMenuSelect">
|
||||
<img class="chapter-options-icon" referrerpolicy="no-referrer" src="/images/teacher/分组76.png" />
|
||||
<n-dropdown v-show="isChapterExpanded" :options="chapterMenuOptions" @select="handleChapterMenuSelect">
|
||||
<img class="chapter-options-icon" :class="{ 'transparent': !isChapterExpanded }"
|
||||
referrerpolicy="no-referrer" src="/images/teacher/分组76.png" />
|
||||
</n-dropdown>
|
||||
</div>
|
||||
|
||||
<div class="chapter-content-item flex-row">
|
||||
<div v-show="isChapterExpanded" class="chapter-content-item flex-row">
|
||||
<div class="content-text-group flex-col justify-between justify-between">
|
||||
<span class="content-title">1.开课彩蛋:新开始</span>
|
||||
<span class="content-description">第一节课程定位程定位与目标</span>
|
||||
@ -45,14 +46,47 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chapter-item-container flex-row justify-between">
|
||||
<img class="chapter-item-thumbnail" referrerpolicy="no-referrer" src="/images/teacher/切片_58.png" />
|
||||
<span class="chapter-item-title">第二章 课前准备</span>
|
||||
<div class="chapter-item flex-row" @click="toggleChapter2Expansion"
|
||||
:class="{ 'collapsed': !isChapter2Expanded }">
|
||||
<img class="chapter-arrow-icon" :class="{ 'rotated': !isChapter2Expanded }" referrerpolicy="no-referrer"
|
||||
:src="isChapter2Expanded ? '/images/teacher/路径18.png' : '/images/teacher/collapse.png'" />
|
||||
<span class="chapter-title">第二章 课前准备</span>
|
||||
<n-dropdown v-show="isChapter2Expanded" :options="chapterMenuOptions" @select="handleChapterMenuSelect">
|
||||
<img class="chapter-options-icon" :class="{ 'transparent': !isChapter2Expanded }"
|
||||
referrerpolicy="no-referrer" src="/images/teacher/分组76.png" />
|
||||
</n-dropdown>
|
||||
</div>
|
||||
<div class="chapter-item-container-next flex-row justify-between">
|
||||
<img class="chapter-item-thumbnail-next" referrerpolicy="no-referrer" src="/images/teacher/切片_58.png" />
|
||||
<span class="chapter-item-title-next">第三章 课前准备</span>
|
||||
<div v-show="isChapter2Expanded" class="chapter-content-item flex-row">
|
||||
<div class="content-text-group flex-col justify-between justify-between">
|
||||
<span class="content-title">2.课程导入:基础知识</span>
|
||||
<span class="content-description">第二节课程基础知识讲解</span>
|
||||
</div>
|
||||
<div class="action-menu flex-col" :class="{ 'visible': isMenuVisible }">
|
||||
<span class="action-rename">重命名</span>
|
||||
<span class="action-delete" @click="openDeleteModal">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chapter-item flex-row" @click="toggleChapter3Expansion"
|
||||
:class="{ 'collapsed': !isChapter3Expanded }">
|
||||
<img class="chapter-arrow-icon" :class="{ 'rotated': !isChapter3Expanded }" referrerpolicy="no-referrer"
|
||||
:src="isChapter3Expanded ? '/images/teacher/路径18.png' : '/images/teacher/collapse.png'" />
|
||||
<span class="chapter-title">第三章 课前准备</span>
|
||||
<n-dropdown v-show="isChapter3Expanded" :options="chapterMenuOptions" @select="handleChapterMenuSelect">
|
||||
<img class="chapter-options-icon" :class="{ 'transparent': !isChapter3Expanded }"
|
||||
referrerpolicy="no-referrer" src="/images/teacher/分组76.png" />
|
||||
</n-dropdown>
|
||||
</div>
|
||||
<div v-show="isChapter3Expanded" class="chapter-content-item flex-row">
|
||||
<div class="content-text-group flex-col justify-between justify-between">
|
||||
<span class="content-title">3.实践操作:技能训练</span>
|
||||
<span class="content-description">第三节实践操作技能训练</span>
|
||||
</div>
|
||||
<div class="action-menu flex-col" :class="{ 'visible': isMenuVisible }">
|
||||
<span class="action-rename">重命名</span>
|
||||
<span class="action-delete" @click="openDeleteModal">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@ -98,12 +132,7 @@
|
||||
<template #suffix>
|
||||
<n-button quaternary size="small" @click="() => removeLessonSection(section.id)">
|
||||
<template #icon>
|
||||
<n-icon size="16">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path fill="currentColor"
|
||||
d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12z" />
|
||||
</svg>
|
||||
</n-icon>
|
||||
<img src="/images/teacher/关闭-灰.png" alt="关闭" style="width: 10px; height: 10px; padding: 0;" />
|
||||
</template>
|
||||
</n-button>
|
||||
</template>
|
||||
@ -122,16 +151,37 @@
|
||||
<div class="exam-section flex-row justify-end">
|
||||
<span class="exam-label">添加考试/练习:</span>
|
||||
<div class="exam-dropdown-container">
|
||||
<n-select v-model:value="section.selectedExamOption" class="exam-dropdown-display"
|
||||
placeholder="请添加考试/练习" :options="examOptions" />
|
||||
<CustomDropdown v-model="section.selectedExamOption" :options="examOptions" placeholder="请添加考试/练习"
|
||||
@change="(value: any) => handleExamOptionChange(section, value)" />
|
||||
<!-- 隐藏的文件输入框 -->
|
||||
<input type="file" :id="`file-upload-${section.id}`" class="file-input"
|
||||
accept=".pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.txt,.zip,.rar"
|
||||
@change="handleFileUpload($event, section)" multiple ref="fileInputRef" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 显示已上传的文件列表 -->
|
||||
<div v-if="section.uploadedFiles && section.uploadedFiles.length > 0"
|
||||
class="uploaded-files-section flex-row justify-end">
|
||||
<span class="uploaded-files-label">已上传文件:</span>
|
||||
<div class="uploaded-files-container">
|
||||
<div v-for="(file, fileIndex) in section.uploadedFiles" :key="fileIndex" class="file-item">
|
||||
<span class="file-name">{{ file.name }}</span>
|
||||
<button class="remove-file-btn" @click="removeFile(section, fileIndex)">
|
||||
<img src="/images/teacher/关闭-灰.png" alt="删除" style="width: 12px; height: 12px;" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="homework-section flex-row justify-end">
|
||||
<span class="homework-label">添加作业:</span>
|
||||
<div class="homework-input-container">
|
||||
<n-select v-model:value="section.homeworkName" class="homework-input" placeholder="请添加作业"
|
||||
:options="homeworkOptions" filterable tag />
|
||||
<HomeworkDropdown v-model="section.homeworkName" :options="homeworkOptions" placeholder="请添加作业"
|
||||
@change="(value: any) => handleHomeworkOptionChange(section, value)" />
|
||||
<!-- 隐藏的文件输入框用于作业上传 -->
|
||||
<input type="file" :id="`homework-file-upload-${section.id}`" style="display: none;" multiple
|
||||
accept=".pdf,.doc,.docx,.txt" @change="(event: any) => handleHomeworkFileUpload(event, section)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -148,6 +198,12 @@
|
||||
|
||||
<n-modal v-model:show="showDeleteModal" preset="dialog" title="确认删除" content="确定要删除这个章节吗?" positive-text="确认"
|
||||
negative-text="取消" @positive-click="handleDeleteConfirm" @negative-click="handleDeleteCancel" />
|
||||
|
||||
<!-- 试卷库模态框 -->
|
||||
<ExamPaperLibraryModal v-model:show="showExamLibraryModal" @confirm="handleExamLibraryConfirm" />
|
||||
|
||||
<!-- 作业库模态框 -->
|
||||
<HomeworkLibraryModal v-model:show="showHomeworkLibraryModal" @confirm="handleHomeworkLibraryConfirm" />
|
||||
</div>
|
||||
|
||||
</n-config-provider>
|
||||
@ -156,6 +212,10 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import type { GlobalThemeOverrides } from 'naive-ui';
|
||||
import CustomDropdown from '@/components/CustomDropdown.vue';
|
||||
import HomeworkDropdown from '@/components/HomeworkDropdown.vue';
|
||||
import ExamPaperLibraryModal from '@/components/ExamPaperLibraryModal.vue';
|
||||
import HomeworkLibraryModal from '@/components/HomeworkLibraryModal.vue';
|
||||
|
||||
// 控制菜单显示状态的响应式变量
|
||||
const isMenuVisible = ref(false);
|
||||
@ -163,8 +223,16 @@ const isMenuVisible = ref(false);
|
||||
// 控制删除确认模态框的显示状态
|
||||
const showDeleteModal = ref(false);
|
||||
|
||||
// 控制试卷库模态框的显示状态
|
||||
const showExamLibraryModal = ref(false);
|
||||
|
||||
// 控制作业库模态框的显示状态
|
||||
const showHomeworkLibraryModal = ref(false);
|
||||
|
||||
// 控制章节内容的展开/收起状态
|
||||
const isChapterExpanded = ref(true);
|
||||
const isChapter2Expanded = ref(false);
|
||||
const isChapter3Expanded = ref(false);
|
||||
|
||||
// 响应式相关状态
|
||||
const isMobile = ref(false);
|
||||
@ -174,21 +242,36 @@ const sidebarCollapsed = ref(false);
|
||||
// 章节名称
|
||||
const chapterName = ref('课前准备');
|
||||
|
||||
// 定义section的类型
|
||||
interface Section {
|
||||
id: number;
|
||||
lessonName: string;
|
||||
coursewareName: string;
|
||||
selectedExamOption: string;
|
||||
homeworkName: string;
|
||||
uploadedFiles: File[];
|
||||
homeworkFiles: File[];
|
||||
}
|
||||
|
||||
// 小节数据结构
|
||||
const sections = ref([
|
||||
const sections = ref<Section[]>([
|
||||
{
|
||||
id: 1,
|
||||
lessonName: '开课彩蛋新开始',
|
||||
coursewareName: '课件准备PPT',
|
||||
selectedExamOption: '',
|
||||
homeworkName: '请添加作业'
|
||||
homeworkName: '请添加作业',
|
||||
uploadedFiles: [],
|
||||
homeworkFiles: []
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
lessonName: '开课彩蛋新开始',
|
||||
coursewareName: '课件准备PPT',
|
||||
selectedExamOption: '',
|
||||
homeworkName: '请添加作业'
|
||||
homeworkName: '请添加作业',
|
||||
uploadedFiles: [],
|
||||
homeworkFiles: []
|
||||
}
|
||||
]);
|
||||
|
||||
@ -205,10 +288,8 @@ const coursewareOptions = [
|
||||
|
||||
// 作业选项
|
||||
const homeworkOptions = [
|
||||
{ label: '请添加作业', value: '请添加作业' },
|
||||
{ label: '课后练习', value: '课后练习' },
|
||||
{ label: '实践作业', value: '实践作业' },
|
||||
{ label: '小组作业', value: '小组作业' }
|
||||
{ label: '从作业库选择', value: '从作业库选择' },
|
||||
{ label: '本地上传', value: '本地上传' }
|
||||
];
|
||||
|
||||
// 输入框引用
|
||||
@ -328,6 +409,14 @@ const toggleChapterExpansion = () => {
|
||||
isChapterExpanded.value = !isChapterExpanded.value;
|
||||
};
|
||||
|
||||
const toggleChapter2Expansion = () => {
|
||||
isChapter2Expanded.value = !isChapter2Expanded.value;
|
||||
};
|
||||
|
||||
const toggleChapter3Expansion = () => {
|
||||
isChapter3Expanded.value = !isChapter3Expanded.value;
|
||||
};
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
checkScreenSize();
|
||||
@ -356,12 +445,97 @@ const addSection = () => {
|
||||
lessonName: '开课彩蛋新开始',
|
||||
coursewareName: '课件准备PPT',
|
||||
selectedExamOption: '',
|
||||
homeworkName: '请添加作业'
|
||||
homeworkName: '请添加作业',
|
||||
uploadedFiles: [],
|
||||
homeworkFiles: []
|
||||
};
|
||||
sections.value.push(newSection);
|
||||
nextSectionId.value++;
|
||||
};
|
||||
|
||||
// 处理考试选项变化
|
||||
const handleExamOptionChange = (section: Section, value: any) => {
|
||||
console.log('选项变化:', value, 'section id:', section.id);
|
||||
// 如果选择的是"本地上传",直接触发文件选择
|
||||
if (value === '本地上传') {
|
||||
console.log('触发文件选择');
|
||||
const fileInput = document.getElementById(`file-upload-${section.id}`) as HTMLInputElement;
|
||||
if (fileInput) {
|
||||
fileInput.click();
|
||||
} else {
|
||||
console.error('找不到文件输入框:', `file-upload-${section.id}`);
|
||||
}
|
||||
} else if (value === '从考试/练习选择') {
|
||||
// 如果选择的是"从考试/练习选择",显示试卷库模态框
|
||||
console.log('准备显示试卷库模态框');
|
||||
showExamLibraryModal.value = true;
|
||||
console.log('showExamLibraryModal.value:', showExamLibraryModal.value);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理作业选项变化
|
||||
const handleHomeworkOptionChange = (section: Section, value: any) => {
|
||||
console.log('作业选项变化:', value, 'section id:', section.id);
|
||||
// 如果选择的是"本地上传",直接触发文件选择
|
||||
if (value === '本地上传') {
|
||||
console.log('触发作业文件选择');
|
||||
const fileInput = document.getElementById(`homework-file-upload-${section.id}`) as HTMLInputElement;
|
||||
if (fileInput) {
|
||||
fileInput.click();
|
||||
} else {
|
||||
console.error('找不到作业文件输入框:', `homework-file-upload-${section.id}`);
|
||||
}
|
||||
} else if (value === '从作业库选择') {
|
||||
// 如果选择的是"从作业库选择",显示作业库模态框
|
||||
console.log('准备显示作业库模态框');
|
||||
showHomeworkLibraryModal.value = true;
|
||||
console.log('showHomeworkLibraryModal.value:', showHomeworkLibraryModal.value);
|
||||
showHomeworkLibraryModal.value = true;
|
||||
console.log('showHomeworkLibraryModal.value:', showHomeworkLibraryModal.value);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理文件上传
|
||||
const handleFileUpload = (event: Event, section: Section) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files) {
|
||||
const files = Array.from(target.files);
|
||||
section.uploadedFiles = files;
|
||||
console.log('文件已上传:', files);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理作业文件上传
|
||||
const handleHomeworkFileUpload = (event: any, section: Section) => {
|
||||
const target = event.target as HTMLInputElement;
|
||||
if (target.files) {
|
||||
const files = Array.from(target.files);
|
||||
section.homeworkFiles = files;
|
||||
console.log('作业文件已上传:', files);
|
||||
}
|
||||
};
|
||||
|
||||
// 删除文件
|
||||
const removeFile = (section: Section, fileIndex: number) => {
|
||||
section.uploadedFiles.splice(fileIndex, 1);
|
||||
};
|
||||
|
||||
// 处理试卷库选择确认
|
||||
const handleExamLibraryConfirm = (selectedExams: any[]) => {
|
||||
console.log('选择的试卷:', selectedExams);
|
||||
// 这里可以处理选择的试卷,比如更新当前section的数据
|
||||
// 暂时只是关闭模态框
|
||||
showExamLibraryModal.value = false;
|
||||
};
|
||||
|
||||
// 处理作业库选择确认
|
||||
const handleHomeworkLibraryConfirm = (selectedHomework: any[]) => {
|
||||
console.log('选择的作业:', selectedHomework);
|
||||
// 这里可以处理选择的作业,比如更新当前section的数据
|
||||
// 暂时只是关闭模态框
|
||||
showHomeworkLibraryModal.value = false;
|
||||
};
|
||||
|
||||
// 删除课节
|
||||
const removeLessonSection = (sectionId: number) => {
|
||||
const index = sections.value.findIndex(section => section.id === sectionId);
|
||||
@ -711,7 +885,6 @@ const removeLessonSection = (sectionId: number) => {
|
||||
|
||||
.block_3 {
|
||||
width: 100%;
|
||||
max-width: 1400px;
|
||||
min-height: 100vh;
|
||||
margin: 15px auto 0;
|
||||
position: relative;
|
||||
@ -831,16 +1004,35 @@ const removeLessonSection = (sectionId: number) => {
|
||||
background: #F5F8FB 100% no-repeat;
|
||||
background-size: 100% 100%;
|
||||
margin: 23px 0 0 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chapter-item.collapsed {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.chapter-item:hover {
|
||||
background: rgba(2, 136, 209, 0.05);
|
||||
}
|
||||
|
||||
.chapter-arrow-icon {
|
||||
margin-left: 10px;
|
||||
width: 9px;
|
||||
height: 11px;
|
||||
margin: 23px 0 0 13px;
|
||||
transform: rotate(180deg);
|
||||
transition: transform 0.3s ease;
|
||||
/* 旋转图标180度 */
|
||||
}
|
||||
|
||||
.chapter-arrow-icon.rotated {
|
||||
width: 11px;
|
||||
height: 9px;
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.chapter-title {
|
||||
width: 131px;
|
||||
height: 21px;
|
||||
@ -852,13 +1044,27 @@ const removeLessonSection = (sectionId: number) => {
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 21px;
|
||||
margin: 15px 0 0 11px;
|
||||
transition: color 0.3s ease;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.chapter-item.collapsed .chapter-title {
|
||||
color: rgba(51, 51, 51, 1);
|
||||
}
|
||||
|
||||
.chapter-options-icon {
|
||||
width: 5px;
|
||||
width: 6px;
|
||||
height: 20px;
|
||||
margin: 17px 16px 0 55px;
|
||||
margin-right: 5px;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.chapter-options-icon.transparent {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
.chapter-item:hover .chapter-options-icon.transparent {
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
|
||||
.chapter-content-item {
|
||||
@ -945,57 +1151,7 @@ const removeLessonSection = (sectionId: number) => {
|
||||
margin: 14px 0 0 20px;
|
||||
}
|
||||
|
||||
.chapter-item-container {
|
||||
width: 151px;
|
||||
height: 26px;
|
||||
margin: 42px 0 0 28px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chapter-item-thumbnail {
|
||||
width: 11px;
|
||||
height: 9px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.chapter-item-title {
|
||||
width: 130px;
|
||||
height: 26px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.chapter-item-container-next {
|
||||
width: 151px;
|
||||
height: 26px;
|
||||
margin: 42px 0 762px 28px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.chapter-item-thumbnail-next {
|
||||
width: 11px;
|
||||
height: 9px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.chapter-item-title-next {
|
||||
width: 130px;
|
||||
height: 26px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 18px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.chapter-detail-container {
|
||||
position: relative;
|
||||
@ -1278,7 +1434,6 @@ const removeLessonSection = (sectionId: number) => {
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
line-height: 18px;
|
||||
margin: 11px 0 0 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@ -1306,7 +1461,6 @@ const removeLessonSection = (sectionId: number) => {
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
line-height: 18px;
|
||||
margin: 10px 0 0 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@ -1335,10 +1489,81 @@ const removeLessonSection = (sectionId: number) => {
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
line-height: 18px;
|
||||
margin: 10px 0 0 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 文件上传相关样式 */
|
||||
.file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.uploaded-files-section {
|
||||
width: 100%;
|
||||
max-width: 540px;
|
||||
height: auto;
|
||||
margin: 10px 0 0 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.uploaded-files-label {
|
||||
width: 120px;
|
||||
height: 18px;
|
||||
overflow-wrap: break-word;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 16px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
line-height: 18px;
|
||||
flex-shrink: 0;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.uploaded-files-container {
|
||||
width: 400px;
|
||||
margin: 1px 0 0 5px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.remove-file-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
border-radius: 2px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.remove-file-btn:hover {
|
||||
background: rgba(255, 77, 79, 0.1);
|
||||
}
|
||||
|
||||
/* 删除未使用的样式 */
|
||||
|
||||
|
||||
@ -1365,7 +1590,6 @@ const removeLessonSection = (sectionId: number) => {
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
line-height: 18px;
|
||||
margin: 9px 0 0 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user