flu-cli 2.0.3 → 2.0.5
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/CHANGELOG.md +28 -6
- package/CLI.md +1 -0
- package/README.md +139 -67
- package/config/templates.js +6 -127
- package/index.js +100 -50
- package/lib/commands/add.js +8 -8
- package/lib/commands/assets.js +183 -0
- package/lib/commands/config.js +41 -1
- package/lib/commands/newClack.js +89 -116
- package/lib/commands/snippets.js +50 -9
- package/lib/commands/template.js +1 -1
- package/lib/templates/templateCopier.js +14 -275
- package/lib/templates/templateManager.js +20 -163
- package/lib/utils/config.js +13 -51
- package/lib/utils/flutterHelper.js +7 -82
- package/lib/utils/i18n.js +7 -0
- package/lib/utils/templateSelectorEnquirer.js +70 -43
- package/locales/en-US.json +59 -0
- package/locales/zh-CN.json +59 -0
- package/package.json +2 -2
- package/release.sh +380 -32
- package/scripts/sync-base-to-templates.js +6 -6
- package/scripts/workspace-clone-all.sh +4 -4
- package/scripts/workspace-status-all.sh +3 -3
- package/lib/generators/project_generator.js +0 -96
- package/lib/generators/state_manager_generator.js +0 -402
- package/templates/README.md +0 -138
- package/templates/base_files/base_list_page.dart.template +0 -174
- package/templates/base_files/base_list_viewmodel.dart.template +0 -134
- package/templates/base_files/base_page.dart.template +0 -251
- package/templates/base_files/base_viewmodel.dart.template +0 -77
- package/templates/base_files/theme/status_views_theme.dart.template +0 -46
- package/templates/snippets/dart.code-snippets +0 -392
package/index.js
CHANGED
|
@@ -4,19 +4,53 @@
|
|
|
4
4
|
* flu-cli v2.0
|
|
5
5
|
* Flutter MVVM 脚手架工具
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* 支持多种架构模板 and 代码生成功能
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
// ========== 加载 .env 文件 ==========
|
|
11
|
+
import { readFileSync, existsSync } from 'fs';
|
|
12
|
+
import { resolve } from 'path';
|
|
13
|
+
|
|
14
|
+
function loadEnvFile () {
|
|
15
|
+
try {
|
|
16
|
+
const envPath = resolve(process.cwd(), '.env');
|
|
17
|
+
if (existsSync(envPath)) {
|
|
18
|
+
const envContent = readFileSync(envPath, 'utf8');
|
|
19
|
+
const lines = envContent.split('\n');
|
|
20
|
+
|
|
21
|
+
for (const line of lines) {
|
|
22
|
+
const trimmed = line.trim();
|
|
23
|
+
// 跳过注释和空行
|
|
24
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
25
|
+
|
|
26
|
+
const [key, ...valueParts] = trimmed.split('=');
|
|
27
|
+
const value = valueParts.join('=').trim();
|
|
28
|
+
|
|
29
|
+
// 移除引号
|
|
30
|
+
const cleanValue = value.replace(/^["']|["']$/g, '');
|
|
31
|
+
|
|
32
|
+
// 只设置未定义的环境变量
|
|
33
|
+
if (!process.env[key]) {
|
|
34
|
+
process.env[key] = cleanValue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// 忽略加载错误
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
loadEnvFile();
|
|
44
|
+
|
|
10
45
|
import { program } from 'commander';
|
|
11
46
|
import chalk from 'chalk';
|
|
12
|
-
import { readFileSync } from 'fs';
|
|
13
47
|
import { fileURLToPath } from 'url';
|
|
14
48
|
import { dirname, join } from 'path';
|
|
15
49
|
import { newProjectWithClack } from './lib/commands/newClack.js';
|
|
16
50
|
import { addComponent } from './lib/commands/add.js';
|
|
17
51
|
import { listTemplates, showTemplateDetail } from './lib/commands/templates.js';
|
|
18
52
|
import { updateTemplates, cleanCache } from './lib/commands/cache.js';
|
|
19
|
-
|
|
53
|
+
import { t } from './lib/utils/i18n.js';
|
|
20
54
|
|
|
21
55
|
// 获取 package.json
|
|
22
56
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -25,10 +59,9 @@ const packageJson = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'ut
|
|
|
25
59
|
// 设置版本和描述
|
|
26
60
|
program
|
|
27
61
|
.version(packageJson.version)
|
|
28
|
-
.description(chalk.cyan('
|
|
62
|
+
.description(chalk.cyan(t('cli.description')));
|
|
29
63
|
|
|
30
64
|
// ========== 创建项目命令(V1 已废弃) ==========
|
|
31
|
-
// V1 命令已移除,请使用 'flu new' 命令
|
|
32
65
|
program
|
|
33
66
|
.command('create')
|
|
34
67
|
.description('⚠️ 已废弃:请使用 flu new 命令')
|
|
@@ -36,11 +69,6 @@ program
|
|
|
36
69
|
console.log(chalk.yellow('\n⚠️ create 命令已在 V2 中废弃\n'));
|
|
37
70
|
console.log(chalk.cyan('请使用新命令:'));
|
|
38
71
|
console.log(chalk.green(' flu new <project-name>\n'));
|
|
39
|
-
console.log(chalk.gray('示例:'));
|
|
40
|
-
console.log(chalk.gray(' flu new my_app --template lite'));
|
|
41
|
-
console.log(chalk.gray(' flu new my_app --template modular'));
|
|
42
|
-
console.log(chalk.gray(' flu new my_app --template clean\n'));
|
|
43
|
-
console.log(chalk.blue('查看帮助:flu new --help\n'));
|
|
44
72
|
process.exit(0);
|
|
45
73
|
});
|
|
46
74
|
|
|
@@ -48,12 +76,16 @@ program
|
|
|
48
76
|
program
|
|
49
77
|
.command('new [project-name]')
|
|
50
78
|
.alias('n')
|
|
51
|
-
.description('
|
|
52
|
-
.option('-t, --template <type>', '
|
|
53
|
-
.option('-s, --state <type>', '
|
|
54
|
-
.option('-d, --dir <path>', '
|
|
55
|
-
.option('--
|
|
56
|
-
.option('--
|
|
79
|
+
.description(t('cmd.new.desc'))
|
|
80
|
+
.option('-t, --template <type>', t('cmd.new.opt.template'))
|
|
81
|
+
.option('-s, --state <type>', t('cmd.new.opt.state'), 'default')
|
|
82
|
+
.option('-d, --dir <path>', t('cmd.new.opt.dir'), process.cwd())
|
|
83
|
+
.option('-p, --package <name>', '指定包名 (e.g., com.example.myapp)')
|
|
84
|
+
.option('-a, --author <name>', '指定作者名称')
|
|
85
|
+
.option('--no-cache', t('cmd.new.opt.no_cache'))
|
|
86
|
+
.option('--no-network', '不包含网络层(默认包含)')
|
|
87
|
+
.option('--remote', t('cmd.new.opt.remote'))
|
|
88
|
+
.option('--flutter-template <type>', 'Flutter official template (app, module, package, plugin)', 'app')
|
|
57
89
|
.action((projectName, options) => {
|
|
58
90
|
newProjectWithClack(projectName, options);
|
|
59
91
|
});
|
|
@@ -62,14 +94,14 @@ program
|
|
|
62
94
|
program
|
|
63
95
|
.command('add [type] [name]')
|
|
64
96
|
.alias('a')
|
|
65
|
-
.description(
|
|
66
|
-
.option('-f, --feature <name>', '
|
|
67
|
-
.option('--stateful', '
|
|
68
|
-
.option('--stateless', '
|
|
69
|
-
.option('--list-page',
|
|
70
|
-
.option('--no-vm', '
|
|
71
|
-
.option('--json <file>', '
|
|
72
|
-
.option('--list', '
|
|
97
|
+
.description(t('cmd.add.desc'))
|
|
98
|
+
.option('-f, --feature <name>', t('cmd.add.opt.feature'))
|
|
99
|
+
.option('--stateful', t('cmd.add.opt.stateful'))
|
|
100
|
+
.option('--stateless', t('cmd.add.opt.stateless'))
|
|
101
|
+
.option('--list-page', t('cmd.add.opt.list_page'))
|
|
102
|
+
.option('--no-vm', t('cmd.add.opt.no_vm'))
|
|
103
|
+
.option('--json <file>', t('cmd.add.opt.json'))
|
|
104
|
+
.option('--list', t('cmd.add.opt.list'))
|
|
73
105
|
.action((type, name, options) => {
|
|
74
106
|
addComponent(type, name, options);
|
|
75
107
|
});
|
|
@@ -78,7 +110,7 @@ program
|
|
|
78
110
|
program
|
|
79
111
|
.command('templates [template-name]')
|
|
80
112
|
.alias('t')
|
|
81
|
-
.description('
|
|
113
|
+
.description(t('cmd.templates.desc'))
|
|
82
114
|
.action((templateName) => {
|
|
83
115
|
if (templateName) {
|
|
84
116
|
showTemplateDetail(templateName);
|
|
@@ -87,15 +119,13 @@ program
|
|
|
87
119
|
}
|
|
88
120
|
});
|
|
89
121
|
|
|
90
|
-
// generate-sm 命令已移除
|
|
91
|
-
|
|
92
122
|
// ========== 缓存管理命令 ==========
|
|
93
123
|
program
|
|
94
124
|
.command('update-templates [template-name]')
|
|
95
125
|
.alias('update')
|
|
96
126
|
.alias('u')
|
|
97
|
-
.description('
|
|
98
|
-
.option('--force', '
|
|
127
|
+
.description(t('cmd.update.desc'))
|
|
128
|
+
.option('--force', t('cmd.update.opt.force'))
|
|
99
129
|
.action((templateName, options) => {
|
|
100
130
|
updateTemplates(templateName, options);
|
|
101
131
|
});
|
|
@@ -103,7 +133,7 @@ program
|
|
|
103
133
|
program
|
|
104
134
|
.command('cache <action>')
|
|
105
135
|
.alias('c')
|
|
106
|
-
.description(
|
|
136
|
+
.description(t('cmd.cache.desc'))
|
|
107
137
|
.action((action) => {
|
|
108
138
|
if (action === 'clean') {
|
|
109
139
|
cleanCache();
|
|
@@ -113,13 +143,25 @@ program
|
|
|
113
143
|
}
|
|
114
144
|
});
|
|
115
145
|
|
|
146
|
+
// ========== 应用资源管理 ==========
|
|
147
|
+
import { configAssets } from './lib/commands/assets.js';
|
|
148
|
+
|
|
149
|
+
program
|
|
150
|
+
.command('assets')
|
|
151
|
+
.alias('as')
|
|
152
|
+
.description(t('cmd.assets.desc'))
|
|
153
|
+
.option('-d, --dir <path>', t('cmd.new.opt.dir'), process.cwd())
|
|
154
|
+
.action((options) => {
|
|
155
|
+
configAssets(options);
|
|
156
|
+
});
|
|
157
|
+
|
|
116
158
|
// ========== 代码片段管理 ==========
|
|
117
159
|
import { syncSnippets } from './lib/commands/snippets.js';
|
|
118
160
|
|
|
119
161
|
program
|
|
120
162
|
.command('sync-snippets')
|
|
121
163
|
.alias('sync')
|
|
122
|
-
.description('
|
|
164
|
+
.description(t('cmd.sync.desc'))
|
|
123
165
|
.action(() => {
|
|
124
166
|
syncSnippets();
|
|
125
167
|
});
|
|
@@ -128,35 +170,34 @@ program
|
|
|
128
170
|
import { listAllTemplates, addTemplate, removeTemplate } from './lib/commands/template.js';
|
|
129
171
|
|
|
130
172
|
const templateCmd = program.command('template');
|
|
131
|
-
|
|
132
173
|
templateCmd
|
|
133
|
-
.description('
|
|
174
|
+
.description(t('cmd.template.desc'))
|
|
134
175
|
.action(() => {
|
|
135
176
|
listAllTemplates();
|
|
136
177
|
});
|
|
137
178
|
|
|
138
179
|
templateCmd
|
|
139
180
|
.command('list')
|
|
140
|
-
.description('
|
|
181
|
+
.description(t('cmd.template.list.desc'))
|
|
141
182
|
.action(() => {
|
|
142
183
|
listAllTemplates();
|
|
143
184
|
});
|
|
144
185
|
|
|
145
186
|
templateCmd
|
|
146
187
|
.command('add <id> <source>')
|
|
147
|
-
.description(
|
|
148
|
-
.option('--local',
|
|
149
|
-
.option('-n, --name <name>', '
|
|
150
|
-
.option('-b, --branch <branch>',
|
|
151
|
-
.option('-d, --description <text>', '
|
|
152
|
-
.option('-f, --force', '
|
|
188
|
+
.description(t('cmd.template.add.desc'))
|
|
189
|
+
.option('--local', t('cmd.template.add.opt.local'))
|
|
190
|
+
.option('-n, --name <name>', t('cmd.template.add.opt.name'))
|
|
191
|
+
.option('-b, --branch <branch>', t('cmd.template.add.opt.branch'))
|
|
192
|
+
.option('-d, --description <text>', t('cmd.template.add.opt.desc'))
|
|
193
|
+
.option('-f, --force', t('cmd.template.add.opt.force'))
|
|
153
194
|
.action((id, source, options) => {
|
|
154
195
|
addTemplate(id, source, options);
|
|
155
196
|
});
|
|
156
197
|
|
|
157
198
|
templateCmd
|
|
158
199
|
.command('remove <id>')
|
|
159
|
-
.description('
|
|
200
|
+
.description(t('cmd.template.remove.desc'))
|
|
160
201
|
.action((id) => {
|
|
161
202
|
removeTemplate(id);
|
|
162
203
|
});
|
|
@@ -167,37 +208,46 @@ import { completion } from './lib/commands/completion.js';
|
|
|
167
208
|
program
|
|
168
209
|
.command('completion')
|
|
169
210
|
.alias('comp')
|
|
170
|
-
.description(
|
|
211
|
+
.description(t('cmd.completion.desc'))
|
|
171
212
|
.action(() => {
|
|
172
213
|
completion();
|
|
173
214
|
});
|
|
174
215
|
|
|
175
|
-
|
|
176
216
|
// ========== 配置管理命令 ==========
|
|
177
|
-
import { initConfig } from './lib/commands/config.js';
|
|
217
|
+
import { initConfig, setConfig, getConfig } from './lib/commands/config.js';
|
|
178
218
|
|
|
179
219
|
const configCmd = program.command('config');
|
|
180
|
-
|
|
181
220
|
configCmd
|
|
182
|
-
.description('
|
|
221
|
+
.description(t('cmd.config.desc'))
|
|
183
222
|
.action(() => {
|
|
184
223
|
configCmd.help();
|
|
185
224
|
});
|
|
186
225
|
|
|
187
226
|
configCmd
|
|
188
227
|
.command('init')
|
|
189
|
-
.description(
|
|
190
|
-
.option('-d, --dir <path>', '
|
|
228
|
+
.description(t('cmd.config.init.desc'))
|
|
229
|
+
.option('-d, --dir <path>', t('cmd.new.opt.dir'), process.cwd())
|
|
191
230
|
.option('-f, --force', '覆盖已存在的配置文件')
|
|
192
231
|
.action((options) => {
|
|
193
232
|
initConfig(options);
|
|
194
233
|
});
|
|
195
234
|
|
|
235
|
+
configCmd
|
|
236
|
+
.command('set <key> <value>')
|
|
237
|
+
.description('Set global configuration (e.g., locale)')
|
|
238
|
+
.action((key, value) => {
|
|
239
|
+
setConfig(key, value);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
configCmd
|
|
243
|
+
.command('get [key]')
|
|
244
|
+
.description('Get global configuration')
|
|
245
|
+
.action((key) => {
|
|
246
|
+
getConfig(key);
|
|
247
|
+
});
|
|
196
248
|
|
|
197
|
-
// 解析命令行参数
|
|
198
249
|
program.parse(process.argv);
|
|
199
250
|
|
|
200
|
-
// 如果没有提供命令,显示帮助信息
|
|
201
251
|
if (process.argv.length === 2) {
|
|
202
252
|
console.log(chalk.bold.cyan('\n🚀 欢迎使用 flu-cli v2.0\n'));
|
|
203
253
|
program.help({ error: false });
|
package/lib/commands/add.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
generateModel,
|
|
13
13
|
generateComponent,
|
|
14
14
|
generateModule
|
|
15
|
-
} from '
|
|
15
|
+
} from 'flu-cli-core';
|
|
16
16
|
|
|
17
17
|
const logger = new ConsoleLogger();
|
|
18
18
|
|
|
@@ -162,7 +162,7 @@ async function addPage (name, options) {
|
|
|
162
162
|
logger.info(`不生成 ViewModel`);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
const success = generatePage(name, {
|
|
165
|
+
const success = await generatePage(name, {
|
|
166
166
|
feature,
|
|
167
167
|
stateful: finalStateful,
|
|
168
168
|
stateless: finalStateless,
|
|
@@ -209,7 +209,7 @@ async function addWidget (name, options) {
|
|
|
209
209
|
logger.info(`类型: StatefulWidget`);
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
const success = generateWidget(name, {
|
|
212
|
+
const success = await generateWidget(name, {
|
|
213
213
|
feature,
|
|
214
214
|
stateful,
|
|
215
215
|
outputDir: process.cwd()
|
|
@@ -234,7 +234,7 @@ async function addComponentItem (name, options) {
|
|
|
234
234
|
logger.info(`功能模块: ${feature}`);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
const success = generateComponent(name, {
|
|
237
|
+
const success = await generateComponent(name, {
|
|
238
238
|
feature,
|
|
239
239
|
outputDir: options.outputDir || process.cwd()
|
|
240
240
|
}, logger);
|
|
@@ -258,7 +258,7 @@ async function addViewModel (name, options) {
|
|
|
258
258
|
logger.info(`功能模块: ${feature}`);
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
const success = generateViewModel(name, {
|
|
261
|
+
const success = await generateViewModel(name, {
|
|
262
262
|
feature,
|
|
263
263
|
outputDir: process.cwd()
|
|
264
264
|
}, logger);
|
|
@@ -282,7 +282,7 @@ async function addService (name, options) {
|
|
|
282
282
|
logger.info(`功能模块: ${feature}`);
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
const success = generateService(name, {
|
|
285
|
+
const success = await generateService(name, {
|
|
286
286
|
feature,
|
|
287
287
|
outputDir: process.cwd()
|
|
288
288
|
}, logger);
|
|
@@ -386,7 +386,7 @@ async function addModel (name, options) {
|
|
|
386
386
|
logger.info(`从 JSON 文件生成: ${json}`);
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
const success = generateModel(name, {
|
|
389
|
+
const success = await generateModel(name, {
|
|
390
390
|
feature,
|
|
391
391
|
jsonFile: options.json || json,
|
|
392
392
|
jsonData,
|
|
@@ -405,7 +405,7 @@ async function addModel (name, options) {
|
|
|
405
405
|
async function addModule (name, options) {
|
|
406
406
|
logger.info(`生成模块: ${name}`);
|
|
407
407
|
|
|
408
|
-
const success = generateModule(name, {
|
|
408
|
+
const success = await generateModule(name, {
|
|
409
409
|
outputDir: options.outputDir || process.cwd()
|
|
410
410
|
});
|
|
411
411
|
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { existsSync } from 'fs';
|
|
5
|
+
import { AppAssetsManager, ConsoleLogger } from 'flu-cli-core';
|
|
6
|
+
import { t } from '../utils/i18n.js';
|
|
7
|
+
|
|
8
|
+
const logger = new ConsoleLogger();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 交互式配置应用资源
|
|
12
|
+
*/
|
|
13
|
+
export async function configAssets (options) {
|
|
14
|
+
const projectPath = options.dir || process.cwd();
|
|
15
|
+
|
|
16
|
+
// 检查是否在 Flutter 项目中
|
|
17
|
+
if (!existsSync(join(projectPath, 'pubspec.yaml'))) {
|
|
18
|
+
logger.error(t('assets.not_flutter'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
p.intro(chalk.cyan.bold(t('assets.intro')));
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const assets = {};
|
|
26
|
+
|
|
27
|
+
// 1. 配置应用图标
|
|
28
|
+
const setupIcon = await p.confirm({
|
|
29
|
+
message: t('assets.setup_icon'),
|
|
30
|
+
initialValue: true
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (p.isCancel(setupIcon)) {
|
|
34
|
+
p.cancel(t('common.cancel'));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (setupIcon) {
|
|
39
|
+
const iconPath = await p.text({
|
|
40
|
+
message: t('assets.icon_path'),
|
|
41
|
+
placeholder: 'assets/logo.png',
|
|
42
|
+
validate: (value) => {
|
|
43
|
+
if (!value) return '路径不能为空';
|
|
44
|
+
if (!existsSync(join(projectPath, value)) && !existsSync(value)) {
|
|
45
|
+
return '找不到该文件,请确认路径是否正确';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (p.isCancel(iconPath)) {
|
|
51
|
+
p.cancel(t('common.cancel'));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
assets.appIcon = iconPath;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 2. 配置启动图
|
|
58
|
+
const setupSplash = await p.confirm({
|
|
59
|
+
message: t('assets.setup_splash'),
|
|
60
|
+
initialValue: true
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (p.isCancel(setupSplash)) {
|
|
64
|
+
p.cancel(t('common.cancel'));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (setupSplash) {
|
|
69
|
+
const splashLogo = await p.text({
|
|
70
|
+
message: t('assets.splash_logo'),
|
|
71
|
+
placeholder: 'assets/logo.png',
|
|
72
|
+
validate: (value) => {
|
|
73
|
+
if (!value) return '路径不能为空';
|
|
74
|
+
if (!existsSync(join(projectPath, value)) && !existsSync(value)) {
|
|
75
|
+
return '找不到该文件,请确认路径是否正确';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (p.isCancel(splashLogo)) {
|
|
81
|
+
p.cancel(t('common.cancel'));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
assets.splashLogo = splashLogo;
|
|
85
|
+
|
|
86
|
+
const bgColor = await p.text({
|
|
87
|
+
message: t('assets.bg_color'),
|
|
88
|
+
placeholder: '#FFFFFF',
|
|
89
|
+
initialValue: '#FFFFFF'
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (p.isCancel(bgColor)) {
|
|
93
|
+
p.cancel(t('common.cancel'));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
assets.splashBackgroundColor = bgColor;
|
|
97
|
+
|
|
98
|
+
const useBgImage = await p.confirm({
|
|
99
|
+
message: t('assets.use_bg_image'),
|
|
100
|
+
initialValue: false
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (p.isCancel(useBgImage)) {
|
|
104
|
+
p.cancel(t('common.cancel'));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (useBgImage) {
|
|
109
|
+
const bgImagePath = await p.text({
|
|
110
|
+
message: t('assets.bg_image_path'),
|
|
111
|
+
validate: (value) => {
|
|
112
|
+
if (!value) return '路径不能为空';
|
|
113
|
+
if (!existsSync(join(projectPath, value)) && !existsSync(value)) {
|
|
114
|
+
return '找不到该文件';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
if (p.isCancel(bgImagePath)) {
|
|
119
|
+
p.cancel(t('common.cancel'));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
assets.splashBackground = bgImagePath;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 暗黑模式支持
|
|
126
|
+
const enableDark = await p.confirm({
|
|
127
|
+
message: t('assets.setup_dark'),
|
|
128
|
+
initialValue: false
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (p.isCancel(enableDark)) {
|
|
132
|
+
p.cancel(t('common.cancel'));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (enableDark) {
|
|
137
|
+
assets.enableDarkMode = true;
|
|
138
|
+
|
|
139
|
+
const darkBgColor = await p.text({
|
|
140
|
+
message: t('assets.dark_bg_color'),
|
|
141
|
+
placeholder: '#000000',
|
|
142
|
+
initialValue: '#000000'
|
|
143
|
+
});
|
|
144
|
+
if (!p.isCancel(darkBgColor)) assets.splashBackgroundColorDark = darkBgColor;
|
|
145
|
+
|
|
146
|
+
const useDarkLogo = await p.confirm({
|
|
147
|
+
message: t('assets.use_dark_logo'),
|
|
148
|
+
initialValue: false
|
|
149
|
+
});
|
|
150
|
+
if (useDarkLogo) {
|
|
151
|
+
const darkLogoPath = await p.text({
|
|
152
|
+
message: t('assets.dark_logo_path')
|
|
153
|
+
});
|
|
154
|
+
if (!p.isCancel(darkLogoPath)) assets.splashLogoDark = darkLogoPath;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (Object.keys(assets).length === 0) {
|
|
160
|
+
p.note(t('assets.no_assets'));
|
|
161
|
+
p.outro(chalk.gray(t('common.bye')));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const s = p.spinner();
|
|
166
|
+
s.start(t('assets.configuring'));
|
|
167
|
+
|
|
168
|
+
const assetsManager = new AppAssetsManager();
|
|
169
|
+
const success = await assetsManager.setupAppAssets(projectPath, assets, logger);
|
|
170
|
+
|
|
171
|
+
if (success) {
|
|
172
|
+
s.stop(t('assets.success'));
|
|
173
|
+
p.outro(chalk.green.bold(t('assets.done')));
|
|
174
|
+
} else {
|
|
175
|
+
s.stop(t('assets.failed'));
|
|
176
|
+
p.outro(chalk.red(t('assets.error_outro')));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
} catch (error) {
|
|
180
|
+
p.cancel(`发生错误: ${error.message}`);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
}
|
package/lib/commands/config.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* 职责:初始化和管理项目配置文件
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { ProjectConfigManager, detectProjectTemplate } from '
|
|
6
|
+
import { ProjectConfigManager, detectProjectTemplate, ConfigManager } from 'flu-cli-core';
|
|
7
7
|
import { writeFileSync, existsSync } from 'fs';
|
|
8
8
|
import { join } from 'path';
|
|
9
9
|
import chalk from 'chalk';
|
|
@@ -68,3 +68,43 @@ export function initConfig (options) {
|
|
|
68
68
|
process.exit(1);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 设置全局配置
|
|
74
|
+
*/
|
|
75
|
+
export function setConfig (key, value) {
|
|
76
|
+
const config = ConfigManager.getInstance();
|
|
77
|
+
|
|
78
|
+
// 目前只支持 locale
|
|
79
|
+
if (key === 'locale') {
|
|
80
|
+
if (!['zh-CN', 'en-US'].includes(value)) {
|
|
81
|
+
console.log(chalk.red(`不支持的语言: ${value}`));
|
|
82
|
+
console.log(chalk.gray('支持: zh-CN, en-US'));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
config.setLocale(value);
|
|
86
|
+
console.log(chalk.green(`✓ 全局配置已更新: ${key} = ${value}`));
|
|
87
|
+
} else {
|
|
88
|
+
console.log(chalk.yellow(`不支持的配置项: ${key}`));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 获取全局配置
|
|
94
|
+
*/
|
|
95
|
+
export function getConfig (key) {
|
|
96
|
+
const config = ConfigManager.getInstance();
|
|
97
|
+
|
|
98
|
+
if (key === 'locale') {
|
|
99
|
+
const val = config.getLocale();
|
|
100
|
+
console.log(`${key} = ${val}`);
|
|
101
|
+
} else {
|
|
102
|
+
// 简单起见,如果 key 未知,显示 list
|
|
103
|
+
if (key) {
|
|
104
|
+
console.log(chalk.yellow(`未知配置项: ${key}`));
|
|
105
|
+
} else {
|
|
106
|
+
console.log(`locale = ${config.getLocale()}`);
|
|
107
|
+
console.log(`author = ${config.getAuthorName()}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|