<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>个人云端小U盘</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; color: #333; }
h1 { border-bottom: 2px solid #eee; padding-bottom: 10px; }
.card { background: #f9f9f9; border: 1px solid #ddd; border-radius: 8px; padding: 20px; margin-bottom: 20px; }
/* 拖拽上传区样式 */
#drop-zone { border: 2px dashed #999; border-radius: 8px; padding: 40px 20px; text-align: center; color: #666; cursor: pointer; transition: background 0.3s; }
#drop-zone.dragover { background: #e3f2fd; border-color: #2196f3; color: #2196f3; }
textarea { width: 100%; height: 120px; margin-bottom: 10px; padding: 10px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px; resize: vertical; }
button { padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
button:hover { background: #0056b3; }
/* 文件列表样式 */
ul { list-style: none; padding: 0; }
li { padding: 10px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; }
li:last-child { border-bottom: none; }
a { color: #007bff; text-decoration: none; word-break: break-all; margin-right: 15px;}
a:hover { text-decoration: underline; }
.status { margin-top: 10px; font-size: 0.9em; color: #28a745; }
</style>
</head>
<body>
<h1>个人云端小U盘</h1>
<!-- 1. 文件上传区 -->
<div class="card">
<h3>文件上传</h3>
<div id="drop-zone">拖拽任意文件到此处,或点击选择文件</div>
<input type="file" id="file-input" style="display: none;" multiple>
<div id="upload-status" class="status"></div>
</div>
<!-- 2. 文本保存区 -->
<div class="card">
<h3>保存文本片段</h3>
<textarea id="text-input" placeholder="在这里输入需要保存的文字..."></textarea>
<button onclick="saveText()">保存为 TXT</button>
<div id="text-status" class="status"></div>
</div>
<!-- 3. 文件列表展示 -->
<div class="card">
<h3 style="display: flex; justify-content: space-between; align-items: center;">
文件列表
<button onclick="loadFiles()" style="font-size: 0.8em; padding: 5px 10px;">刷新</button>
</h3>
<ul id="file-list"></ul>
</div>
<script>
const dropZone = document.getElementById('drop-zone');
const fileInput = document.getElementById('file-input');
// 初始化加载文件列表
window.onload = loadFiles;
// 点击触发文件选择
dropZone.addEventListener('click', () => fileInput.click());
// 处理文件选择
fileInput.addEventListener('change', (e) => handleFiles(e.target.files));
// 处理拖拽事件
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('dragover');
});
dropZone.addEventListener('dragleave', (e) => {
e.preventDefault();
dropZone.classList.remove('dragover');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('dragover');
handleFiles(e.dataTransfer.files);
});
// 核心上传逻辑
async function handleFiles(files) {
if (files.length === 0) return;
const statusDiv = document.getElementById('upload-status');
for (let i = 0; i < files.length; i++) {
const formData = new FormData();
formData.append('file', files[i]);
statusDiv.innerText = `正在上传: ${files[i].name}...`;
try {
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
if (response.ok) {
statusDiv.innerText = `上传成功: ${files[i].name}`;
} else {
statusDiv.innerText = `上传失败: ${files[i].name}`;
}
} catch (error) {
statusDiv.innerText = `网络错误`;
}
}
// 上传完成后刷新列表并清空 file input
fileInput.value = '';
setTimeout(() => { statusDiv.innerText = ''; }, 3000);
loadFiles();
}
// 保存文本逻辑
async function saveText() {
const text = document.getElementById('text-input').value;
const statusDiv = document.getElementById('text-status');
if (!text.trim()) {
statusDiv.innerText = '文本为空!';
return;
}
statusDiv.innerText = '正在保存...';
try {
const response = await fetch('/api/save_text', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: text })
});
if (response.ok) {
statusDiv.innerText = '保存成功!';
document.getElementById('text-input').value = '';
loadFiles(); // 刷新列表
} else {
statusDiv.innerText = '保存失败!';
}
} catch (error) {
statusDiv.innerText = '网络错误';
}
setTimeout(() => { statusDiv.innerText = ''; }, 3000);
}
// 获取并渲染文件列表
async function loadFiles() {
const list = document.getElementById('file-list');
list.innerHTML = '<li>加载中...</li>';
try {
const response = await fetch('/api/files');
const data = await response.json();
list.innerHTML = '';
if (data.files.length === 0) {
list.innerHTML = '<li>暂无文件</li>';
return;
}
data.files.forEach(file => {
const li = document.createElement('li');
// 链接指向 FastAPI 挂载的 /download 目录
li.innerHTML = `
<a href="/download/${encodeURIComponent(file)}" target="_blank">${file}</a>
`;
list.appendChild(li);
});
} catch (error) {
list.innerHTML = '<li>无法加载文件列表</li>';
}
}
</script>
</body>
</html>