Files
pengxiao a3eb5c7b2d init: TEALab 2025 实验室网站项目
从百度网盘 /apps/bypy/dofile/ 下载的完整项目结构,包含:
- dofile/: Flask 后端(端口 5000)+ 静态前端(端口 6002)
- officefile/: 项目相关文档
- .gitignore: Python venv / 日志 / 缓存

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 01:07:19 +08:00

391 lines
14 KiB
JavaScript

// Admin Panel JavaScript
let currentArticles = [];
let currentResources = [];
let currentTeamMembers = [];
// 检查管理员权限
async function checkAdminAccess() {
try {
const response = await window.DAELAPI.auth.checkAuth();
if (!response.authenticated || !response.user.is_admin) {
alert('需要管理员权限才能访问此页面');
window.location.href = 'website.html';
return false;
}
document.getElementById('admin-user').textContent = `管理员: ${response.user.username}`;
return true;
} catch (error) {
alert('无法验证权限,请先登录');
window.location.href = 'login.html';
return false;
}
}
// Tab切换
document.querySelectorAll('.admin-tab').forEach(tab => {
tab.addEventListener('click', () => {
const tabName = tab.dataset.tab;
// 更新tab样式
document.querySelectorAll('.admin-tab').forEach(t => {
t.classList.remove('active', 'border-black', 'text-black');
t.classList.add('text-gray-500');
});
tab.classList.add('active', 'border-black', 'text-black');
tab.classList.remove('text-gray-500');
// 更新内容
document.querySelectorAll('.admin-tab-content').forEach(content => {
content.classList.add('hidden');
});
document.getElementById(`tab-${tabName}`).classList.remove('hidden');
// 加载对应内容
if (tabName === 'articles') loadArticles();
else if (tabName === 'resources') loadResources();
else if (tabName === 'team') loadTeamMembers();
});
});
// 加载文章列表
async function loadArticles() {
try {
const response = await window.DAELAPI.content.getArticles('news', false);
currentArticles = response.articles;
displayArticles(currentArticles);
} catch (error) {
console.error('Failed to load articles:', error);
document.getElementById('articles-list').innerHTML = '<p class="text-red-600">加载失败</p>';
}
}
// 显示文章列表
function displayArticles(articles) {
const container = document.getElementById('articles-list');
if (articles.length === 0) {
container.innerHTML = '<p class="text-gray-500">暂无文章</p>';
return;
}
container.innerHTML = articles.map(article => `
<div class="bg-white border border-gray-200 p-6 rounded">
<div class="flex justify-between items-start">
<div class="flex-1">
<h3 class="text-lg font-bold mb-2">${article.title}</h3>
<p class="text-sm text-gray-500 mb-2">${article.summary || article.content.substring(0, 100)}...</p>
<div class="flex gap-4 text-xs text-gray-400">
<span>分类: ${article.category}</span>
<span>${article.is_protected ? '🔒 受保护' : '公开'}</span>
<span>${article.published ? '已发布' : '草稿'}</span>
<span>${new Date(article.created_at).toLocaleDateString()}</span>
</div>
</div>
<div class="flex gap-2 ml-4">
<button onclick="editArticle(${article.id})" class="text-sm text-blue-600 hover:text-blue-800">编辑</button>
<button onclick="deleteArticle(${article.id})" class="text-sm text-red-600 hover:text-red-800">删除</button>
</div>
</div>
</div>
`).join('');
}
// 显示文章表单
function showArticleForm(articleId = null) {
const modal = document.getElementById('article-modal');
const form = document.getElementById('article-form');
const title = document.getElementById('article-modal-title');
if (articleId) {
const article = currentArticles.find(a => a.id === articleId);
if (article) {
title.textContent = '编辑文章';
document.getElementById('article-id').value = article.id;
document.getElementById('article-title').value = article.title;
document.getElementById('article-summary').value = article.summary || '';
document.getElementById('article-content').value = article.content;
document.getElementById('article-category').value = article.category;
document.getElementById('article-published').value = article.published.toString();
document.getElementById('article-protected').checked = article.is_protected;
}
} else {
title.textContent = '新建文章';
form.reset();
document.getElementById('article-id').value = '';
}
modal.classList.remove('hidden');
}
// 关闭文章表单
function closeArticleForm() {
document.getElementById('article-modal').classList.add('hidden');
}
// 保存文章
async function saveArticle(event) {
event.preventDefault();
const articleId = document.getElementById('article-id').value;
const articleData = {
title: document.getElementById('article-title').value,
summary: document.getElementById('article-summary').value,
content: document.getElementById('article-content').value,
category: document.getElementById('article-category').value,
published: document.getElementById('article-published').value === 'true',
is_protected: document.getElementById('article-protected').checked
};
try {
if (articleId) {
await window.DAELAPI.content.updateArticle(articleId, articleData);
} else {
await window.DAELAPI.content.createArticle(articleData);
}
closeArticleForm();
loadArticles();
} catch (error) {
alert('保存失败: ' + error.message);
}
}
// 编辑文章
function editArticle(articleId) {
showArticleForm(articleId);
}
// 删除文章
async function deleteArticle(articleId) {
if (!confirm('确定要删除这篇文章吗?')) return;
try {
await window.DAELAPI.content.deleteArticle(articleId);
loadArticles();
} catch (error) {
alert('删除失败: ' + error.message);
}
}
// 加载资源列表
async function loadResources() {
try {
const response = await window.DAELAPI.content.getResources();
currentResources = response.resources;
displayResources(currentResources);
} catch (error) {
console.error('Failed to load resources:', error);
document.getElementById('resources-list').innerHTML = '<p class="text-red-600">加载失败</p>';
}
}
// 显示资源列表
function displayResources(resources) {
const container = document.getElementById('resources-list');
if (resources.length === 0) {
container.innerHTML = '<p class="text-gray-500">暂无资源</p>';
return;
}
container.innerHTML = resources.map(resource => `
<div class="bg-white border border-gray-200 p-6 rounded">
<div class="flex justify-between items-start">
<div class="flex-1">
<h3 class="text-lg font-bold mb-2">${resource.name}</h3>
<p class="text-sm text-gray-500 mb-2">${resource.description || ''}</p>
<div class="flex gap-4 text-xs text-gray-400">
<span>分类: ${resource.category}</span>
<span>${resource.is_protected ? '🔒 受保护' : '公开'}</span>
<span>大小: ${(resource.file_size / 1024 / 1024).toFixed(2)} MB</span>
<span>下载: ${resource.download_count} 次</span>
</div>
</div>
<div class="flex gap-2 ml-4">
<button onclick="window.DAELAPI.api.downloadResource(${resource.id})" class="text-sm text-blue-600 hover:text-blue-800">下载</button>
<button onclick="deleteResource(${resource.id})" class="text-sm text-red-600 hover:text-red-800">删除</button>
</div>
</div>
</div>
`).join('');
}
// 显示资源表单
function showResourceForm() {
document.getElementById('resource-modal').classList.remove('hidden');
}
// 关闭资源表单
function closeResourceForm() {
document.getElementById('resource-modal').classList.add('hidden');
document.getElementById('resource-form').reset();
}
// 保存资源
async function saveResource(event) {
event.preventDefault();
const fileInput = document.getElementById('resource-file');
if (!fileInput.files[0]) {
alert('请选择文件');
return;
}
try {
await window.DAELAPI.content.uploadResource(
fileInput.files[0],
document.getElementById('resource-name').value,
document.getElementById('resource-description').value,
document.getElementById('resource-category').value,
document.getElementById('resource-protected').checked
);
closeResourceForm();
loadResources();
} catch (error) {
alert('上传失败: ' + error.message);
}
}
// 删除资源
async function deleteResource(resourceId) {
if (!confirm('确定要删除这个资源吗?')) return;
// 注意:需要添加删除资源的API端点
alert('删除功能需要后端支持');
}
// 加载团队成员
async function loadTeamMembers() {
try {
const response = await window.DAELAPI.content.getTeam();
currentTeamMembers = response.members;
displayTeamMembers(currentTeamMembers);
} catch (error) {
console.error('Failed to load team members:', error);
document.getElementById('team-list').innerHTML = '<p class="text-red-600">加载失败</p>';
}
}
// 显示团队成员
function displayTeamMembers(members) {
const container = document.getElementById('team-list');
if (members.length === 0) {
container.innerHTML = '<p class="text-gray-500">暂无成员</p>';
return;
}
container.innerHTML = members.map(member => `
<div class="bg-white border border-gray-200 p-6 rounded">
<div class="flex justify-between items-start">
<div class="flex-1">
<h3 class="text-lg font-bold mb-2">${member.name}</h3>
<p class="text-sm text-gray-600 mb-2">${member.title || ''}</p>
<p class="text-sm text-gray-500 mb-2">${member.bio || ''}</p>
<div class="flex gap-4 text-xs text-gray-400">
<span>角色: ${member.role}</span>
<span>排序: ${member.order}</span>
</div>
</div>
<div class="flex gap-2 ml-4">
<button onclick="editTeamMember(${member.id})" class="text-sm text-blue-600 hover:text-blue-800">编辑</button>
<button onclick="deleteTeamMember(${member.id})" class="text-sm text-red-600 hover:text-red-800">删除</button>
</div>
</div>
</div>
`).join('');
}
// 显示团队成员表单
function showTeamForm(memberId = null) {
const modal = document.getElementById('team-modal');
const form = document.getElementById('team-form');
if (memberId) {
const member = currentTeamMembers.find(m => m.id === memberId);
if (member) {
document.getElementById('team-id').value = member.id;
document.getElementById('team-name').value = member.name;
document.getElementById('team-title').value = member.title || '';
document.getElementById('team-title-en').value = member.title_en || '';
document.getElementById('team-bio').value = member.bio || '';
document.getElementById('team-bio-en').value = member.bio_en || '';
document.getElementById('team-role').value = member.role;
document.getElementById('team-order').value = member.order;
document.getElementById('team-email').value = member.email || '';
document.getElementById('team-website').value = member.website || '';
}
} else {
form.reset();
document.getElementById('team-id').value = '';
}
modal.classList.remove('hidden');
}
// 关闭团队成员表单
function closeTeamForm() {
document.getElementById('team-modal').classList.add('hidden');
}
// 保存团队成员
async function saveTeamMember(event) {
event.preventDefault();
const memberId = document.getElementById('team-id').value;
const memberData = {
name: document.getElementById('team-name').value,
title: document.getElementById('team-title').value,
title_en: document.getElementById('team-title-en').value,
bio: document.getElementById('team-bio').value,
bio_en: document.getElementById('team-bio-en').value,
role: document.getElementById('team-role').value,
order: parseInt(document.getElementById('team-order').value) || 0,
email: document.getElementById('team-email').value,
website: document.getElementById('team-website').value
};
try {
if (memberId) {
// 更新功能需要后端支持
alert('更新功能需要后端支持');
} else {
await window.DAELAPI.content.createTeamMember(memberData);
}
closeTeamForm();
loadTeamMembers();
} catch (error) {
alert('保存失败: ' + error.message);
}
}
// 编辑团队成员
function editTeamMember(memberId) {
showTeamForm(memberId);
}
// 删除团队成员
async function deleteTeamMember(memberId) {
if (!confirm('确定要删除这个成员吗?')) return;
// 注意:需要添加删除成员的API端点
alert('删除功能需要后端支持');
}
// 初始化
document.addEventListener('DOMContentLoaded', async () => {
if (await checkAdminAccess()) {
loadArticles();
// 退出按钮
document.getElementById('logout-btn').addEventListener('click', async () => {
await logout();
});
}
});