import os import json import uuid from datetime import datetime from flask import Flask, render_template, request, jsonify app = Flask(__name__) DATA_FILE = os.environ.get("DATA_FILE", "requests.json") DEFAULT_REQUESTS = [ { "id": "1", "title": "增加暗色模式", "description": "建议增加暗色模式支持,方便夜间使用。", "category": "界面设计 (UI/UX)", "votes": 15, "status": "planned", "created_at": datetime.now().isoformat(), "comments": [] }, { "id": "2", "title": "支持图片上传", "description": "在提交反馈时,希望可以上传截图,这样能更直观地说明问题。", "category": "功能建议 (Feature)", "votes": 8, "status": "pending", "created_at": datetime.now().isoformat(), "comments": [] }, { "id": "3", "title": "移动端适配优化", "description": "目前在手机上查看列表时,排版有些拥挤,建议优化移动端显示。", "category": "界面设计 (UI/UX)", "votes": 12, "status": "in_progress", "created_at": datetime.now().isoformat(), "comments": [] } ] def load_data(): if not os.path.exists(DATA_FILE): save_data(DEFAULT_REQUESTS) return DEFAULT_REQUESTS try: with open(DATA_FILE, "r", encoding="utf-8") as f: data = json.load(f) if not isinstance(data, list): # If data is corrupted (not a list), backup and reset print(f"Warning: {DATA_FILE} contains invalid data (not a list). Resetting.") os.rename(DATA_FILE, DATA_FILE + ".bak") save_data(DEFAULT_REQUESTS) return DEFAULT_REQUESTS return data except Exception as e: print(f"Error loading data: {e}. Resetting.") # If file is corrupted, reset if os.path.exists(DATA_FILE): os.rename(DATA_FILE, DATA_FILE + ".bak") save_data(DEFAULT_REQUESTS) return DEFAULT_REQUESTS def save_data(data): try: with open(DATA_FILE, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) except Exception as e: print(f"Error saving data: {e}") @app.route("/") def index(): return render_template("index.html") @app.route("/api/requests", methods=["GET"]) def get_requests(): data = load_data() # Sort by votes (desc) then date (desc) data.sort(key=lambda x: (x.get("votes", 0), x.get("created_at", "")), reverse=True) return jsonify(data) @app.route("/api/requests", methods=["POST"]) def add_request(): data = load_data() payload = request.json if not payload.get("title") or not payload.get("description"): return jsonify({"error": "Title and description are required"}), 400 new_request = { "id": str(uuid.uuid4()), "title": payload["title"], "description": payload["description"], "category": payload.get("category", "General"), "votes": 1, "status": "pending", # pending, planned, in_progress, completed, rejected "created_at": datetime.now().isoformat(), "comments": [] } data.append(new_request) save_data(data) return jsonify(new_request) @app.route("/api/requests//vote", methods=["POST"]) def vote_request(req_id): data = load_data() for req in data: if req["id"] == req_id: req["votes"] = req.get("votes", 0) + 1 save_data(data) return jsonify({"success": True, "votes": req["votes"]}) return jsonify({"error": "Request not found"}), 404 @app.route("/api/requests//status", methods=["POST"]) def update_status(req_id): # Simple admin check (in a real app, use auth) # Here we just trust the client for the demo/MVP purpose payload = request.json new_status = payload.get("status") if new_status not in ["pending", "planned", "in_progress", "completed", "rejected"]: return jsonify({"error": "Invalid status"}), 400 data = load_data() for req in data: if req["id"] == req_id: req["status"] = new_status save_data(data) return jsonify({"success": True, "status": new_status}) return jsonify({"error": "Request not found"}), 404 if __name__ == "__main__": app.run(host="0.0.0.0", port=7860)