Files
school-meal/run.py
T
Chunyu d7553520ce feat: 现代化翻页组件 + 完整项目更新
- 新增 Pagination 通用组件:首页/上一页/页码/下一页/末页导航
- PickModal 和 SwapModal 集成分页功能,每页20项
- 搜索/筛选切换自动回到第1页
- 现代化CSS样式:hover浮起动效、主色高亮、移动端适配
- 新增 dashboard、admin 管理模板
- 菜系(cuisine)模型和迁移
- 构建脚本 build.py 支持 PyInstaller 打包
- 前端资源重新构建
2026-08-28 13:44:21 +08:00

156 lines
6.1 KiB
Python

"""
\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()