NAC_Blockchain/nac-webdev-init/src/generator.rs

578 lines
13 KiB
Rust

use anyhow::{Context, Result};
use colored::*;
use std::fs;
use std::path::{Path, PathBuf};
use crate::template;
pub fn generate_project(name: &str, template_name: &str, output_dir: &Path) -> Result<()> {
// 验证模板存在
let template = template::get_template(template_name)
.ok_or_else(|| anyhow::anyhow!("模板 '{}' 不存在", template_name))?;
println!("📝 使用模板: {}", template.name.bright_green());
println!("📂 创建目录: {}", output_dir.display().to_string().bright_yellow());
// 创建项目目录
fs::create_dir_all(output_dir)
.context("创建项目目录失败")?;
// 根据模板类型生成不同的项目结构
match template_name {
"wallet" => generate_wallet_project(name, output_dir)?,
"exchange" => generate_exchange_project(name, output_dir)?,
_ => generate_standard_project(name, template_name, output_dir)?,
}
Ok(())
}
fn generate_wallet_project(name: &str, output_dir: &Path) -> Result<()> {
println!("💼 生成NAC钱包项目...");
// 创建目录结构
create_dir_structure(output_dir, &[
"src",
"src/components",
"src/hooks",
"src/utils",
"src/services",
"src/stores",
"public",
])?;
// 生成package.json
let package_json = format!(r#"{{
"name": "{}",
"version": "1.0.0",
"type": "module",
"scripts": {{
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}},
"dependencies": {{
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.0",
"@tanstack/react-query": "^5.0.0",
"zustand": "^4.4.0",
"axios": "^1.6.0"
}},
"devDependencies": {{
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@vitejs/plugin-react": "^4.2.0",
"vite": "^5.0.0",
"typescript": "^5.3.0"
}}
}}
"#, name);
fs::write(output_dir.join("package.json"), package_json)?;
// 生成vite.config.js
let vite_config = r#"import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 3000
}
})
"#;
fs::write(output_dir.join("vite.config.js"), vite_config)?;
// 生成index.html
let index_html = format!(r#"<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{} - NAC钱包</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
"#, name);
fs::write(output_dir.join("index.html"), index_html)?;
// 生成src/main.jsx
let main_jsx = r#"import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
"#;
fs::write(output_dir.join("src/main.jsx"), main_jsx)?;
// 生成src/App.jsx
let app_jsx = r#"import { useState } from 'react'
import WalletConnector from './components/WalletConnector'
import './App.css'
function App() {
const [account, setAccount] = useState(null)
return (
<div className="app">
<header>
<h1>NAC 钱包</h1>
<WalletConnector onConnect={setAccount} />
</header>
{account && (
<main>
<div className="account-info">
<h2>账户信息</h2>
<p>地址: {account.address}</p>
<p>余额: {account.balance} XTZH</p>
</div>
</main>
)}
</div>
)
}
export default App
"#;
fs::write(output_dir.join("src/App.jsx"), app_jsx)?;
// 生成WalletConnector组件
let wallet_connector = r#"import { useState } from 'react'
export default function WalletConnector({ onConnect }) {
const [loading, setLoading] = useState(false)
const handleConnect = async () => {
setLoading(true)
try {
// TODO: 实现NAC钱包连接逻辑
const account = {
address: 'nac1...',
balance: '1000.00'
}
onConnect(account)
} catch (error) {
console.error('连接失败:', error)
} finally {
setLoading(false)
}
}
return (
<button onClick={handleConnect} disabled={loading}>
{loading ? '连接中...' : '连接钱包'}
</button>
)
}
"#;
fs::write(output_dir.join("src/components/WalletConnector.jsx"), wallet_connector)?;
// 生成CSS
let app_css = r#".app {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.account-info {
background: #f5f5f5;
padding: 1.5rem;
border-radius: 8px;
}
"#;
fs::write(output_dir.join("src/App.css"), app_css)?;
fs::write(output_dir.join("src/index.css"), "* { margin: 0; padding: 0; box-sizing: border-box; }")?;
// 生成README
let readme = format!(r#"# {} - NAC钱包
NAC原生公链钱包应用
## 功能特性
- 钱包连接与管理
- 资产查看与转账
- 交易历史记录
- 宪法收据验证
## 开发
```bash
npm install
npm run dev
```
## 构建
```bash
npm run build
```
"#, name);
fs::write(output_dir.join("README.md"), readme)?;
Ok(())
}
fn generate_exchange_project(name: &str, output_dir: &Path) -> Result<()> {
println!("🏦 生成RWA交易所项目...");
// 创建目录结构
create_dir_structure(output_dir, &[
"src",
"src/components",
"src/pages",
"src/hooks",
"src/utils",
"src/services",
"src/stores",
"public",
])?;
// 生成package.json
let package_json = format!(r#"{{
"name": "{}",
"version": "1.0.0",
"type": "module",
"scripts": {{
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}},
"dependencies": {{
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.0",
"@tanstack/react-query": "^5.0.0",
"zustand": "^4.4.0",
"axios": "^1.6.0",
"recharts": "^2.10.0"
}},
"devDependencies": {{
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@vitejs/plugin-react": "^4.2.0",
"vite": "^5.0.0",
"typescript": "^5.3.0"
}}
}}
"#, name);
fs::write(output_dir.join("package.json"), package_json)?;
// 生成vite.config.js
let vite_config = r#"import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
})
"#;
fs::write(output_dir.join("vite.config.js"), vite_config)?;
// 生成index.html
let index_html = format!(r#"<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{} - NAC RWA交易所</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
"#, name);
fs::write(output_dir.join("index.html"), index_html)?;
// 生成src/main.jsx
let main_jsx = r#"import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
)
"#;
fs::write(output_dir.join("src/main.jsx"), main_jsx)?;
// 生成src/App.jsx
let app_jsx = r#"import { Routes, Route } from 'react-router-dom'
import HomePage from './pages/HomePage'
import TradePage from './pages/TradePage'
import './App.css'
function App() {
return (
<div className="app">
<nav className="navbar">
<h1>NAC RWA交易所</h1>
<div className="nav-links">
<a href="/">首页</a>
<a href="/trade">交易</a>
</div>
</nav>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/trade" element={<TradePage />} />
</Routes>
</div>
)
}
export default App
"#;
fs::write(output_dir.join("src/App.jsx"), app_jsx)?;
// 生成HomePage
let home_page = r#"export default function HomePage() {
return (
<div className="home-page">
<h2>欢迎来到NAC RWA交易所</h2>
<p>全球首个RWA原生公链交易平台</p>
<div className="features">
<div className="feature-card">
<h3>资产上架</h3>
<p>一键将RWA资产上链交易</p>
</div>
<div className="feature-card">
<h3>碎片化交易</h3>
<p>支持资产碎片化,降低投资门槛</p>
</div>
<div className="feature-card">
<h3>跨链桥接</h3>
<p>多链资产互通,流动性最大化</p>
</div>
</div>
</div>
)
}
"#;
fs::write(output_dir.join("src/pages/HomePage.jsx"), home_page)?;
// 生成TradePage
let trade_page = r#"import { useState } from 'react'
export default function TradePage() {
const [orderType, setOrderType] = useState('buy')
const [amount, setAmount] = useState('')
const [price, setPrice] = useState('')
const handleSubmit = (e) => {
e.preventDefault()
console.log('提交订单:', { orderType, amount, price })
}
return (
<div className="trade-page">
<div className="order-book">
<h3>订单簿</h3>
{/* TODO: 实现订单簿 */}
</div>
<div className="trade-form">
<h3>下单</h3>
<form onSubmit={handleSubmit}>
<div className="order-type">
<button
type="button"
className={orderType === 'buy' ? 'active' : ''}
onClick={() => setOrderType('buy')}
>
买入
</button>
<button
type="button"
className={orderType === 'sell' ? 'active' : ''}
onClick={() => setOrderType('sell')}
>
卖出
</button>
</div>
<input
type="number"
placeholder="价格"
value={price}
onChange={(e) => setPrice(e.target.value)}
/>
<input
type="number"
placeholder="数量"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<button type="submit">
{orderType === 'buy' ? '买入' : '卖出'}
</button>
</form>
</div>
</div>
)
}
"#;
fs::write(output_dir.join("src/pages/TradePage.jsx"), trade_page)?;
// 生成CSS
let app_css = r#".app {
min-height: 100vh;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background: #1a1a1a;
color: white;
}
.nav-links a {
margin-left: 1.5rem;
color: white;
text-decoration: none;
}
.home-page {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.feature-card {
padding: 1.5rem;
background: #f5f5f5;
border-radius: 8px;
}
.trade-page {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 1.5rem;
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.trade-form form {
display: flex;
flex-direction: column;
gap: 1rem;
}
.order-type {
display: flex;
gap: 0.5rem;
}
.order-type button {
flex: 1;
padding: 0.75rem;
border: none;
background: #e0e0e0;
cursor: pointer;
}
.order-type button.active {
background: #4CAF50;
color: white;
}
"#;
fs::write(output_dir.join("src/App.css"), app_css)?;
fs::write(output_dir.join("src/index.css"), "* { margin: 0; padding: 0; box-sizing: border-box; }")?;
// 生成README
let readme = format!(r#"# {} - NAC RWA交易所
NAC原生公链RWA资产交易平台
## 功能特性
- 资产上架与交易
- 订单簿与撮合引擎
- 碎片化交易支持
- 跨链资产桥接
- 实时行情数据
## 开发
```bash
npm install
npm run dev
```
## 构建
```bash
npm run build
```
## API接口
后端API运行在 `http://localhost:8080`
主要接口:
- GET /api/assets - 获取资产列表
- GET /api/orderbook/:asset - 获取订单簿
- POST /api/orders - 创建订单
- GET /api/trades - 获取交易历史
"#, name);
fs::write(output_dir.join("README.md"), readme)?;
Ok(())
}
fn generate_standard_project(_name: &str, _template_name: &str, _output_dir: &Path) -> Result<()> {
// TODO: 实现标准模板生成
Ok(())
}
fn create_dir_structure(base: &Path, dirs: &[&str]) -> Result<()> {
for dir in dirs {
fs::create_dir_all(base.join(dir))?;
}
Ok(())
}