更新数据同步

This commit is contained in:
2025-11-19 18:22:32 +08:00
parent f6702ddf98
commit 0839e19a3e

View File

@@ -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>