1577 lines
38 KiB
Vue
1577 lines
38 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"
|
||
:class="{ 'btn-default--active': 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">
|
||
<div style="flex: 1;">
|
||
<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" style="width: 100%" />
|
||
</div>
|
||
|
||
<!-- 自定义分页器 -->
|
||
<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">
|
||
<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" />
|
||
|
||
<!-- 新建文件夹模态框 -->
|
||
<CommonModal :visible="showCreateFolderModal" title="新建文件夹" @close="closeCreateFolderModal"
|
||
@confirm="handleCreateFolder">
|
||
<template #content="{ getValue }">
|
||
<CreateFolderContent :visible="showCreateFolderModal" :get-value="getValue" />
|
||
</template>
|
||
</CommonModal>
|
||
|
||
<!-- 移动文件模态框 -->
|
||
<CommonModal :visible="showMoveFileModal" title="移动文件" @close="closeMoveFileModal" @confirm="handleMoveFiles">
|
||
<template #content="{ getValue }">
|
||
<MoveFileContent :visible="showMoveFileModal" :available-folders="fileList.filter(f => f.type === 'folder')"
|
||
:get-value="getValue" />
|
||
</template>
|
||
</CommonModal>
|
||
|
||
<!-- 重命名模态框 -->
|
||
<CommonModal :visible="showRenameModal" title="重命名" @close="closeRenameModal" @confirm="handleRename">
|
||
<template #content>
|
||
<div class="rename-content">
|
||
<n-input
|
||
v-model:value="renameInputValue"
|
||
placeholder="请输入新的文件名"
|
||
style="width: 100%"
|
||
ref="renameInputRef"
|
||
@keyup.enter="handleRename"
|
||
/>
|
||
</div>
|
||
</template>
|
||
</CommonModal>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, h, onMounted, onUnmounted, nextTick } from 'vue'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import { NButton, NDropdown, NTag, NInput, useMessage, NDataTable } 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'
|
||
import CommonModal from '@/components/common/CommonModal.vue'
|
||
import CreateFolderContent from '@/components/common/CreateFolderContent.vue'
|
||
import MoveFileContent from '@/components/common/MoveFileContent.vue'
|
||
|
||
const message = useMessage()
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
|
||
// 文件类型定义
|
||
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 showCreateFolderModal = ref(false)
|
||
const showMoveFileModal = ref(false)
|
||
const showRenameModal = ref(false)
|
||
|
||
// 存储待删除的项目信息
|
||
const itemsToDelete = ref<{ type: 'single' | 'multiple', data: any }>({ type: 'single', data: null })
|
||
|
||
// 存储当前要重命名的文件
|
||
const currentRenameFile = ref<FileItem | null>(null)
|
||
// 重命名输入值
|
||
const renameInputValue = ref('')
|
||
|
||
// 重命名输入框引用
|
||
const renameInputRef = ref<InstanceType<typeof NInput> | null>(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/teacher/folder.jpg',
|
||
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: 50,
|
||
// index: 70,
|
||
// name: 400, // 名称列需要更宽,因为文件名可能很长
|
||
// size: 80, // 大小列缩小
|
||
// creator: 100, // 创建人列缩小
|
||
// createTime: 160, // 创建时间列稍微缩小
|
||
// actions: 300 // 操作列稍微缩小
|
||
// }
|
||
|
||
// // 根据屏幕宽度调整列宽
|
||
// if (width < 1200) {
|
||
// // 小屏幕:减少各列宽度,但保持比例
|
||
// return {
|
||
// selection: 40,
|
||
// index: 60,
|
||
// name: Math.max(250, width * 0.35), // 名称列保持较大比例
|
||
// size: 70,
|
||
// creator: 80,
|
||
// createTime: 130,
|
||
// actions: Math.max(250, width * 0.25)
|
||
// }
|
||
// } else if (width < 1600) {
|
||
// // 中等屏幕:保持基础宽度
|
||
// return baseColumns
|
||
// } else {
|
||
// // 大屏幕:适当增加宽度,但保持合理比例
|
||
// return {
|
||
// selection: 50,
|
||
// index: 80,
|
||
// name: 500, // 名称列在大屏幕上更宽
|
||
// size: 90,
|
||
// creator: 120,
|
||
// createTime: 180,
|
||
// actions: 350
|
||
// }
|
||
// }
|
||
// })
|
||
|
||
// 在组件挂载时添加事件监听器
|
||
onMounted(() => {
|
||
window.addEventListener('resize', handleResize)
|
||
})
|
||
|
||
// 在组件卸载时移除事件监听器
|
||
onUnmounted(() => {
|
||
window.removeEventListener('resize', handleResize)
|
||
})
|
||
|
||
// 表格列配置
|
||
const columns = computed((): DataTableColumns<FileItem> => [
|
||
{
|
||
type: 'selection',
|
||
width: 50 // 选择框固定宽度
|
||
},
|
||
{
|
||
title: '序号',
|
||
key: 'index',
|
||
width: 70, // 序号固定宽度
|
||
render: (_row: FileItem, index: number) => index + 1
|
||
},
|
||
{
|
||
title: '名称',
|
||
key: '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: 80 // 大小列固定较小宽度
|
||
},
|
||
{
|
||
title: '创建人',
|
||
key: 'creator',
|
||
width: 100 // 创建人列固定较小宽度
|
||
},
|
||
{
|
||
title: '创建时间',
|
||
key: 'createTime',
|
||
width: 160 // 创建时间列固定宽度
|
||
},
|
||
{
|
||
title: '操作',
|
||
key: 'actions',
|
||
width: 300, // 操作列固定宽度
|
||
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 = () => {
|
||
showCreateFolderModal.value = true
|
||
}
|
||
|
||
const moveFiles = () => {
|
||
if (selectedFiles.value.length === 0) return
|
||
showMoveFileModal.value = true
|
||
}
|
||
|
||
// 关闭新建文件夹模态框
|
||
const closeCreateFolderModal = () => {
|
||
showCreateFolderModal.value = false
|
||
}
|
||
|
||
// 关闭移动文件模态框
|
||
const closeMoveFileModal = () => {
|
||
showMoveFileModal.value = false
|
||
}
|
||
|
||
// 处理创建文件夹
|
||
const handleCreateFolder = (folderName: string) => {
|
||
console.log('handleCreateFolder 接收到参数:', folderName)
|
||
|
||
// 创建新的文件夹对象
|
||
const newFolder: FileItem = {
|
||
id: Date.now(),
|
||
name: folderName,
|
||
type: 'folder',
|
||
size: '0B',
|
||
creator: '王建国', // 这里可以从用户状态获取
|
||
createTime: new Date().toLocaleString('zh-CN', {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
}).replace(/\//g, '.'),
|
||
isTop: false,
|
||
expanded: false,
|
||
children: []
|
||
}
|
||
|
||
console.log('创建的新文件夹对象:', newFolder)
|
||
|
||
// 添加到文件列表
|
||
fileList.value.push(newFolder)
|
||
|
||
// 显示成功消息
|
||
message.success(`文件夹 "${folderName}" 创建成功`)
|
||
|
||
// 关闭模态框
|
||
showCreateFolderModal.value = false
|
||
}
|
||
|
||
// 处理移动文件
|
||
const handleMoveFiles = (targetFolder: any) => {
|
||
// 这里实现移动文件的逻辑
|
||
message.success(`成功移动 ${selectedFiles.value.length} 个文件到 "${targetFolder.name}"`)
|
||
selectedFiles.value = [] // 清空选择
|
||
|
||
// 关闭模态框
|
||
showMoveFileModal.value = false
|
||
}
|
||
|
||
const deleteSelected = () => {
|
||
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) => {
|
||
if (file.type === 'folder') {
|
||
// 跳转到文件夹浏览页面
|
||
router.push({
|
||
name: 'FolderBrowser',
|
||
params: {
|
||
id: route.params.id, // 课程ID
|
||
folderId: file.id.toString()
|
||
}
|
||
})
|
||
} else {
|
||
// 跳转到单个文件查看页面
|
||
router.push({
|
||
name: 'FileViewer',
|
||
params: {
|
||
id: route.params.id, // 课程ID
|
||
fileId: file.id.toString()
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
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) => {
|
||
// 存储当前要重命名的文件
|
||
currentRenameFile.value = file
|
||
// 设置输入框的初始值
|
||
renameInputValue.value = file.name
|
||
showRenameModal.value = true
|
||
|
||
// 使用 nextTick 确保模态框渲染后再聚焦输入框
|
||
nextTick(() => {
|
||
renameInputRef.value?.focus()
|
||
})
|
||
}
|
||
|
||
// 关闭重命名模态框
|
||
const closeRenameModal = () => {
|
||
showRenameModal.value = false
|
||
currentRenameFile.value = null
|
||
renameInputValue.value = ''
|
||
}
|
||
|
||
// 处理重命名
|
||
const handleRename = () => {
|
||
if (!currentRenameFile.value || !renameInputValue.value.trim()) {
|
||
message.error('文件名不能为空')
|
||
return
|
||
}
|
||
|
||
const newName = renameInputValue.value.trim()
|
||
const oldName = currentRenameFile.value.name
|
||
|
||
// 检查名称是否有变化
|
||
if (newName === oldName) {
|
||
message.info('文件名未发生变化')
|
||
closeRenameModal()
|
||
return
|
||
}
|
||
|
||
// 查找原文件并更新名称
|
||
const originalFile = findFileById(fileList.value, currentRenameFile.value.id)
|
||
if (originalFile) {
|
||
originalFile.name = newName
|
||
message.success(`文件重命名成功:"${oldName}" → "${newName}"`)
|
||
} else {
|
||
message.error('未找到要重命名的文件')
|
||
}
|
||
|
||
closeRenameModal()
|
||
}
|
||
|
||
// 递归查找文件
|
||
const findFileById = (files: FileItem[], id: number): FileItem | null => {
|
||
for (const file of files) {
|
||
if (file.id === id) {
|
||
return file
|
||
}
|
||
if (file.children) {
|
||
const found = findFileById(file.children, id)
|
||
if (found) return found
|
||
}
|
||
}
|
||
return null
|
||
}
|
||
|
||
// 递归查找文件在树形结构中的位置
|
||
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;
|
||
overflow: auto;
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 顶部工具栏 */
|
||
.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-default--active {
|
||
border-color: #1890ff !important;
|
||
color: #1890ff !important;
|
||
}
|
||
.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;
|
||
}
|
||
|
||
/* 重命名模态框内容样式 */
|
||
.rename-content {
|
||
padding: 10px 0;
|
||
}
|
||
|
||
.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;
|
||
flex: 1;
|
||
}
|
||
|
||
/* Naive UI 表格样式定制 */
|
||
:deep(.file-data-table) {
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
padding: 40px;
|
||
}
|
||
|
||
/* 表格自适应布局 */
|
||
:deep(.file-data-table .n-data-table-wrapper) {
|
||
overflow-x: auto;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-base-table) {
|
||
width: 100%;
|
||
table-layout: fixed;
|
||
}
|
||
|
||
/* 名称列自动占用剩余空间 */
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="name"]),
|
||
:deep(.file-data-table .n-data-table-th[data-col-key="name"]) {
|
||
max-width: 0;
|
||
width: auto;
|
||
}
|
||
|
||
/* 表格头部样式 */
|
||
: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;
|
||
word-break: break-word;
|
||
white-space: normal;
|
||
}
|
||
|
||
/* 序号列居中对齐 */
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="index"]) {
|
||
text-align: center !important;
|
||
}
|
||
|
||
/* 隐藏序号列的展开占位符,避免影响居中 */
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="index"] .n-data-table-expand-placeholder) {
|
||
display: none;
|
||
}
|
||
|
||
/* 确保序号列的展开触发器也居中 */
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="index"] .n-data-table-expand-trigger) {
|
||
margin-right: 4px;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-th[data-col-key="index"]) {
|
||
text-align: center !important;
|
||
}
|
||
|
||
/* 名称列居中对齐 */
|
||
: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-td[data-col-key="size"]),
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="creator"]),
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="createTime"]),
|
||
:deep(.file-data-table .n-data-table-td[data-col-key="actions"]) {
|
||
text-align: center !important;
|
||
}
|
||
|
||
:deep(.file-data-table .n-data-table-th[data-col-key="size"]),
|
||
:deep(.file-data-table .n-data-table-th[data-col-key="creator"]),
|
||
:deep(.file-data-table .n-data-table-th[data-col-key="createTime"]),
|
||
:deep(.file-data-table .n-data-table-th[data-col-key="actions"]) {
|
||
text-align: center !important;
|
||
}
|
||
|
||
: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) {
|
||
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-wrapper) {
|
||
overflow-x: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
/* 操作按钮在小屏幕下换行 */
|
||
: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>
|