commit 7ce1e58a6eda638151523b18505764f51d766c17 Author: 树萌芽 <3205788256@qq.com> Date: Sat Feb 14 00:46:04 2026 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f5a6da0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,79 @@ +# 依赖目录 +node_modules/ +package-lock.json +yarn.lock +pnpm-lock.yaml + +# 构建输出 +dist/ +build/ +*.exe +*.out +*.test + +# Go 编译输出 +*.exe +*.test +*.out +*.dll +*.so +*.dylib + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +venv/ +env/ + +# Java +*.class +*.jar +*.war +*.ear +target/ +.mvn/ + +# 数据文件 +data/data.json + +# 日志 +*.log + +# 操作系统文件 +.DS_Store +Thumbs.db +desktop.ini + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# 测试覆盖率 +coverage/ +.nyc_output/ + +# 环境变量 +.env +.env.local +.env.*.local diff --git a/README.md b/README.md new file mode 100644 index 0000000..f923eca --- /dev/null +++ b/README.md @@ -0,0 +1,174 @@ +# QuickStack - 前后端分离项目初始化工具 + +[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) + +> 🚀 **QuickStack** - 一款强大的全栈项目初始化工具,让你在几秒钟内搭建好前后端分离的开发环境。 + +## ✨ 功能特性 + +- **多种前端框架支持**: React, Vue +- **丰富的后端选择**: Go(标准库/Gin), Python(Flask/FastAPI/Django), Java(Spring Boot), JavaScript(Express.js/NestJS) +- **集成 Tailwind CSS**: 一键配置现代化的 CSS 框架 +- **自动生成启动脚本**: Windows BAT 脚本,双击即可启动项目 +- **跨域配置**: 所有后端模板均已配置 CORS,前后端联调无障碍 +- **交互式 CLI**: 友好的命令行交互界面 + +## 📦 支持的技术栈 + +### 前端框架 +- ⚛️ React (Vite + React) +- 💚 Vue (Vite + Vue) + +### 后端框架 +- 🐹 Go (标准库 http) +- 🚀 Go (Gin 框架) +- 🐍 Python (Flask) +- ⚡ Python (FastAPI) +- 🎯 Python (Django) +- ☕ Java (Spring Boot) +- 🟨 JavaScript (Express.js) +- 🐈‍⬛ JavaScript (NestJS) + +## 🔧 环境要求 + +- Python 3.8+ +- Node.js 16+ (前端项目和 JS 后端需要) +- Go 1.18+ (Go 后端需要) +- Java 17+ 和 Maven 3.6+ (Spring Boot 后端需要) + +## 🚀 使用方法 + +### 1. 克隆项目 + +```bash +git clone +cd QuickStack +``` + +### 2. 运行初始化脚本 + +```bash +python main.py +``` + +### 3. 按照提示操作 + +- 输入项目名称(英文) +- 选择前端框架(React/Vue) +- 选择是否使用 Tailwind CSS +- 选择后端框架 + +### 4. 启动项目 + +进入生成的项目目录,双击运行: + +- `开启前端.bat` - 启动前端开发服务器 +- `开启后端.bat` - 启动后端服务 +- `构建前端.bat` - 构建前端生产版本 + +## 📁 项目结构 + +``` +QuickStack/ +├── main.py # 主程序入口 +├── utils.py # 工具函数 +├── directory.py # 目录管理 +├── scripts.py # 启动脚本生成 +├── frontend/ # 前端模块 +│ ├── react.py # React 初始化 +│ ├── vue.py # Vue 初始化 +│ └── tailwind.py # Tailwind CSS 配置 +├── backend/ # 后端模块 +│ ├── golang.py # Go 初始化 +│ ├── python_flask.py # Flask 初始化 +│ ├── python_fastapi.py# FastAPI 初始化 +│ ├── python_django.py # Django 初始化 +│ ├── java_spring.py # Spring Boot 初始化 +│ ├── js_express.py # Express.js 初始化 +│ └── js_nestjs.py # NestJS 初始化 +└── README.md # 项目说明 +``` + +## 🎯 生成的项目示例 + +``` +myproject/ +├── myproject-frontend/ # 前端项目 +│ ├── src/ +│ ├── package.json +│ └── ... +├── myproject-backend/ # 后端项目 +│ ├── src/ 或 main.go 等 +│ └── ... +├── 开启前端.bat # 启动前端 +├── 开启后端.bat # 启动后端 +└── 构建前端.bat # 构建前端 +``` + +## 🔌 API 端点 + +所有后端模板都包含健康检查端点: + +``` +GET http://localhost:8080/api/health +``` + +响应示例: +```json +{ + "status": "ok", + "message": "Welcome to myproject API" +} +``` + +## ⚙️ 自定义配置 + +### Tailwind CSS + +如果选择使用 Tailwind CSS,会自动: +- 安装 tailwindcss、postcss、autoprefixer +- 初始化配置文件 +- 更新 CSS 文件 +- 创建示例组件 + +### CORS 跨域 + +所有后端模板均已配置 CORS,允许: +- 来源: `*` (所有域名) +- 方法: GET, POST, PUT, DELETE, OPTIONS +- 请求头: Content-Type, Authorization 等 + +## 📝 注意事项 + +1. **Windows 专用**: 本项目生成的启动脚本是 `.bat` 格式,专用于 Windows 系统 +2. **Python 虚拟环境**: Python 后端会自动创建虚拟环境并安装依赖 +3. **npm 依赖**: 前端项目会自动安装 npm 依赖 +4. **端口**: 后端服务默认运行在 8080 端口 + +## 🐛 常见问题 + +### Q: 前端项目创建失败? +A: 请确保已安装 Node.js (16+) 和 npm,并检查网络连接。 + +### Q: Python 后端依赖安装失败? +A: 请确保 Python 环境正常,并检查 pip 是否可用。可以手动进入目录运行 `pip install -r requirements.txt`。 + +### Q: 如何修改默认端口? +A: 修改后端项目的配置文件或代码中的端口设置即可。 + +## 🤝 贡献 + +欢迎提交 Issue 和 Pull Request! + +## 📄 许可证 + +MIT License + +## 💖 致谢 + +感谢使用 QuickStack!祝开发愉快! + +--- + +**QuickStack** - 让全栈开发更简单 🚀 diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..34ed050 --- /dev/null +++ b/backend/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +""" +后端模块包 +""" + +from backend.golang import init_golang_project, init_gin_project +from backend.python_flask import init_flask_project +from backend.python_fastapi import init_fastapi_project +from backend.python_django import init_django_project +from backend.java_spring import init_spring_project +from backend.js_express import init_express_project +from backend.js_nestjs import init_nestjs_project + +__all__ = [ + 'init_golang_project', + 'init_gin_project', + 'init_flask_project', + 'init_fastapi_project', + 'init_django_project', + 'init_spring_project', + 'init_express_project', + 'init_nestjs_project' +] diff --git a/backend/golang.py b/backend/golang.py new file mode 100644 index 0000000..40aa8d6 --- /dev/null +++ b/backend/golang.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- +""" +Go 后端项目初始化模块 +""" + +import subprocess +import sys + + +def run_command_with_progress(cmd, cwd, description): + """运行命令并显示实时输出""" + try: + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + + process = subprocess.Popen( + cmd, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0 + ) + + for line in process.stdout: + try: + decoded_line = line.decode('utf-8', errors='replace') + except: + try: + decoded_line = line.decode('gbk', errors='replace') + except: + decoded_line = line.decode('latin-1', errors='replace') + print(decoded_line, end='') + + process.wait() + + if process.returncode == 0: + print(f"\n{'=' * 60}") + print(f"✅ {description} - 完成") + print(f"{'=' * 60}\n") + return True + else: + print(f"\n{'=' * 60}") + print(f"❌ {description} - 失败 (错误码: {process.returncode})") + print(f"{'=' * 60}\n") + return False + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def init_golang_project(backend_dir, project_name): + """初始化 Go 后端项目""" + print("\n🚀 初始化 Go 后端项目...") + + # 初始化 Go 模块 + success = run_command_with_progress( + f"go mod init {project_name}-backend", + backend_dir, + "初始化 Go 模块" + ) + + if not success: + print("\n💡 提示: 请确保已安装 Go") + print(" 下载地址: https://golang.org/dl/") + sys.exit(1) + + # 创建 main.go - 使用标准库 + main_go = backend_dir / "main.go" + main_go.write_text(f'''package main + +import ( + "encoding/json" + "log" + "net/http" +) + +func main() {{ + mux := http.NewServeMux() + + // 健康检查接口 + mux.HandleFunc("GET /api/health", healthHandler) + + // 添加 CORS 中间件 + handler := corsMiddleware(mux) + + log.Println("🚀 服务器启动: http://localhost:8080") + log.Println("📍 健康检查: http://localhost:8080/api/health") + log.Fatal(http.ListenAndServe(":8080", handler)) +}} + +func healthHandler(w http.ResponseWriter, r *http.Request) {{ + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]string{{ + "status": "ok", + "message": "Welcome to {project_name} API", + }}) +}} + +func corsMiddleware(next http.Handler) http.Handler {{ + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {{ + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") + + if r.Method == "OPTIONS" {{ + w.WriteHeader(http.StatusNoContent) + return + }} + + next.ServeHTTP(w, r) + }}) +}} +''', encoding='utf-8') + + # 整理依赖 + run_command_with_progress("go mod tidy", backend_dir, "整理 Go 依赖") + + print("\n✅ Go 后端项目初始化成功") + print("💡 启动命令: go run main.go") + print("📝 注意: 使用 Go 标准库,无需第三方依赖") + + +def init_gin_project(backend_dir, project_name): + """初始化 Go Gin 后端项目""" + print("\n🚀 初始化 Go Gin 后端项目...") + + # 初始化 Go 模块 + success = run_command_with_progress( + f"go mod init {project_name}-backend", + backend_dir, + "初始化 Go 模块" + ) + + if not success: + print("\n💡 提示: 请确保已安装 Go") + print(" 下载地址: https://golang.org/dl/") + sys.exit(1) + + # 拉取 Gin 依赖 + deps_ok = run_command_with_progress( + "go get github.com/gin-gonic/gin github.com/gin-contrib/cors", + backend_dir, + "安装 Gin 依赖" + ) + + if not deps_ok: + print("\n❌ 无法安装 Gin 依赖,请检查 Go 环境和网络") + sys.exit(1) + + # 创建 main.go - Gin 框架 + main_go = backend_dir / "main.go" + main_go.write_text(f'''package main + +import ( + "log" + "time" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" +) + +func main() {{ + r := gin.New() + r.Use(gin.Logger()) + r.Use(gin.Recovery()) + + // CORS 配置 + r.Use(cors.New(cors.Config{{ + AllowOrigins: []string{{"*"}}, + AllowMethods: []string{{"GET", "POST", "PUT", "DELETE", "OPTIONS"}}, + AllowHeaders: []string{{"Origin", "Content-Type", "Authorization"}}, + ExposeHeaders: []string{{"Content-Length"}}, + AllowCredentials: false, + MaxAge: 12 * time.Hour, + }})) + + // 健康检查 + r.GET("/api/health", func(c *gin.Context) {{ + c.JSON(200, gin.H{{ + "status": "ok", + "message": "Welcome to {project_name} API", + }}) + }}) + + addr := ":8080" + log.Printf("🚀 Gin 服务启动: http://localhost%s", addr) + log.Printf("📍 健康检查: http://localhost%s/api/health", addr) + + if err := r.Run(addr); err != nil {{ + log.Fatalf("启动失败: %v", err) + }} +}} +''', encoding='utf-8') + + # 整理依赖 + run_command_with_progress("go mod tidy", backend_dir, "整理 Go 依赖") + + print("\n✅ Go Gin 后端项目初始化成功") + print("💡 启动命令: go run main.go") diff --git a/backend/java_spring.py b/backend/java_spring.py new file mode 100644 index 0000000..81bd3d7 --- /dev/null +++ b/backend/java_spring.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +""" +Java Spring Boot 后端项目初始化模块 +""" + + +def init_spring_project(backend_dir, project_name): + """初始化 Spring Boot 项目""" + print("\n🚀 初始化 Spring Boot 项目...") + + # 创建基本的 Spring Boot 项目结构 + src_main = backend_dir / "src" / "main" + src_main_java = src_main / "java" / "com" / project_name.replace("-", "") + src_main_resources = src_main / "resources" + + src_main_java.mkdir(parents=True, exist_ok=True) + src_main_resources.mkdir(parents=True, exist_ok=True) + + # 创建主应用类 + package_name = project_name.replace("-", "") + app_java = src_main_java / "Application.java" + app_java.write_text(f'''package com.{package_name}; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.CrossOrigin; +import java.util.HashMap; +import java.util.Map; + +@SpringBootApplication +@RestController +@CrossOrigin(origins = "*") +public class Application {{ + + public static void main(String[] args) {{ + System.out.println("🚀 服务器启动: http://localhost:8080"); + System.out.println("📍 健康检查: http://localhost:8080/api/health"); + SpringApplication.run(Application.class, args); + }} + + @GetMapping("/api/health") + public Map health() {{ + Map response = new HashMap<>(); + response.put("status", "ok"); + response.put("message", "Welcome to {project_name} API"); + return response; + }} +}} +''', encoding='utf-8') + + # 创建 application.properties + app_properties = src_main_resources / "application.properties" + app_properties.write_text(f'''server.port=8080 +spring.application.name={project_name} +''', encoding='utf-8') + + # 创建 pom.xml + pom_xml = backend_dir / "pom.xml" + pom_xml.write_text(f''' + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.0 + + + + com.{package_name} + {project_name}-backend + 0.0.1-SNAPSHOT + {project_name} + + + 17 + + + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + +''', encoding='utf-8') + + print("\n✅ Spring Boot 项目初始化成功") + print("💡 启动命令: mvn spring-boot:run") + print("⚠️ 注意: 需要安装 Maven 和 JDK 17+ 才能运行此项目") diff --git a/backend/js_express.py b/backend/js_express.py new file mode 100644 index 0000000..f9aba16 --- /dev/null +++ b/backend/js_express.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +""" +JavaScript Express.js 后端项目初始化模块 +""" + +import subprocess +import sys + + +def run_command_with_progress(cmd, cwd, description): + """运行命令并显示实时输出""" + try: + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + + process = subprocess.Popen( + cmd, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0 + ) + + for line in process.stdout: + try: + decoded_line = line.decode('utf-8', errors='replace') + except: + try: + decoded_line = line.decode('gbk', errors='replace') + except: + decoded_line = line.decode('latin-1', errors='replace') + print(decoded_line, end='') + + process.wait() + + if process.returncode == 0: + print(f"\n{'=' * 60}") + print(f"✅ {description} - 完成") + print(f"{'=' * 60}\n") + return True + else: + print(f"\n{'=' * 60}") + print(f"❌ {description} - 失败 (错误码: {process.returncode})") + print(f"{'=' * 60}\n") + return False + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def init_express_project(backend_dir, project_name): + """初始化 Express.js 项目""" + print("\n🚀 初始化 Express.js 项目...") + + # 初始化 npm 项目 + success = run_command_with_progress( + "npm init -y", + backend_dir, + "初始化 npm 项目" + ) + + if not success: + print("\n💡 提示: 请确保已安装 Node.js 和 npm") + print(" 下载地址: https://nodejs.org/") + sys.exit(1) + + # 安装依赖 + run_command_with_progress( + "npm install express cors", + backend_dir, + "安装 Express.js 依赖" + ) + + # 安装开发依赖 + run_command_with_progress( + "npm install -D nodemon", + backend_dir, + "安装开发依赖 (nodemon)" + ) + + # 创建 app.js + app_js = backend_dir / "app.js" + app_js.write_text(f'''const express = require('express'); +const cors = require('cors'); + +const app = express(); +const PORT = 8080; + +// 中间件 +app.use(cors()); +app.use(express.json()); + +// 健康检查接口 +app.get('/api/health', (req, res) => {{ + res.json({{ + status: 'ok', + message: 'Welcome to {project_name} API' + }}); +}}); + +// 示例接口 +app.get('/api/hello', (req, res) => {{ + res.json({{ message: 'Hello from Express.js!' }}); +}}); + +// 启动服务器 +app.listen(PORT, () => {{ + console.log('🚀 服务器启动: http://localhost:' + PORT); + console.log('📍 健康检查: http://localhost:' + PORT + '/api/health'); +}}); +''', encoding='utf-8') + + # 更新 package.json 添加脚本 + package_json = backend_dir / "package.json" + import json + pkg = json.loads(package_json.read_text(encoding='utf-8')) + pkg['scripts'] = { + 'start': 'node app.js', + 'dev': 'nodemon app.js' + } + pkg['name'] = f'{project_name}-backend' + package_json.write_text(json.dumps(pkg, indent=2, ensure_ascii=False), encoding='utf-8') + + print("\n✅ Express.js 项目初始化成功") + print("💡 启动命令: npm run dev (开发模式) 或 npm start (生产模式)") diff --git a/backend/js_nestjs.py b/backend/js_nestjs.py new file mode 100644 index 0000000..1fcf3a5 --- /dev/null +++ b/backend/js_nestjs.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +""" +JavaScript NestJS 后端项目初始化模块 +""" + +import subprocess +import sys +import shutil + + +def run_command_interactive(cmd, cwd, description): + """运行命令并支持用户交互""" + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + print(f"💡 提示: 此步骤可能需要您进行交互操作") + print(f"{'=' * 60}\n") + + try: + result = subprocess.run(cmd, cwd=cwd, shell=True) + + print(f"\n{'=' * 60}") + if result.returncode == 0: + print(f"✅ {description} - 完成") + else: + print(f"❌ {description} - 失败 (错误码: {result.returncode})") + print(f"{'=' * 60}\n") + + return result.returncode == 0 + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def run_command_with_progress(cmd, cwd, description): + """运行命令并显示实时输出""" + try: + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + + process = subprocess.Popen( + cmd, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0 + ) + + for line in process.stdout: + try: + decoded_line = line.decode('utf-8', errors='replace') + except: + try: + decoded_line = line.decode('gbk', errors='replace') + except: + decoded_line = line.decode('latin-1', errors='replace') + print(decoded_line, end='') + + process.wait() + + if process.returncode == 0: + print(f"\n{'=' * 60}") + print(f"✅ {description} - 完成") + print(f"{'=' * 60}\n") + return True + else: + print(f"\n{'=' * 60}") + print(f"❌ {description} - 失败 (错误码: {process.returncode})") + print(f"{'=' * 60}\n") + return False + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def init_nestjs_project(backend_dir, project_name): + """初始化 NestJS 项目""" + print("\n🚀 初始化 NestJS 项目...") + print("\n⚠️ 重要提示:") + print(" 1. NestJS CLI 会询问使用哪个包管理器,建议选择 npm") + print(" 2. 创建过程可能需要几分钟,请耐心等待\n") + + # 删除空目录,因为 NestJS CLI 需要创建目录 + backend_dir.rmdir() + + # 使用 NestJS CLI 创建项目 + success = run_command_interactive( + f"npx @nestjs/cli new {backend_dir.name} --skip-git", + backend_dir.parent, + "创建 NestJS 项目" + ) + + if not success: + # 如果失败,重新创建目录 + backend_dir.mkdir(exist_ok=True) + print("\n💡 提示: 请确保已安装 Node.js 和 npm") + print(" 下载地址: https://nodejs.org/") + sys.exit(1) + + # 检查目录是否创建成功 + if not backend_dir.exists(): + print("❌ 项目目录创建失败") + sys.exit(1) + + # 修改默认端口为 8080 并添加 CORS + main_ts = backend_dir / "src" / "main.ts" + if main_ts.exists(): + main_ts.write_text(f'''import {{ NestFactory }} from '@nestjs/core'; +import {{ AppModule }} from './app.module'; + +async function bootstrap() {{ + const app = await NestFactory.create(AppModule); + + // 启用 CORS + app.enableCors(); + + // 设置全局前缀 + app.setGlobalPrefix('api'); + + await app.listen(8080); + console.log('🚀 服务器启动: http://localhost:8080'); + console.log('📍 健康检查: http://localhost:8080/api/health'); +}} +bootstrap(); +''', encoding='utf-8') + + # 修改 AppController 添加健康检查 + app_controller = backend_dir / "src" / "app.controller.ts" + if app_controller.exists(): + app_controller.write_text(f'''import {{ Controller, Get }} from '@nestjs/common'; +import {{ AppService }} from './app.service'; + +@Controller() +export class AppController {{ + constructor(private readonly appService: AppService) {{}} + + @Get('health') + health() {{ + return {{ + status: 'ok', + message: 'Welcome to {project_name} API', + }}; + }} + + @Get('hello') + getHello(): string {{ + return this.appService.getHello(); + }} +}} +''', encoding='utf-8') + + print("\n✅ NestJS 项目初始化成功") + print("💡 启动命令: npm run start:dev (开发模式) 或 npm run start (生产模式)") + print("📚 NestJS 文档: https://docs.nestjs.com/") diff --git a/backend/python_django.py b/backend/python_django.py new file mode 100644 index 0000000..76e6564 --- /dev/null +++ b/backend/python_django.py @@ -0,0 +1,206 @@ +# -*- coding: utf-8 -*- +""" +Python Django 后端项目初始化模块 +""" + +import subprocess +import sys + + +def run_command_with_progress(cmd, cwd, description): + """运行命令并显示实时输出""" + try: + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + + process = subprocess.Popen( + cmd, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0 + ) + + for line in process.stdout: + try: + decoded_line = line.decode('utf-8', errors='replace') + except: + try: + decoded_line = line.decode('gbk', errors='replace') + except: + decoded_line = line.decode('latin-1', errors='replace') + print(decoded_line, end='') + + process.wait() + + if process.returncode == 0: + print(f"\n{'=' * 60}") + print(f"✅ {description} - 完成") + print(f"{'=' * 60}\n") + return True + else: + print(f"\n{'=' * 60}") + print(f"❌ {description} - 失败 (错误码: {process.returncode})") + print(f"{'=' * 60}\n") + return False + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def init_django_project(backend_dir, project_name): + """初始化 Django 项目""" + print("\n🚀 初始化 Django 项目...") + + # 创建虚拟环境 + success = run_command_with_progress( + f'"{sys.executable}" -m venv venv', + backend_dir, + "创建 Python 虚拟环境" + ) + + if not success: + print("\n⚠️ 虚拟环境创建失败,请检查 Python 安装") + return + + venv_python = backend_dir / "venv" / "Scripts" / "python.exe" + venv_pip = backend_dir / "venv" / "Scripts" / "pip.exe" + + if not venv_python.exists(): + print("\n⚠️ 虚拟环境创建失败") + return + + # 安装 Django 和 CORS 支持 + run_command_with_progress( + f'"{venv_pip}" install django django-cors-headers', + backend_dir, + "安装 Django 依赖" + ) + + # 使用 django-admin 创建项目 + django_admin = backend_dir / "venv" / "Scripts" / "django-admin.exe" + run_command_with_progress( + f'"{django_admin}" startproject config .', + backend_dir, + "创建 Django 项目" + ) + + # 创建 api 应用 + run_command_with_progress( + f'"{venv_python}" manage.py startapp api', + backend_dir, + "创建 api 应用" + ) + + # 创建 requirements.txt + requirements = backend_dir / "requirements.txt" + requirements.write_text('''Django==5.0.0 +django-cors-headers==4.3.0 +''', encoding='utf-8') + + # 修改 settings.py 添加 CORS 和 api 应用 + settings_file = backend_dir / "config" / "settings.py" + if settings_file.exists(): + settings_content = settings_file.read_text(encoding='utf-8') + + # 添加 INSTALLED_APPS + settings_content = settings_content.replace( + "INSTALLED_APPS = [", + """INSTALLED_APPS = [ + 'corsheaders', + 'api',""" + ) + + # 添加 MIDDLEWARE + settings_content = settings_content.replace( + "MIDDLEWARE = [", + """MIDDLEWARE = [ + 'corsheaders.middleware.CorsMiddleware',""" + ) + + # 添加 CORS 配置 + settings_content += """ + +# CORS 配置 +CORS_ALLOW_ALL_ORIGINS = True + +# 允许的请求头 +CORS_ALLOW_HEADERS = [ + 'accept', + 'accept-encoding', + 'authorization', + 'content-type', + 'dnt', + 'origin', + 'user-agent', + 'x-csrftoken', + 'x-requested-with', +] +""" + settings_file.write_text(settings_content, encoding='utf-8') + + # 创建 api/views.py + api_views = backend_dir / "api" / "views.py" + api_views.write_text(f'''from django.http import JsonResponse + + +def health(request): + """健康检查接口""" + return JsonResponse({{ + 'status': 'ok', + 'message': 'Welcome to {project_name} API' + }}) + + +def hello(request): + """示例接口""" + return JsonResponse({{ + 'message': 'Hello from Django!' + }}) +''', encoding='utf-8') + + # 创建 api/urls.py + api_urls = backend_dir / "api" / "urls.py" + api_urls.write_text('''from django.urls import path +from . import views + +urlpatterns = [ + path('health', views.health, name='health'), + path('hello', views.hello, name='hello'), +] +''', encoding='utf-8') + + # 修改主 urls.py + main_urls = backend_dir / "config" / "urls.py" + main_urls.write_text('''from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path('admin/', admin.site.urls), + path('api/', include('api.urls')), +] +''', encoding='utf-8') + + # 创建启动脚本 run.py + run_py = backend_dir / "run.py" + run_py.write_text('''#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") + print("🚀 服务器启动: http://localhost:8080") + print("📍 健康检查: http://localhost:8080/api/health") + print("🔧 管理后台: http://localhost:8080/admin/") + + from django.core.management import execute_from_command_line + execute_from_command_line(["manage.py", "runserver", "0.0.0.0:8080"]) +''', encoding='utf-8') + + print("\n✅ Django 项目初始化成功") + print("💡 启动命令: venv\\Scripts\\python run.py") + print("🔧 管理后台: http://localhost:8080/admin/") + print("📝 提示: 首次运行前执行 venv\\Scripts\\python manage.py migrate") diff --git a/backend/python_fastapi.py b/backend/python_fastapi.py new file mode 100644 index 0000000..955438b --- /dev/null +++ b/backend/python_fastapi.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +""" +Python FastAPI 后端项目初始化模块 +""" + +import subprocess +import sys + + +def run_command_with_progress(cmd, cwd, description): + """运行命令并显示实时输出""" + try: + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + + process = subprocess.Popen( + cmd, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0 + ) + + for line in process.stdout: + try: + decoded_line = line.decode('utf-8', errors='replace') + except: + try: + decoded_line = line.decode('gbk', errors='replace') + except: + decoded_line = line.decode('latin-1', errors='replace') + print(decoded_line, end='') + + process.wait() + + if process.returncode == 0: + print(f"\n{'=' * 60}") + print(f"✅ {description} - 完成") + print(f"{'=' * 60}\n") + return True + else: + print(f"\n{'=' * 60}") + print(f"❌ {description} - 失败 (错误码: {process.returncode})") + print(f"{'=' * 60}\n") + return False + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def init_fastapi_project(backend_dir, project_name): + """初始化 FastAPI 项目""" + print("\n🚀 初始化 FastAPI 项目...") + + # 创建 main.py + main_py = backend_dir / "main.py" + main_py.write_text(f'''from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +import uvicorn + +app = FastAPI(title="{project_name} API") + +# 允许跨域 +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +@app.get("/api/health") +async def health(): + return {{ + "status": "ok", + "message": "Welcome to {project_name} API" + }} + +if __name__ == "__main__": + print("🚀 服务器启动: http://localhost:8080") + print("📍 健康检查: http://localhost:8080/api/health") + print("📚 API文档: http://localhost:8080/docs") + uvicorn.run(app, host="0.0.0.0", port=8080) +''', encoding='utf-8') + + # 创建 requirements.txt + requirements = backend_dir / "requirements.txt" + requirements.write_text('''fastapi==0.109.0 +uvicorn[standard]==0.27.0 +''', encoding='utf-8') + + # 创建虚拟环境并安装依赖 + success = run_command_with_progress( + f'"{sys.executable}" -m venv venv', + backend_dir, + "创建 Python 虚拟环境" + ) + + if success: + venv_python = backend_dir / "venv" / "Scripts" / "python.exe" + if venv_python.exists(): + success = run_command_with_progress( + f'"{venv_python}" -m pip install -r requirements.txt', + backend_dir, + "安装 FastAPI 依赖" + ) + + if success: + print("\n✅ FastAPI 项目初始化成功") + print("💡 启动命令: venv\\Scripts\\python main.py") + print("📚 API文档: http://localhost:8080/docs") + else: + print("\n⚠️ FastAPI 项目创建成功,但依赖安装失败") + print(f" 请手动运行: cd {project_name}-backend && venv\\Scripts\\pip install -r requirements.txt") + else: + print("\n⚠️ 虚拟环境创建失败,请检查 Python 安装") diff --git a/backend/python_flask.py b/backend/python_flask.py new file mode 100644 index 0000000..65d38f6 --- /dev/null +++ b/backend/python_flask.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +""" +Python Flask 后端项目初始化模块 +""" + +import subprocess +import sys + + +def run_command_with_progress(cmd, cwd, description): + """运行命令并显示实时输出""" + try: + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + + process = subprocess.Popen( + cmd, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0 + ) + + for line in process.stdout: + try: + decoded_line = line.decode('utf-8', errors='replace') + except: + try: + decoded_line = line.decode('gbk', errors='replace') + except: + decoded_line = line.decode('latin-1', errors='replace') + print(decoded_line, end='') + + process.wait() + + if process.returncode == 0: + print(f"\n{'=' * 60}") + print(f"✅ {description} - 完成") + print(f"{'=' * 60}\n") + return True + else: + print(f"\n{'=' * 60}") + print(f"❌ {description} - 失败 (错误码: {process.returncode})") + print(f"{'=' * 60}\n") + return False + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def init_flask_project(backend_dir, project_name): + """初始化 Flask 项目""" + print("\n🚀 初始化 Flask 项目...") + + # 创建 app.py + app_py = backend_dir / "app.py" + app_py.write_text(f'''from flask import Flask, jsonify +from flask_cors import CORS + +app = Flask(__name__) +CORS(app) # 允许跨域 + +@app.route('/api/health', methods=['GET']) +def health(): + return jsonify({{ + 'status': 'ok', + 'message': 'Welcome to {project_name} API' + }}) + +if __name__ == '__main__': + print("🚀 服务器启动: http://localhost:8080") + print("📍 健康检查: http://localhost:8080/api/health") + app.run(debug=True, host='0.0.0.0', port=8080) +''', encoding='utf-8') + + # 创建 requirements.txt + requirements = backend_dir / "requirements.txt" + requirements.write_text('''Flask==3.0.0 +flask-cors==4.0.0 +''', encoding='utf-8') + + # 创建虚拟环境并安装依赖 + success = run_command_with_progress( + f'"{sys.executable}" -m venv venv', + backend_dir, + "创建 Python 虚拟环境" + ) + + if success: + venv_python = backend_dir / "venv" / "Scripts" / "python.exe" + if venv_python.exists(): + success = run_command_with_progress( + f'"{venv_python}" -m pip install -r requirements.txt', + backend_dir, + "安装 Flask 依赖" + ) + + if success: + print("\n✅ Flask 项目初始化成功") + print("💡 启动命令: venv\\Scripts\\python app.py") + else: + print("\n⚠️ Flask 项目创建成功,但依赖安装失败") + print(f" 请手动运行: cd {project_name}-backend && venv\\Scripts\\pip install -r requirements.txt") + else: + print("\n⚠️ 虚拟环境创建失败,请检查 Python 安装") diff --git a/directory.py b/directory.py new file mode 100644 index 0000000..2fcd03f --- /dev/null +++ b/directory.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +""" +目录管理模块 +""" + +import sys +import shutil +from pathlib import Path +from utils import get_script_dir + + +def create_directory_structure(project_name): + """创建项目目录结构""" + print(f"\n📁 创建项目目录: {project_name}") + + # 获取脚本所在目录 + script_dir = get_script_dir() + project_root = script_dir / project_name + + if project_root.exists(): + overwrite = input(f"⚠️ 项目目录 {project_name} 已存在,是否覆盖? (y/n): ").strip().lower() + if overwrite != 'y': + print("❌ 操作已取消") + sys.exit(0) + shutil.rmtree(project_root) + + # 创建主目录 + project_root.mkdir(exist_ok=True) + + # 创建前后端目录 + frontend_dir = project_root / f"{project_name}-frontend" + backend_dir = project_root / f"{project_name}-backend" + + frontend_dir.mkdir(exist_ok=True) + backend_dir.mkdir(exist_ok=True) + + print(f"✅ 目录创建成功: {project_root}") + + return project_root, frontend_dir, backend_dir diff --git a/frontend/__init__.py b/frontend/__init__.py new file mode 100644 index 0000000..4346605 --- /dev/null +++ b/frontend/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" +前端模块包 +""" + +from frontend.react import init_react_project +from frontend.vue import init_vue_project +from frontend.tailwind import setup_tailwind + +__all__ = ['init_react_project', 'init_vue_project', 'setup_tailwind'] diff --git a/frontend/react.py b/frontend/react.py new file mode 100644 index 0000000..cbeb440 --- /dev/null +++ b/frontend/react.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +""" +React 项目初始化模块 +""" + +import subprocess +import sys + + +def run_command_interactive(cmd, cwd, description): + """运行命令并支持用户交互""" + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + print(f"💡 提示: 此步骤需要您进行交互操作") + print(f"{'=' * 60}\n") + + try: + result = subprocess.run(cmd, cwd=cwd, shell=True) + + print(f"\n{'=' * 60}") + if result.returncode == 0: + print(f"✅ {description} - 完成") + else: + print(f"❌ {description} - 失败 (错误码: {result.returncode})") + print(f"{'=' * 60}\n") + + return result.returncode == 0 + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def run_command_with_progress(cmd, cwd, description): + """运行命令并显示实时输出""" + try: + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + + process = subprocess.Popen( + cmd, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0 + ) + + for line in process.stdout: + try: + decoded_line = line.decode('utf-8', errors='replace') + except: + try: + decoded_line = line.decode('gbk', errors='replace') + except: + decoded_line = line.decode('latin-1', errors='replace') + print(decoded_line, end='') + + process.wait() + + if process.returncode == 0: + print(f"\n{'=' * 60}") + print(f"✅ {description} - 完成") + print(f"{'=' * 60}\n") + return True + else: + print(f"\n{'=' * 60}") + print(f"❌ {description} - 失败 (错误码: {process.returncode})") + print(f"{'=' * 60}\n") + return False + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def init_react_project(frontend_dir, project_name): + """初始化 React 项目""" + print("\n🚀 初始化 React 项目...") + print("\n⚠️ 重要提示:") + print(" 1. 当询问 'Use rolldown-vite?' 时,建议选择 No") + print(" 2. 当询问 'Install and start now?' 时,请选择 No(否则会启动服务器)") + print(" 3. 我们会在之后单独安装依赖\n") + + # 删除空目录,因为 create-vite 需要在不存在的目录中创建 + frontend_dir.rmdir() + + # 使用 Vite 创建 React 项目 + cmd = f'npm create vite@latest {frontend_dir.name} -- --template react' + success = run_command_interactive(cmd, frontend_dir.parent, "创建 React 项目结构") + + if not success: + print("\n💡 提示: 请确保已安装 Node.js 和 npm") + print(" 下载地址: https://nodejs.org/") + sys.exit(1) + + # 检查目录是否创建成功 + if not frontend_dir.exists(): + print("❌ 项目目录创建失败") + sys.exit(1) + + # 检查是否已安装依赖 + node_modules = frontend_dir / "node_modules" + if not node_modules.exists(): + print("\n⏳ 开始安装依赖...") + success = run_command_with_progress("npm install", frontend_dir, "安装 React 项目依赖") + + if not success: + print("⚠️ 依赖安装失败,请稍后手动运行: cd {}-frontend && npm install".format(project_name)) + + print("\n✅ React 项目初始化成功") diff --git a/frontend/tailwind.py b/frontend/tailwind.py new file mode 100644 index 0000000..be303c4 --- /dev/null +++ b/frontend/tailwind.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- +""" +Tailwind CSS 配置模块 +""" + +import subprocess + + +def run_command_with_progress(cmd, cwd, description): + """运行命令并显示实时输出""" + try: + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + + process = subprocess.Popen( + cmd, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0 + ) + + for line in process.stdout: + try: + decoded_line = line.decode('utf-8', errors='replace') + except: + try: + decoded_line = line.decode('gbk', errors='replace') + except: + decoded_line = line.decode('latin-1', errors='replace') + print(decoded_line, end='') + + process.wait() + + if process.returncode == 0: + print(f"\n{'=' * 60}") + print(f"✅ {description} - 完成") + print(f"{'=' * 60}\n") + return True + else: + print(f"\n{'=' * 60}") + print(f"❌ {description} - 失败 (错误码: {process.returncode})") + print(f"{'=' * 60}\n") + return False + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def setup_tailwind(frontend_dir, framework): + """配置 Tailwind CSS""" + print("\n🎨 配置 Tailwind CSS...") + + # 安装 Tailwind 依赖 + success = run_command_with_progress( + "npm install -D tailwindcss postcss autoprefixer", + frontend_dir, + "安装 Tailwind CSS 依赖" + ) + + if not success: + print("⚠️ Tailwind 安装失败,请稍后手动安装") + return False + + # 初始化 Tailwind 配置 + run_command_with_progress( + "npx tailwindcss init -p", + frontend_dir, + "初始化 Tailwind 配置" + ) + + # 根据框架配置 tailwind.config.js + if framework == "react": + content_config = '"./index.html", "./src/**/*.{js,ts,jsx,tsx}"' + else: # vue + content_config = '"./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"' + + tailwind_config = frontend_dir / "tailwind.config.js" + tailwind_config.write_text(f'''/** @type {{import('tailwindcss').Config}} */ +export default {{ + content: [{content_config}], + theme: {{ + extend: {{}}, + }}, + plugins: [], +}} +''', encoding='utf-8') + + # 创建或修改 CSS 文件 + if framework == "react": + css_file = frontend_dir / "src" / "index.css" + else: # vue + css_file = frontend_dir / "src" / "style.css" + + # 在 CSS 文件开头添加 Tailwind 指令 + tailwind_directives = '''@tailwind base; +@tailwind components; +@tailwind utilities; + +''' + + if css_file.exists(): + original_css = css_file.read_text(encoding='utf-8') + css_file.write_text(tailwind_directives + original_css, encoding='utf-8') + else: + css_file.write_text(tailwind_directives, encoding='utf-8') + + # 创建示例组件展示 Tailwind + if framework == "react": + create_react_tailwind_example(frontend_dir) + else: + create_vue_tailwind_example(frontend_dir) + + print("\n✅ Tailwind CSS 配置成功") + print("💡 提示: 可以在组件中使用 Tailwind 类名了") + return True + + +def create_react_tailwind_example(frontend_dir): + """创建 React Tailwind 示例""" + app_jsx = frontend_dir / "src" / "App.jsx" + app_jsx.write_text('''function App() { + return ( +
+
+

