- 后端: 新增 appeal_reason_type, appeal_evidence_urls 字段 - 后端: 新建 upload_routes.py 图片上传接口 - 前端: history 页面添加快捷理由选择器 + 截图上传 - 前端: admin-review 页面展示证据图片 + 点击预览 - 新增 SQL 更新脚本 update_appeal_fields.sql Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
68 lines
1.9 KiB
Python
68 lines
1.9 KiB
Python
import os
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
from flask import Blueprint, current_app, request, send_from_directory
|
|
from flask_jwt_extended import jwt_required
|
|
from werkzeug.utils import secure_filename
|
|
|
|
from app.utils.auth import current_user
|
|
from app.utils.response import fail, ok
|
|
|
|
|
|
upload_bp = Blueprint("upload", __name__)
|
|
|
|
ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "gif", "webg"}
|
|
MAX_FILE_SIZE = 5 * 1024 * 1024 # 5MB
|
|
|
|
|
|
def allowed_file(filename: str) -> bool:
|
|
ext = (filename.rsplit(".", 1)[-1] if "." in filename else "").lower()
|
|
return ext in ALLOWED_EXTENSIONS
|
|
|
|
|
|
def generate_filename(original: str) -> str:
|
|
ext = original.rsplit(".", 1)[-1] if "." in original else "jpg"
|
|
timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
|
|
unique = uuid.uuid4().hex[:8]
|
|
return f"{timestamp}_{unique}.{ext.lower()}"
|
|
|
|
|
|
@upload_bp.post("/image")
|
|
@jwt_required()
|
|
def upload_image():
|
|
user = current_user()
|
|
if not user:
|
|
return fail("用户不存在", 404)
|
|
|
|
if "file" not in request.files:
|
|
return fail("未上传文件", 400)
|
|
|
|
file = request.files["file"]
|
|
if not file.filename:
|
|
return fail("文件名无效", 400)
|
|
|
|
if not allowed_file(file.filename):
|
|
return fail("仅支持 png/jpg/jpeg/gif/webg 格式", 400)
|
|
|
|
upload_folder = current_app.config.get("UPLOAD_FOLDER")
|
|
if not upload_folder:
|
|
return fail("上传目录未配置", 500)
|
|
|
|
os.makedirs(upload_folder, exist_ok=True)
|
|
|
|
filename = generate_filename(secure_filename(file.filename))
|
|
filepath = os.path.join(upload_folder, filename)
|
|
file.save(filepath)
|
|
|
|
url = f"/api/upload/images/{filename}"
|
|
return ok({"url": url, "filename": filename}, "上传成功")
|
|
|
|
|
|
@upload_bp.get("/images/<filename>")
|
|
def get_image(filename: str):
|
|
upload_folder = current_app.config.get("UPLOAD_FOLDER")
|
|
if not upload_folder:
|
|
return fail("上传目录未配置", 500)
|
|
|
|
return send_from_directory(upload_folder, filename) |