""" \u5b66\u6821\u8ba2\u9910\u83dc\u5355\u751f\u6210\u5668 - EXE \u5165\u53e3 \u53cc\u51fb\u8fd0\u884c\u6b64\u811a\u672c\u6216\u6253\u5305\u540e\u7684 EXE\uff0c\u81ea\u52a8\u5b8c\u6210\uff1a 1. \u521d\u59cb\u5316\u6570\u636e\u5e93\uff08\u9996\u6b21\u8fd0\u884c\u81ea\u52a8\u8fc1\u79fb + \u5199\u5165\u793a\u4f8b\u83dc\u54c1\uff09 2. \u542f\u52a8 Django \u670d\u52a1\uff08\u540c\u65f6\u6258\u7ba1\u524d\u7aef\u9759\u6001\u9875\u9762\uff09 3. 自动打开浏览器(默认)或原生窗口(--gui 模式) """ import os import sys import threading import time import webbrowser # Ensure UTF-8 output on Windows console (fixes GBK encoding errors with rich) if sys.platform == "win32": os.system("chcp 65001 >nul 2>&1") try: sys.stdout.reconfigure(encoding="utf-8", errors="replace") sys.stderr.reconfigure(encoding="utf-8", errors="replace") except Exception: pass from rich.console import Console from rich.panel import Panel from rich.text import Text from rich.table import Table from rich import box console = Console() GUI_MODE = "--gui" in sys.argv def _frozen_dir(): if getattr(sys, "frozen", False): return sys._MEIPASS return os.path.dirname(os.path.abspath(__file__)) def _app_dir(): if getattr(sys, "frozen", False): return os.path.dirname(sys.executable) return os.path.dirname(os.path.abspath(__file__)) def setup_environment(): base = _frozen_dir() app = _app_dir() sys.path.insert(0, base) # In dev mode, add backend/ to path so config and meals are importable backend_dir = os.path.join(base, 'backend') if os.path.isdir(backend_dir) and backend_dir not in sys.path: sys.path.insert(0, backend_dir) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") os.environ["DJANGO_DEBUG"] = "True" os.environ["DJANGO_SECRET_KEY"] = "exe-local-secret-key-do-not-use-in-production" os.environ["DJANGO_ALLOWED_HOSTS"] = "127.0.0.1,localhost" os.environ["DJANGO_DB_PATH"] = os.path.join(app, "db.sqlite3") os.environ["DJANGO_STATIC_URL"] = "/static/" os.environ["EXE_MODE"] = "1" static_fe = os.path.join(base, "backend", "static", "frontend") if not os.path.isdir(static_fe): static_fe = os.path.join(base, "static", "frontend") os.environ["FRONTEND_DIR"] = static_fe def init_database(): import django django.setup() from django.core.management import call_command with console.status("[bold cyan]\u6b63\u5728\u8fc1\u79fb\u6570\u636e\u5e93...", spinner="dots"): call_command("migrate", "--run-syncdb", verbosity=0) console.print(" [green]\u2713[/green] \u6570\u636e\u5e93\u8fc1\u79fb\u5b8c\u6210") from meals.models import Dish if Dish.objects.count() == 0: with console.status("[bold cyan]\u6b63\u5728\u5199\u5165\u793a\u4f8b\u83dc\u54c1\u6570\u636e...", spinner="dots"): try: call_command("seed_dishes", verbosity=0) except Exception: pass console.print(" [green]\u2713[/green] \u793a\u4f8b\u83dc\u54c1\u6570\u636e\u5df2\u5199\u5165") else: console.print(" [green]\u2713[/green] \u83dc\u54c1\u6570\u636e\u5df2\u5b58\u5728\uff0c\u8df3\u8fc7") from django.contrib.auth import get_user_model User = get_user_model() if not User.objects.filter(username="admin").exists(): User.objects.create_superuser("admin", "admin@example.com", "admin123") console.print(" [green]\u2713[/green] \u5df2\u521b\u5efa\u7ba1\u7406\u5458 [bold]admin[/bold] / [bold]admin123[/bold]") else: console.print(" [green]\u2713[/green] \u7ba1\u7406\u5458\u8d26\u53f7\u5df2\u5b58\u5728") def open_browser(port): time.sleep(2) webbrowser.open(f"http://127.0.0.1:{port}/") def print_banner(port): logo = Text() logo.append(" _____ _ _ ____ \n", style="bold cyan") logo.append(" / ____| | (_) | _ \\ \n", style="bold cyan") logo.append("| (___ | |__ __ _ _ __ _ ___ ___ _ __ | |_) | __ ___ _____ _ __ \n", style="bold cyan") logo.append(" \\___ \\| '_ \\ / _` | '__| |/ __/ _ \\| '_ \\| _ < / _` \\ \\ /\\ / / _ \\| '_ \\ \n", style="bold cyan") logo.append(" ____) | | | | (_| | | | | (_| (_) | | | | |_) | (_| |\\ V V / (_) | | | |\n", style="bold cyan") logo.append("|_____/|_| |_|\\__,_|_| |_|\\___\\___/|_| |_|____/ \\__,_| \\_/\\_/ \\___/|_| |_|\n", style="bold cyan") info_table = Table(show_header=False, box=box.SIMPLE, padding=(0, 2)) info_table.add_column("key", style="bold white") info_table.add_column("value", style="cyan") info_table.add_row("\u5bfc\u822a\u9996\u9875", f"http://127.0.0.1:{port}/") info_table.add_row("\u83dc\u5355\u751f\u6210\u5668", f"http://127.0.0.1:{port}/app/") info_table.add_row("\u540e\u53f0\u7ba1\u7406", f"http://127.0.0.1:{port}/admin") info_table.add_row("\u7ba1\u7406\u5458", "admin / admin123") info_table.add_row("\u505c\u6b62\u670d\u52a1", "Ctrl + C") from rich.console import Group as RenderGroup console.print(Panel( RenderGroup(logo, Text(""), info_table), title="[bold green]\u5b66\u6821\u8ba2\u9910\u83dc\u5355\u751f\u6210\u5668[/bold green]", subtitle="[dim]School Meal Planner[/dim]", border_style="bright_blue", padding=(1, 2), )) # manager.py is no longer launched separately; the web dashboard IS the manager def main(): if GUI_MODE: from desktop import main as gui_main gui_main() return console.clear() setup_environment() console.print() console.print("[bold cyan]\u6b63\u5728\u521d\u59cb\u5316\u7cfb\u7edf...[/bold cyan]") console.print() init_database() port = 8000 print_banner(port) # Auto-open dashboard in browser after server starts threading.Thread(target=open_browser, args=(port,), daemon=True).start() console.print("[dim]Django \u670d\u52a1\u542f\u52a8\u4e2d...[/dim]") console.print() from django.core.management import call_command call_command("runserver", f"127.0.0.1:{port}", "--noreload", verbosity=1) if __name__ == "__main__": main()