+ 🚀 React + Tailwind +

+

+ 项目已成功初始化!Tailwind CSS 已配置完成。 +

+
+ + +
+
+
+ ) +} + +export default App +''', encoding='utf-8') + + +def create_vue_tailwind_example(frontend_dir): + """创建 Vue Tailwind 示例""" + app_vue = frontend_dir / "src" / "App.vue" + app_vue.write_text(''' + + + + +''', encoding='utf-8') diff --git a/frontend/vue.py b/frontend/vue.py new file mode 100644 index 0000000..2aecae4 --- /dev/null +++ b/frontend/vue.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +""" +Vue 项目初始化模块 +""" + +import subprocess +import sys + + +def run_command_interactive(cmd, cwd, description): + """运行命令并支持用户交互""" + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + print(f"💡 提示: 此步骤需要您进行交互操作") + print(f"{'=' * 60}\n") + + try: + result = subprocess.run(cmd, cwd=cwd, shell=True) + + print(f"\n{'=' * 60}") + if result.returncode == 0: + print(f"✅ {description} - 完成") + else: + print(f"❌ {description} - 失败 (错误码: {result.returncode})") + print(f"{'=' * 60}\n") + + return result.returncode == 0 + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def run_command_with_progress(cmd, cwd, description): + """运行命令并显示实时输出""" + try: + print(f"\n{'=' * 60}") + print(f"执行: {description}") + print(f"{'=' * 60}") + + process = subprocess.Popen( + cmd, + cwd=cwd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0 + ) + + for line in process.stdout: + try: + decoded_line = line.decode('utf-8', errors='replace') + except: + try: + decoded_line = line.decode('gbk', errors='replace') + except: + decoded_line = line.decode('latin-1', errors='replace') + print(decoded_line, end='') + + process.wait() + + if process.returncode == 0: + print(f"\n{'=' * 60}") + print(f"✅ {description} - 完成") + print(f"{'=' * 60}\n") + return True + else: + print(f"\n{'=' * 60}") + print(f"❌ {description} - 失败 (错误码: {process.returncode})") + print(f"{'=' * 60}\n") + return False + + except Exception as e: + print(f"\n❌ 执行失败: {str(e)}") + return False + + +def init_vue_project(frontend_dir, project_name): + """初始化 Vue 项目""" + print("\n🚀 初始化 Vue 项目...") + print("\n⚠️ 重要提示:") + print(" 1. 当询问 'Use rolldown-vite?' 时,建议选择 No") + print(" 2. 当询问 'Install and start now?' 时,请选择 No(否则会启动服务器)") + print(" 3. 我们会在之后单独安装依赖\n") + + # 删除空目录 + frontend_dir.rmdir() + + # 使用 Vite 创建 Vue 项目 + cmd = f'npm create vite@latest {frontend_dir.name} -- --template vue' + success = run_command_interactive(cmd, frontend_dir.parent, "创建 Vue 项目结构") + + if not success: + print("\n💡 提示: 请确保已安装 Node.js 和 npm") + print(" 下载地址: https://nodejs.org/") + sys.exit(1) + + # 检查目录是否创建成功 + if not frontend_dir.exists(): + print("❌ 项目目录创建失败") + sys.exit(1) + + # 检查是否已安装依赖 + node_modules = frontend_dir / "node_modules" + if not node_modules.exists(): + print("\n⏳ 开始安装依赖...") + success = run_command_with_progress("npm install", frontend_dir, "安装 Vue 项目依赖") + + if not success: + print("⚠️ 依赖安装失败,请稍后手动运行: cd {}-frontend && npm install".format(project_name)) + + print("\n✅ Vue 项目初始化成功") diff --git a/main.py b/main.py new file mode 100644 index 0000000..1874f16 --- /dev/null +++ b/main.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +前后端分离项目初始化脚本 - 主程序 +""" + +import sys +from utils import print_banner, get_project_name, select_frontend, select_backend, select_use_tailwind +from directory import create_directory_structure +from frontend import init_react_project, init_vue_project, setup_tailwind +from backend import ( + init_golang_project, + init_gin_project, + init_flask_project, + init_fastapi_project, + init_django_project, + init_spring_project, + init_express_project, + init_nestjs_project +) +from scripts import create_bat_scripts + + +def main(): + """主函数""" + print_banner() + + # 获取项目信息 + project_name = get_project_name() + frontend_type = select_frontend() + use_tailwind = select_use_tailwind() + backend_type = select_backend() + + # 创建目录结构 + project_root, frontend_dir, backend_dir = create_directory_structure(project_name) + + # 初始化前端项目 + if frontend_type == "react": + init_react_project(frontend_dir, project_name) + elif frontend_type == "vue": + init_vue_project(frontend_dir, project_name) + + # 配置 Tailwind CSS + if use_tailwind: + setup_tailwind(frontend_dir, frontend_type) + + # 初始化后端项目 + if backend_type == "golang": + init_golang_project(backend_dir, project_name) + elif backend_type == "gin": + init_gin_project(backend_dir, project_name) + elif backend_type == "flask": + init_flask_project(backend_dir, project_name) + elif backend_type == "fastapi": + init_fastapi_project(backend_dir, project_name) + elif backend_type == "django": + init_django_project(backend_dir, project_name) + elif backend_type == "spring": + init_spring_project(backend_dir, project_name) + elif backend_type == "express": + init_express_project(backend_dir, project_name) + elif backend_type == "nestjs": + init_nestjs_project(backend_dir, project_name) + + # 创建 BAT 脚本 + create_bat_scripts(project_root, project_name, frontend_type, backend_type) + + # 完成 + print("\n" + "=" * 60) + print("🎉 项目初始化完成!") + print("=" * 60) + print(f"\n📁 项目位置: {project_root}") + print(f" ├── {project_name}-frontend ({frontend_type.upper()})") + print(f" ├── {project_name}-backend ({backend_type.upper()})") + print(f" ├── 开启前端.bat") + print(f" ├── 开启后端.bat") + print(f" └── 构建前端.bat") + print("\n💡 使用说明:") + print(f" 1. 双击 '开启前端.bat' 启动前端开发服务器") + print(f" 2. 双击 '开启后端.bat' 启动后端服务") + print(f" 3. 双击 '构建前端.bat' 构建前端生产版本") + print("\n✨ 祝开发愉快!") + + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + print("\n\n❌ 操作已取消") + sys.exit(0) + except Exception as e: + print(f"\n❌ 发生错误: {e}") + import traceback + traceback.print_exc() + sys.exit(1) diff --git a/scripts.py b/scripts.py new file mode 100644 index 0000000..68ac134 --- /dev/null +++ b/scripts.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +""" +启动脚本生成模块 +""" + + +def create_bat_scripts(project_root, project_name, frontend_type, backend_type): + """创建启动脚本""" + print("\n📝 创建启动脚本...") + + # 前端启动命令 + frontend_start_cmd = "npm run dev" + + # 后端启动命令 + backend_start_commands = { + "golang": "go run main.go", + "gin": "go run main.go", + "flask": "venv\\Scripts\\python app.py", + "fastapi": "venv\\Scripts\\python main.py", + "django": "venv\\Scripts\\python run.py", + "spring": "mvn spring-boot:run", + "express": "npm run dev", + "nestjs": "npm run start:dev" + } + backend_start_cmd = backend_start_commands.get(backend_type, "echo 未知后端类型") + + # 1. 开启前端.bat + start_frontend = project_root / "开启前端.bat" + start_frontend.write_text(f'''@echo off +chcp 65001 >nul +echo ==================================== +echo 启动前端项目 ({frontend_type.upper()}) +echo ==================================== +cd {project_name}-frontend +{frontend_start_cmd} +pause +''', encoding='utf-8') + + # 2. 开启后端.bat + start_backend = project_root / "开启后端.bat" + start_backend.write_text(f'''@echo off +chcp 65001 >nul +echo ==================================== +echo 启动后端项目 ({backend_type.upper()}) +echo ==================================== +cd {project_name}-backend +{backend_start_cmd} +pause +''', encoding='utf-8') + + # 3. 构建前端.bat + build_frontend = project_root / "构建前端.bat" + build_frontend.write_text(f'''@echo off +chcp 65001 >nul +echo ==================================== +echo 构建前端项目 ({frontend_type.upper()}) +echo ==================================== +cd {project_name}-frontend +npm run build +echo. +echo ✅ 构建完成!输出目录: dist +pause +''', encoding='utf-8') + + print("✅ 启动脚本创建成功") diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..3b65a01 --- /dev/null +++ b/utils.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +""" +工具函数模块 +""" + +import sys +from pathlib import Path + + +def print_banner(): + """打印欢迎信息""" + print("=" * 60) + print(" 前后端分离项目初始化工具") + print("=" * 60) + print() + + +def get_project_name(): + """获取项目名称""" + while True: + project_name = input("请输入项目英文名(如 mengyaping): ").strip() + if project_name and project_name.replace("_", "").replace("-", "").isalnum(): + return project_name + print("❌ 项目名称无效,请使用英文字母、数字、下划线或短横线") + + +def select_frontend(): + """选择前端技术栈""" + print("\n📦 请选择前端技术栈:") + print("1. React") + print("2. Vue") + + while True: + choice = input("请输入选项 (1-2): ").strip() + if choice == "1": + return "react" + elif choice == "2": + return "vue" + print("❌ 无效选项,请重新输入") + + +def select_use_tailwind(): + """选择是否使用 Tailwind CSS""" + print("\n🎨 是否使用 Tailwind CSS?") + print("1. 是 (推荐)") + print("2. 否") + + while True: + choice = input("请输入选项 (1-2): ").strip() + if choice == "1": + return True + elif choice == "2": + return False + print("❌ 无效选项,请重新输入") + + +def select_backend(): + """选择后端技术栈""" + print("\n🔧 请选择后端技术栈:") + print("1. Go (标准库)") + print("2. Go (Gin)") + print("3. Python (Flask)") + print("4. Python (FastAPI)") + print("5. Python (Django)") + print("6. Java (Spring Boot)") + print("7. JavaScript (Express.js)") + print("8. JavaScript (NestJS)") + + while True: + choice = input("请输入选项 (1-8): ").strip() + if choice == "1": + return "golang" + elif choice == "2": + return "gin" + elif choice == "3": + return "flask" + elif choice == "4": + return "fastapi" + elif choice == "5": + return "django" + elif choice == "6": + return "spring" + elif choice == "7": + return "express" + elif choice == "8": + return "nestjs" + print("❌ 无效选项,请重新输入") + + +def get_script_dir(): + """获取脚本所在目录""" + if getattr(sys, 'frozen', False): + # 打包后的exe + return Path(sys.executable).parent + else: + # 直接运行的py文件 + return Path(__file__).parent