@pikecode/api-key-manager 1.0.38 → 1.0.42
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 +921 -2
- package/bin/akm.js +120 -3
- package/package.json +12 -5
- package/src/CommandRegistry.js +25 -0
- package/src/commands/BaseCommand.js +67 -0
- package/src/commands/add.js +133 -153
- package/src/commands/backup.js +14 -1
- package/src/commands/batch.js +314 -0
- package/src/commands/benchmark.js +344 -0
- package/src/commands/current.js +30 -14
- package/src/commands/edit.js +66 -46
- package/src/commands/health.js +222 -0
- package/src/commands/list.js +30 -11
- package/src/commands/remove.js +22 -3
- package/src/commands/stats.js +282 -0
- package/src/commands/switch/launch-args-helper.js +84 -0
- package/src/commands/switch/status-helper.js +124 -0
- package/src/commands/switch.js +226 -164
- package/src/commands/validate.js +310 -0
- package/src/config.js +243 -2
- package/src/constants/index.js +246 -0
- package/src/index.js +10 -3
- package/src/utils/codex-files.js +66 -14
- package/src/utils/codex-launcher.js +3 -0
- package/src/utils/config-opener.js +15 -0
- package/src/utils/env-utils.js +1 -1
- package/src/utils/error-handler.js +26 -26
- package/src/utils/health-checker.js +350 -0
- package/src/utils/inquirer-setup.js +11 -0
- package/src/utils/provider-status-checker.js +29 -10
- package/src/utils/ui-helper.js +87 -85
- package/src/utils/update-checker.js +25 -7
- package/src/utils/validator.js +12 -12
package/src/utils/ui-helper.js
CHANGED
|
@@ -1,38 +1,7 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
|
|
3
3
|
class UIHelper {
|
|
4
|
-
//
|
|
5
|
-
static colors = {
|
|
6
|
-
primary: chalk.cyan,
|
|
7
|
-
secondary: chalk.blue,
|
|
8
|
-
success: chalk.green,
|
|
9
|
-
warning: chalk.yellow,
|
|
10
|
-
error: chalk.red,
|
|
11
|
-
info: chalk.white,
|
|
12
|
-
muted: chalk.gray,
|
|
13
|
-
accent: chalk.magenta
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// 图标
|
|
17
|
-
static icons = {
|
|
18
|
-
success: '✅',
|
|
19
|
-
error: '❌',
|
|
20
|
-
warning: '⚠️',
|
|
21
|
-
info: 'ℹ️',
|
|
22
|
-
loading: '⏳',
|
|
23
|
-
arrow: '→',
|
|
24
|
-
back: '🔙',
|
|
25
|
-
home: '🏠',
|
|
26
|
-
settings: '⚙️',
|
|
27
|
-
add: '➕',
|
|
28
|
-
edit: '✏️',
|
|
29
|
-
delete: '🗑️',
|
|
30
|
-
launch: '🚀',
|
|
31
|
-
list: '📋',
|
|
32
|
-
config: '🛠️',
|
|
33
|
-
current: '🎯',
|
|
34
|
-
search: '🔍'
|
|
35
|
-
};
|
|
4
|
+
// 创建标题
|
|
36
5
|
|
|
37
6
|
// 创建标题
|
|
38
7
|
static createTitle(text, icon = '') {
|
|
@@ -47,36 +16,36 @@ class UIHelper {
|
|
|
47
16
|
|
|
48
17
|
// 创建项目列表
|
|
49
18
|
static createItem(label, value, isSelected = false) {
|
|
50
|
-
const icon = isSelected ?
|
|
51
|
-
const color = isSelected ?
|
|
19
|
+
const icon = isSelected ? UIHelper.icons.current : '•';
|
|
20
|
+
const color = isSelected ? UIHelper.colors.primary : UIHelper.colors.info;
|
|
52
21
|
return `${color(icon)} ${label}`;
|
|
53
22
|
}
|
|
54
23
|
|
|
55
24
|
// 创建操作按钮
|
|
56
25
|
static createButton(label, action, icon = '') {
|
|
57
26
|
const fullIcon = icon ? `${icon} ` : '';
|
|
58
|
-
return `${
|
|
27
|
+
return `${UIHelper.colors.accent(fullIcon)}${UIHelper.colors.info(label)}`;
|
|
59
28
|
}
|
|
60
29
|
|
|
61
30
|
// 创建状态指示器
|
|
62
31
|
static createStatus(status, label) {
|
|
63
32
|
const statusConfig = {
|
|
64
|
-
current: { icon:
|
|
65
|
-
active: { icon: '🟢', color:
|
|
66
|
-
inactive: { icon: '⚫', color:
|
|
67
|
-
loading: { icon:
|
|
68
|
-
error: { icon:
|
|
33
|
+
current: { icon: UIHelper.icons.current, color: UIHelper.colors.success },
|
|
34
|
+
active: { icon: '🟢', color: UIHelper.colors.success },
|
|
35
|
+
inactive: { icon: '⚫', color: UIHelper.colors.muted },
|
|
36
|
+
loading: { icon: UIHelper.icons.loading, color: UIHelper.colors.warning },
|
|
37
|
+
error: { icon: UIHelper.icons.error, color: UIHelper.colors.error }
|
|
69
38
|
};
|
|
70
39
|
|
|
71
40
|
const config = statusConfig[status] || statusConfig.inactive;
|
|
72
|
-
return `${config.color(config.icon)} ${
|
|
41
|
+
return `${config.color(config.icon)} ${UIHelper.colors.info(label)}`;
|
|
73
42
|
}
|
|
74
43
|
|
|
75
44
|
// 格式化供应商信息
|
|
76
45
|
static formatProvider(provider) {
|
|
77
46
|
const status = provider.current ? 'current' : 'inactive';
|
|
78
|
-
const statusText =
|
|
79
|
-
const displayName =
|
|
47
|
+
const statusText = UIHelper.createStatus(status, provider.name);
|
|
48
|
+
const displayName = UIHelper.colors.secondary(`(${provider.displayName})`);
|
|
80
49
|
|
|
81
50
|
return `${statusText} ${displayName}`;
|
|
82
51
|
}
|
|
@@ -88,30 +57,30 @@ class UIHelper {
|
|
|
88
57
|
const filled = '█'.repeat(progress);
|
|
89
58
|
const emptySpace = '░'.repeat(empty);
|
|
90
59
|
const percentage = Math.floor((current / total) * 100);
|
|
91
|
-
|
|
92
|
-
return `${
|
|
60
|
+
|
|
61
|
+
return `${UIHelper.colors.primary(filled)}${UIHelper.colors.muted(emptySpace)} ${UIHelper.colors.info(percentage + '%')}`;
|
|
93
62
|
}
|
|
94
63
|
|
|
95
64
|
// 创建表格
|
|
96
65
|
static createTable(headers, rows) {
|
|
97
66
|
const columnWidths = headers.map(header => Math.max(header.length, ...rows.map(row => String(row[headers.indexOf(header)]).length)));
|
|
98
|
-
|
|
67
|
+
|
|
99
68
|
let result = '';
|
|
100
|
-
|
|
69
|
+
|
|
101
70
|
// 表头
|
|
102
71
|
const headerRow = headers.map((header, i) => header.padEnd(columnWidths[i])).join(' │ ');
|
|
103
|
-
result += `${
|
|
104
|
-
|
|
72
|
+
result += `${UIHelper.colors.primary(headerRow)}\n`;
|
|
73
|
+
|
|
105
74
|
// 分隔线
|
|
106
75
|
const separator = columnWidths.map(width => '─'.repeat(width)).join('─┼─');
|
|
107
|
-
result += `${
|
|
108
|
-
|
|
76
|
+
result += `${UIHelper.colors.muted(separator)}\n`;
|
|
77
|
+
|
|
109
78
|
// 数据行
|
|
110
79
|
rows.forEach(row => {
|
|
111
80
|
const dataRow = row.map((cell, i) => String(cell).padEnd(columnWidths[i])).join(' │ ');
|
|
112
|
-
result += `${
|
|
81
|
+
result += `${UIHelper.colors.info(dataRow)}\n`;
|
|
113
82
|
});
|
|
114
|
-
|
|
83
|
+
|
|
115
84
|
return result;
|
|
116
85
|
}
|
|
117
86
|
|
|
@@ -120,41 +89,41 @@ class UIHelper {
|
|
|
120
89
|
const lines = content.split('\n');
|
|
121
90
|
const maxLineLength = Math.max(...lines.map(line => line.length));
|
|
122
91
|
const horizontalBorder = '─'.repeat(maxLineLength + 4);
|
|
123
|
-
|
|
124
|
-
let result = `${
|
|
125
|
-
result += `${
|
|
126
|
-
result += `${
|
|
127
|
-
|
|
92
|
+
|
|
93
|
+
let result = `${UIHelper.colors.primary(`┌─${horizontalBorder}─┐`)}\n`;
|
|
94
|
+
result += `${UIHelper.colors.primary('│')} ${chalk.bold.white(icon ? `${icon} ` : '')}${chalk.bold.white(title)}${' '.repeat(maxLineLength - title.length - (icon ? 2 : 0))} ${UIHelper.colors.primary('│')}\n`;
|
|
95
|
+
result += `${UIHelper.colors.primary('├─')}${UIHelper.colors.muted(horizontalBorder)}${UIHelper.colors.primary('─┤')}\n`;
|
|
96
|
+
|
|
128
97
|
lines.forEach(line => {
|
|
129
|
-
result += `${
|
|
98
|
+
result += `${UIHelper.colors.primary('│')} ${UIHelper.colors.info(line)}${' '.repeat(maxLineLength - line.length)} ${UIHelper.colors.primary('│')}\n`;
|
|
130
99
|
});
|
|
131
|
-
|
|
132
|
-
result += `${
|
|
100
|
+
|
|
101
|
+
result += `${UIHelper.colors.primary('└─')}${UIHelper.colors.muted(horizontalBorder)}${UIHelper.colors.primary('─┘')}`;
|
|
133
102
|
return result;
|
|
134
103
|
}
|
|
135
104
|
|
|
136
105
|
// 创建操作菜单
|
|
137
106
|
static createMenu(title, options) {
|
|
138
|
-
let result = `${
|
|
139
|
-
|
|
107
|
+
let result = `${UIHelper.createTitle(title, UIHelper.icons.list)}\n\n`;
|
|
108
|
+
|
|
140
109
|
options.forEach((option, index) => {
|
|
141
|
-
const number =
|
|
110
|
+
const number = UIHelper.colors.muted(`[${index + 1}]`);
|
|
142
111
|
const icon = option.icon || '•';
|
|
143
|
-
const description = option.description ?
|
|
144
|
-
result += `${number} ${
|
|
112
|
+
const description = option.description ? UIHelper.colors.muted(` - ${option.description}`) : '';
|
|
113
|
+
result += `${number} ${UIHelper.colors.accent(icon)} ${UIHelper.colors.info(option.label)}${description}\n`;
|
|
145
114
|
});
|
|
146
|
-
|
|
147
|
-
result += `\n${
|
|
148
|
-
result += `${
|
|
149
|
-
|
|
115
|
+
|
|
116
|
+
result += `\n${UIHelper.colors.muted(UIHelper.createSeparator())}\n`;
|
|
117
|
+
result += `${UIHelper.colors.warning('请选择操作 (输入数字): ')}`;
|
|
118
|
+
|
|
150
119
|
return result;
|
|
151
120
|
}
|
|
152
121
|
|
|
153
122
|
// 创建确认对话框
|
|
154
123
|
static createConfirmDialog(message, options = ['确认', '取消']) {
|
|
155
|
-
return `${
|
|
156
|
-
`${
|
|
157
|
-
`${
|
|
124
|
+
return `${UIHelper.colors.warning(message)}\n\n` +
|
|
125
|
+
`${UIHelper.colors.success('[Y]')} ${UIHelper.colors.info(options[0])} ` +
|
|
126
|
+
`${UIHelper.colors.error('[N]')} ${UIHelper.colors.info(options[1])}`;
|
|
158
127
|
}
|
|
159
128
|
|
|
160
129
|
// 格式化时间
|
|
@@ -162,32 +131,32 @@ class UIHelper {
|
|
|
162
131
|
const date = new Date(dateString);
|
|
163
132
|
const now = new Date();
|
|
164
133
|
const diff = now - date;
|
|
165
|
-
|
|
134
|
+
|
|
166
135
|
if (diff < 60000) return '刚刚';
|
|
167
136
|
if (diff < 3600000) return `${Math.floor(diff / 60000)} 分钟前`;
|
|
168
137
|
if (diff < 86400000) return `${Math.floor(diff / 3600000)} 小时前`;
|
|
169
138
|
if (diff < 2592000000) return `${Math.floor(diff / 86400000)} 天前`;
|
|
170
|
-
|
|
139
|
+
|
|
171
140
|
return date.toLocaleDateString('zh-CN');
|
|
172
141
|
}
|
|
173
142
|
|
|
174
143
|
// 创建搜索框
|
|
175
144
|
static createSearchBox(placeholder = '搜索...') {
|
|
176
|
-
return `${
|
|
145
|
+
return `${UIHelper.colors.info(UIHelper.icons.search)} ${UIHelper.colors.muted(placeholder)}`;
|
|
177
146
|
}
|
|
178
147
|
|
|
179
148
|
// 创建提示框
|
|
180
149
|
static createTooltip(text) {
|
|
181
|
-
return `${
|
|
150
|
+
return `${UIHelper.colors.muted('💡 ' + text)}`;
|
|
182
151
|
}
|
|
183
152
|
|
|
184
153
|
// 创建加载动画
|
|
185
154
|
static createLoadingAnimation(text = '加载中...') {
|
|
186
155
|
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
187
156
|
let frameIndex = 0;
|
|
188
|
-
|
|
157
|
+
|
|
189
158
|
return setInterval(() => {
|
|
190
|
-
process.stdout.write(`\r${
|
|
159
|
+
process.stdout.write(`\r${UIHelper.colors.warning(frames[frameIndex])} ${UIHelper.colors.info(text)}`);
|
|
191
160
|
frameIndex = (frameIndex + 1) % frames.length;
|
|
192
161
|
}, 100);
|
|
193
162
|
}
|
|
@@ -200,12 +169,12 @@ class UIHelper {
|
|
|
200
169
|
|
|
201
170
|
// 创建快捷键提示
|
|
202
171
|
static createShortcutHint(key, action) {
|
|
203
|
-
return `${
|
|
172
|
+
return `${UIHelper.colors.muted('[')}${UIHelper.colors.primary(key)}${UIHelper.colors.muted(']')} ${UIHelper.colors.info(action)}`;
|
|
204
173
|
}
|
|
205
174
|
|
|
206
175
|
// 创建 ESC 键提示
|
|
207
176
|
static createESCHint(action = '返回') {
|
|
208
|
-
return `${
|
|
177
|
+
return `${UIHelper.colors.muted('[')}${UIHelper.colors.primary('ESC')}${UIHelper.colors.muted(']')} ${UIHelper.colors.info(action)}`;
|
|
209
178
|
}
|
|
210
179
|
|
|
211
180
|
// 创建提示行
|
|
@@ -213,16 +182,49 @@ class UIHelper {
|
|
|
213
182
|
if (!pairs.length) {
|
|
214
183
|
return '';
|
|
215
184
|
}
|
|
216
|
-
const hints = pairs.map(([key, action]) =>
|
|
217
|
-
return `${
|
|
185
|
+
const hints = pairs.map(([key, action]) => UIHelper.createShortcutHint(key, action));
|
|
186
|
+
return `${UIHelper.colors.muted('提示: ')}${hints.join(UIHelper.colors.muted(' · '))}`;
|
|
218
187
|
}
|
|
219
188
|
|
|
220
189
|
// 创建步骤指示
|
|
221
190
|
static createStepIndicator(current, total, label) {
|
|
222
|
-
const prefix =
|
|
223
|
-
const title = label ? ` ${
|
|
191
|
+
const prefix = UIHelper.colors.muted(`步骤 ${current}/${total}`);
|
|
192
|
+
const title = label ? ` ${UIHelper.colors.info(label)}` : '';
|
|
224
193
|
return `${prefix}${title}`;
|
|
225
194
|
}
|
|
226
195
|
}
|
|
227
196
|
|
|
197
|
+
// 颜色主题
|
|
198
|
+
UIHelper.colors = {
|
|
199
|
+
primary: chalk.cyan,
|
|
200
|
+
secondary: chalk.blue,
|
|
201
|
+
success: chalk.green,
|
|
202
|
+
warning: chalk.yellow,
|
|
203
|
+
error: chalk.red,
|
|
204
|
+
info: chalk.white,
|
|
205
|
+
muted: chalk.gray,
|
|
206
|
+
accent: chalk.magenta
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// 图标
|
|
210
|
+
UIHelper.icons = {
|
|
211
|
+
success: '✅',
|
|
212
|
+
error: '❌',
|
|
213
|
+
warning: '⚠️',
|
|
214
|
+
info: 'ℹ️',
|
|
215
|
+
loading: '⏳',
|
|
216
|
+
arrow: '→',
|
|
217
|
+
back: '🔙',
|
|
218
|
+
home: '🏠',
|
|
219
|
+
settings: '⚙️',
|
|
220
|
+
add: '➕',
|
|
221
|
+
edit: '✏️',
|
|
222
|
+
delete: '🗑️',
|
|
223
|
+
launch: '🚀',
|
|
224
|
+
list: '📋',
|
|
225
|
+
config: '🛠️',
|
|
226
|
+
current: '🎯',
|
|
227
|
+
search: '🔍'
|
|
228
|
+
};
|
|
229
|
+
|
|
228
230
|
module.exports = { UIHelper };
|
|
@@ -1,7 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update Checker Utility
|
|
3
|
+
* 检查 npm 包更新
|
|
4
|
+
* @module utils/update-checker
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
const chalk = require('chalk');
|
|
2
8
|
const inquirer = require('inquirer');
|
|
3
9
|
const spawn = require('cross-spawn');
|
|
4
10
|
|
|
11
|
+
/**
|
|
12
|
+
* 比较两个版本号
|
|
13
|
+
* @param {string} a - 版本号 A
|
|
14
|
+
* @param {string} b - 版本号 B
|
|
15
|
+
* @returns {number} -1 表示 a < b, 0 表示相等, 1 表示 a > b
|
|
16
|
+
*/
|
|
5
17
|
function compareVersions(a, b) {
|
|
6
18
|
const pa = String(a).split('.').map(Number);
|
|
7
19
|
const pb = String(b).split('.').map(Number);
|
|
@@ -15,16 +27,22 @@ function compareVersions(a, b) {
|
|
|
15
27
|
return 0;
|
|
16
28
|
}
|
|
17
29
|
|
|
30
|
+
/**
|
|
31
|
+
* 获取 npm 包的最新版本号
|
|
32
|
+
* @param {string} pkgName - 包名
|
|
33
|
+
* @param {number} [timeoutMs=4000] - 超时时间(毫秒)
|
|
34
|
+
* @returns {Promise<string|null>} 最新版本号,失败返回 null
|
|
35
|
+
*/
|
|
18
36
|
function getLatestVersion(pkgName, timeoutMs = 4000) {
|
|
19
|
-
return new Promise((resolve,
|
|
37
|
+
return new Promise((resolve, _reject) => {
|
|
20
38
|
let done = false;
|
|
21
39
|
const child = spawn('npm', ['view', pkgName, 'version', '--json'], {
|
|
22
40
|
shell: process.platform === 'win32',
|
|
23
|
-
stdio: ['ignore', 'pipe', 'ignore']
|
|
41
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
24
42
|
});
|
|
25
43
|
|
|
26
44
|
let out = '';
|
|
27
|
-
child.stdout.on('data', (d) => (out += d.toString()))
|
|
45
|
+
child.stdout.on('data', (d) => (out += d.toString()));
|
|
28
46
|
|
|
29
47
|
const t = setTimeout(() => {
|
|
30
48
|
if (done) return;
|
|
@@ -86,8 +104,8 @@ async function checkForUpdates({ packageName, currentVersion }) {
|
|
|
86
104
|
type: 'confirm',
|
|
87
105
|
name: 'doUpdate',
|
|
88
106
|
message: '是否立即更新并重启?',
|
|
89
|
-
default: false
|
|
90
|
-
}
|
|
107
|
+
default: false
|
|
108
|
+
}
|
|
91
109
|
]);
|
|
92
110
|
|
|
93
111
|
if (!doUpdate) return;
|
|
@@ -96,7 +114,7 @@ async function checkForUpdates({ packageName, currentVersion }) {
|
|
|
96
114
|
await new Promise((resolve) => {
|
|
97
115
|
const child = spawn('npm', ['i', '-g', `${packageName}@latest`], {
|
|
98
116
|
shell: process.platform === 'win32',
|
|
99
|
-
stdio: 'inherit'
|
|
117
|
+
stdio: 'inherit'
|
|
100
118
|
});
|
|
101
119
|
child.on('close', (code) => resolve(code === 0));
|
|
102
120
|
}).then((ok) => {
|
|
@@ -113,7 +131,7 @@ async function checkForUpdates({ packageName, currentVersion }) {
|
|
|
113
131
|
|
|
114
132
|
const child = spawn(restartCommand, restartArgs, {
|
|
115
133
|
shell: process.platform === 'win32',
|
|
116
|
-
stdio: 'inherit'
|
|
134
|
+
stdio: 'inherit'
|
|
117
135
|
});
|
|
118
136
|
child.on('close', (code) => {
|
|
119
137
|
process.exit(code || 0);
|
package/src/utils/validator.js
CHANGED
|
@@ -15,8 +15,8 @@ const validator = {
|
|
|
15
15
|
|
|
16
16
|
// 禁止使用保留名称 (Windows)
|
|
17
17
|
const reserved = ['CON', 'PRN', 'AUX', 'NUL', 'COM1', 'COM2', 'COM3', 'COM4',
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'LPT1', 'LPT2',
|
|
19
|
+
'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'];
|
|
20
20
|
if (reserved.includes(name.toUpperCase())) {
|
|
21
21
|
return '供应商名称不能使用系统保留名称';
|
|
22
22
|
}
|
|
@@ -38,15 +38,15 @@ const validator = {
|
|
|
38
38
|
if (displayName === null || displayName === undefined || displayName === '') {
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
if (typeof displayName !== 'string') {
|
|
43
43
|
return '显示名称必须是字符串';
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
if (displayName.length > 100) {
|
|
47
47
|
return '显示名称不能超过100个字符';
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
return null;
|
|
51
51
|
},
|
|
52
52
|
|
|
@@ -54,17 +54,17 @@ const validator = {
|
|
|
54
54
|
if (!url || typeof url !== 'string') {
|
|
55
55
|
return required ? 'URL不能为空' : null;
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
try {
|
|
59
59
|
new URL(url);
|
|
60
60
|
} catch (error) {
|
|
61
61
|
return '请输入有效的URL';
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
|
65
65
|
return 'URL必须以http://或https://开头';
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
return null;
|
|
69
69
|
},
|
|
70
70
|
|
|
@@ -101,19 +101,19 @@ const validator = {
|
|
|
101
101
|
if (!model) {
|
|
102
102
|
return null;
|
|
103
103
|
}
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
if (typeof model !== 'string') {
|
|
106
106
|
return '模型名称必须是字符串';
|
|
107
107
|
}
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
if (model.trim().length === 0) {
|
|
110
110
|
return '模型名称不能为空字符串';
|
|
111
111
|
}
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
if (model.length > 100) {
|
|
114
114
|
return '模型名称不能超过100个字符';
|
|
115
115
|
}
|
|
116
|
-
|
|
116
|
+
|
|
117
117
|
return null;
|
|
118
118
|
},
|
|
119
119
|
|