a3eb5c7b2d
从百度网盘 /apps/bypy/dofile/ 下载的完整项目结构,包含: - dofile/: Flask 后端(端口 5000)+ 静态前端(端口 6002) - officefile/: 项目相关文档 - .gitignore: Python venv / 日志 / 缓存 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
257 lines
8.0 KiB
Python
257 lines
8.0 KiB
Python
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
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|