Files
SI_TEALab_2025_LabWebsite/dofile/js/meetings.js
T
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

370 lines
14 KiB
JavaScript

// Meetings Management JavaScript
let currentMeetings = [];
let currentFilter = 'all';
// 检查登录状态
async function checkLogin() {
try {
const response = await window.DAELAPI.auth.checkAuth();
if (!response.authenticated) {
window.location.href = 'login.html';
return false;
}
return true;
} catch (error) {
window.location.href = 'login.html';
return false;
}
}
// 加载组会列表
async function loadMeetings() {
try {
const response = await window.DAELAPI.meetings.getMeetings();
currentMeetings = response.meetings;
displayMeetings(currentMeetings);
} catch (error) {
console.error('Failed to load meetings:', error);
document.getElementById('meetings-list').innerHTML = '<p class="text-red-600">加载失败</p>';
}
}
// 显示组会列表
function displayMeetings(meetings) {
const container = document.getElementById('meetings-list');
// 根据筛选器过滤
let filteredMeetings = meetings;
if (currentFilter !== 'all') {
filteredMeetings = meetings.filter(m => m.status === currentFilter);
}
if (filteredMeetings.length === 0) {
container.innerHTML = '<p class="text-gray-500 text-center py-12">暂无组会</p>';
return;
}
container.innerHTML = filteredMeetings.map(meeting => {
const date = new Date(meeting.date);
const isOwner = meeting.organizer_id === (window.currentUser?.id);
return `
<div class="bg-white border border-gray-200 p-6 rounded-lg hover:shadow-md transition-shadow">
<div class="flex justify-between items-start">
<div class="flex-1">
<div class="flex items-center gap-3 mb-2">
<h3 class="text-xl font-bold">${meeting.title}</h3>
<span class="text-xs px-2 py-1 rounded ${getStatusColor(meeting.status)}">${getStatusText(meeting.status)}</span>
<span class="text-xs px-2 py-1 rounded bg-gray-100">${getTypeText(meeting.meeting_type)}</span>
</div>
<p class="text-gray-600 text-sm mb-3">${meeting.description || ''}</p>
<div class="flex gap-6 text-sm text-gray-500">
<span>📅 ${date.toLocaleDateString('zh-CN')}</span>
<span>🕐 ${meeting.time || ''}</span>
<span>📍 ${meeting.location || '未指定'}</span>
<span>👤 组织者: ${meeting.organizer_name || ''}</span>
<span>👥 报名: ${meeting.attendee_count || 0} 人</span>
</div>
</div>
<div class="flex gap-2 ml-4">
<button onclick="viewMeeting(${meeting.id})" class="text-sm text-blue-600 hover:text-blue-800 px-3 py-1 border border-blue-600 rounded">查看</button>
${isOwner ? `
<button onclick="editMeeting(${meeting.id})" class="text-sm text-gray-600 hover:text-gray-800 px-3 py-1 border border-gray-600 rounded">编辑</button>
<button onclick="deleteMeeting(${meeting.id})" class="text-sm text-red-600 hover:text-red-800 px-3 py-1 border border-red-600 rounded">删除</button>
` : ''}
</div>
</div>
</div>
`;
}).join('');
}
// 状态颜色
function getStatusColor(status) {
const colors = {
'planned': 'bg-blue-100 text-blue-800',
'ongoing': 'bg-green-100 text-green-800',
'completed': 'bg-gray-100 text-gray-800',
'cancelled': 'bg-red-100 text-red-800'
};
return colors[status] || 'bg-gray-100 text-gray-800';
}
// 状态文本
function getStatusText(status) {
const texts = {
'planned': '计划中',
'ongoing': '进行中',
'completed': '已结束',
'cancelled': '已取消'
};
return texts[status] || status;
}
// 类型文本
function getTypeText(type) {
const texts = {
'weekly': '周会',
'monthly': '月会',
'special': '专题会'
};
return texts[type] || type;
}
// 显示组会表单
function showMeetingForm(meetingId = null) {
const modal = document.getElementById('meeting-modal');
const form = document.getElementById('meeting-form');
const title = document.getElementById('meeting-modal-title');
if (meetingId) {
const meeting = currentMeetings.find(m => m.id === meetingId);
if (meeting) {
title.textContent = '编辑组会';
document.getElementById('meeting-id').value = meeting.id;
document.getElementById('meeting-title').value = meeting.title;
document.getElementById('meeting-description').value = meeting.description || '';
document.getElementById('meeting-date').value = meeting.date;
document.getElementById('meeting-time').value = meeting.time || '';
document.getElementById('meeting-location').value = meeting.location || '';
document.getElementById('meeting-type').value = meeting.meeting_type;
document.getElementById('meeting-status').value = meeting.status;
}
} else {
title.textContent = '创建组会';
form.reset();
document.getElementById('meeting-id').value = '';
// 设置默认日期为今天
const today = new Date().toISOString().split('T')[0];
document.getElementById('meeting-date').value = today;
}
modal.classList.remove('hidden');
}
// 关闭组会表单
function closeMeetingForm() {
document.getElementById('meeting-modal').classList.add('hidden');
}
// 保存组会
async function saveMeeting(event) {
event.preventDefault();
const meetingId = document.getElementById('meeting-id').value;
const meetingData = {
title: document.getElementById('meeting-title').value,
description: document.getElementById('meeting-description').value,
date: document.getElementById('meeting-date').value,
time: document.getElementById('meeting-time').value,
location: document.getElementById('meeting-location').value,
meeting_type: document.getElementById('meeting-type').value,
status: document.getElementById('meeting-status').value
};
try {
if (meetingId) {
await window.DAELAPI.meetings.updateMeeting(meetingId, meetingData);
} else {
await window.DAELAPI.meetings.createMeeting(meetingData);
}
closeMeetingForm();
loadMeetings();
} catch (error) {
alert('保存失败: ' + error.message);
}
}
// 查看组会详情
async function viewMeeting(meetingId) {
try {
const response = await window.DAELAPI.meetings.getMeeting(meetingId);
const meeting = response.meeting;
displayMeetingDetail(meeting);
} catch (error) {
alert('加载失败: ' + error.message);
}
}
// 显示组会详情
function displayMeetingDetail(meeting) {
const modal = document.getElementById('meeting-detail-modal');
const container = document.getElementById('meeting-detail-content');
const date = new Date(meeting.date);
const isOwner = meeting.organizer_id === (window.currentUser?.id);
container.innerHTML = `
<div class="flex justify-between items-start mb-6">
<h3 class="text-2xl font-bold">${meeting.title}</h3>
<button onclick="closeMeetingDetail()" class="text-gray-400 hover:text-gray-600">✕</button>
</div>
<div class="space-y-4 mb-6">
<div>
<span class="text-sm text-gray-500">日期时间:</span>
<span class="text-sm">${date.toLocaleDateString('zh-CN')} ${meeting.time || ''}</span>
</div>
<div>
<span class="text-sm text-gray-500">地点:</span>
<span class="text-sm">${meeting.location || '未指定'}</span>
</div>
<div>
<span class="text-sm text-gray-500">组织者:</span>
<span class="text-sm">${meeting.organizer_name || ''}</span>
</div>
<div>
<span class="text-sm text-gray-500">类型:</span>
<span class="text-sm">${getTypeText(meeting.meeting_type)}</span>
</div>
<div>
<span class="text-sm text-gray-500">状态:</span>
<span class="text-sm ${getStatusColor(meeting.status)} px-2 py-1 rounded">${getStatusText(meeting.status)}</span>
</div>
${meeting.description ? `
<div>
<span class="text-sm text-gray-500">描述:</span>
<p class="text-sm mt-1">${meeting.description}</p>
</div>
` : ''}
</div>
<div class="mb-6">
<h4 class="font-bold mb-3">参会人员 (${meeting.attendees?.length || 0})</h4>
<div class="space-y-2">
${meeting.attendees && meeting.attendees.length > 0 ?
meeting.attendees.map(attendee => `
<div class="flex items-center justify-between p-2 bg-gray-50 rounded">
<span class="text-sm">${attendee.username}</span>
<span class="text-xs text-gray-500">${getStatusText(attendee.status)}</span>
</div>
`).join('') :
'<p class="text-sm text-gray-500">暂无报名</p>'
}
</div>
${!isOwner && meeting.status === 'planned' ? `
<button onclick="registerForMeeting(${meeting.id})" class="mt-3 bg-black text-white px-4 py-2 rounded text-sm hover:bg-gray-800">
报名参会
</button>
` : ''}
</div>
${meeting.meeting_notes ? `
<div class="mb-6">
<h4 class="font-bold mb-3">会议记录</h4>
<div class="p-4 bg-gray-50 rounded text-sm whitespace-pre-wrap">${meeting.meeting_notes}</div>
</div>
` : ''}
${meeting.files && meeting.files.length > 0 ? `
<div class="mb-6">
<h4 class="font-bold mb-3">附件 (${meeting.files.length})</h4>
<div class="space-y-2">
${meeting.files.map(file => `
<div class="flex items-center justify-between p-2 bg-gray-50 rounded">
<span class="text-sm">${file.name}</span>
<button onclick="window.DAELAPI.meetings.downloadMeetingFile(${meeting.id}, ${file.id})"
class="text-sm text-blue-600 hover:text-blue-800">
下载
</button>
</div>
`).join('')}
</div>
</div>
` : ''}
${isOwner ? `
<div class="flex gap-4">
<button onclick="editMeeting(${meeting.id})" class="bg-black text-white px-4 py-2 rounded text-sm hover:bg-gray-800">
编辑
</button>
<button onclick="deleteMeeting(${meeting.id})" class="bg-red-600 text-white px-4 py-2 rounded text-sm hover:bg-red-700">
删除
</button>
</div>
` : ''}
`;
modal.classList.remove('hidden');
}
// 关闭组会详情
function closeMeetingDetail() {
document.getElementById('meeting-detail-modal').classList.add('hidden');
}
// 编辑组会
function editMeeting(meetingId) {
closeMeetingDetail();
showMeetingForm(meetingId);
}
// 删除组会
async function deleteMeeting(meetingId) {
if (!confirm('确定要删除这个组会吗?')) return;
try {
await window.DAELAPI.meetings.deleteMeeting(meetingId);
closeMeetingDetail();
loadMeetings();
} catch (error) {
alert('删除失败: ' + error.message);
}
}
// 报名参会
async function registerForMeeting(meetingId) {
try {
await window.DAELAPI.meetings.registerMeeting(meetingId);
alert('报名成功!');
viewMeeting(meetingId); // 刷新详情
} catch (error) {
alert('报名失败: ' + error.message);
}
}
// 筛选器切换
document.querySelectorAll('.filter-tab').forEach(tab => {
tab.addEventListener('click', () => {
document.querySelectorAll('.filter-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');
currentFilter = tab.dataset.filter;
displayMeetings(currentMeetings);
});
});
// 初始化
document.addEventListener('DOMContentLoaded', async () => {
if (await checkLogin()) {
// 获取当前用户信息
try {
const authResponse = await window.DAELAPI.auth.checkAuth();
window.currentUser = authResponse.user;
} catch (error) {
console.error('Failed to get user info:', error);
}
loadMeetings();
// 退出按钮
document.getElementById('logout-btn').addEventListener('click', async () => {
await logout();
});
}
});