- 新增 Pagination 通用组件:首页/上一页/页码/下一页/末页导航 - PickModal 和 SwapModal 集成分页功能,每页20项 - 搜索/筛选切换自动回到第1页 - 现代化CSS样式:hover浮起动效、主色高亮、移动端适配 - 新增 dashboard、admin 管理模板 - 菜系(cuisine)模型和迁移 - 构建脚本 build.py 支持 PyInstaller 打包 - 前端资源重新构建
57 lines
1.7 KiB
Python
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.')
|