205 lines
6.6 KiB
Python
205 lines
6.6 KiB
Python
from fastapi import APIRouter, HTTPException
|
||
from typing import Dict, Any
|
||
from pathlib import Path
|
||
import re
|
||
|
||
router = APIRouter()
|
||
|
||
def to_snake(name: str) -> str:
|
||
return name.replace(' ', '_').replace('-', '_').lower()
|
||
|
||
@router.post("/dev/create-pagetype-template")
|
||
async def create_pagetypes(payload: Dict[str, Any]):
|
||
try:
|
||
name = payload.get("pagetype")
|
||
app = payload.get("app", "jingrow")
|
||
module = payload.get("module", "").replace('.', '/').lower()
|
||
create_frontend = bool(payload.get("create_frontend", True))
|
||
create_backend = bool(payload.get("create_backend", True))
|
||
if not name:
|
||
raise ValueError("pagetype is required")
|
||
slug = to_snake(name)
|
||
|
||
current = Path(__file__).resolve()
|
||
# project root (apps/jingrow/jingrow/core/api/dev.py) -> go up 5
|
||
root = current.parents[5]
|
||
|
||
frontend_path = None
|
||
backend_path = None
|
||
frontend_exists = False
|
||
backend_exists = False
|
||
|
||
if create_frontend:
|
||
fp = root / "apps" / app / "frontend" / module / "pagetype" / slug / f"{slug}_toolbar.vue"
|
||
fp.parent.mkdir(parents=True, exist_ok=True)
|
||
if fp.exists():
|
||
frontend_exists = True
|
||
else:
|
||
fp.write_text("<template>\n <div></div>\n</template>\n<script setup lang=\"ts\">\n</script>\n", encoding="utf-8")
|
||
frontend_path = str(fp)
|
||
|
||
if create_backend:
|
||
bp = root / "apps" / app / app / app / module / "pagetype" / slug / f"{slug}.py"
|
||
bp.parent.mkdir(parents=True, exist_ok=True)
|
||
if bp.exists():
|
||
backend_exists = True
|
||
else:
|
||
bp.write_text("# coding: utf-8\n\n# Blank template for PageType backend hooks\n", encoding="utf-8")
|
||
backend_path = str(bp)
|
||
|
||
return {
|
||
"success": True,
|
||
"frontend_path": frontend_path,
|
||
"backend_path": backend_path,
|
||
"frontend_exists": frontend_exists,
|
||
"backend_exists": backend_exists
|
||
}
|
||
except Exception as e:
|
||
raise HTTPException(status_code=400, detail=str(e))
|
||
|
||
|
||
@router.post("/dev/create-app-template")
|
||
async def create_app_template(payload: Dict[str, Any]):
|
||
"""创建现代化的App模板,符合最佳实践"""
|
||
try:
|
||
app_name = payload.get("appName", "").strip()
|
||
app_title = payload.get("appTitle", "").strip()
|
||
publisher = payload.get("publisher", "").strip()
|
||
description = payload.get("description", "").strip()
|
||
email = payload.get("email", "").strip()
|
||
license_type = payload.get("license", "MIT")
|
||
# 自动生成模块名称,与bench new-app保持一致
|
||
module_name = app_title # 使用app_title作为模块名称
|
||
# 默认包含所有功能,简化用户选择
|
||
include_api = True
|
||
include_frontend = True
|
||
include_tests = True
|
||
cloud_compatible = True
|
||
|
||
if not app_name:
|
||
raise ValueError("App name is required")
|
||
if not app_title:
|
||
raise ValueError("App title is required")
|
||
if not publisher:
|
||
raise ValueError("Publisher is required")
|
||
if not description:
|
||
raise ValueError("Description is required")
|
||
|
||
# 验证app名称格式
|
||
if not re.match(r'^[a-z][a-z0-9_]*$', app_name):
|
||
raise ValueError("App name must start with lowercase letter and contain only lowercase letters, numbers, and underscores")
|
||
|
||
current = Path(__file__).resolve()
|
||
root = current.parents[5] # 调整路径层级
|
||
|
||
# 创建app目录结构 - 保存到apps/app_name
|
||
app_dir = root / "apps" / app_name
|
||
app_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
# 创建frontend和app_name子目录
|
||
frontend_dir = app_dir / "frontend"
|
||
backend_dir = app_dir / app_name
|
||
frontend_dir.mkdir(parents=True, exist_ok=True)
|
||
backend_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
# 创建app内部结构(在app_name目录下)
|
||
app_inner_dir = backend_dir
|
||
|
||
# 创建hooks.py
|
||
hooks_content = f'''app_name = "{app_name}"
|
||
app_title = "{app_title}"
|
||
app_publisher = "{publisher}"
|
||
app_description = "{description}"
|
||
app_email = "{email}"
|
||
app_license = "{license_type.lower()}"
|
||
'''
|
||
|
||
hooks_file = app_inner_dir / "hooks.py"
|
||
hooks_file.write_text(hooks_content, encoding="utf-8")
|
||
|
||
# 创建__init__.py
|
||
init_content = f'''__version__ = "0.0.1"
|
||
'''
|
||
(app_inner_dir / "__init__.py").write_text(init_content, encoding="utf-8")
|
||
|
||
# 创建modules.txt
|
||
modules_content = f'''{app_title}
|
||
'''
|
||
(app_inner_dir / "modules.txt").write_text(modules_content, encoding="utf-8")
|
||
|
||
# 创建目录结构
|
||
(app_inner_dir / "config").mkdir(exist_ok=True)
|
||
(app_inner_dir / "config" / "__init__.py").write_text("", encoding="utf-8")
|
||
|
||
(app_inner_dir / "public").mkdir(exist_ok=True)
|
||
(app_inner_dir / "public" / "css").mkdir(exist_ok=True)
|
||
(app_inner_dir / "public" / "js").mkdir(exist_ok=True)
|
||
(app_inner_dir / "public" / ".gitkeep").write_text("", encoding="utf-8")
|
||
|
||
# 创建module目录(与config、public平级)
|
||
(app_inner_dir / app_name).mkdir(exist_ok=True)
|
||
(app_inner_dir / app_name / "__init__.py").write_text("", encoding="utf-8")
|
||
|
||
# 创建README.md(最小化文档)
|
||
readme_content = f'''# {app_title}
|
||
|
||
{description}
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
pip install -e .
|
||
```
|
||
|
||
## 开发
|
||
|
||
```bash
|
||
pip install -e ".[dev]"
|
||
```
|
||
|
||
## 许可证
|
||
|
||
{license_type} License
|
||
'''
|
||
(app_dir / "README.md").write_text(readme_content, encoding="utf-8")
|
||
|
||
pyproject_content = f'''[build-system]
|
||
requires = ["setuptools>=61.0", "wheel"]
|
||
build-backend = "setuptools.build_meta"
|
||
|
||
[project]
|
||
name = "{app_name}"
|
||
version = "0.0.1"
|
||
description = "{description}"
|
||
authors = [
|
||
{{name = "{publisher}", email = "{email}"}}
|
||
]
|
||
license = {{text = "{license_type}"}}
|
||
requires-python = ">=3.8"
|
||
|
||
dependencies = [
|
||
# Add your app-specific dependencies here
|
||
]
|
||
|
||
[project.optional-dependencies]
|
||
dev = [
|
||
"pytest>=7.0.0",
|
||
"black>=23.0.0",
|
||
]
|
||
'''
|
||
(app_dir / "pyproject.toml").write_text(pyproject_content, encoding="utf-8")
|
||
|
||
return {
|
||
"success": True,
|
||
"appName": app_name,
|
||
"appTitle": app_title,
|
||
"appPath": str(app_dir),
|
||
"backendPath": str(app_inner_dir),
|
||
"frontendPath": str(frontend_dir) if include_frontend else None
|
||
}
|
||
|
||
except Exception as e:
|
||
raise HTTPException(status_code=400, detail=str(e))
|
||
|
||
|