更新数据同步
This commit is contained in:
@@ -0,0 +1,799 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>文档中心</title>
|
||||||
|
<!-- Tailwind CSS v3 -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<!-- Font Awesome -->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||||
|
<!-- 统一的 Tailwind 配置 -->
|
||||||
|
<script>
|
||||||
|
tailwind.config = {
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: '#e6f7ff',
|
||||||
|
secondary: '#f0f7ff',
|
||||||
|
accent: '#1890ff',
|
||||||
|
'accent-light': '#e6f7ff',
|
||||||
|
'accent-hover': '#bae7ff',
|
||||||
|
'text-primary': '#333333',
|
||||||
|
'text-secondary': '#666666',
|
||||||
|
'border-color': '#d9d9d9'
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
'card': '0 2px 8px rgba(0, 0, 0, 0.1)',
|
||||||
|
'hover': '0 4px 12px rgba(0, 0, 0, 0.15)',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style type="text/tailwindcss">
|
||||||
|
@layer utilities {
|
||||||
|
.content-auto {
|
||||||
|
content-visibility: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition-height {
|
||||||
|
transition: max-height 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||||
|
background: #c1c1c1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #a8a8a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-in {
|
||||||
|
animation: fadeIn 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.slide-down {
|
||||||
|
animation: slideDown 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideDown {
|
||||||
|
from {
|
||||||
|
transform: translateY(-10px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pulse {
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-50 font-sans text-text-primary min-h-screen flex flex-col">
|
||||||
|
<!-- 页面容器 -->
|
||||||
|
<div class="flex-grow flex flex-col md:flex-row p-4 md:p-6 gap-6 h-[calc(100vh-5px)]">
|
||||||
|
<!-- 左侧文件夹导航 -->
|
||||||
|
<div class="w-full md:w-64 lg:w-72 bg-primary rounded-lg shadow-card flex flex-col overflow-hidden">
|
||||||
|
<!-- 文件夹搜索 -->
|
||||||
|
<div class="p-4 border-b border-border-color">
|
||||||
|
<div class="relative">
|
||||||
|
<input type="text" id="folderSearch" placeholder="搜索文件夹..."
|
||||||
|
class="w-full pl-10 pr-4 py-2 rounded-lg border border-border-color focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent">
|
||||||
|
<i class="fa fa-search absolute left-3 top-3 text-text-secondary"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文件夹列表 -->
|
||||||
|
<div class="flex-grow overflow-y-auto scrollbar-thin p-2">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<!-- 文件夹组1 -->
|
||||||
|
<div class="folder-group" th:each="folders : ${folderTrees}">
|
||||||
|
<div class="flex items-center justify-between p-2 rounded-md hover:bg-accent-hover cursor-pointer"
|
||||||
|
onclick="toggleFolderGroup(this)">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<i class="fa fa-folder-o mr-2 text-accent"></i>
|
||||||
|
<span th:text="${folders.getFolder().getFolderName()}"></span>
|
||||||
|
</div>
|
||||||
|
<i class="fa fa-chevron-right text-xs transition-transform duration-300"></i>
|
||||||
|
</div>
|
||||||
|
<div class="pl-6 mt-1 folder-content max-h-0 overflow-hidden transition-height"
|
||||||
|
th:each="childFolders : ${folders.getChildFolders()}">
|
||||||
|
<div class="space-y-1">
|
||||||
|
<div class="p-2 rounded-md hover:bg-accent-hover cursor-pointer folder-item">
|
||||||
|
<i class="fa fa-folder-o mr-2 text-accent"></i>
|
||||||
|
<span th:text="${childFolders.getFolderName()}"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 创建文件夹按钮 -->
|
||||||
|
<div class="p-4 border-t border-border-color">
|
||||||
|
<button id="createFolderBtn"
|
||||||
|
class="w-full flex items-center justify-center p-2 bg-accent text-white rounded-lg hover:bg-blue-600 transition-colors">
|
||||||
|
<i class="fa fa-plus mr-2"></i>
|
||||||
|
<span>创建文件夹</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧文件操作和展示区 -->
|
||||||
|
<div class="flex-grow flex flex-col bg-secondary rounded-lg shadow-card overflow-hidden">
|
||||||
|
<!-- 顶部搜索和上传区域 -->
|
||||||
|
<div class="p-4 border-b border-border-color flex flex-col sm:flex-row gap-4">
|
||||||
|
<!-- 文件搜索 -->
|
||||||
|
<div class="flex-grow relative">
|
||||||
|
<input type="text" id="fileSearch" placeholder="搜索文件..."
|
||||||
|
class="w-full pl-10 pr-4 py-2 rounded-lg border border-border-color focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent">
|
||||||
|
<i class="fa fa-search absolute left-3 top-3 text-text-secondary"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 上传文件按钮 -->
|
||||||
|
<button id="uploadFileBtn"
|
||||||
|
class="flex items-center justify-center px-4 py-2 bg-accent text-white rounded-lg hover:bg-blue-600 transition-colors">
|
||||||
|
<i class="fa fa-upload mr-2"></i>
|
||||||
|
<span>上传文件</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文件列表区域 -->
|
||||||
|
<div class="flex-grow overflow-y-auto scrollbar-thin p-4">
|
||||||
|
<div id="fileList" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||||
|
<!-- 文件项1 -->
|
||||||
|
<div class="bg-white rounded-lg shadow-card p-4 hover:shadow-hover transition-shadow"
|
||||||
|
th:each="file : ${files}">
|
||||||
|
<div class="flex items-center mb-3">
|
||||||
|
<img src="https://p3-doubao-search-sign.byteimg.com/labis/fc16ba2cc6e083aacff2c3629bd48364~tplv-be4g95zd3a-image.jpeg?rk3s=542c0f93&x-expires=1779099593&x-signature=ZOIIEOF4OonT%2B1U3qJMy0ggfOwM%3D"
|
||||||
|
alt="文档" class="file-icon mr-3">
|
||||||
|
<div class="flex-grow">
|
||||||
|
<h3 class="font-medium truncate" th:text="${file.getFileName()}"></h3>
|
||||||
|
<p class="text-xs text-text-secondary">2023-06-15 | 2.4MB</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<button class="text-accent hover:text-blue-700 transition-colors"
|
||||||
|
onclick="downloadFile('project-plan.docx')">
|
||||||
|
<i class="fa fa-download mr-1"></i> 下载
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态提示 -->
|
||||||
|
<div id="emptyState" class="hidden flex flex-col items-center justify-center py-10">
|
||||||
|
<div class="w-24 h-24 mb-4 opacity-50">
|
||||||
|
<i class="fa fa-folder-open-o text-6xl text-text-secondary"></i>
|
||||||
|
</div>
|
||||||
|
<p class="text-text-secondary text-lg">当前文件夹为空</p>
|
||||||
|
<p class="text-text-secondary text-sm mt-2">点击"上传文件"按钮添加文件</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 创建文件夹弹窗 -->
|
||||||
|
<div id="createFolderModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
|
||||||
|
<div class="bg-white rounded-lg shadow-lg w-full max-w-md p-6 fade-in">
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h3 class="text-lg font-medium">创建文件夹</h3>
|
||||||
|
<button onclick="closeCreateFolderModal()" class="text-text-secondary hover:text-text-primary">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<form id="createFolderForm" onsubmit="createFolder(event)">
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="folderName" class="block text-sm font-medium text-text-secondary mb-1">文件夹名称</label>
|
||||||
|
<input type="text" id="folderName" required
|
||||||
|
class="w-full px-3 py-2 border border-border-color rounded-md focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent">
|
||||||
|
</div>
|
||||||
|
<div class="mb-6">
|
||||||
|
<label for="folderParent" class="block text-sm font-medium text-text-secondary mb-1">父文件夹</label>
|
||||||
|
<select id="folderParent"
|
||||||
|
class="w-full px-3 py-2 border border-border-color rounded-md focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent">
|
||||||
|
<option value="">根目录</option>
|
||||||
|
<option value="project-docs">项目文档</option>
|
||||||
|
<option value="tech-docs">技术文档</option>
|
||||||
|
<option value="test-docs">测试文档</option>
|
||||||
|
<option value="meeting-notes">会议记录</option>
|
||||||
|
<option value="training-materials">培训资料</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<button type="button" onclick="closeCreateFolderModal()"
|
||||||
|
class="px-4 py-2 border border-border-color rounded-md mr-2 hover:bg-gray-50 transition-colors">
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
<button type="submit"
|
||||||
|
class="px-4 py-2 bg-accent text-white rounded-md hover:bg-blue-600 transition-colors">
|
||||||
|
创建
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 上传文件弹窗 -->
|
||||||
|
<div id="uploadFileModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
|
||||||
|
<div class="bg-white rounded-lg shadow-lg w-full max-w-4xl p-6 fade-in">
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h3 class="text-lg font-medium">上传文件</h3>
|
||||||
|
<button onclick="closeUploadFileModal()" class="text-text-secondary hover:text-text-primary">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 上传区域 -->
|
||||||
|
<div id="uploadArea"
|
||||||
|
class="border-2 border-dashed border-border-color rounded-lg p-8 mb-6 text-center hover:border-accent transition-colors cursor-pointer"
|
||||||
|
onclick="document.getElementById('fileInput').click()">
|
||||||
|
<div class="w-16 h-16 mx-auto mb-4 opacity-50">
|
||||||
|
<i class="fa fa-cloud-upload text-4xl text-text-secondary"></i>
|
||||||
|
</div>
|
||||||
|
<p class="text-text-secondary mb-2">拖拽文件到此处或点击上传</p>
|
||||||
|
<p class="text-text-secondary text-sm">支持批量上传,单个文件不超过100MB</p>
|
||||||
|
<input type="file" id="fileInput" multiple class="hidden" onchange="handleFiles(this.files)">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 上传文件夹选择 -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<label for="uploadFolder" class="block text-sm font-medium text-text-secondary mb-1">上传到文件夹</label>
|
||||||
|
<select id="uploadFolder"
|
||||||
|
class="w-full px-3 py-2 border border-border-color rounded-md focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent">
|
||||||
|
<option value="project-plan">项目计划</option>
|
||||||
|
<option value="requirements">需求文档</option>
|
||||||
|
<option value="design">设计文档</option>
|
||||||
|
<option value="architecture">架构文档</option>
|
||||||
|
<option value="api">API文档</option>
|
||||||
|
<option value="database">数据库文档</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 上传文件列表 -->
|
||||||
|
<div class="mb-6 max-h-64 overflow-y-auto scrollbar-thin">
|
||||||
|
<h4 class="text-sm font-medium text-text-secondary mb-2">待上传文件</h4>
|
||||||
|
<div id="uploadFileList" class="space-y-2">
|
||||||
|
<!-- 上传文件项将通过JavaScript动态添加 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<button type="button" onclick="closeUploadFileModal()"
|
||||||
|
class="px-4 py-2 border border-border-color rounded-md mr-2 hover:bg-gray-50 transition-colors">
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
<button id="startUploadBtn" type="button" onclick="startUpload()"
|
||||||
|
class="px-4 py-2 bg-accent text-white rounded-md hover:bg-blue-600 transition-colors">
|
||||||
|
开始上传
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 消息提示 -->
|
||||||
|
<div id="messageToast"
|
||||||
|
class="fixed bottom-4 right-4 px-4 py-3 rounded-lg shadow-lg bg-white transform translate-y-20 opacity-0 transition-all duration-300 z-50 flex items-center">
|
||||||
|
<i id="messageIcon" class="fa fa-check-circle text-green-500 mr-2"></i>
|
||||||
|
<span id="messageText">操作成功</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 全局变量
|
||||||
|
let currentFolder = null;
|
||||||
|
let uploadFiles = [];
|
||||||
|
|
||||||
|
// 页面加载完成后执行
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
// 绑定创建文件夹按钮事件
|
||||||
|
document.getElementById('createFolderBtn').addEventListener('click', openCreateFolderModal);
|
||||||
|
|
||||||
|
// 绑定上传文件按钮事件
|
||||||
|
document.getElementById('uploadFileBtn').addEventListener('click', openUploadFileModal);
|
||||||
|
|
||||||
|
// 绑定文件夹搜索事件
|
||||||
|
document.getElementById('folderSearch').addEventListener('input', searchFolders);
|
||||||
|
|
||||||
|
// 绑定文件搜索事件
|
||||||
|
document.getElementById('fileSearch').addEventListener('input', searchFiles);
|
||||||
|
|
||||||
|
// 绑定拖拽上传事件
|
||||||
|
const uploadArea = document.getElementById('uploadArea');
|
||||||
|
uploadArea.addEventListener('dragover', handleDragOver);
|
||||||
|
uploadArea.addEventListener('drop', handleDrop);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 文件夹组展开/折叠
|
||||||
|
function toggleFolderGroup(element) {
|
||||||
|
const content = element.nextElementSibling;
|
||||||
|
const icon = element.querySelector('.fa-chevron-right');
|
||||||
|
|
||||||
|
if (content.style.maxHeight) {
|
||||||
|
content.style.maxHeight = null;
|
||||||
|
icon.style.transform = 'rotate(0deg)';
|
||||||
|
} else {
|
||||||
|
content.style.maxHeight = content.scrollHeight + 'px';
|
||||||
|
icon.style.transform = 'rotate(90deg)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索文件夹
|
||||||
|
function searchFolders() {
|
||||||
|
const searchTerm = document.getElementById('folderSearch').value.toLowerCase();
|
||||||
|
const folderGroups = document.querySelectorAll('.folder-group');
|
||||||
|
|
||||||
|
folderGroups.forEach(group => {
|
||||||
|
const groupTitle = group.querySelector('.flex.items-center span').textContent.toLowerCase();
|
||||||
|
const folderItems = group.querySelectorAll('.folder-item');
|
||||||
|
let hasVisibleItem = false;
|
||||||
|
|
||||||
|
// 检查文件夹组标题是否匹配搜索词
|
||||||
|
if (groupTitle.includes(searchTerm)) {
|
||||||
|
group.style.display = 'block';
|
||||||
|
hasVisibleItem = true;
|
||||||
|
} else {
|
||||||
|
// 检查文件夹项是否匹配搜索词
|
||||||
|
folderItems.forEach(item => {
|
||||||
|
const itemTitle = item.querySelector('span').textContent.toLowerCase();
|
||||||
|
if (itemTitle.includes(searchTerm)) {
|
||||||
|
item.style.display = 'block';
|
||||||
|
hasVisibleItem = true;
|
||||||
|
} else {
|
||||||
|
item.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果有可见项则显示文件夹组,否则隐藏
|
||||||
|
group.style.display = hasVisibleItem ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索文件
|
||||||
|
function searchFiles() {
|
||||||
|
const searchTerm = document.getElementById('fileSearch').value.toLowerCase();
|
||||||
|
const fileItems = document.querySelectorAll('#fileList > div');
|
||||||
|
const emptyState = document.getElementById('emptyState');
|
||||||
|
let visibleCount = 0;
|
||||||
|
|
||||||
|
fileItems.forEach(item => {
|
||||||
|
const fileName = item.querySelector('h3').textContent.toLowerCase();
|
||||||
|
if (fileName.includes(searchTerm)) {
|
||||||
|
item.style.display = 'block';
|
||||||
|
visibleCount++;
|
||||||
|
} else {
|
||||||
|
item.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果没有可见文件,显示空状态
|
||||||
|
if (visibleCount === 0) {
|
||||||
|
emptyState.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
emptyState.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载文件
|
||||||
|
function downloadFile(fileName) {
|
||||||
|
showMessage(`正在准备下载 ${fileName}...`);
|
||||||
|
|
||||||
|
// 这里应该是实际的下载API调用
|
||||||
|
setTimeout(() => {
|
||||||
|
// 模拟下载完成
|
||||||
|
showMessage(`${fileName} 下载成功`);
|
||||||
|
|
||||||
|
// 实际项目中,这里应该调用后端API进行文件下载
|
||||||
|
// 例如:window.location.href = `/api/download/${fileName}`;
|
||||||
|
}, 800);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开创建文件夹弹窗
|
||||||
|
function openCreateFolderModal() {
|
||||||
|
document.getElementById('createFolderModal').classList.remove('hidden');
|
||||||
|
document.getElementById('folderName').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭创建文件夹弹窗
|
||||||
|
function closeCreateFolderModal() {
|
||||||
|
document.getElementById('createFolderModal').classList.add('hidden');
|
||||||
|
document.getElementById('createFolderForm').reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建文件夹
|
||||||
|
function createFolder(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const folderName = document.getElementById('folderName').value;
|
||||||
|
const folderParent = document.getElementById('folderParent').value;
|
||||||
|
|
||||||
|
if (!folderName) {
|
||||||
|
showMessage('请输入文件夹名称', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showMessage(`正在创建文件夹: ${folderName}...`);
|
||||||
|
|
||||||
|
// 这里应该是实际的API调用,现在使用模拟数据
|
||||||
|
setTimeout(() => {
|
||||||
|
// 模拟创建成功
|
||||||
|
closeCreateFolderModal();
|
||||||
|
showMessage(`文件夹 ${folderName} 创建成功`);
|
||||||
|
|
||||||
|
// 实际项目中,这里应该调用后端API创建文件夹
|
||||||
|
// 例如:
|
||||||
|
// fetch('/api/folders', {
|
||||||
|
// method: 'POST',
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/json',
|
||||||
|
// },
|
||||||
|
// body: JSON.stringify({
|
||||||
|
// name: folderName,
|
||||||
|
// parentId: folderParent
|
||||||
|
// }),
|
||||||
|
// })
|
||||||
|
// .then(response => response.json())
|
||||||
|
// .then(data => {
|
||||||
|
// closeCreateFolderModal();
|
||||||
|
// showMessage(`文件夹 ${folderName} 创建成功`);
|
||||||
|
// // 刷新文件夹列表
|
||||||
|
// })
|
||||||
|
// .catch(error => {
|
||||||
|
// showMessage('创建文件夹失败', 'error');
|
||||||
|
// });
|
||||||
|
}, 800);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开上传文件弹窗
|
||||||
|
function openUploadFileModal() {
|
||||||
|
document.getElementById('uploadFileModal').classList.remove('hidden');
|
||||||
|
document.getElementById('uploadFileList').innerHTML = '';
|
||||||
|
uploadFiles = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭上传文件弹窗
|
||||||
|
function closeUploadFileModal() {
|
||||||
|
document.getElementById('uploadFileModal').classList.add('hidden');
|
||||||
|
document.getElementById('fileInput').value = '';
|
||||||
|
uploadFiles = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理拖拽文件
|
||||||
|
function handleDragOver(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
document.getElementById('uploadArea').classList.add('border-accent');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理文件放置
|
||||||
|
function handleDrop(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
document.getElementById('uploadArea').classList.remove('border-accent');
|
||||||
|
|
||||||
|
if (event.dataTransfer.files.length > 0) {
|
||||||
|
handleFiles(event.dataTransfer.files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理选择的文件
|
||||||
|
function handleFiles(files) {
|
||||||
|
if (files.length === 0) return;
|
||||||
|
|
||||||
|
// 添加文件到上传列表
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
const file = files[i];
|
||||||
|
|
||||||
|
// 检查文件是否已在上传列表中
|
||||||
|
const isDuplicate = uploadFiles.some(f => f.name === file.name && f.size === file.size);
|
||||||
|
if (isDuplicate) continue;
|
||||||
|
|
||||||
|
// 添加文件到上传列表
|
||||||
|
uploadFiles.push(file);
|
||||||
|
|
||||||
|
// 创建文件项
|
||||||
|
const fileItem = document.createElement('div');
|
||||||
|
fileItem.className = 'flex items-center justify-between p-2 border border-border-color rounded-md';
|
||||||
|
fileItem.innerHTML = `
|
||||||
|
<div class="flex items-center">
|
||||||
|
<i class="fa fa-file-o mr-2 text-accent"></i>
|
||||||
|
<div class="flex-grow">
|
||||||
|
<p class="text-sm truncate">${file.name}</p>
|
||||||
|
<p class="text-xs text-text-secondary">${formatFileSize(file.size)}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="upload-progress w-32 h-2 bg-gray-200 rounded-full mr-2 hidden">
|
||||||
|
<div class="upload-progress-bar h-full bg-accent rounded-full" style="width: 0%"></div>
|
||||||
|
</div>
|
||||||
|
<button class="text-text-secondary hover:text-red-500 transition-colors" onclick="removeUploadFile(this, ${i})">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
document.getElementById('uploadFileList').appendChild(fileItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除上传文件
|
||||||
|
function removeUploadFile(element, index) {
|
||||||
|
// 移除文件项
|
||||||
|
element.closest('div.flex.items-center.justify-between').remove();
|
||||||
|
|
||||||
|
// 从上传列表中移除文件
|
||||||
|
uploadFiles.splice(index, 1);
|
||||||
|
|
||||||
|
// 更新剩余文件的索引
|
||||||
|
const fileItems = document.querySelectorAll('#uploadFileList button');
|
||||||
|
fileItems.forEach((item, newIndex) => {
|
||||||
|
item.setAttribute('onclick', `removeUploadFile(this, ${newIndex})`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始上传
|
||||||
|
function startUpload() {
|
||||||
|
if (uploadFiles.length === 0) {
|
||||||
|
showMessage('请先选择要上传的文件', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadFolder = document.getElementById('uploadFolder').value;
|
||||||
|
showMessage(`正在上传 ${uploadFiles.length} 个文件...`);
|
||||||
|
|
||||||
|
// 禁用上传按钮
|
||||||
|
const uploadBtn = document.getElementById('startUploadBtn');
|
||||||
|
uploadBtn.disabled = true;
|
||||||
|
uploadBtn.innerHTML = '<i class="fa fa-spinner fa-spin mr-2"></i> 上传中...';
|
||||||
|
|
||||||
|
// 显示进度条
|
||||||
|
const progressBars = document.querySelectorAll('.upload-progress');
|
||||||
|
progressBars.forEach(bar => {
|
||||||
|
bar.classList.remove('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 模拟上传进度
|
||||||
|
let completedFiles = 0;
|
||||||
|
uploadFiles.forEach((file, index) => {
|
||||||
|
simulateUploadProgress(index, file, () => {
|
||||||
|
completedFiles++;
|
||||||
|
|
||||||
|
// 检查是否所有文件都上传完成
|
||||||
|
if (completedFiles === uploadFiles.length) {
|
||||||
|
setTimeout(() => {
|
||||||
|
// 启用上传按钮
|
||||||
|
uploadBtn.disabled = false;
|
||||||
|
uploadBtn.innerHTML = '开始上传';
|
||||||
|
|
||||||
|
// 清空上传列表
|
||||||
|
document.getElementById('uploadFileList').innerHTML = '';
|
||||||
|
uploadFiles = [];
|
||||||
|
|
||||||
|
// 关闭上传弹窗
|
||||||
|
closeUploadFileModal();
|
||||||
|
|
||||||
|
// 显示成功消息
|
||||||
|
showMessage(`${completedFiles} 个文件上传成功`);
|
||||||
|
|
||||||
|
// 刷新当前文件夹的文件列表
|
||||||
|
if (currentFolder) {
|
||||||
|
loadFiles(currentFolder);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 实际项目中,这里应该调用后端API上传文件
|
||||||
|
// 例如:
|
||||||
|
// const formData = new FormData();
|
||||||
|
// uploadFiles.forEach(file => {
|
||||||
|
// formData.append('files', file);
|
||||||
|
// });
|
||||||
|
// formData.append('folderId', uploadFolder);
|
||||||
|
//
|
||||||
|
// fetch('/api/upload', {
|
||||||
|
// method: 'POST',
|
||||||
|
// body: formData,
|
||||||
|
// })
|
||||||
|
// .then(response => response.json())
|
||||||
|
// .then(data => {
|
||||||
|
// // 处理上传成功
|
||||||
|
// })
|
||||||
|
// .catch(error => {
|
||||||
|
// // 处理上传失败
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟上传进度
|
||||||
|
function simulateUploadProgress(index, file, callback) {
|
||||||
|
const progressBar = document.querySelectorAll('.upload-progress-bar')[index];
|
||||||
|
let progress = 0;
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
progress += Math.random() * 20;
|
||||||
|
if (progress >= 100) {
|
||||||
|
progress = 100;
|
||||||
|
clearInterval(interval);
|
||||||
|
setTimeout(callback, 500);
|
||||||
|
}
|
||||||
|
progressBar.style.width = `${progress}%`;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化文件大小
|
||||||
|
function formatFileSize(bytes) {
|
||||||
|
if (bytes < 1024) return bytes + ' B';
|
||||||
|
else if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
|
||||||
|
else return (bytes / 1048576).toFixed(1) + ' MB';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示消息提示
|
||||||
|
function showMessage(message, type = 'success') {
|
||||||
|
const toast = document.getElementById('messageToast');
|
||||||
|
const icon = document.getElementById('messageIcon');
|
||||||
|
const text = document.getElementById('messageText');
|
||||||
|
|
||||||
|
// 设置消息内容和类型
|
||||||
|
text.textContent = message;
|
||||||
|
|
||||||
|
if (type === 'success') {
|
||||||
|
icon.className = 'fa fa-check-circle text-green-500 mr-2';
|
||||||
|
} else if (type === 'error') {
|
||||||
|
icon.className = 'fa fa-exclamation-circle text-red-500 mr-2';
|
||||||
|
} else if (type === 'warning') {
|
||||||
|
icon.className = 'fa fa-exclamation-triangle text-yellow-500 mr-2';
|
||||||
|
} else if (type === 'info') {
|
||||||
|
icon.className = 'fa fa-info-circle text-blue-500 mr-2';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示消息提示
|
||||||
|
toast.classList.remove('translate-y-20', 'opacity-0');
|
||||||
|
|
||||||
|
// 3秒后自动关闭
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.classList.add('translate-y-20', 'opacity-0');
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后端API接口方法(与Spring Boot联调)
|
||||||
|
const api = {
|
||||||
|
// 获取文件夹列表
|
||||||
|
getFolders: function () {
|
||||||
|
// 实际项目中,这里应该调用后端API获取文件夹列表
|
||||||
|
// return fetch('/api/folders')
|
||||||
|
// .then(response => response.json())
|
||||||
|
// .catch(error => {
|
||||||
|
// showMessage('获取文件夹列表失败', 'error');
|
||||||
|
// console.error(error);
|
||||||
|
// return [];
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取文件列表
|
||||||
|
getFiles: function (folderId) {
|
||||||
|
// 实际项目中,这里应该调用后端API获取文件列表
|
||||||
|
// return fetch(`/api/folders/${folderId}/files`)
|
||||||
|
// .then(response => response.json())
|
||||||
|
// .catch(error => {
|
||||||
|
// showMessage('获取文件列表失败', 'error');
|
||||||
|
// console.error(error);
|
||||||
|
// return [];
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
|
||||||
|
// 创建文件夹
|
||||||
|
createFolder: function (name, parentId) {
|
||||||
|
// 实际项目中,这里应该调用后端API创建文件夹
|
||||||
|
// return fetch('/api/folders', {
|
||||||
|
// method: 'POST',
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/json',
|
||||||
|
// },
|
||||||
|
// body: JSON.stringify({
|
||||||
|
// name: name,
|
||||||
|
// parentId: parentId
|
||||||
|
// }),
|
||||||
|
// })
|
||||||
|
// .then(response => response.json())
|
||||||
|
// .catch(error => {
|
||||||
|
// showMessage('创建文件夹失败', 'error');
|
||||||
|
// console.error(error);
|
||||||
|
// throw error;
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传文件
|
||||||
|
uploadFiles: function (files, folderId) {
|
||||||
|
// 实际项目中,这里应该调用后端API上传文件
|
||||||
|
// const formData = new FormData();
|
||||||
|
// files.forEach(file => {
|
||||||
|
// formData.append('files', file);
|
||||||
|
// });
|
||||||
|
// formData.append('folderId', folderId);
|
||||||
|
//
|
||||||
|
// return fetch('/api/upload', {
|
||||||
|
// method: 'POST',
|
||||||
|
// body: formData,
|
||||||
|
// })
|
||||||
|
// .then(response => response.json())
|
||||||
|
// .catch(error => {
|
||||||
|
// showMessage('上传文件失败', 'error');
|
||||||
|
// console.error(error);
|
||||||
|
// throw error;
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
|
||||||
|
// 下载文件
|
||||||
|
downloadFile: function (fileId) {
|
||||||
|
// 实际项目中,这里应该调用后端API下载文件
|
||||||
|
// window.location.href = `/api/files/${fileId}/download`;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除文件
|
||||||
|
deleteFile: function (fileId) {
|
||||||
|
// 实际项目中,这里应该调用后端API删除文件
|
||||||
|
// return fetch(`/api/files/${fileId}`, {
|
||||||
|
// method: 'DELETE',
|
||||||
|
// })
|
||||||
|
// .then(response => {
|
||||||
|
// if (!response.ok) {
|
||||||
|
// throw new Error('删除文件失败');
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// .catch(error => {
|
||||||
|
// showMessage('删除文件失败', 'error');
|
||||||
|
// console.error(error);
|
||||||
|
// throw error;
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user