更新数据同步
This commit is contained in:
@@ -1,511 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>文档中心</title>
|
||||
<script th:src="@{/css/tailwindcss.css}"></script>
|
||||
<link rel="stylesheet" th:href="@{/font-awesome/css/font-awesome.min.css}">
|
||||
|
||||
<!-- 配置Tailwind自定义颜色 -->
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: '#3B82F6',
|
||||
secondary: '#DBEAFE',
|
||||
neutral: '#F3F4F6',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style type="text/tailwindcss">
|
||||
@layer utilities {
|
||||
.content-auto {
|
||||
content-visibility: auto;
|
||||
}
|
||||
|
||||
.scrollbar-thin {
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.scrollbar-thin::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(156, 163, 175, 0.5);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.fade-out {
|
||||
animation: fadeOut 3s forwards;
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
70% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-100 min-h-screen flex flex-col">
|
||||
<!-- 主容器 -->
|
||||
<div class="flex-1 p-4 pb-[10px]">
|
||||
<div class="flex h-full gap-4">
|
||||
<!-- 左侧文件夹区域 -->
|
||||
<div class="w-1/4 bg-white rounded-lg shadow-md overflow-hidden flex flex-col h-[calc(100vh-2.5rem)]">
|
||||
<!-- 文件夹搜索 -->
|
||||
<div class="p-4 bg-secondary">
|
||||
<div class="relative">
|
||||
<input type="text" id="folderSearch" placeholder="搜索文件夹..."
|
||||
class="w-full pl-10 pr-4 py-2 rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50">
|
||||
<i class="fa fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文件夹列表 -->
|
||||
<div class="flex-1 overflow-y-auto scrollbar-thin p-2">
|
||||
<!-- 文件夹分组1 -->
|
||||
<div class="mb-2" th:each=" folders : ${folderTrees}">
|
||||
<div class="folder-group-header bg-secondary/70 rounded-md p-2 cursor-pointer flex items-center justify-between"
|
||||
th:onclick="toggleFolderGroup('project')">
|
||||
<span class="font-medium" th:text="${folders.getFolder().getFolderName()}"></span>
|
||||
<i id="project-icon" class="fa fa-chevron-right text-sm transition-transform duration-300"></i>
|
||||
</div>
|
||||
<div id="project" class="folder-group hidden pl-4 mt-1 space-y-1"
|
||||
th:each="childFolder : ${folders.getChildFolders()}">
|
||||
<div class="folder-item p-2 rounded hover:bg-gray-100 cursor-pointer flex items-center"
|
||||
th:onclick="showFilesInFolder([[${childFolder.getFolderId()}]])">
|
||||
<i class="fa fa-folder text-yellow-500 mr-2"></i>
|
||||
<span th:text="${childFolder.getFolderName()}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 创建文件夹按钮 -->
|
||||
<div class="p-4 border-t border-gray-200">
|
||||
<button id="createFolderBtn"
|
||||
class="w-full bg-primary text-white py-2 rounded-md hover:bg-primary/90 flex items-center justify-center transition-colors"
|
||||
onclick="openCreateFolderModal()">
|
||||
<i class="fa fa-plus mr-2"></i> 创建文件夹
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧文件区域 -->
|
||||
<div class="w-3/4 bg-gradient-to-br from-blue-50 to-indigo-50 rounded-lg shadow-md overflow-hidden flex flex-col h-[calc(100vh-2.5rem)]">
|
||||
<!-- 文件操作栏 -->
|
||||
<div class="p-4 bg-secondary/80 flex flex-col sm:flex-row gap-3">
|
||||
<!-- 文件搜索 -->
|
||||
<div class="relative flex-1">
|
||||
<input type="text" id="fileSearch" placeholder="搜索文件..."
|
||||
class="w-full pl-10 pr-4 py-2 rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50">
|
||||
<i class="fa fa-search absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
|
||||
</div>
|
||||
|
||||
<!-- 上传按钮 -->
|
||||
<button id="uploadBtn"
|
||||
class="bg-primary text-white py-2 px-4 rounded-md hover:bg-primary/90 flex items-center transition-colors"
|
||||
onclick="openUploadModal()">
|
||||
<i class="fa fa-upload mr-2"></i> 上传文件
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 文件列表 -->
|
||||
<div class="flex-1 overflow-y-auto scrollbar-thin p-4">
|
||||
<div id="allFiles" class="file-list">
|
||||
<!-- 需求文档 -->
|
||||
<div class="file-item bg-white rounded-lg p-3 mb-3 shadow-sm hover:shadow-md transition-shadow flex items-center justify-between"
|
||||
th:each="file: ${files}" th:data-folder="${file.getFolderId()}">
|
||||
<div class="flex items-center">
|
||||
<div class="w-10 h-10 bg-red-100 rounded flex items-center justify-center mr-3">
|
||||
<i class="fa fa-file-word-o text-red-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-medium" th:text="${file.getFileName()}"></div>
|
||||
<div class="text-sm text-gray-500"><span th:text="${file.getFileSize()}"></span> <span
|
||||
th:text="${file.getFilePath()}"></span> <span
|
||||
th:text="${file.getUploadTime()}"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="text-primary hover:text-primary/80 transition-colors"
|
||||
th:onclick="downloadFile([[${file.getFileId()}]])">
|
||||
<i class="fa fa-download"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 创建文件夹弹窗 -->
|
||||
<div id="createFolderModal" class="fixed inset-0 bg-black/50 flex items-center justify-center hidden z-50">
|
||||
<div class="bg-white rounded-lg shadow-lg w-full max-w-md p-6">
|
||||
<h3 class="text-lg font-semibold mb-4">创建新文件夹</h3>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">文件夹名称</label>
|
||||
<input type="text" id="folderName"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary/50">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">所属分组</label>
|
||||
<select id="folderGroup"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary/50">
|
||||
<option th:each="folder :${folderTrees}" th:value="${folder.getFolder().getFolderId()}"
|
||||
th:text="${folder.getFolder().getFolderName()}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex justify-end gap-3 pt-2">
|
||||
<button onclick="closeCreateFolderModal()"
|
||||
class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">取消
|
||||
</button>
|
||||
<button onclick="createFolder()"
|
||||
class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors">创建
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 上传文件弹窗 -->
|
||||
<div id="uploadModal" class="fixed inset-0 bg-black/50 flex items-center justify-center hidden z-50">
|
||||
<div class="bg-white rounded-lg shadow-lg w-full max-w-2xl p-6">
|
||||
<h3 class="text-lg font-semibold mb-4">上传文件</h3>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">选择文件夹</label>
|
||||
<select id="uploadFolder"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary/50">
|
||||
<option th:each="folder :${folderTrees}" th:value="${folder.getFolder().getFolderId()}"
|
||||
th:text="${folder.getFolder().getFolderName()}"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="dropArea"
|
||||
class="border-2 border-dashed border-gray-300 rounded-md p-8 text-center hover:border-primary transition-colors cursor-pointer">
|
||||
<i class="fa fa-cloud-upload text-4xl text-gray-400 mb-2"></i>
|
||||
<p class="text-gray-500">拖拽文件到此处或 <span class="text-primary">点击上传</span></p>
|
||||
<input type="file" id="fileInput" class="hidden" multiple>
|
||||
</div>
|
||||
|
||||
<!-- 上传进度 -->
|
||||
<div id="uploadProgress" class="hidden">
|
||||
<div class="text-sm font-medium mb-1">上传中...</div>
|
||||
<div class="w-full bg-gray-200 rounded-full h-2.5">
|
||||
<div id="progressBar" class="bg-primary h-2.5 rounded-full" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 上传文件列表 -->
|
||||
<div id="uploadFilesList" class="hidden">
|
||||
<div class="text-sm font-medium mb-2">上传文件列表:</div>
|
||||
<div id="uploadFiles" class="space-y-1 max-h-32 overflow-y-auto scrollbar-thin"></div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-3 pt-2">
|
||||
<button onclick="closeUploadModal()"
|
||||
class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">取消
|
||||
</button>
|
||||
<button onclick="startUpload()"
|
||||
class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors">开始上传
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 消息提示 -->
|
||||
<div id="messageAlert"
|
||||
class="fixed bottom-4 right-4 bg-gray-800 text-white px-4 py-3 rounded-md shadow-lg opacity-0 pointer-events-none transition-opacity z-50"></div>
|
||||
|
||||
<script>
|
||||
// 文件夹分组展开/折叠
|
||||
function toggleFolderGroup(groupId) {
|
||||
const group = document.getElementById(groupId);
|
||||
const icon = document.getElementById(`${groupId}-icon`);
|
||||
|
||||
// 关闭其他所有分组
|
||||
document.querySelectorAll('.folder-group').forEach(item => {
|
||||
if (item.id !== groupId) {
|
||||
item.classList.add('hidden');
|
||||
document.getElementById(`${item.id}-icon`).classList.remove('rotate-90');
|
||||
document.getElementById(`${item.id}-icon`).classList.add('fa-chevron-right');
|
||||
}
|
||||
});
|
||||
|
||||
// 切换当前分组
|
||||
group.classList.toggle('hidden');
|
||||
if (!group.classList.contains('hidden')) {
|
||||
icon.classList.remove('fa-chevron-right');
|
||||
icon.classList.add('fa-chevron-down', 'rotate-90');
|
||||
} else {
|
||||
icon.classList.remove('fa-chevron-down', 'rotate-90');
|
||||
icon.classList.add('fa-chevron-right');
|
||||
}
|
||||
}
|
||||
|
||||
// 显示文件夹下的文件
|
||||
function showFilesInFolder(folderId) {
|
||||
const fileItems = document.querySelectorAll('.file-item');
|
||||
|
||||
fileItems.forEach(item => {
|
||||
if (item.dataset.folder === folderId || folderId === 'all') {
|
||||
item.classList.remove('hidden');
|
||||
} else {
|
||||
item.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
showMessage(`已切换到文件夹: ${folderId}`);
|
||||
}
|
||||
|
||||
// 文件夹搜索
|
||||
document.getElementById('folderSearch').addEventListener('input', function (e) {
|
||||
const searchTerm = e.target.value.toLowerCase();
|
||||
const folderItems = document.querySelectorAll('.folder-item');
|
||||
|
||||
folderItems.forEach(item => {
|
||||
const folderName = item.textContent.toLowerCase();
|
||||
if (folderName.includes(searchTerm)) {
|
||||
item.classList.remove('hidden');
|
||||
} else {
|
||||
item.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 文件搜索
|
||||
document.getElementById('fileSearch').addEventListener('input', function (e) {
|
||||
const searchTerm = e.target.value.toLowerCase();
|
||||
const fileItems = document.querySelectorAll('.file-item');
|
||||
|
||||
fileItems.forEach(item => {
|
||||
const fileName = item.querySelector('.font-medium').textContent.toLowerCase();
|
||||
if (fileName.includes(searchTerm)) {
|
||||
item.classList.remove('hidden');
|
||||
} else {
|
||||
item.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 创建文件夹弹窗
|
||||
function openCreateFolderModal() {
|
||||
document.getElementById('createFolderModal').classList.remove('hidden');
|
||||
}
|
||||
|
||||
function closeCreateFolderModal() {
|
||||
document.getElementById('createFolderModal').classList.add('hidden');
|
||||
document.getElementById('folderName').value = '';
|
||||
}
|
||||
|
||||
// 上传文件弹窗
|
||||
function openUploadModal() {
|
||||
document.getElementById('uploadModal').classList.remove('hidden');
|
||||
document.getElementById('fileInput').value = '';
|
||||
document.getElementById('uploadFilesList').classList.add('hidden');
|
||||
document.getElementById('uploadFiles').innerHTML = '';
|
||||
document.getElementById('uploadProgress').classList.add('hidden');
|
||||
document.getElementById('progressBar').style.width = '0%';
|
||||
}
|
||||
|
||||
function closeUploadModal() {
|
||||
document.getElementById('uploadModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
// 拖拽上传
|
||||
const dropArea = document.getElementById('dropArea');
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
|
||||
dropArea.addEventListener('click', () => fileInput.click());
|
||||
|
||||
fileInput.addEventListener('change', handleFiles);
|
||||
|
||||
dropArea.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
dropArea.classList.add('border-primary');
|
||||
});
|
||||
|
||||
dropArea.addEventListener('dragleave', () => {
|
||||
dropArea.classList.remove('border-primary');
|
||||
});
|
||||
|
||||
dropArea.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
dropArea.classList.remove('border-primary');
|
||||
handleFiles(e);
|
||||
});
|
||||
|
||||
function handleFiles(e) {
|
||||
const files = e.target.files || e.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
const uploadFilesList = document.getElementById('uploadFiles');
|
||||
uploadFilesList.innerHTML = '';
|
||||
|
||||
Array.from(files).forEach(file => {
|
||||
const fileItem = document.createElement('div');
|
||||
fileItem.className = 'flex items-center justify-between p-2 bg-gray-50 rounded';
|
||||
fileItem.innerHTML = `
|
||||
<div class="flex items-center">
|
||||
<i class="fa fa-file-o mr-2 text-gray-500"></i>
|
||||
<span class="text-sm truncate max-w-[200px]">${file.name}</span>
|
||||
</div>
|
||||
<span class="text-xs text-gray-500">${formatFileSize(file.size)}</span>
|
||||
`;
|
||||
uploadFilesList.appendChild(fileItem);
|
||||
});
|
||||
|
||||
document.getElementById('uploadFilesList').classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
// 消息提示
|
||||
function showMessage(message) {
|
||||
const alert = document.getElementById('messageAlert');
|
||||
alert.textContent = message;
|
||||
alert.classList.remove('opacity-0', 'pointer-events-none');
|
||||
alert.classList.add('opacity-100', 'pointer-events-auto');
|
||||
|
||||
setTimeout(() => {
|
||||
alert.classList.remove('opacity-100', 'pointer-events-auto');
|
||||
alert.classList.add('opacity-0', 'pointer-events-none');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 与Spring Boot后端交互的方法
|
||||
|
||||
// 创建文件夹
|
||||
function createFolder() {
|
||||
const folderName = document.getElementById('folderName').value.trim();
|
||||
const folderGroup = document.getElementById('folderGroup').value;
|
||||
|
||||
if (!folderName) {
|
||||
showMessage('请输入文件夹名称');
|
||||
return;
|
||||
}
|
||||
|
||||
// 模拟后端请求
|
||||
setTimeout(() => {
|
||||
// 实际项目中替换为真实的API调用
|
||||
/*
|
||||
fetch('/api/folders', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: folderName,
|
||||
groupId: folderGroup
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showMessage('文件夹创建成功');
|
||||
closeCreateFolderModal();
|
||||
// 刷新文件夹列表
|
||||
} else {
|
||||
showMessage('创建失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showMessage('创建失败: 网络错误');
|
||||
});
|
||||
*/
|
||||
|
||||
showMessage(`文件夹 "${folderName}" 创建成功`);
|
||||
closeCreateFolderModal();
|
||||
}, 800);
|
||||
}
|
||||
|
||||
// 开始上传
|
||||
function startUpload() {
|
||||
const files = fileInput.files;
|
||||
if (files.length === 0) {
|
||||
showMessage('请选择要上传的文件');
|
||||
return;
|
||||
}
|
||||
|
||||
const folderId = document.getElementById('uploadFolder').value;
|
||||
|
||||
// 模拟上传进度
|
||||
document.getElementById('uploadProgress').classList.remove('hidden');
|
||||
let progress = 0;
|
||||
const progressBar = document.getElementById('progressBar');
|
||||
|
||||
const interval = setInterval(() => {
|
||||
progress += 5;
|
||||
progressBar.style.width = `${progress}%`;
|
||||
|
||||
if (progress >= 100) {
|
||||
clearInterval(interval);
|
||||
setTimeout(() => {
|
||||
showMessage('文件上传成功');
|
||||
closeUploadModal();
|
||||
}, 500);
|
||||
}
|
||||
}, 200);
|
||||
|
||||
// 实际项目中替换为真实的文件上传
|
||||
/*
|
||||
const formData = new FormData();
|
||||
Array.from(files).forEach(file => {
|
||||
formData.append('files', file);
|
||||
});
|
||||
formData.append('folderId', folderId);
|
||||
|
||||
fetch('/api/files/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showMessage('文件上传成功');
|
||||
closeUploadModal();
|
||||
// 刷新文件列表
|
||||
} else {
|
||||
showMessage('上传失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showMessage('上传失败: 网络错误');
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
// 下载文件
|
||||
function downloadFile(fileId) {
|
||||
// 实际项目中替换为真实的下载链接
|
||||
/*
|
||||
window.location.href = `/api/files/download/${fileId}`;
|
||||
*/
|
||||
|
||||
showMessage('文件下载中...');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user