1335 lines
31 KiB
Vue
1335 lines
31 KiB
Vue
<template>
|
||
<div class="courseware-management">
|
||
<!-- 顶部操作栏 -->
|
||
<div class="toolbar">
|
||
<h2>全部课件</h2>
|
||
<div class="toolbar-actions">
|
||
<button class="btn btn-primary" @click="addCourseware">添加课件</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-danger" @click="deleteSelected" :disabled="selectedFiles.length === 0">删除</button>
|
||
|
||
<div class="search-box">
|
||
<input type="text" placeholder="请输入想要搜索的内容" v-model="searchKeyword" />
|
||
<button class="btn btn-search" @click="searchFiles">搜索</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 文件列表表格 -->
|
||
<div class="table-box">
|
||
<n-config-provider :locale="zhCN" :date-locale="dateZhCN">
|
||
<n-data-table :columns="columns" :data="paginatedFiles" :row-key="rowKey" :checked-row-keys="selectedFiles"
|
||
@update:checked-row-keys="handleCheck" :bordered="false" :single-line="false" size="medium"
|
||
class="file-data-table" :row-class-name="rowClassName" />
|
||
</n-config-provider>
|
||
|
||
<!-- 自定义分页器 -->
|
||
<div class="custom-pagination">
|
||
<div class="pagination-content">
|
||
<div class="page-numbers">
|
||
<span class="page-number nav-button" :class="{ disabled: currentPage === 1 }" @click="goToPage('first')">
|
||
首页
|
||
</span>
|
||
<span class="page-number nav-button" :class="{ disabled: currentPage === 1 }" @click="goToPage('prev')">
|
||
上一页
|
||
</span>
|
||
|
||
<span v-for="page in visiblePages" :key="page" class="page-number page-number-bordered"
|
||
:class="{ active: page === currentPage }" @click="goToPage(page)">
|
||
{{ page }}
|
||
</span>
|
||
|
||
<span v-if="showRightEllipsis" class="page-number">...</span>
|
||
<span v-if="totalPages > 1" class="page-number page-number-bordered" @click="goToPage(totalPages)">
|
||
{{ totalPages }}
|
||
</span>
|
||
|
||
<span class="page-number nav-button" :class="{ disabled: currentPage === totalPages }"
|
||
@click="goToPage('next')">
|
||
下一页
|
||
</span>
|
||
<span class="page-number nav-button" :class="{ disabled: currentPage === totalPages }"
|
||
@click="goToPage('last')">
|
||
尾页
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 添加课件模态框 -->
|
||
<div v-if="showAddCoursewareModal" class="modal-overlay" @click="closeAddCoursewareModal">
|
||
<AddCoursewareModal @close="closeAddCoursewareModal" />
|
||
</div>
|
||
|
||
<!-- 上传文件模态框 -->
|
||
<div v-if="showUploadFileModal" class="modal-overlay" @click="closeUploadFileModal">
|
||
<UploadFileModal @close="closeUploadFileModal" />
|
||
</div>
|
||
|
||
<!-- 删除确认模态框 -->
|
||
<DeleteFolderConfirmModal
|
||
v-if="showDeleteConfirmModal"
|
||
:show="showDeleteConfirmModal"
|
||
@confirm="confirmDelete"
|
||
@cancel="cancelDelete"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, h, onMounted, onUnmounted } from 'vue'
|
||
import { NButton, NDropdown, NTag, useMessage, NDataTable, NConfigProvider, zhCN, dateZhCN } from 'naive-ui'
|
||
import type { DataTableColumns, DropdownOption } from 'naive-ui'
|
||
import AddCoursewareModal from './AddCoursewareModal.vue'
|
||
import UploadFileModal from './UploadFileModal.vue'
|
||
import DeleteFolderConfirmModal from '@/components/common/DeleteFolderConfirmModal.vue'
|
||
|
||
const message = useMessage()
|
||
|
||
// 文件类型定义
|
||
interface FileItem {
|
||
id: number
|
||
name: string
|
||
type: string
|
||
size: string
|
||
creator: string
|
||
createTime: string
|
||
isTop: boolean
|
||
children?: FileItem[]
|
||
expanded?: boolean
|
||
}
|
||
|
||
// 搜索关键词
|
||
const searchKeyword = ref('')
|
||
|
||
// 选中的文件行
|
||
const selectedFiles = ref<number[]>([])
|
||
|
||
// 控制模态框显示
|
||
const showAddCoursewareModal = ref(false)
|
||
const showUploadFileModal = ref(false)
|
||
const showDeleteConfirmModal = ref(false)
|
||
|
||
// 存储待删除的项目信息
|
||
const itemsToDelete = ref<{ type: 'single' | 'multiple', data: any }>({ type: 'single', data: null })
|
||
|
||
// 存储当前要上传文件的目标文件夹
|
||
const currentUploadTarget = ref<FileItem | null>(null)
|
||
|
||
// 文件列表数据
|
||
const fileList = ref<FileItem[]>([
|
||
{
|
||
id: 1,
|
||
name: '文件名称文件名称文件名称',
|
||
type: 'folder',
|
||
size: '1MB',
|
||
creator: '王建国',
|
||
createTime: '2025.07.25 09:20',
|
||
isTop: true,
|
||
expanded: false,
|
||
children: [
|
||
{
|
||
id: 2,
|
||
name: '这是一个表格文件.xlsx',
|
||
type: 'excel',
|
||
size: '1MB',
|
||
creator: '王建国',
|
||
createTime: '2025.07.25 09:20',
|
||
isTop: false
|
||
},
|
||
{
|
||
id: 3,
|
||
name: '这是一个表格文件.xlsx',
|
||
type: 'excel',
|
||
size: '1MB',
|
||
creator: '王建国',
|
||
createTime: '2025.07.25 09:20',
|
||
isTop: false
|
||
},
|
||
{
|
||
id: 4,
|
||
name: '这是一个表格文件.xlsx',
|
||
type: 'word',
|
||
size: '1MB',
|
||
creator: '王建国',
|
||
createTime: '2025.07.25 09:20',
|
||
isTop: false
|
||
},
|
||
{
|
||
id: 5,
|
||
name: '这是一个表格文件.xlsx',
|
||
type: 'pdf',
|
||
size: '1MB',
|
||
creator: '王建国',
|
||
createTime: '2025.07.25 09:20',
|
||
isTop: false
|
||
},
|
||
{
|
||
id: 6,
|
||
name: '这是一个表格文件.xlsx',
|
||
type: 'video',
|
||
size: '1MB',
|
||
creator: '王建国',
|
||
createTime: '2025.07.25 09:20',
|
||
isTop: false
|
||
}
|
||
]
|
||
}
|
||
])
|
||
|
||
// 将树形结构展平为列表
|
||
const flattenFiles = (files: FileItem[]): FileItem[] => {
|
||
const result: FileItem[] = []
|
||
files.forEach((file: FileItem) => {
|
||
result.push(file)
|
||
if (file.children && file.expanded) {
|
||
result.push(...flattenFiles(file.children))
|
||
}
|
||
})
|
||
return result
|
||
}
|
||
|
||
// 过滤后的文件列表(优化版,置顶文件优先显示)
|
||
const filteredFiles = computed(() => {
|
||
const allFiles = flattenFiles(fileList.value)
|
||
let filtered = allFiles
|
||
|
||
// 如果有搜索关键词,先过滤
|
||
if (searchKeyword.value) {
|
||
filtered = allFiles.filter((file: FileItem) =>
|
||
file.name.toLowerCase().includes(searchKeyword.value.toLowerCase())
|
||
)
|
||
}
|
||
|
||
// 对过滤后的文件进行排序:置顶文件在前,其他文件按原顺序
|
||
return filtered.sort((a: FileItem, b: FileItem) => {
|
||
if (a.isTop && !b.isTop) return -1
|
||
if (!a.isTop && b.isTop) return 1
|
||
return 0
|
||
})
|
||
})
|
||
|
||
// 获取文件图标
|
||
const getFileIcon = (type: string) => {
|
||
const iconMap: { [key: string]: string } = {
|
||
folder: '/images/activity/file.png',
|
||
excel: '/images/activity/xls.png',
|
||
word: '/images/activity/wrod.png',
|
||
pdf: '/images/activity/pdf.png',
|
||
ppt: '/images/activity/ppt.png',
|
||
video: '/images/activity/file.png'
|
||
}
|
||
return iconMap[type] || '/images/activity/file.png'
|
||
}
|
||
|
||
// 表格行键
|
||
const rowKey = (row: FileItem) => row.id
|
||
|
||
// 表格选择处理
|
||
const handleCheck = (rowKeys: number[]) => {
|
||
selectedFiles.value = rowKeys
|
||
}
|
||
|
||
// 行样式名称
|
||
const rowClassName = () => {
|
||
return 'file-table-row'
|
||
}
|
||
|
||
// 分页相关状态
|
||
const currentPage = ref(1)
|
||
const pageSize = ref(10)
|
||
const totalPages = computed(() => Math.ceil(filteredFiles.value.length / pageSize.value))
|
||
|
||
// 可见的页码范围
|
||
const visiblePages = computed(() => {
|
||
const pages = []
|
||
const current = currentPage.value
|
||
const total = totalPages.value
|
||
|
||
if (total <= 7) {
|
||
// 如果总页数小于等于7,显示所有页码
|
||
for (let i = 1; i <= total; i++) {
|
||
pages.push(i)
|
||
}
|
||
} else {
|
||
// 显示当前页附近的页码
|
||
const start = Math.max(1, current - 2)
|
||
const end = Math.min(total, current + 2)
|
||
|
||
for (let i = start; i <= end; i++) {
|
||
pages.push(i)
|
||
}
|
||
}
|
||
|
||
return pages
|
||
})
|
||
|
||
// 是否显示右侧省略号
|
||
const showRightEllipsis = computed(() => {
|
||
return currentPage.value < totalPages.value - 3
|
||
})
|
||
|
||
// 分页方法
|
||
const goToPage = (page: string | number) => {
|
||
if (typeof page === 'string') {
|
||
switch (page) {
|
||
case 'first':
|
||
currentPage.value = 1
|
||
break
|
||
case 'prev':
|
||
if (currentPage.value > 1) currentPage.value--
|
||
break
|
||
case 'next':
|
||
if (currentPage.value < totalPages.value) currentPage.value++
|
||
break
|
||
case 'last':
|
||
currentPage.value = totalPages.value
|
||
break
|
||
}
|
||
} else {
|
||
currentPage.value = page
|
||
}
|
||
}
|
||
|
||
// 分页后的数据
|
||
const paginatedFiles = computed(() => {
|
||
const start = (currentPage.value - 1) * pageSize.value
|
||
const end = start + pageSize.value
|
||
return filteredFiles.value.slice(start, end)
|
||
})
|
||
|
||
// 更多操作菜单选项
|
||
const getMoreOptions = (row: FileItem): DropdownOption[] => [
|
||
{
|
||
label: '重命名',
|
||
key: 'rename',
|
||
icon: () => h('img', {
|
||
src: '/images/teacher/重命名.png',
|
||
alt: '重命名',
|
||
style: { width: '16px', height: '16px' }
|
||
})
|
||
},
|
||
{
|
||
label: row.isTop ? '取消置顶' : '置顶',
|
||
key: 'toggle-top',
|
||
icon: () => h('img', {
|
||
src: '/images/teacher/置顶.png',
|
||
alt: '置顶',
|
||
style: { width: '16px', height: '16px' }
|
||
})
|
||
},
|
||
{
|
||
label: '权限设置',
|
||
key: 'permissions',
|
||
icon: () => h('img', {
|
||
src: '/images/teacher/权限设置.png',
|
||
alt: '权限设置',
|
||
style: { width: '16px', height: '16px' }
|
||
})
|
||
},
|
||
{
|
||
label: '下载',
|
||
key: 'download',
|
||
icon: () => h('img', {
|
||
src: '/images/teacher/下载.png',
|
||
alt: '下载',
|
||
style: { width: '16px', height: '16px' }
|
||
})
|
||
}
|
||
]
|
||
|
||
// 处理更多操作
|
||
const handleMoreAction = (key: string, row: FileItem) => {
|
||
switch (key) {
|
||
case 'rename':
|
||
renameFile(row)
|
||
break
|
||
case 'toggle-top':
|
||
toggleTop(row)
|
||
break
|
||
case 'permissions':
|
||
setPermissions(row)
|
||
break
|
||
case 'download':
|
||
downloadFile(row)
|
||
break
|
||
}
|
||
}
|
||
|
||
// 响应式列宽计算
|
||
// const getResponsiveColumns = () => {
|
||
// const screenWidth = window.innerWidth
|
||
|
||
// // 基础列宽配置
|
||
// const baseColumns = {
|
||
// selection: 40,
|
||
// index: 80,
|
||
// name: 270,
|
||
// size: 100,
|
||
// creator: 120,
|
||
// createTime: 180,
|
||
// actions: 320
|
||
// }
|
||
|
||
// // 根据屏幕宽度调整列宽
|
||
// if (screenWidth < 1200) {
|
||
// // 小屏幕:减少各列宽度
|
||
// return {
|
||
// selection: 35,
|
||
// index: 60,
|
||
// name: Math.max(200, screenWidth * 0.25),
|
||
// size: 80,
|
||
// creator: 100,
|
||
// createTime: 140,
|
||
// actions: Math.max(280, screenWidth * 0.3)
|
||
// }
|
||
// } else if (screenWidth < 1600) {
|
||
// // 中等屏幕:保持基础宽度
|
||
// return baseColumns
|
||
// } else {
|
||
// // 大屏幕:适当增加宽度
|
||
// return {
|
||
// selection: 45,
|
||
// index: 90,
|
||
// name: 320,
|
||
// size: 110,
|
||
// creator: 130,
|
||
// createTime: 200,
|
||
// actions: 360
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// 屏幕宽度响应式数据
|
||
const screenWidth = ref(window.innerWidth)
|
||
|
||
// 监听窗口大小变化
|
||
const handleResize = () => {
|
||
screenWidth.value = window.innerWidth
|
||
}
|
||
|
||
// 响应式列配置计算属性
|
||
const responsiveColumns = computed(() => {
|
||
const width = screenWidth.value
|
||
|
||
// 基础列宽配置
|
||
const baseColumns = {
|
||
selection: 40,
|
||
index: 80,
|
||
name: 270,
|
||
size: 100,
|
||
creator: 120,
|
||
createTime: 180,
|
||
actions: 320
|
||
}
|
||
|
||
// 根据屏幕宽度调整列宽
|
||
if (width < 1200) {
|
||
// 小屏幕:减少各列宽度
|
||
return {
|
||
selection: 35,
|
||
index: 60,
|
||
name: Math.max(200, width * 0.25),
|
||
size: 80,
|
||
creator: 100,
|
||
createTime: 140,
|
||
actions: Math.max(280, width * 0.3)
|
||
}
|
||
} else if (width < 1600) {
|
||
// 中等屏幕:保持基础宽度
|
||
return baseColumns
|
||
} else {
|
||
// 大屏幕:适当增加宽度
|
||
return {
|
||
selection: 45,
|
||
index: 90,
|
||
name: 320,
|
||
size: 110,
|
||
creator: 130,
|
||
createTime: 200,
|
||
actions: 360
|
||
}
|
||
}
|
||
})
|
||
|
||
// 在组件挂载时添加事件监听器
|
||
onMounted(() => {
|
||
window.addEventListener('resize', handleResize)
|
||
})
|
||
|
||
// 在组件卸载时移除事件监听器
|
||
onUnmounted(() => {
|
||
window.removeEventListener('resize', handleResize)
|
||
})
|
||
|
||
// 表格列配置
|
||
const columns = computed((): DataTableColumns<FileItem> => [
|
||
{
|
||
type: 'selection',
|
||
width: responsiveColumns.value.selection
|
||
},
|
||
{
|
||
title: '序号',
|
||
key: 'index',
|
||
width: responsiveColumns.value.index,
|
||
render: (_row: FileItem, index: number) => index + 1
|
||
},
|
||
{
|
||
title: '名称',
|
||
key: 'name',
|
||
width: responsiveColumns.value.name,
|
||
ellipsis: {
|
||
tooltip: true
|
||
},
|
||
render: (row: FileItem) => {
|
||
return h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', justifyContent: 'center' } }, [
|
||
// 如果是文件夹,添加展开/收起按钮
|
||
row.type === 'folder' ? h('svg', {
|
||
viewBox: '0 0 16 16',
|
||
fill: 'none',
|
||
xmlns: 'http://www.w3.org/2000/svg',
|
||
style: {
|
||
cursor: 'pointer',
|
||
width: '12px',
|
||
height: '12px',
|
||
color: '#666',
|
||
marginRight: '4px',
|
||
transition: 'transform 0.3s ease',
|
||
transform: row.expanded ? 'rotate(90deg)' : 'rotate(0deg)'
|
||
},
|
||
onClick: (e: Event) => {
|
||
e.stopPropagation()
|
||
toggleFolder(row)
|
||
}
|
||
}, [
|
||
h('path', {
|
||
d: 'M5.64645 3.14645C5.45118 3.34171 5.45118 3.65829 5.64645 3.85355L9.79289 8L5.64645 12.1464C5.45118 12.3417 5.45118 12.6583 5.64645 12.8536C5.84171 13.0488 6.15829 13.0488 6.35355 12.8536L10.8536 8.35355C11.0488 8.15829 11.0488 7.84171 10.8536 7.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645Z',
|
||
fill: 'currentColor'
|
||
})
|
||
]) : null,
|
||
h('img', {
|
||
src: getFileIcon(row.type),
|
||
alt: row.type,
|
||
style: { width: '16px', height: '16px' }
|
||
}),
|
||
h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } }, [
|
||
h('span', { style: { color: '#062333' } }, row.name),
|
||
row.isTop ? h(NTag, { type: 'info', size: 'small' }, { default: () => '置顶' }) : null
|
||
])
|
||
])
|
||
}
|
||
},
|
||
{
|
||
title: '大小',
|
||
key: 'size',
|
||
width: responsiveColumns.value.size
|
||
},
|
||
{
|
||
title: '创建人',
|
||
key: 'creator',
|
||
width: responsiveColumns.value.creator
|
||
},
|
||
{
|
||
title: '创建时间',
|
||
key: 'createTime',
|
||
width: responsiveColumns.value.createTime
|
||
},
|
||
{
|
||
title: '操作',
|
||
key: 'actions',
|
||
width: responsiveColumns.value.actions,
|
||
render: (row: FileItem) => {
|
||
const buttons = []
|
||
|
||
// 只有文件夹类型才显示上传文件按钮
|
||
if (row.type === 'folder') {
|
||
buttons.push(
|
||
h(NButton, {
|
||
size: 'small',
|
||
type: 'info',
|
||
secondary: true,
|
||
onClick: () => uploadFile(row)
|
||
}, { default: () => '上传文件' })
|
||
)
|
||
}
|
||
|
||
// 其他按钮始终显示
|
||
buttons.push(
|
||
h(NButton, {
|
||
size: 'small',
|
||
type: 'primary',
|
||
secondary: true,
|
||
onClick: () => viewFile(row)
|
||
}, { default: () => '查看' }),
|
||
h(NButton, {
|
||
size: 'small',
|
||
type: 'error',
|
||
secondary: true,
|
||
onClick: () => deleteFile(row)
|
||
}, { default: () => '删除' }),
|
||
h(NDropdown, {
|
||
options: getMoreOptions(row),
|
||
onSelect: (key: string) => handleMoreAction(key, row)
|
||
}, {
|
||
default: () => h(NButton, { size: 'small', secondary: true }, { default: () => '更多' })
|
||
})
|
||
)
|
||
|
||
return h('div', { style: { display: 'flex', gap: '8px', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'center' } }, buttons)
|
||
}
|
||
}
|
||
])
|
||
|
||
// 文件操作方法
|
||
const addCourseware = () => {
|
||
showAddCoursewareModal.value = true
|
||
}
|
||
|
||
// 关闭添加课件模态框
|
||
const closeAddCoursewareModal = () => {
|
||
showAddCoursewareModal.value = false
|
||
}
|
||
|
||
const createFolder = () => {
|
||
message.info('新建文件夹功能')
|
||
}
|
||
|
||
const moveFiles = () => {
|
||
if (selectedFiles.value.length === 0) return
|
||
message.info(`移动 ${selectedFiles.value.length} 个文件`)
|
||
}
|
||
|
||
const deleteSelected = () => {
|
||
if (selectedFiles.value.length === 0) return
|
||
// 存储要删除的文件信息
|
||
itemsToDelete.value = {
|
||
type: 'multiple',
|
||
data: selectedFiles.value
|
||
}
|
||
showDeleteConfirmModal.value = true
|
||
}
|
||
|
||
const searchFiles = () => {
|
||
message.info('搜索文件: ' + searchKeyword.value)
|
||
}
|
||
|
||
const uploadFile = (file: FileItem) => {
|
||
currentUploadTarget.value = file
|
||
showUploadFileModal.value = true
|
||
}
|
||
|
||
// 关闭上传文件模态框
|
||
const closeUploadFileModal = () => {
|
||
showUploadFileModal.value = false
|
||
currentUploadTarget.value = null
|
||
}
|
||
|
||
const viewFile = (file: FileItem) => {
|
||
message.info('查看文件: ' + file.name)
|
||
}
|
||
|
||
const deleteFile = (file: FileItem) => {
|
||
// 存储要删除的文件信息
|
||
itemsToDelete.value = {
|
||
type: 'single',
|
||
data: file
|
||
}
|
||
showDeleteConfirmModal.value = true
|
||
}
|
||
|
||
// 确认删除
|
||
const confirmDelete = () => {
|
||
if (itemsToDelete.value.type === 'multiple') {
|
||
// 批量删除
|
||
const idsToDelete = itemsToDelete.value.data as number[]
|
||
idsToDelete.forEach((id: number) => {
|
||
const index = fileList.value.findIndex((f: FileItem) => f.id === id)
|
||
if (index > -1) {
|
||
fileList.value.splice(index, 1)
|
||
}
|
||
})
|
||
selectedFiles.value = []
|
||
message.success(`成功删除 ${idsToDelete.length} 个文件`)
|
||
} else {
|
||
// 单个删除
|
||
const file = itemsToDelete.value.data as FileItem
|
||
const index = fileList.value.findIndex((f: FileItem) => f.id === file.id)
|
||
if (index > -1) {
|
||
fileList.value.splice(index, 1)
|
||
message.success('删除成功')
|
||
}
|
||
}
|
||
showDeleteConfirmModal.value = false
|
||
itemsToDelete.value = { type: 'single', data: null }
|
||
}
|
||
|
||
// 取消删除
|
||
const cancelDelete = () => {
|
||
showDeleteConfirmModal.value = false
|
||
itemsToDelete.value = { type: 'single', data: null }
|
||
}
|
||
|
||
const renameFile = (file: FileItem) => {
|
||
const newName = prompt('请输入新的文件名:', file.name)
|
||
if (newName && newName !== file.name) {
|
||
file.name = newName
|
||
message.success('重命名成功')
|
||
}
|
||
}
|
||
|
||
// 递归查找文件在树形结构中的位置
|
||
const findFileInTree = (files: FileItem[], targetId: number): { parent: FileItem | null, index: number } | null => {
|
||
for (let i = 0; i < files.length; i++) {
|
||
const file = files[i]
|
||
if (file.id === targetId) {
|
||
return { parent: null, index: i }
|
||
}
|
||
if (file.children) {
|
||
for (let j = 0; j < file.children.length; j++) {
|
||
if (file.children[j].id === targetId) {
|
||
return { parent: file, index: j }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return null
|
||
}
|
||
|
||
// 优化后的置顶功能,支持文件夹内部置顶
|
||
const toggleTop = (file: FileItem) => {
|
||
file.isTop = !file.isTop
|
||
|
||
if (file.isTop) {
|
||
// 置顶:在当前位置进行置顶
|
||
const result = findFileInTree(fileList.value, file.id)
|
||
if (result) {
|
||
if (result.parent) {
|
||
// 如果是子文件,在父文件夹内部置顶
|
||
const children = result.parent.children!
|
||
const [topFile] = children.splice(result.index, 1)
|
||
children.unshift(topFile)
|
||
} else {
|
||
// 如果是根级别文件,在根级别置顶
|
||
const [topFile] = fileList.value.splice(result.index, 1)
|
||
fileList.value.unshift(topFile)
|
||
}
|
||
}
|
||
message.success('已置顶')
|
||
} else {
|
||
// 取消置顶:在当前位置取消置顶
|
||
const result = findFileInTree(fileList.value, file.id)
|
||
if (result) {
|
||
if (result.parent) {
|
||
// 如果是子文件,在父文件夹内部取消置顶
|
||
const children = result.parent.children!
|
||
const [unTopFile] = children.splice(result.index, 1)
|
||
children.push(unTopFile)
|
||
} else {
|
||
// 如果是根级别文件,在根级别取消置顶
|
||
const [unTopFile] = fileList.value.splice(result.index, 1)
|
||
fileList.value.push(unTopFile)
|
||
}
|
||
}
|
||
message.success('已取消置顶')
|
||
}
|
||
}
|
||
|
||
const setPermissions = (file: FileItem) => {
|
||
message.info('权限设置: ' + file.name)
|
||
}
|
||
|
||
const downloadFile = (file: FileItem) => {
|
||
message.info('下载文件: ' + file.name)
|
||
}
|
||
|
||
// 切换文件夹展开/收起状态
|
||
const toggleFolder = (folder: FileItem) => {
|
||
if (folder.type === 'folder' && folder.children) {
|
||
folder.expanded = !folder.expanded
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.courseware-management {
|
||
width: 100%;
|
||
background: #fff;
|
||
height: 100%;
|
||
overflow: auto;
|
||
}
|
||
|
||
/* 顶部工具栏 */
|
||
.toolbar {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-right: 25px;
|
||
background: #fff;
|
||
padding: 30px 0 20px 30px;
|
||
border-bottom: 2px solid #F6F6F6;
|
||
}
|
||
|
||
.toolbar h2 {
|
||
margin: 0;
|
||
font-size: 18px;
|
||
color: #333;
|
||
}
|
||
|
||
.toolbar-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 7px 16px;
|
||
border: none;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: #0288D1;
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: #40a9ff;
|
||
}
|
||
|
||
.btn-new {
|
||
background-color: #fff;
|
||
border: 1px solid #0288D1;
|
||
color: #0288D1;
|
||
}
|
||
|
||
.btn-default {
|
||
background: white;
|
||
color: #999999;
|
||
border: 1px solid #999999;
|
||
}
|
||
|
||
.btn-default:hover {
|
||
border-color: #1890ff;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.btn-danger {
|
||
background: white;
|
||
color: #FF4D4F;
|
||
border: 1px solid #FF4D4F;
|
||
}
|
||
|
||
.btn-danger:hover {
|
||
background: #ff7875;
|
||
}
|
||
|
||
.btn-default:disabled,
|
||
.btn-danger:disabled {
|
||
/* opacity: 0.5; */
|
||
/* cursor: not-allowed; */
|
||
}
|
||
|
||
/* 模态框遮罩层样式 */
|
||
.modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.search-box {
|
||
display: flex;
|
||
align-items: center;
|
||
border: 1px solid #F1F3F4;
|
||
border-radius: 2px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.search-box input {
|
||
border: none;
|
||
padding: 6px 12px;
|
||
outline: none;
|
||
width: 200px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.btn-search {
|
||
background: #0288D1;
|
||
color: white;
|
||
border: none;
|
||
padding: 6px 16px;
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.btn-search:hover {
|
||
background: #0277bd;
|
||
}
|
||
|
||
.table-box {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
/* Naive UI 表格样式定制 */
|
||
:deep(.file-data-table) {
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
padding: 40px;
|
||
}
|
||
|
||
/* 表格头部样式 */
|
||
:deep(.file-data-table .n-data-table-thead) {
|
||
background: #fafafa;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-th) {
|
||
background: #fafafa;
|
||
font-weight: 500;
|
||
color: #062333;
|
||
font-size: 14px;
|
||
border-bottom: 1px solid #e8e8e8;
|
||
padding: 12px 8px;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 表格行样式 */
|
||
:deep(.file-data-table .n-data-table-td) {
|
||
font-size: 13px;
|
||
color: #062333;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
padding: 12px 8px;
|
||
vertical-align: middle;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 名称列左对齐 */
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="name"]) {
|
||
text-align: center;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-th[data-col-key="name"]) {
|
||
text-align: center;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-tr:hover) {
|
||
background: #fafafa;
|
||
}
|
||
|
||
/* 复选框样式 */
|
||
:deep(.file-data-table .n-checkbox) {
|
||
--n-size: 16px;
|
||
}
|
||
|
||
/* 按钮组样式调整 */
|
||
:deep(.file-data-table .n-button) {
|
||
font-size: 12px;
|
||
height: 28px;
|
||
padding: 0 12px;
|
||
margin: 2px;
|
||
}
|
||
|
||
/* 下拉菜单样式 */
|
||
:deep(.n-dropdown-option) {
|
||
font-size: 12px;
|
||
padding: 8px 12px;
|
||
}
|
||
|
||
/* 分页样式 */
|
||
:deep(.n-data-table__pagination) {
|
||
position: relative;
|
||
padding: 20px 0;
|
||
margin-top: 20px;
|
||
background: #fff;
|
||
}
|
||
|
||
:deep(.n-pagination) {
|
||
justify-content: center;
|
||
margin: 0;
|
||
}
|
||
|
||
/* 当前页面颜色调整 */
|
||
:deep(.n-pagination-item--active) {
|
||
background-color: #0088D1 !important;
|
||
border-color: #0088D1 !important;
|
||
color: #fff !important;
|
||
}
|
||
|
||
:deep(.n-pagination-item--active:hover) {
|
||
background-color: #0077B8 !important;
|
||
border-color: #0077B8 !important;
|
||
}
|
||
|
||
/* 分页按钮悬停效果 */
|
||
:deep(.n-pagination-item:hover:not(.n-pagination-item--disabled):not(.n-pagination-item--active)) {
|
||
background-color: #f5f5f5;
|
||
border-color: #0088D1;
|
||
color: #0088D1;
|
||
}
|
||
|
||
/* 快速跳转输入框样式 */
|
||
:deep(.n-pagination-quick-jumper .n-input) {
|
||
width: 50px;
|
||
}
|
||
|
||
|
||
|
||
/* 页面大小选择器样式 */
|
||
:deep(.n-select .n-base-selection) {
|
||
border-color: #e0e0e0;
|
||
}
|
||
|
||
:deep(.n-select .n-base-selection:hover) {
|
||
border-color: #0088D1;
|
||
}
|
||
|
||
/* 标签样式 */
|
||
:deep(.n-tag) {
|
||
font-size: 10px;
|
||
height: 18px;
|
||
line-height: 16px;
|
||
padding: 0 6px;
|
||
}
|
||
|
||
/* 输入框样式 */
|
||
:deep(.n-input) {
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 表格行样式 */
|
||
:deep(.file-table-row) {
|
||
transition: background-color 0.2s;
|
||
}
|
||
|
||
:deep(.file-table-row:hover) {
|
||
background-color: #f8f9fa;
|
||
}
|
||
|
||
/* 操作按钮容器 */
|
||
:deep(.file-data-table .n-data-table-td:last-child) {
|
||
padding: 8px;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-table) {
|
||
border-spacing: 0;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-th:first-child),
|
||
:deep(.file-data-table .n-data-table-td:first-child) {
|
||
padding-left: 16px;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-th:last-child),
|
||
:deep(.file-data-table .n-data-table-td:last-child) {
|
||
padding-right: 16px;
|
||
}
|
||
|
||
/* 表格边框 */
|
||
:deep(.file-data-table .n-data-table-table) {
|
||
border: 1px solid #f0f0f0;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
/* 隐藏序号列中的展开图标 */
|
||
:deep(.file-data-table .n-data-table-expand-trigger) {
|
||
display: none !important;
|
||
}
|
||
|
||
/* 操作按钮样式 - 只有边框和文字颜色,无背景色 */
|
||
:deep(.file-data-table .n-button--info-type.n-button--secondary) {
|
||
background-color: transparent !important;
|
||
border: 1px solid #0288D1;
|
||
color: #0288D1;
|
||
}
|
||
|
||
:deep(.file-data-table .n-button--info-type.n-button--secondary:hover) {
|
||
background-color: rgba(32, 128, 240, 0.05) !important;
|
||
border: 1px solid #0288D1;
|
||
color: #248DD3;
|
||
}
|
||
|
||
:deep(.file-data-table .n-button--primary-type.n-button--secondary) {
|
||
background-color: transparent !important;
|
||
border: 1px solid #0288D1;
|
||
color: #0288D1;
|
||
}
|
||
|
||
:deep(.file-data-table .n-button--primary-type.n-button--secondary:hover) {
|
||
background-color: rgba(24, 160, 88, 0.05) !important;
|
||
border: 1px solid #0288D1;
|
||
color: #0288D1;
|
||
}
|
||
|
||
:deep(.file-data-table .n-button--error-type.n-button--secondary) {
|
||
background-color: transparent !important;
|
||
border: 1px solid #FF4D4F;
|
||
color: #FD8485;
|
||
}
|
||
|
||
:deep(.file-data-table .n-button--error-type.n-button--secondary:hover) {
|
||
background-color: rgba(208, 48, 80, 0.05) !important;
|
||
border: 1px solid #FF4D4F;
|
||
color: #FD8485;
|
||
}
|
||
|
||
:deep(.file-data-table .n-button--default-type.n-button--secondary) {
|
||
background-color: transparent !important;
|
||
border: 1px solid #4165D7;
|
||
color: #4165D7;
|
||
}
|
||
|
||
:deep(.file-data-table .n-button--default-type.n-button--secondary:hover) {
|
||
background-color: rgba(0, 0, 0, 0.02) !important;
|
||
border: 1px solid #4165D7;
|
||
color: #4165D7;
|
||
}
|
||
|
||
/* 下拉菜单图标悬停效果 */
|
||
:deep(.n-dropdown-option:hover img[alt="重命名"]) {
|
||
content: url('/images/teacher/重命名-选中.png');
|
||
}
|
||
|
||
:deep(.n-dropdown-option:hover img[alt="置顶"]) {
|
||
content: url('/images/teacher/置顶-选中.png');
|
||
}
|
||
|
||
:deep(.n-dropdown-option:hover img[alt="权限设置"]) {
|
||
content: url('/images/teacher/权限设置-选中.png');
|
||
}
|
||
|
||
:deep(.n-dropdown-option:hover img[alt="下载"]) {
|
||
content: url('/images/teacher/下载-选中.png');
|
||
}
|
||
|
||
/* 自定义分页器样式 */
|
||
.custom-pagination {
|
||
display: flex;
|
||
justify-content: center;
|
||
background: #fff;
|
||
padding: 20px 0;
|
||
margin-top: auto;
|
||
width: 100%;
|
||
}
|
||
|
||
.pagination-content {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin: 0 auto;
|
||
padding: 0 10px;
|
||
}
|
||
|
||
.page-numbers {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 0;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.page-number {
|
||
display: inline-block;
|
||
min-width: 38px;
|
||
height: 38px;
|
||
line-height: 38px;
|
||
text-align: center;
|
||
color: #333;
|
||
text-decoration: none;
|
||
font-size: 14px;
|
||
padding: 0 5px;
|
||
margin: 0 4px;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.page-number-bordered {
|
||
border: 1px solid #d9d9d9;
|
||
}
|
||
|
||
.page-number.active {
|
||
background-color: #0088D1;
|
||
color: white;
|
||
border-color: #0088D1;
|
||
}
|
||
|
||
.page-number:hover:not(.disabled) {
|
||
color: #0088D1;
|
||
border-color: #0088D1;
|
||
}
|
||
|
||
.page-number.disabled {
|
||
color: #ccc;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.page-number.disabled:hover {
|
||
color: #ccc;
|
||
border-color: #d9d9d9;
|
||
}
|
||
|
||
.nav-button {
|
||
padding: 0 8px;
|
||
border: none;
|
||
}
|
||
|
||
.nav-button:hover:not(.disabled) {
|
||
color: #0088D1;
|
||
}
|
||
|
||
/* 响应式样式 */
|
||
@media (max-width: 1200px) {
|
||
.toolbar {
|
||
flex-direction: column;
|
||
gap: 15px;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.toolbar-actions {
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.search-box input {
|
||
width: 150px;
|
||
}
|
||
|
||
/* 表格在小屏幕下的优化 */
|
||
:deep(.file-data-table) {
|
||
padding: 20px;
|
||
}
|
||
|
||
/* 操作按钮在小屏幕下换行 */
|
||
:deep(.file-data-table .n-data-table-td:last-child .n-button) {
|
||
margin: 2px;
|
||
font-size: 11px;
|
||
padding: 0 8px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.toolbar {
|
||
padding: 20px 15px;
|
||
}
|
||
|
||
.toolbar h2 {
|
||
font-size: 16px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 6px 12px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.search-box input {
|
||
width: 120px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
/* 表格在移动端的优化 */
|
||
:deep(.file-data-table) {
|
||
padding: 10px;
|
||
}
|
||
|
||
/* 隐藏某些列在移动端 */
|
||
:deep(.file-data-table .n-data-table-th[data-col-key="creator"]),
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="creator"]) {
|
||
display: none;
|
||
}
|
||
|
||
/* 操作按钮在移动端垂直排列 */
|
||
:deep(.file-data-table .n-data-table-td:last-child > div) {
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-td:last-child .n-button) {
|
||
width: 100%;
|
||
margin: 1px 0;
|
||
}
|
||
|
||
/* 分页器在移动端的优化 */
|
||
.page-numbers {
|
||
flex-wrap: wrap;
|
||
gap: 4px;
|
||
}
|
||
|
||
.page-number {
|
||
min-width: 32px;
|
||
height: 32px;
|
||
line-height: 32px;
|
||
font-size: 12px;
|
||
margin: 0 2px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
.toolbar-actions {
|
||
flex-direction: column;
|
||
width: 100%;
|
||
}
|
||
|
||
.search-box {
|
||
width: 100%;
|
||
}
|
||
|
||
.search-box input {
|
||
width: 100%;
|
||
}
|
||
|
||
/* 进一步隐藏列 */
|
||
:deep(.file-data-table .n-data-table-th[data-col-key="createTime"]),
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="createTime"]) {
|
||
display: none;
|
||
}
|
||
|
||
/* 表格内容在超小屏幕下的优化 */
|
||
:deep(.file-data-table .n-data-table-td) {
|
||
padding: 8px 4px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-th) {
|
||
padding: 8px 4px;
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
|
||
/* 表格横向滚动优化 */
|
||
:deep(.file-data-table .n-data-table-wrapper) {
|
||
overflow-x: auto;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-base-table) {
|
||
min-width: 100%;
|
||
}
|
||
|
||
/* 确保表格内容不会溢出 */
|
||
:deep(.file-data-table .n-data-table-td) {
|
||
word-break: break-word;
|
||
white-space: normal;
|
||
}
|
||
|
||
/* 名称列文本溢出处理 */
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="name"] span) {
|
||
max-width: 100%;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
display: inline-block;
|
||
}
|
||
</style>
|