init: TEALab 2025 实验室网站项目
从百度网盘 /apps/bypy/dofile/ 下载的完整项目结构,包含: - dofile/: Flask 后端(端口 5000)+ 静态前端(端口 6002) - officefile/: 项目相关文档 - .gitignore: Python venv / 日志 / 缓存 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
from flask import Blueprint, request, jsonify, send_from_directory, current_app
|
||||
from flask_login import login_required, current_user
|
||||
from werkzeug.utils import secure_filename
|
||||
import sys
|
||||
import os
|
||||
from datetime import datetime, date, time
|
||||
|
||||
# 添加父目录到路径
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
from models import db, Meeting, MeetingRegistration, MeetingFile, User
|
||||
|
||||
bp = Blueprint('meetings', __name__)
|
||||
|
||||
def allowed_file(filename, allowed_extensions):
|
||||
"""检查文件扩展名是否允许"""
|
||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowed_extensions
|
||||
|
||||
@bp.route('/meetings', methods=['GET'])
|
||||
@login_required
|
||||
def get_meetings():
|
||||
"""获取组会列表(实验室成员可查看所有)"""
|
||||
status = request.args.get('status')
|
||||
meeting_type = request.args.get('type')
|
||||
|
||||
query = Meeting.query
|
||||
|
||||
if status:
|
||||
query = query.filter_by(status=status)
|
||||
if meeting_type:
|
||||
query = query.filter_by(meeting_type=meeting_type)
|
||||
|
||||
meetings = query.order_by(Meeting.date.desc(), Meeting.time.desc()).all()
|
||||
|
||||
return jsonify({
|
||||
'meetings': [meeting.to_dict() for meeting in meetings]
|
||||
}), 200
|
||||
|
||||
@bp.route('/meetings/<int:meeting_id>', methods=['GET'])
|
||||
@login_required
|
||||
def get_meeting(meeting_id):
|
||||
"""获取单个组会详情"""
|
||||
meeting = Meeting.query.get_or_404(meeting_id)
|
||||
|
||||
# 获取参会人员列表
|
||||
registrations = MeetingRegistration.query.filter_by(meeting_id=meeting_id).all()
|
||||
attendees = [reg.to_dict() for reg in registrations]
|
||||
|
||||
# 获取文件列表
|
||||
files = MeetingFile.query.filter_by(meeting_id=meeting_id).all()
|
||||
file_list = [f.to_dict() for f in files]
|
||||
|
||||
result = meeting.to_dict()
|
||||
result['attendees'] = attendees
|
||||
result['files'] = file_list
|
||||
|
||||
return jsonify({'meeting': result}), 200
|
||||
|
||||
@bp.route('/meetings', methods=['POST'])
|
||||
@login_required
|
||||
def create_meeting():
|
||||
"""创建组会(需要登录)"""
|
||||
data = request.get_json()
|
||||
|
||||
# 解析日期和时间
|
||||
meeting_date = datetime.strptime(data['date'], '%Y-%m-%d').date() if data.get('date') else None
|
||||
meeting_time = datetime.strptime(data['time'], '%H:%M').time() if data.get('time') else None
|
||||
|
||||
meeting = Meeting(
|
||||
title=data.get('title'),
|
||||
description=data.get('description'),
|
||||
date=meeting_date,
|
||||
time=meeting_time,
|
||||
location=data.get('location'),
|
||||
organizer_id=current_user.id,
|
||||
status=data.get('status', 'planned'),
|
||||
meeting_type=data.get('meeting_type', 'weekly')
|
||||
)
|
||||
|
||||
db.session.add(meeting)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'message': 'Meeting created successfully',
|
||||
'meeting': meeting.to_dict()
|
||||
}), 201
|
||||
|
||||
@bp.route('/meetings/<int:meeting_id>', methods=['PUT'])
|
||||
@login_required
|
||||
def update_meeting(meeting_id):
|
||||
"""更新组会(只有创建者可以编辑)"""
|
||||
meeting = Meeting.query.get_or_404(meeting_id)
|
||||
|
||||
# 检查权限:只有创建者可以编辑
|
||||
if meeting.organizer_id != current_user.id:
|
||||
return jsonify({'error': 'Only the organizer can edit this meeting'}), 403
|
||||
|
||||
data = request.get_json()
|
||||
|
||||
if 'title' in data:
|
||||
meeting.title = data['title']
|
||||
if 'description' in data:
|
||||
meeting.description = data['description']
|
||||
if 'date' in data:
|
||||
meeting.date = datetime.strptime(data['date'], '%Y-%m-%d').date()
|
||||
if 'time' in data:
|
||||
meeting.time = datetime.strptime(data['time'], '%H:%M').time()
|
||||
if 'location' in data:
|
||||
meeting.location = data['location']
|
||||
if 'status' in data:
|
||||
meeting.status = data['status']
|
||||
if 'meeting_type' in data:
|
||||
meeting.meeting_type = data['meeting_type']
|
||||
if 'meeting_notes' in data:
|
||||
meeting.meeting_notes = data['meeting_notes']
|
||||
|
||||
meeting.updated_at = datetime.utcnow()
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'message': 'Meeting updated successfully',
|
||||
'meeting': meeting.to_dict()
|
||||
}), 200
|
||||
|
||||
@bp.route('/meetings/<int:meeting_id>', methods=['DELETE'])
|
||||
@login_required
|
||||
def delete_meeting(meeting_id):
|
||||
"""删除组会(只有创建者可以删除)"""
|
||||
meeting = Meeting.query.get_or_404(meeting_id)
|
||||
|
||||
# 检查权限
|
||||
if meeting.organizer_id != current_user.id:
|
||||
return jsonify({'error': 'Only the organizer can delete this meeting'}), 403
|
||||
|
||||
db.session.delete(meeting)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({'message': 'Meeting deleted successfully'}), 200
|
||||
|
||||
@bp.route('/meetings/<int:meeting_id>/register', methods=['POST'])
|
||||
@login_required
|
||||
def register_meeting(meeting_id):
|
||||
"""报名参加组会"""
|
||||
meeting = Meeting.query.get_or_404(meeting_id)
|
||||
|
||||
# 检查是否已报名
|
||||
existing = MeetingRegistration.query.filter_by(
|
||||
meeting_id=meeting_id,
|
||||
user_id=current_user.id
|
||||
).first()
|
||||
|
||||
if existing:
|
||||
return jsonify({'error': 'Already registered'}), 400
|
||||
|
||||
registration = MeetingRegistration(
|
||||
meeting_id=meeting_id,
|
||||
user_id=current_user.id,
|
||||
status='registered'
|
||||
)
|
||||
|
||||
db.session.add(registration)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'message': 'Registered successfully',
|
||||
'registration': registration.to_dict()
|
||||
}), 201
|
||||
|
||||
@bp.route('/meetings/<int:meeting_id>/checkin', methods=['POST'])
|
||||
@login_required
|
||||
def checkin_meeting(meeting_id):
|
||||
"""签到组会"""
|
||||
registration = MeetingRegistration.query.filter_by(
|
||||
meeting_id=meeting_id,
|
||||
user_id=current_user.id
|
||||
).first_or_404()
|
||||
|
||||
registration.status = 'checked_in'
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'message': 'Checked in successfully',
|
||||
'registration': registration.to_dict()
|
||||
}), 200
|
||||
|
||||
@bp.route('/meetings/<int:meeting_id>/files', methods=['POST'])
|
||||
@login_required
|
||||
def upload_meeting_file(meeting_id):
|
||||
"""上传组会文件(只有创建者可以上传)"""
|
||||
meeting = Meeting.query.get_or_404(meeting_id)
|
||||
|
||||
# 检查权限
|
||||
if meeting.organizer_id != current_user.id:
|
||||
return jsonify({'error': 'Only the organizer can upload files'}), 403
|
||||
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'No file provided'}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'No file selected'}), 400
|
||||
|
||||
if file and allowed_file(file.filename, {'pdf', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'zip', 'rar'}):
|
||||
filename = secure_filename(file.filename)
|
||||
uploads_dir = current_app.config['UPLOAD_FOLDER']
|
||||
meeting_dir = os.path.join(uploads_dir, 'meetings', str(meeting_id))
|
||||
os.makedirs(meeting_dir, exist_ok=True)
|
||||
|
||||
filepath = os.path.join(meeting_dir, filename)
|
||||
file.save(filepath)
|
||||
|
||||
meeting_file = MeetingFile(
|
||||
meeting_id=meeting_id,
|
||||
name=request.form.get('name', filename),
|
||||
file_path=f'/uploads/meetings/{meeting_id}/{filename}',
|
||||
file_size=os.path.getsize(filepath),
|
||||
file_type=filename.rsplit('.', 1)[1].lower(),
|
||||
uploader_id=current_user.id
|
||||
)
|
||||
|
||||
db.session.add(meeting_file)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'message': 'File uploaded successfully',
|
||||
'file': meeting_file.to_dict()
|
||||
}), 201
|
||||
|
||||
return jsonify({'error': 'Invalid file type'}), 400
|
||||
|
||||
@bp.route('/meetings/<int:meeting_id>/files/<int:file_id>', methods=['GET'])
|
||||
@login_required
|
||||
def download_meeting_file(meeting_id, file_id):
|
||||
"""下载组会文件"""
|
||||
meeting_file = MeetingFile.query.filter_by(
|
||||
meeting_id=meeting_id,
|
||||
id=file_id
|
||||
).first_or_404()
|
||||
|
||||
uploads_dir = current_app.config['UPLOAD_FOLDER']
|
||||
file_path = os.path.join(uploads_dir, 'meetings', str(meeting_id), os.path.basename(meeting_file.file_path))
|
||||
|
||||
return send_from_directory(
|
||||
os.path.dirname(file_path),
|
||||
os.path.basename(file_path),
|
||||
as_attachment=True
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user