Files
school-meal/backend/meals/views_spa.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

57 lines
1.7 KiB
Python

import mimetypes
import os
from django.http import FileResponse, HttpResponseNotFound
from django.views.decorators.csrf import ensure_csrf_cookie
_FE_DIR_CACHE = None
_INDEX_CACHE = None
def _get_frontend_dir():
global _FE_DIR_CACHE
if _FE_DIR_CACHE is None:
import sys
if getattr(sys, 'frozen', False):
_FE_DIR_CACHE = os.path.join(sys._MEIPASS, 'backend', 'static', 'frontend')
else:
env_dir = os.environ.get('FRONTEND_DIR')
if env_dir and os.path.isdir(env_dir):
_FE_DIR_CACHE = env_dir
else:
_FE_DIR_CACHE = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
'static', 'frontend',
)
return _FE_DIR_CACHE
def _get_index_path():
global _INDEX_CACHE
if _INDEX_CACHE is None:
p = os.path.join(_get_frontend_dir(), 'index.html')
_INDEX_CACHE = p if os.path.isfile(p) else ''
return _INDEX_CACHE
def _serve_file(filepath):
ct, _ = mimetypes.guess_type(filepath)
return FileResponse(open(filepath, 'rb'), content_type=ct or 'application/octet-stream')
@ensure_csrf_cookie
def spa_serve(request, path=None):
"""Serve built React assets or fall back to index.html."""
fdir = _get_frontend_dir()
req_path = (path or '').lstrip('/')
if req_path:
target = os.path.normpath(os.path.join(fdir, req_path))
if target.startswith(os.path.normpath(fdir)) and os.path.isfile(target):
return _serve_file(target)
index = _get_index_path()
if index:
return _serve_file(index)
return HttpResponseNotFound('Frontend not built. Run build.py first.')