create-pubinfo 2.0.0-beta.31 → 2.0.0-beta.32
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/dist/index.js +337 -350
- package/package.json +8 -9
- package/templates/pubinfo-template/package.json +8 -8
- package/templates/pubinfo-template/src/views/system/login/components/LoginForm.vue +5 -44
- package/templates/pubinfo-template/src/views/system/login/components/PasswordLogin.vue +5 -9
- package/templates/pubinfo-template/src/views/system/login/index.vue +11 -29
package/dist/index.js
CHANGED
|
@@ -1,400 +1,387 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/index.ts
|
|
4
2
|
import { Command } from "commander";
|
|
5
|
-
import
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
import fs, { existsSync, readFileSync, readdirSync, renameSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { dirname, resolve } from "node:path";
|
|
6
|
+
import process, { cwd } from "node:process";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
9
|
+
import { parseJSON, parseJSONC, stringifyJSON } from "confbox";
|
|
10
|
+
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
11
|
+
import colors from "ansi-colors";
|
|
12
|
+
import { ofetch } from "ofetch";
|
|
13
|
+
import ora from "ora";
|
|
14
|
+
import { coerce, compare } from "semver";
|
|
15
|
+
import fonts from "cfonts";
|
|
16
|
+
import { downloadTemplate } from "giget";
|
|
17
|
+
import { rimrafSync } from "rimraf";
|
|
6
18
|
|
|
7
|
-
|
|
19
|
+
//#region package.json
|
|
20
|
+
var name = "create-pubinfo";
|
|
21
|
+
var type = "module";
|
|
22
|
+
var version = "2.0.0-beta.32";
|
|
23
|
+
var description = "初始化项目框架";
|
|
24
|
+
var author = "Werheng <werheng.zhang@gmail.com>";
|
|
25
|
+
var license = "MIT";
|
|
26
|
+
var bin = { "pubinfo": "./dist/index.js" };
|
|
27
|
+
var files = ["dist", "templates"];
|
|
28
|
+
var scripts = {
|
|
29
|
+
"dev": "tsdown --watch src",
|
|
30
|
+
"build": "tsdown",
|
|
31
|
+
"cli": "node dist/index.js",
|
|
32
|
+
"cli:clean": "rimraf ./my-app",
|
|
33
|
+
"lint": "eslint . --cache --fix"
|
|
34
|
+
};
|
|
35
|
+
var dependencies = {
|
|
36
|
+
"@inquirer/prompts": "catalog:node",
|
|
37
|
+
"ansi-colors": "catalog:node",
|
|
38
|
+
"cfonts": "catalog:node",
|
|
39
|
+
"commander": "catalog:node",
|
|
40
|
+
"confbox": "catalog:node",
|
|
41
|
+
"consola": "catalog:browser",
|
|
42
|
+
"giget": "catalog:node",
|
|
43
|
+
"ofetch": "catalog:http",
|
|
44
|
+
"ora": "catalog:node",
|
|
45
|
+
"rimraf": "catalog:node",
|
|
46
|
+
"semver": "catalog:node"
|
|
47
|
+
};
|
|
48
|
+
var devDependencies = { "@types/node": "catalog:ts" };
|
|
8
49
|
var package_default = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"templates"
|
|
21
|
-
],
|
|
22
|
-
scripts: {
|
|
23
|
-
dev: "tsup --watch src",
|
|
24
|
-
build: "tsup",
|
|
25
|
-
cli: "node dist/index.js",
|
|
26
|
-
"cli:clean": "rimraf ./my-app",
|
|
27
|
-
lint: "eslint . --cache --fix"
|
|
28
|
-
},
|
|
29
|
-
dependencies: {
|
|
30
|
-
"@inquirer/prompts": "^5.5.0",
|
|
31
|
-
"ansi-colors": "^4.1.3",
|
|
32
|
-
cfonts: "^3.3.0",
|
|
33
|
-
commander: "^12.1.0",
|
|
34
|
-
confbox: "^0.1.8",
|
|
35
|
-
consola: "^3.4.2",
|
|
36
|
-
giget: "^1.2.5",
|
|
37
|
-
ofetch: "^1.4.1",
|
|
38
|
-
ora: "^8.2.0",
|
|
39
|
-
rimraf: "^6.0.1",
|
|
40
|
-
semver: "^7.7.2"
|
|
41
|
-
},
|
|
42
|
-
devDependencies: {
|
|
43
|
-
"@types/node": "^22.15.27",
|
|
44
|
-
tsup: "catalog:"
|
|
45
|
-
}
|
|
50
|
+
name,
|
|
51
|
+
type,
|
|
52
|
+
version,
|
|
53
|
+
description,
|
|
54
|
+
author,
|
|
55
|
+
license,
|
|
56
|
+
bin,
|
|
57
|
+
files,
|
|
58
|
+
scripts,
|
|
59
|
+
dependencies,
|
|
60
|
+
devDependencies
|
|
46
61
|
};
|
|
47
62
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// src/utils.ts
|
|
55
|
-
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
56
|
-
import * as fs from "fs";
|
|
57
|
-
import { readFile, writeFile } from "fs/promises";
|
|
58
|
-
import { resolve } from "path";
|
|
59
|
-
import { parseJSON, parseJSONC, stringifyJSON } from "confbox";
|
|
60
|
-
import consola from "consola";
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/utils.ts
|
|
65
|
+
/**
|
|
66
|
+
* 重写文件内容
|
|
67
|
+
*/
|
|
61
68
|
function rewriteFile(path, fn) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
if (!existsSync(path)) {
|
|
70
|
+
consola.error(`RewriteFile fail: ${path} does not exist`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const content = readFileSync(path, { encoding: "utf-8" });
|
|
75
|
+
writeFileSync(path, fn(content));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
consola.error(`RewriteFile fail: ${error}`);
|
|
78
|
+
}
|
|
72
79
|
}
|
|
73
80
|
function copyDir(srcDir, destDir) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
82
|
+
for (const file of fs.readdirSync(srcDir)) {
|
|
83
|
+
const srcFile = resolve(srcDir, file);
|
|
84
|
+
const destFile = resolve(destDir, file);
|
|
85
|
+
copy(srcFile, destFile);
|
|
86
|
+
}
|
|
80
87
|
}
|
|
81
88
|
function copy(src, dest) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
} else {
|
|
86
|
-
fs.copyFileSync(src, dest);
|
|
87
|
-
}
|
|
89
|
+
const stat = fs.statSync(src);
|
|
90
|
+
if (stat.isDirectory()) copyDir(src, dest);
|
|
91
|
+
else fs.copyFileSync(src, dest);
|
|
88
92
|
}
|
|
89
93
|
async function readJSON(path) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
const blob = await readFile(path, "utf-8");
|
|
95
|
+
let parsed;
|
|
96
|
+
try {
|
|
97
|
+
parsed = parseJSON(blob);
|
|
98
|
+
} catch {
|
|
99
|
+
parsed = parseJSONC(blob);
|
|
100
|
+
}
|
|
101
|
+
return parsed;
|
|
98
102
|
}
|
|
99
103
|
async function writeJSON(path, json) {
|
|
100
|
-
|
|
104
|
+
await writeFile(path, stringifyJSON(json));
|
|
101
105
|
}
|
|
102
106
|
function assignValues(target, source) {
|
|
103
|
-
|
|
104
|
-
target[key] = value;
|
|
105
|
-
}
|
|
107
|
+
for (const [key, value] of Object.entries(source)) target[key] = value;
|
|
106
108
|
}
|
|
107
|
-
function validateInput(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
return true;
|
|
109
|
+
function validateInput(input$1) {
|
|
110
|
+
const forbiddenChars = /[<>:"/\\|?*\s]/;
|
|
111
|
+
if (forbiddenChars.test(input$1)) return "错误提示: 该值不能包含空格或者非法字符 (例如, <>:\"/\\|?*).";
|
|
112
|
+
return true;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const newPath = resolve2(targetPath, newName || oldName);
|
|
145
|
-
renameSync(oldPath, newPath);
|
|
146
|
-
}
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/core/generate.ts
|
|
117
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
118
|
+
function generate(options, version$1) {
|
|
119
|
+
const root = cwd();
|
|
120
|
+
const templateDir = resolve(__dirname, "../templates", `pubinfo-template`);
|
|
121
|
+
const targetPath = resolve(root, options.dir);
|
|
122
|
+
copy(templateDir, targetPath);
|
|
123
|
+
rewriteFile(resolve(targetPath, "src/settings.ts"), (content) => {
|
|
124
|
+
return content.replace(/storagePrefix:\s*'([^']*)'/g, `storagePrefix: '${options.key}'`);
|
|
125
|
+
});
|
|
126
|
+
rewriteFile(resolve(targetPath, "openapi.config.ts"), (content) => {
|
|
127
|
+
return content.replace(/enabled:[^,]+,/g, `enabled: ${options.openapi},`);
|
|
128
|
+
});
|
|
129
|
+
rewriteFile(resolve(targetPath, "package.json"), (content) => {
|
|
130
|
+
const pattern = /"(@?pubinfo(?:\/module-(?:auth|rbac))?)":\s*"[^"]+"/g;
|
|
131
|
+
return content.replace(pattern, (_match, pkgName) => {
|
|
132
|
+
return `"${pkgName}": "${version$1}"`;
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
const renameFiles = {
|
|
136
|
+
_gitignore: ".gitignore",
|
|
137
|
+
_npmrc: ".npmrc"
|
|
138
|
+
};
|
|
139
|
+
for (const [oldName, newName] of Object.entries(renameFiles)) {
|
|
140
|
+
const oldPath = resolve(targetPath, oldName);
|
|
141
|
+
const newPath = resolve(targetPath, newName || oldName);
|
|
142
|
+
renameSync(oldPath, newPath);
|
|
143
|
+
}
|
|
147
144
|
}
|
|
148
145
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
var APPS = [
|
|
164
|
-
{ name: "\u7528\u6237\u6743\u9650\u7CFB\u7EDF\uFF08rbac\uFF09", value: "rbac" }
|
|
165
|
-
];
|
|
166
|
-
var METADATA_DIR = "configs/metadata";
|
|
167
|
-
var META_FILENAME = "pubinfo.json";
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/v1/constant.ts
|
|
148
|
+
const REMOTE_URL = "http://106.53.74.49:20000/templates";
|
|
149
|
+
const PKG_NAME = "monorepo-project-template";
|
|
150
|
+
const VERSION_FILE = "version.json";
|
|
151
|
+
const SETTING_FILE_PATH = "src/settings.default.ts";
|
|
152
|
+
const OPENAPI_FILE_PATH = "openapi.config.ts";
|
|
153
|
+
const APPS_DIR = "apps";
|
|
154
|
+
const APPS = [{
|
|
155
|
+
name: "用户权限系统(rbac)",
|
|
156
|
+
value: "rbac"
|
|
157
|
+
}];
|
|
158
|
+
const METADATA_DIR = "configs/metadata";
|
|
159
|
+
const META_FILENAME = "pubinfo.json";
|
|
168
160
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
import consola2 from "consola";
|
|
172
|
-
import { ofetch } from "ofetch";
|
|
173
|
-
import ora from "ora";
|
|
174
|
-
import { compare } from "semver";
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/v1/fetch.ts
|
|
175
163
|
async function fetchVersion() {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
164
|
+
const versions = await ofetch(`${REMOTE_URL}/${VERSION_FILE}`);
|
|
165
|
+
versions.sort((v1, v2) => -compare(v1, v2));
|
|
166
|
+
return {
|
|
167
|
+
latest: versions[0],
|
|
168
|
+
list: versions
|
|
169
|
+
};
|
|
182
170
|
}
|
|
183
171
|
async function fetchData() {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
process.exit(1);
|
|
200
|
-
} finally {
|
|
201
|
-
spinner.stop();
|
|
202
|
-
}
|
|
172
|
+
const spinner = ora({
|
|
173
|
+
text: "检测网络连接...",
|
|
174
|
+
color: "blue"
|
|
175
|
+
});
|
|
176
|
+
spinner.start();
|
|
177
|
+
try {
|
|
178
|
+
const version$1 = await fetchVersion();
|
|
179
|
+
return { version: version$1 };
|
|
180
|
+
} catch (error) {
|
|
181
|
+
if (error.message.includes(REMOTE_URL)) error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
|
|
182
|
+
consola.error(`网络连接异常: ${error.message}`);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
} finally {
|
|
185
|
+
spinner.stop();
|
|
186
|
+
}
|
|
203
187
|
}
|
|
204
188
|
|
|
205
|
-
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/core/init.ts
|
|
206
191
|
async function init() {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
192
|
+
try {
|
|
193
|
+
const answer = {};
|
|
194
|
+
answer.dir = await input({
|
|
195
|
+
message: "目录名称(dir)",
|
|
196
|
+
default: "my-app",
|
|
197
|
+
validate: validateInput
|
|
198
|
+
});
|
|
199
|
+
answer.key = await input({
|
|
200
|
+
message: "项目标识(key)",
|
|
201
|
+
default: answer.dir,
|
|
202
|
+
validate: validateInput
|
|
203
|
+
});
|
|
204
|
+
if (existsSync(answer.dir)) {
|
|
205
|
+
const overwrite = await confirm({ message: `目录 ${colors.cyan(answer.dir)} 已存在,是否覆盖?` });
|
|
206
|
+
if (!overwrite) throw Error;
|
|
207
|
+
}
|
|
208
|
+
answer.openapi = await confirm({
|
|
209
|
+
message: "运行时自动生成接口对接文件,若关闭可通过指令生成(openapi)",
|
|
210
|
+
default: false
|
|
211
|
+
});
|
|
212
|
+
const V1orV2 = await select({
|
|
213
|
+
message: "使用 v1 or v2 版本?",
|
|
214
|
+
default: "v2",
|
|
215
|
+
choices: ["v1", "v2"]
|
|
216
|
+
});
|
|
217
|
+
const isV1 = V1orV2 === "v1";
|
|
218
|
+
if (isV1) {
|
|
219
|
+
const { version: version$1 } = await fetchData();
|
|
220
|
+
answer.optionsV1 = JSON.parse(JSON.stringify(answer));
|
|
221
|
+
answer.optionsV1.version = await select({
|
|
222
|
+
message: "框架版本号(version)",
|
|
223
|
+
default: version$1.latest,
|
|
224
|
+
choices: version$1.list
|
|
225
|
+
});
|
|
226
|
+
answer.optionsV1.apps = await checkbox({
|
|
227
|
+
message: "选择应用模块(apps)",
|
|
228
|
+
choices: APPS,
|
|
229
|
+
validate: (input$1) => {
|
|
230
|
+
if (input$1.length === 0) return "请至少选择一个应用";
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
return answer;
|
|
236
|
+
} catch {
|
|
237
|
+
consola.fail("操作终止");
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
251
240
|
}
|
|
252
241
|
|
|
253
|
-
|
|
254
|
-
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region src/log.ts
|
|
255
244
|
function bootstrop() {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
245
|
+
printLoGo("PUBINFO");
|
|
246
|
+
function printLoGo(logo) {
|
|
247
|
+
fonts.say(logo, {
|
|
248
|
+
font: "simple3d",
|
|
249
|
+
align: "left",
|
|
250
|
+
background: "transparent",
|
|
251
|
+
letterSpacing: 1,
|
|
252
|
+
lineHeight: 1,
|
|
253
|
+
space: true,
|
|
254
|
+
maxLength: 0,
|
|
255
|
+
spaceless: false,
|
|
256
|
+
gradient: ["blue", "magenta"],
|
|
257
|
+
independentGradient: false,
|
|
258
|
+
transitionGradient: false,
|
|
259
|
+
env: "node"
|
|
260
|
+
});
|
|
261
|
+
}
|
|
273
262
|
}
|
|
274
263
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
name: "pubinfo",
|
|
286
|
-
version: input2,
|
|
287
|
-
headers: { Authorization: `token ${auth}` },
|
|
288
|
-
tar: `${REMOTE_URL}/${PKG_NAME}-${semver?.version}.tar.gz`
|
|
289
|
-
};
|
|
264
|
+
//#endregion
|
|
265
|
+
//#region src/v1/download.ts
|
|
266
|
+
const pubinfo = async (input$1, { auth }) => {
|
|
267
|
+
const semver = coerce(input$1);
|
|
268
|
+
return {
|
|
269
|
+
name: "pubinfo",
|
|
270
|
+
version: input$1,
|
|
271
|
+
headers: { Authorization: `token ${auth}` },
|
|
272
|
+
tar: `${REMOTE_URL}/${PKG_NAME}-${semver?.version}.tar.gz`
|
|
273
|
+
};
|
|
290
274
|
};
|
|
291
275
|
async function download(options) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
finish();
|
|
308
|
-
}
|
|
276
|
+
const finish = loading();
|
|
277
|
+
try {
|
|
278
|
+
await downloadTemplate(`pubinfo:${PKG_NAME}-${options.version}`, {
|
|
279
|
+
providers: { pubinfo },
|
|
280
|
+
force: true,
|
|
281
|
+
forceClean: true,
|
|
282
|
+
dir: options.dir
|
|
283
|
+
});
|
|
284
|
+
} catch (error) {
|
|
285
|
+
if (error.message.includes(REMOTE_URL)) error.message = error.message.replace(REMOTE_URL, "[REMOTE_URL]");
|
|
286
|
+
consola.error(`下载失败: ${error.message}`);
|
|
287
|
+
process.exit(1);
|
|
288
|
+
} finally {
|
|
289
|
+
finish();
|
|
290
|
+
}
|
|
309
291
|
}
|
|
310
292
|
function loading() {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
293
|
+
const startTime = Date.now();
|
|
294
|
+
const spinner = ora({
|
|
295
|
+
text: "下载中...",
|
|
296
|
+
color: "green"
|
|
297
|
+
});
|
|
298
|
+
spinner.start();
|
|
299
|
+
return () => {
|
|
300
|
+
const { green, yellow } = colors;
|
|
301
|
+
spinner.stop();
|
|
302
|
+
consola.success(`${green("下载完成, 用时")} ${yellow(`${Date.now() - startTime}`)} ${green("ms.")}`);
|
|
303
|
+
};
|
|
322
304
|
}
|
|
323
305
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
import { resolve as resolve3 } from "path";
|
|
327
|
-
import process4 from "process";
|
|
328
|
-
import consola5 from "consola";
|
|
329
|
-
import { rimrafSync } from "rimraf";
|
|
306
|
+
//#endregion
|
|
307
|
+
//#region src/v1/rewrite.ts
|
|
330
308
|
async function rewrite(options) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
309
|
+
const { dir } = options;
|
|
310
|
+
const root = process.cwd();
|
|
311
|
+
const projectDir = resolve(root, dir);
|
|
312
|
+
writeMetaJSON(resolve(projectDir, METADATA_DIR), options);
|
|
313
|
+
writeApps(resolve(projectDir, APPS_DIR), options);
|
|
336
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* 写入项目整体配置
|
|
317
|
+
*/
|
|
337
318
|
async function writeMetaJSON(metaDir, options) {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
319
|
+
const { key, version: version$1, apps, openapi } = options;
|
|
320
|
+
const path = resolve(metaDir, META_FILENAME);
|
|
321
|
+
try {
|
|
322
|
+
const json = await readJSON(path);
|
|
323
|
+
assignValues(json, {
|
|
324
|
+
key,
|
|
325
|
+
version: version$1,
|
|
326
|
+
apps,
|
|
327
|
+
openapi
|
|
328
|
+
});
|
|
329
|
+
await writeJSON(path, json);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
consola.error(`初始化 metadata 失败: ${error}`);
|
|
332
|
+
}
|
|
352
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* 处理目录 `/apps` 下的各个应用
|
|
336
|
+
*/
|
|
353
337
|
function writeApps(appsDir, options) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
338
|
+
const { key, apps = [], openapi } = options;
|
|
339
|
+
if (!existsSync(appsDir)) {
|
|
340
|
+
consola.error(`初始化 apps 失败: ${appsDir} 不存在`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
readdirSync(appsDir).forEach((app) => {
|
|
345
|
+
const appPath = resolve(appsDir, app);
|
|
346
|
+
const settingPath = resolve(appPath, SETTING_FILE_PATH);
|
|
347
|
+
const openapiPath = resolve(appPath, OPENAPI_FILE_PATH);
|
|
348
|
+
if (!apps.includes(app)) {
|
|
349
|
+
rimrafSync(appPath);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
rewriteFile(settingPath, (content) => {
|
|
353
|
+
return content.replace(/storagePrefix:\s*'([^']*)'/g, `storagePrefix: '${key}'`);
|
|
354
|
+
});
|
|
355
|
+
rewriteFile(openapiPath, (content) => {
|
|
356
|
+
return content.replace(/enabled:[^,]+,/g, `enabled: ${openapi},`);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
} catch (error) {
|
|
360
|
+
consola.error(`初始化 apps 失败: ${error}`);
|
|
361
|
+
}
|
|
378
362
|
}
|
|
379
363
|
|
|
380
|
-
|
|
364
|
+
//#endregion
|
|
365
|
+
//#region src/index.ts
|
|
381
366
|
async function main() {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
367
|
+
const program = new Command();
|
|
368
|
+
program.name(package_default.name).description(package_default.description).version(package_default.version);
|
|
369
|
+
program.description("初始化框架").action(async () => {
|
|
370
|
+
bootstrop();
|
|
371
|
+
try {
|
|
372
|
+
const answer = await init();
|
|
373
|
+
if (answer.optionsV1) {
|
|
374
|
+
await download(answer.optionsV1);
|
|
375
|
+
await rewrite(answer.optionsV1);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
generate(answer, package_default.version);
|
|
379
|
+
} catch (error) {
|
|
380
|
+
consola.error(error);
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
program.parse();
|
|
399
384
|
}
|
|
400
385
|
main();
|
|
386
|
+
|
|
387
|
+
//#endregion
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-pubinfo",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.32",
|
|
5
5
|
"description": "初始化项目框架",
|
|
6
6
|
"author": "Werheng <werheng.zhang@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -13,25 +13,24 @@
|
|
|
13
13
|
"templates"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@inquirer/prompts": "^
|
|
16
|
+
"@inquirer/prompts": "^7.6.0",
|
|
17
17
|
"ansi-colors": "^4.1.3",
|
|
18
18
|
"cfonts": "^3.3.0",
|
|
19
|
-
"commander": "^
|
|
20
|
-
"confbox": "^0.
|
|
19
|
+
"commander": "^14.0.0",
|
|
20
|
+
"confbox": "^0.2.2",
|
|
21
21
|
"consola": "^3.4.2",
|
|
22
|
-
"giget": "^
|
|
22
|
+
"giget": "^2.0.0",
|
|
23
23
|
"ofetch": "^1.4.1",
|
|
24
24
|
"ora": "^8.2.0",
|
|
25
25
|
"rimraf": "^6.0.1",
|
|
26
26
|
"semver": "^7.7.2"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@types/node": "^
|
|
30
|
-
"tsup": "^8.5.0"
|
|
29
|
+
"@types/node": "^24.0.10"
|
|
31
30
|
},
|
|
32
31
|
"scripts": {
|
|
33
|
-
"dev": "
|
|
34
|
-
"build": "
|
|
32
|
+
"dev": "tsdown --watch src",
|
|
33
|
+
"build": "tsdown",
|
|
35
34
|
"cli": "node dist/index.js",
|
|
36
35
|
"cli:clean": "rimraf ./my-app",
|
|
37
36
|
"lint": "eslint . --cache --fix"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "pubinfo-template",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"private": true,
|
|
5
|
-
"packageManager": "pnpm@10.
|
|
5
|
+
"packageManager": "pnpm@10.12.4",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "pubinfo dev",
|
|
8
8
|
"build": "pubinfo build",
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@ant-design/icons-vue": "^7.0.1",
|
|
18
|
-
"@pubinfo/module-auth": "^2.0.0-beta.
|
|
19
|
-
"@pubinfo/module-rbac": "^2.0.0-beta.
|
|
18
|
+
"@pubinfo/module-auth": "^2.0.0-beta.31",
|
|
19
|
+
"@pubinfo/module-rbac": "^2.0.0-beta.31",
|
|
20
20
|
"@pubinfo/pro-components": "^1.7.1",
|
|
21
21
|
"@vueuse/core": "^12.8.2",
|
|
22
|
-
"alova": "^3.
|
|
22
|
+
"alova": "^3.3.4",
|
|
23
23
|
"ant-design-vue": "^4.2.6",
|
|
24
24
|
"dayjs": "^1.11.13",
|
|
25
|
-
"pubinfo": "^2.0.0-beta.
|
|
25
|
+
"pubinfo": "^2.0.0-beta.31"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@commitlint/config-conventional": "^19.8.1",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"@pubinfo/preset-openapi": "^0.8.4",
|
|
32
32
|
"commitizen": "^4.3.1",
|
|
33
33
|
"commitlint": "^19.8.1",
|
|
34
|
-
"eslint": "^9.
|
|
35
|
-
"lint-staged": "^16.1.
|
|
34
|
+
"eslint": "^9.30.1",
|
|
35
|
+
"lint-staged": "^16.1.2",
|
|
36
36
|
"simple-git-hooks": "^2.13.0",
|
|
37
|
-
"stylelint": "^16.
|
|
37
|
+
"stylelint": "^16.21.0",
|
|
38
38
|
"typescript": "^5.8.3"
|
|
39
39
|
},
|
|
40
40
|
"config": {
|
|
@@ -9,60 +9,21 @@ const { tabs, initialTab, changeActiveTab } = useLoginTabs();
|
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
11
|
<template>
|
|
12
|
-
<div class="
|
|
13
|
-
<div class="
|
|
12
|
+
<div class="flex flex-col w-456px [background:transparent]">
|
|
13
|
+
<div class="flex flex-row overflow-hidden border border-solid border-[#e7e8e9] rounded-1">
|
|
14
14
|
<div
|
|
15
15
|
v-for="(tab, index) in tabs"
|
|
16
16
|
:key="tab.title"
|
|
17
|
-
class="
|
|
18
|
-
:class="
|
|
17
|
+
class="flex flex-row items-center justify-center h-10 text-base cursor-pointer rounded"
|
|
18
|
+
:class="[initialTab === index ? 'text-[#2f6bff] bg-[#ecf1fd]' : 'text-[#8a8e92] ']"
|
|
19
19
|
:style="{ width: `${100 / tabs.length}%` }"
|
|
20
20
|
@click="changeActiveTab(index)"
|
|
21
21
|
>
|
|
22
22
|
{{ tab.title }}
|
|
23
23
|
</div>
|
|
24
24
|
</div>
|
|
25
|
-
<div class="
|
|
25
|
+
<div class="relative min-h-350px">
|
|
26
26
|
<component :is="tabs[initialTab].component" :key="tabs[initialTab].title" :name="tabs[initialTab].title" />
|
|
27
27
|
</div>
|
|
28
28
|
</div>
|
|
29
29
|
</template>
|
|
30
|
-
|
|
31
|
-
<style scoped lang="scss">
|
|
32
|
-
.login-warp {
|
|
33
|
-
display: flex;
|
|
34
|
-
flex-direction: column;
|
|
35
|
-
width: 456px;
|
|
36
|
-
background: transparent;
|
|
37
|
-
|
|
38
|
-
.login-tabs {
|
|
39
|
-
display: flex;
|
|
40
|
-
flex-direction: row;
|
|
41
|
-
overflow: hidden;
|
|
42
|
-
border: 1px solid #e7e8e9;
|
|
43
|
-
border-radius: 4px;
|
|
44
|
-
|
|
45
|
-
.login-tab {
|
|
46
|
-
display: flex;
|
|
47
|
-
flex-direction: row;
|
|
48
|
-
align-items: center;
|
|
49
|
-
justify-content: center;
|
|
50
|
-
height: 40px;
|
|
51
|
-
font-size: 16px;
|
|
52
|
-
color: #8a8e92;
|
|
53
|
-
cursor: pointer;
|
|
54
|
-
border-radius: 4px;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.active {
|
|
58
|
-
color: #2f6bff;
|
|
59
|
-
background: #ecf1fd;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.login-form {
|
|
64
|
-
position: relative;
|
|
65
|
-
min-height: 350px;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
</style>
|
|
@@ -113,7 +113,7 @@ const AUTH_4A_ENABLED = import.meta.env.VITE_AUTH_4A_ENABLED === 'true';
|
|
|
113
113
|
</script>
|
|
114
114
|
|
|
115
115
|
<template>
|
|
116
|
-
<div class="
|
|
116
|
+
<div class="mt-10">
|
|
117
117
|
<AForm ref="loginForm" :model="formState" :rules="rules" @finish="onSubmit">
|
|
118
118
|
<a-form-item name="account">
|
|
119
119
|
<a-input
|
|
@@ -202,13 +202,9 @@ const AUTH_4A_ENABLED = import.meta.env.VITE_AUTH_4A_ENABLED === 'true';
|
|
|
202
202
|
</div>
|
|
203
203
|
</template>
|
|
204
204
|
|
|
205
|
-
<style scoped
|
|
206
|
-
.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
:deep(.ant-input-group-addon) {
|
|
210
|
-
padding: 0 !important;
|
|
211
|
-
overflow: hidden;
|
|
212
|
-
}
|
|
205
|
+
<style scoped>
|
|
206
|
+
:deep(.ant-input-group-addon) {
|
|
207
|
+
padding: 0 !important;
|
|
208
|
+
overflow: hidden;
|
|
213
209
|
}
|
|
214
210
|
</style>
|
|
@@ -105,41 +105,23 @@ const designDescription = [
|
|
|
105
105
|
</div>
|
|
106
106
|
</template>
|
|
107
107
|
|
|
108
|
-
<style
|
|
108
|
+
<style scoped>
|
|
109
109
|
.warp {
|
|
110
|
-
|
|
111
|
-
display: flex;
|
|
112
|
-
flex-direction: row;
|
|
113
|
-
width: 100%;
|
|
114
|
-
height: 100%;
|
|
115
|
-
overflow: hidden;
|
|
110
|
+
--at-apply: relative flex flex-row w-full h-full overflow-hidden;
|
|
116
111
|
background: url("@/assets/images/login-bg.webp") no-repeat;
|
|
117
112
|
background-size: cover;
|
|
113
|
+
}
|
|
118
114
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
overflow: hidden;
|
|
123
|
-
}
|
|
115
|
+
.warp .warp-blank {
|
|
116
|
+
--at-apply: flex-auto basis-0 overflow-hidden;
|
|
117
|
+
}
|
|
124
118
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
align-items: center;
|
|
129
|
-
height: 33px;
|
|
130
|
-
margin-bottom: 35px;
|
|
131
|
-
font-size: 24px;
|
|
132
|
-
font-weight: 400;
|
|
133
|
-
color: #151e26;
|
|
134
|
-
}
|
|
119
|
+
.warp .logo-group {
|
|
120
|
+
--at-apply: flex flex-row items-center h-33px mb-35px text-6 font-400 text-[#151e26];
|
|
121
|
+
}
|
|
135
122
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
font-size: 38px;
|
|
139
|
-
font-weight: 800;
|
|
140
|
-
color: #072347;
|
|
141
|
-
letter-spacing: 1.5px;
|
|
142
|
-
}
|
|
123
|
+
.warp .title-group {
|
|
124
|
+
--at-apply: h-52px text-38px font-800 text-[#072347] tracking-[1.5px];
|
|
143
125
|
}
|
|
144
126
|
|
|
145
127
|
@media (width < 1024px) {
|