@agile-team/robot-cli 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +443 -0
- package/bin/index.js +341 -0
- package/lib/cache.js +120 -0
- package/lib/create.js +946 -0
- package/lib/download.js +191 -0
- package/lib/templates.js +355 -0
- package/lib/utils.js +344 -0
- package/package.json +82 -0
package/lib/download.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// lib/download.js - 修复版本
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import fetch from 'node-fetch';
|
|
6
|
+
import extract from 'extract-zip';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
|
|
13
|
+
// 缓存目录
|
|
14
|
+
const CACHE_DIR = path.join(os.homedir(), '.robot-cli', 'cache');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 下载模板
|
|
18
|
+
* @param {Object} template - 模板配置
|
|
19
|
+
* @param {Object} options - 选项
|
|
20
|
+
* @returns {string} - 模板路径
|
|
21
|
+
*/
|
|
22
|
+
export async function downloadTemplate(template, options = {}) {
|
|
23
|
+
const { useCache = true, spinner } = options;
|
|
24
|
+
|
|
25
|
+
// 验证模板参数
|
|
26
|
+
if (!template) {
|
|
27
|
+
throw new Error('模板参数不能为空');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!template.key && !template.repo) {
|
|
31
|
+
throw new Error(`模板配置无效: ${JSON.stringify(template)}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 获取缓存键值,优先使用 key,其次使用 repo 的最后部分
|
|
35
|
+
const cacheKey = template.key || template.repo?.split('/').pop() || 'unknown-template';
|
|
36
|
+
const cachePath = path.join(CACHE_DIR, cacheKey);
|
|
37
|
+
|
|
38
|
+
// 检查缓存
|
|
39
|
+
if (useCache && fs.existsSync(cachePath)) {
|
|
40
|
+
if (spinner) {
|
|
41
|
+
spinner.text = '📂 使用缓存模板...';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 验证缓存完整性
|
|
45
|
+
const packageJsonPath = path.join(cachePath, 'package.json');
|
|
46
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
47
|
+
return cachePath;
|
|
48
|
+
} else {
|
|
49
|
+
// 缓存损坏,删除重新下载
|
|
50
|
+
if (spinner) {
|
|
51
|
+
spinner.text = '🔄 缓存损坏,重新下载...';
|
|
52
|
+
}
|
|
53
|
+
await fs.remove(cachePath);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 如果是本地测试模板,直接返回缓存路径
|
|
58
|
+
if (template.localTest || !template.repo) {
|
|
59
|
+
if (fs.existsSync(cachePath)) {
|
|
60
|
+
return cachePath;
|
|
61
|
+
} else {
|
|
62
|
+
throw new Error([
|
|
63
|
+
'本地测试模板不存在',
|
|
64
|
+
'',
|
|
65
|
+
chalk.red.bold('问题描述:'),
|
|
66
|
+
` 测试模板路径不存在: ${cachePath}`,
|
|
67
|
+
'',
|
|
68
|
+
chalk.green.bold('解决方案:'),
|
|
69
|
+
' 1. 运行测试环境设置: npm run test:setup',
|
|
70
|
+
' 2. 或创建测试缓存: npm run test',
|
|
71
|
+
' 3. 检查模板是否正确创建',
|
|
72
|
+
'',
|
|
73
|
+
chalk.blue.bold('可用命令:'),
|
|
74
|
+
' npm run test:setup --setup # 创建完整测试环境',
|
|
75
|
+
' npm run test:clean # 清理测试环境'
|
|
76
|
+
].join('\n'));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 下载远程模板
|
|
81
|
+
if (spinner) {
|
|
82
|
+
spinner.text = '📥 从 ' + template.repo + ' 下载最新模板...';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const downloadUrl = 'https://github.com/' + template.repo + '/archive/refs/heads/main.zip';
|
|
87
|
+
const tempZipPath = path.join(os.tmpdir(), cacheKey + '-' + Date.now() + '.zip');
|
|
88
|
+
const tempExtractPath = path.join(os.tmpdir(), cacheKey + '-extract-' + Date.now());
|
|
89
|
+
|
|
90
|
+
// 检查网络连接
|
|
91
|
+
if (spinner) {
|
|
92
|
+
spinner.text = '🌐 检查网络连接...';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 下载zip文件
|
|
96
|
+
const response = await fetch(downloadUrl, {
|
|
97
|
+
timeout: 30000, // 30秒超时
|
|
98
|
+
headers: {
|
|
99
|
+
'User-Agent': 'Robot-CLI/1.0.0'
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (spinner) {
|
|
108
|
+
spinner.text = '📦 下载中...';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const buffer = await response.buffer();
|
|
112
|
+
await fs.writeFile(tempZipPath, buffer);
|
|
113
|
+
|
|
114
|
+
if (spinner) {
|
|
115
|
+
spinner.text = '📂 解压模板文件...';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 解压文件
|
|
119
|
+
await extract(tempZipPath, { dir: tempExtractPath });
|
|
120
|
+
|
|
121
|
+
// 找到解压后的项目目录 (通常是 reponame-main/)
|
|
122
|
+
const extractedItems = await fs.readdir(tempExtractPath);
|
|
123
|
+
const projectDir = extractedItems.find(item =>
|
|
124
|
+
item.endsWith('-main') || item.endsWith('-master')
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (!projectDir) {
|
|
128
|
+
throw new Error(`解压后找不到项目目录,可用目录: ${extractedItems.join(', ')}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const sourcePath = path.join(tempExtractPath, projectDir);
|
|
132
|
+
|
|
133
|
+
// 验证模板完整性
|
|
134
|
+
const packageJsonPath = path.join(sourcePath, 'package.json');
|
|
135
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
136
|
+
throw new Error(`模板缺少 package.json 文件`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 确保缓存目录存在
|
|
140
|
+
await fs.ensureDir(CACHE_DIR);
|
|
141
|
+
|
|
142
|
+
// 移动到缓存目录
|
|
143
|
+
if (fs.existsSync(cachePath)) {
|
|
144
|
+
await fs.remove(cachePath);
|
|
145
|
+
}
|
|
146
|
+
await fs.move(sourcePath, cachePath);
|
|
147
|
+
|
|
148
|
+
// 清理临时文件
|
|
149
|
+
await fs.remove(tempZipPath).catch(() => {});
|
|
150
|
+
await fs.remove(tempExtractPath).catch(() => {});
|
|
151
|
+
|
|
152
|
+
return cachePath;
|
|
153
|
+
|
|
154
|
+
} catch (error) {
|
|
155
|
+
// 清理可能的临时文件
|
|
156
|
+
try {
|
|
157
|
+
const tempFiles = await fs.readdir(os.tmpdir());
|
|
158
|
+
const robotTempFiles = tempFiles.filter(file =>
|
|
159
|
+
file.includes(cacheKey) && (file.endsWith('.zip') || file.includes('extract'))
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
for (const file of robotTempFiles) {
|
|
163
|
+
await fs.remove(path.join(os.tmpdir(), file)).catch(() => {});
|
|
164
|
+
}
|
|
165
|
+
} catch (cleanupError) {
|
|
166
|
+
// 忽略清理错误
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// 网络相关错误处理
|
|
170
|
+
if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
|
|
171
|
+
throw new Error(`网络连接失败: 无法连接到 GitHub\n请检查网络连接或稍后重试`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (error.code === 'ETIMEDOUT' || error.type === 'request-timeout') {
|
|
175
|
+
throw new Error(`下载超时: 模板文件较大或网络较慢\n请稍后重试或使用 --no-cache 选项`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 重新抛出错误,保持原始错误信息
|
|
179
|
+
throw new Error(`模板下载失败: ${error.message}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 清除所有缓存
|
|
185
|
+
*/
|
|
186
|
+
export async function clearCache() {
|
|
187
|
+
if (fs.existsSync(CACHE_DIR)) {
|
|
188
|
+
await fs.remove(CACHE_DIR);
|
|
189
|
+
}
|
|
190
|
+
await fs.ensureDir(CACHE_DIR);
|
|
191
|
+
}
|
package/lib/templates.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
// lib/templates.js - 统一Robot命名风格
|
|
2
|
+
export const TEMPLATE_CATEGORIES = {
|
|
3
|
+
frontend: {
|
|
4
|
+
name: '🎨 前端项目',
|
|
5
|
+
stacks: {
|
|
6
|
+
vue: {
|
|
7
|
+
name: 'Vue.js',
|
|
8
|
+
patterns: {
|
|
9
|
+
monolith: {
|
|
10
|
+
name: '单体应用',
|
|
11
|
+
templates: {
|
|
12
|
+
'robot-admin': {
|
|
13
|
+
name: 'Robot Admin 完整版',
|
|
14
|
+
description: '包含30+完整示例、权限管理、图表组件、最佳实践等等',
|
|
15
|
+
repo: 'ChenyCHENYU/Robot_Admin',
|
|
16
|
+
features: ['Naive UI', 'Vue Router', 'Pinia', '权限管理', '动态路由', '图表组件', '性能优化等等'],
|
|
17
|
+
version: 'full',
|
|
18
|
+
localTest: true // 标记为测试模板
|
|
19
|
+
},
|
|
20
|
+
'robot-admin-base': {
|
|
21
|
+
name: 'Robot Admin 精简版',
|
|
22
|
+
description: '基础架构、核心功能、快速启动',
|
|
23
|
+
repo: 'ChenyCHENYU/Robot_Admin_Base',
|
|
24
|
+
features: ['Naive UI', 'Vue Router', 'Pinia', '基础布局'],
|
|
25
|
+
version: 'base',
|
|
26
|
+
localTest: true // 标记为测试模板
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
monorepo: {
|
|
31
|
+
name: 'Monorepo 架构',
|
|
32
|
+
templates: {
|
|
33
|
+
'robot-monorepo': {
|
|
34
|
+
name: 'Robot Monorepo 完整版',
|
|
35
|
+
description: 'bun workspace + 多包管理 + 共享组件库',
|
|
36
|
+
repo: 'ChenyCHENYU/Robot_Monorepo',
|
|
37
|
+
features: ['bun workspace', 'shared components', 'build tools', 'CI/CD'],
|
|
38
|
+
version: 'full'
|
|
39
|
+
},
|
|
40
|
+
'robot-monorepo-base': {
|
|
41
|
+
name: 'Robot Monorepo 精简版',
|
|
42
|
+
description: '基础 monorepo 结构 + 核心配置',
|
|
43
|
+
repo: 'ChenyCHENYU/Robot_Monorepo_Base',
|
|
44
|
+
features: ['bun workspace', 'basic structure'],
|
|
45
|
+
version: 'base'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
microfrontend: {
|
|
50
|
+
name: '微前端架构',
|
|
51
|
+
templates: {
|
|
52
|
+
'robot-micro': {
|
|
53
|
+
name: 'Robot微前端 完整版',
|
|
54
|
+
description: 'MicroApp + Vite插件模块联邦 + 多应用示例',
|
|
55
|
+
repo: 'ChenyCHENYU/Robot_Micro',
|
|
56
|
+
features: ['MicroApp', 'Vite模块联邦', '多应用', '路由共享'],
|
|
57
|
+
version: 'full'
|
|
58
|
+
},
|
|
59
|
+
'robot-micro-base': {
|
|
60
|
+
name: 'Robot微前端 精简版',
|
|
61
|
+
description: '基础 MicroApp 架构 + 主子应用',
|
|
62
|
+
repo: 'ChenyCHENYU/Robot_Micro_Base',
|
|
63
|
+
features: ['MicroApp', '基础配置'],
|
|
64
|
+
version: 'base'
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
react: {
|
|
71
|
+
name: 'React.js',
|
|
72
|
+
patterns: {
|
|
73
|
+
monolith: {
|
|
74
|
+
name: '单体应用',
|
|
75
|
+
templates: {
|
|
76
|
+
'robot-react': {
|
|
77
|
+
name: 'Robot React 完整版',
|
|
78
|
+
description: 'Ant Design + 完整功能演示',
|
|
79
|
+
repo: 'ChenyCHENYU/Robot_React',
|
|
80
|
+
features: ['Ant Design', 'React Router', 'Redux Toolkit'],
|
|
81
|
+
version: 'full'
|
|
82
|
+
},
|
|
83
|
+
'robot-react-base': {
|
|
84
|
+
name: 'Robot React 精简版',
|
|
85
|
+
description: '基础React + 核心功能',
|
|
86
|
+
repo: 'ChenyCHENYU/Robot_React_Base',
|
|
87
|
+
features: ['React', 'React Router', '基础组件'],
|
|
88
|
+
version: 'base'
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
mobile: {
|
|
97
|
+
name: '📱 移动端项目',
|
|
98
|
+
stacks: {
|
|
99
|
+
uniapp: {
|
|
100
|
+
name: 'uni-app',
|
|
101
|
+
patterns: {
|
|
102
|
+
multiplatform: {
|
|
103
|
+
name: '多端应用',
|
|
104
|
+
templates: {
|
|
105
|
+
'robot-uniapp': {
|
|
106
|
+
name: 'Robot uni-app 完整版',
|
|
107
|
+
description: '多端适配 + 插件市场 + 完整示例',
|
|
108
|
+
repo: 'ChenyCHENYU/Robot_Uniapp',
|
|
109
|
+
features: ['多端发布', 'uView UI', '插件集成'],
|
|
110
|
+
version: 'full'
|
|
111
|
+
},
|
|
112
|
+
'robot-uniapp-base': {
|
|
113
|
+
name: 'Robot uni-app 精简版',
|
|
114
|
+
description: '基础框架 + 核心功能',
|
|
115
|
+
repo: 'ChenyCHENYU/Robot_Uniapp_Base',
|
|
116
|
+
features: ['基础框架', '路由配置'],
|
|
117
|
+
version: 'base'
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
tarao: {
|
|
124
|
+
name: 'Tarao',
|
|
125
|
+
patterns: {
|
|
126
|
+
native: {
|
|
127
|
+
name: '原生应用',
|
|
128
|
+
templates: {
|
|
129
|
+
'robot-tarao': {
|
|
130
|
+
name: 'Robot Tarao 完整版',
|
|
131
|
+
description: '原生性能 + 跨平台 + 完整功能(暂无,后续完善)',
|
|
132
|
+
repo: 'ChenyCHENYU/Robot_Tarao',
|
|
133
|
+
features: ['原生性能', '跨平台', '完整功能'],
|
|
134
|
+
version: 'full',
|
|
135
|
+
status: 'coming-soon'
|
|
136
|
+
},
|
|
137
|
+
'robot-tarao-base': {
|
|
138
|
+
name: 'Robot Tarao 精简版',
|
|
139
|
+
description: '基础 Tarao 框架(暂无,后续完善)',
|
|
140
|
+
repo: 'ChenyCHENYU/Robot_Tarao_Base',
|
|
141
|
+
features: ['基础框架', '核心功能'],
|
|
142
|
+
version: 'base',
|
|
143
|
+
status: 'coming-soon'
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
backend: {
|
|
152
|
+
name: '🚀 后端项目',
|
|
153
|
+
stacks: {
|
|
154
|
+
nestjs: {
|
|
155
|
+
name: 'NestJS',
|
|
156
|
+
patterns: {
|
|
157
|
+
api: {
|
|
158
|
+
name: 'API服务',
|
|
159
|
+
templates: {
|
|
160
|
+
'robot-nest': {
|
|
161
|
+
name: 'Robot NestJS 完整版',
|
|
162
|
+
description: 'NestJS + TypeORM + JWT + Swagger + Redis + 完整生态',
|
|
163
|
+
repo: 'ChenyCHENYU/Robot_Nest',
|
|
164
|
+
features: ['NestJS', 'TypeORM', 'JWT认证', 'ApiFox文档', 'Redis', '微服务'],
|
|
165
|
+
version: 'full'
|
|
166
|
+
},
|
|
167
|
+
'robot-nest-base': {
|
|
168
|
+
name: 'Robot NestJS 精简版',
|
|
169
|
+
description: '基础 NestJS + 核心模块',
|
|
170
|
+
repo: 'ChenyCHENYU/Robot_Nest_Base',
|
|
171
|
+
features: ['NestJS', '基础路由', '错误处理'],
|
|
172
|
+
version: 'base'
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
microservice: {
|
|
177
|
+
name: '微服务架构',
|
|
178
|
+
templates: {
|
|
179
|
+
'robot-nest-micro': {
|
|
180
|
+
name: 'Robot NestJS微服务版',
|
|
181
|
+
description: 'NestJS + 微服务架构 + gRPC + 服务发现',
|
|
182
|
+
repo: 'ChenyCHENYU/Robot_Nest_Micro',
|
|
183
|
+
features: ['NestJS', '微服务', 'gRPC', 'Redis', '服务发现'],
|
|
184
|
+
version: 'micro'
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
koa: {
|
|
191
|
+
name: 'Koa3',
|
|
192
|
+
patterns: {
|
|
193
|
+
api: {
|
|
194
|
+
name: 'API服务',
|
|
195
|
+
templates: {
|
|
196
|
+
'robot-koa': {
|
|
197
|
+
name: 'Robot Koa3 完整版',
|
|
198
|
+
description: 'Koa3 + TypeScript + JWT + 数据库 + 中间件',
|
|
199
|
+
repo: 'ChenyCHENYU/Robot_Koa',
|
|
200
|
+
features: ['Koa3', 'TypeScript', 'JWT认证', 'MySQL', '中间件'],
|
|
201
|
+
version: 'full'
|
|
202
|
+
},
|
|
203
|
+
'robot-koa-base': {
|
|
204
|
+
name: 'Robot Koa3 精简版',
|
|
205
|
+
description: '基础Koa3 + 核心中间件',
|
|
206
|
+
repo: 'ChenyCHENYU/Robot_Koa_Base',
|
|
207
|
+
features: ['Koa3', '基础路由', '错误处理'],
|
|
208
|
+
version: 'base'
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
desktop: {
|
|
217
|
+
name: '💻 桌面端项目',
|
|
218
|
+
stacks: {
|
|
219
|
+
electron: {
|
|
220
|
+
name: 'Electron',
|
|
221
|
+
patterns: {
|
|
222
|
+
desktop: {
|
|
223
|
+
name: '桌面应用',
|
|
224
|
+
templates: {
|
|
225
|
+
'robot-electron': {
|
|
226
|
+
name: 'Robot Electron 完整版',
|
|
227
|
+
description: 'Vue3 + Electron + 自动更新 + 原生能力',
|
|
228
|
+
repo: 'ChenyCHENYU/Robot_Electron',
|
|
229
|
+
features: ['Vue3', 'Electron', '自动更新', '原生API'],
|
|
230
|
+
version: 'full'
|
|
231
|
+
},
|
|
232
|
+
'robot-electron-base': {
|
|
233
|
+
name: 'Robot Electron 精简版',
|
|
234
|
+
description: '基础Electron + Vue框架',
|
|
235
|
+
repo: 'ChenyCHENYU/Robot_Electron_Base',
|
|
236
|
+
features: ['Vue3', 'Electron', '基础功能'],
|
|
237
|
+
version: 'base'
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
tauri: {
|
|
244
|
+
name: 'Tauri',
|
|
245
|
+
patterns: {
|
|
246
|
+
desktop: {
|
|
247
|
+
name: '桌面应用',
|
|
248
|
+
templates: {
|
|
249
|
+
'robot-tauri': {
|
|
250
|
+
name: 'Robot Tauri 完整版',
|
|
251
|
+
description: 'Rust后端 + Vue前端 + 原生性能',
|
|
252
|
+
repo: 'ChenyCHENYU/Robot_Tauri',
|
|
253
|
+
features: ['Tauri', 'Vue3', 'Rust backend', '原生性能'],
|
|
254
|
+
version: 'full'
|
|
255
|
+
},
|
|
256
|
+
'robot-tauri-base': {
|
|
257
|
+
name: 'Robot Tauri 精简版',
|
|
258
|
+
description: '基础Tauri + Vue框架',
|
|
259
|
+
repo: 'ChenyCHENYU/Robot_Tauri_Base',
|
|
260
|
+
features: ['Tauri', 'Vue3', '基础功能'],
|
|
261
|
+
version: 'base'
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* 获取所有模板的扁平化列表
|
|
273
|
+
*/
|
|
274
|
+
export function getAllTemplates() {
|
|
275
|
+
const templates = {};
|
|
276
|
+
|
|
277
|
+
Object.values(TEMPLATE_CATEGORIES).forEach(category => {
|
|
278
|
+
Object.values(category.stacks).forEach(stack => {
|
|
279
|
+
Object.values(stack.patterns).forEach(pattern => {
|
|
280
|
+
Object.assign(templates, pattern.templates);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
return templates;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* 根据分类获取模板
|
|
290
|
+
*/
|
|
291
|
+
export function getTemplatesByCategory(categoryKey, stackKey, patternKey) {
|
|
292
|
+
const category = TEMPLATE_CATEGORIES[categoryKey];
|
|
293
|
+
if (!category) return {};
|
|
294
|
+
|
|
295
|
+
const stack = category.stacks[stackKey];
|
|
296
|
+
if (!stack) return {};
|
|
297
|
+
|
|
298
|
+
const pattern = stack.patterns[patternKey];
|
|
299
|
+
if (!pattern) return {};
|
|
300
|
+
|
|
301
|
+
return pattern.templates;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* 搜索模板
|
|
306
|
+
*/
|
|
307
|
+
export function searchTemplates(keyword) {
|
|
308
|
+
const allTemplates = getAllTemplates();
|
|
309
|
+
const results = {};
|
|
310
|
+
|
|
311
|
+
Object.entries(allTemplates).forEach(([key, template]) => {
|
|
312
|
+
const searchText = `${template.name} ${template.description} ${template.features.join(' ')}`.toLowerCase();
|
|
313
|
+
if (searchText.includes(keyword.toLowerCase())) {
|
|
314
|
+
results[key] = template;
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
return results;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* 获取推荐模板(基于使用频率或团队偏好)- 统一Robot命名
|
|
323
|
+
*/
|
|
324
|
+
export function getRecommendedTemplates() {
|
|
325
|
+
const allTemplates = getAllTemplates();
|
|
326
|
+
const recommended = {};
|
|
327
|
+
|
|
328
|
+
// 使用统一的Robot命名风格
|
|
329
|
+
const recommendedKeys = [
|
|
330
|
+
'robot-admin', // Vue后台管理 - 最常用
|
|
331
|
+
'robot-uniapp', // 移动端开发 - 跨平台
|
|
332
|
+
'robot-nest', // 后端API - 企业级
|
|
333
|
+
'robot-electron', // 桌面应用 - 全栈
|
|
334
|
+
'robot-react', // React项目 - 前端选择
|
|
335
|
+
'robot-koa' // 轻量后端 - 快速开发
|
|
336
|
+
];
|
|
337
|
+
|
|
338
|
+
recommendedKeys.forEach(key => {
|
|
339
|
+
if (allTemplates[key]) {
|
|
340
|
+
recommended[key] = allTemplates[key];
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// 如果没有找到足够的推荐模板,补充一些
|
|
345
|
+
if (Object.keys(recommended).length < 4) {
|
|
346
|
+
const availableKeys = Object.keys(allTemplates);
|
|
347
|
+
for (const key of availableKeys) {
|
|
348
|
+
if (!recommended[key] && Object.keys(recommended).length < 6) {
|
|
349
|
+
recommended[key] = allTemplates[key];
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return recommended;
|
|
355
|
+
}
|