578 lines
13 KiB
Rust
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(())
|
|
}
|