fix: 支持带空格的名称参数

- 修改 /profile remove 命令,支持删除带空格的配置名称(如 'IPA 上传')
- 修改 /config remove 命令,支持删除带空格的存储桶名称
- 修改 /path remove 命令,支持删除带空格的预设路径名称
- 修改 /profile add 命令,支持带空格的配置名称
- 修改 /config add 命令,支持带空格的存储桶名称
- 修改 /path add 命令,支持带空格的路径名称

参数解析逻辑:
- 先提取子命令(第一个空格前的内容)
- 剩余内容作为参数文本
- remove 命令:整个参数文本作为名称(支持空格)
- add 命令:从后往前解析固定参数,其余合并为名称
This commit is contained in:
饭团
2026-03-14 21:46:02 +08:00
parent 3045cc86d5
commit 67fb630069

View File

@@ -527,8 +527,15 @@ async function doUpload(chatId, feishu, uploader, info) {
async function handleConfigCommandV2(message, content, feishu, uploader) { async function handleConfigCommandV2(message, content, feishu, uploader) {
const chatId = message.chat_id; const chatId = message.chat_id;
const text = content.text || ''; const text = content.text || '';
const args = text.replace(/^\/(config|qc)\s*/i, '').trim().split(/\s+/);
const subCommand = args[0]; // 提取命令后的剩余文本
const remainingText = text.replace(/^\/(config|qc)\s*/i, '').trim();
// 先提取子命令
const spaceIndex = remainingText.indexOf(' ');
const subCommand = spaceIndex === -1 ? remainingText : remainingText.substring(0, spaceIndex);
const paramsText = spaceIndex === -1 ? '' : remainingText.substring(spaceIndex + 1).trim();
const args = paramsText ? paramsText.split(/\s+/) : [];
const configPath = path.join(process.cwd(), 'config', 'qiniu-config.json'); const configPath = path.join(process.cwd(), 'config', 'qiniu-config.json');
@@ -540,15 +547,16 @@ async function handleConfigCommandV2(message, content, feishu, uploader) {
await feishu.sendCard(chatId, createBucketsListCard(configData)); await feishu.sendCard(chatId, createBucketsListCard(configData));
} else if (subCommand === 'add') { } else if (subCommand === 'add') {
// /config add <名称> <accessKey> <secretKey> <bucket> <region> <domain> // /config add <名称> <accessKey> <secretKey> <bucket> <region> <domain>
if (args.length < 7) { if (args.length < 6) {
throw new Error('用法:/config add <名称> <accessKey> <secretKey> <bucket> <region> <domain>\n示例/config add mybucket xxxxxx yyyyyy my-bucket z0 https://cdn.example.com'); throw new Error('用法:/config add <名称> <accessKey> <secretKey> <bucket> <region> <domain>\n示例/config add mybucket xxxxxx yyyyyy my-bucket z0 https://cdn.example.com');
} }
const name = args[1]; // 名称支持空格:从后往前解析,最后 5 个参数是固定的,其余是名称
const accessKey = args[2]; const domain = args[args.length - 1];
const secretKey = args[3]; const region = args[args.length - 2];
const bucket = args[4]; const bucket = args[args.length - 3];
const region = args[5]; const secretKey = args[args.length - 4];
const domain = args[6]; const accessKey = args[args.length - 5];
const name = args.slice(0, args.length - 5).join(' ');
// 验证区域代码 // 验证区域代码
const validRegions = ['z0', 'z1', 'z2', 'na0', 'as0']; const validRegions = ['z0', 'z1', 'z2', 'na0', 'as0'];
@@ -570,13 +578,15 @@ async function handleConfigCommandV2(message, content, feishu, uploader) {
content: { text: `✅ 已添加存储桶配置:**${name}**\n存储桶:${bucket}\n区域:${region}\n域名:${domain}` } content: { text: `✅ 已添加存储桶配置:**${name}**\n存储桶:${bucket}\n区域:${region}\n域名:${domain}` }
}); });
} else if (subCommand === 'remove' || subCommand === 'del') { } else if (subCommand === 'remove' || subCommand === 'del') {
if (args.length < 2) { if (!paramsText) {
throw new Error('用法:/config remove <名称>'); throw new Error('用法:/config remove <名称>\n示例/config remove my bucket');
} }
const name = args[1]; // 整个 paramsText 就是名称 (支持空格)
const name = paramsText;
if (!fullConfig.buckets[name]) { if (!fullConfig.buckets[name]) {
throw new Error(`存储桶 "${name}" 不存在,可用:${Object.keys(fullConfig.buckets).join(', ')}`); const availableBuckets = Object.keys(fullConfig.buckets).join(', ');
throw new Error(`存储桶 "${name}" 不存在\n可用存储桶:${availableBuckets || '无'}`);
} }
// 不允许删除 default 存储桶 // 不允许删除 default 存储桶
@@ -621,8 +631,15 @@ async function handleConfigCommandV2(message, content, feishu, uploader) {
async function handlePathCommandV2(message, content, feishu) { async function handlePathCommandV2(message, content, feishu) {
const chatId = message.chat_id; const chatId = message.chat_id;
const text = content.text || ''; const text = content.text || '';
const args = text.replace(/^\/path\s*/i, '').trim().split(/\s+/);
const subCommand = args[0]; // 提取命令后的剩余文本
const remainingText = text.replace(/^\/path\s*/i, '').trim();
// 先提取子命令
const spaceIndex = remainingText.indexOf(' ');
const subCommand = spaceIndex === -1 ? remainingText : remainingText.substring(0, spaceIndex);
const paramsText = spaceIndex === -1 ? '' : remainingText.substring(spaceIndex + 1).trim();
const args = paramsText ? paramsText.split(/\s+/) : [];
const configPath = path.join(process.cwd(), 'config', 'qiniu-config.json'); const configPath = path.join(process.cwd(), 'config', 'qiniu-config.json');
@@ -633,11 +650,12 @@ async function handlePathCommandV2(message, content, feishu) {
const paths = fullConfig.uploadPaths || {}; const paths = fullConfig.uploadPaths || {};
await feishu.sendCard(chatId, createPathsListCard(paths)); await feishu.sendCard(chatId, createPathsListCard(paths));
} else if (subCommand === 'add') { } else if (subCommand === 'add') {
if (args.length < 3) { if (args.length < 2) {
throw new Error('用法:/path add <名称> <路径>\n示例/path add backup /backup/'); throw new Error('用法:/path add <名称> <路径>\n示例/path add backup /backup/');
} }
const name = args[1]; // 名称支持空格:第一个参数之后的所有内容作为路径
const pathValue = args[2]; const name = args[0];
const pathValue = args.slice(1).join(' ');
fullConfig.uploadPaths = fullConfig.uploadPaths || {}; fullConfig.uploadPaths = fullConfig.uploadPaths || {};
fullConfig.uploadPaths[name] = pathValue; fullConfig.uploadPaths[name] = pathValue;
@@ -647,13 +665,15 @@ async function handlePathCommandV2(message, content, feishu) {
content: { text: `✅ 已添加预设路径:**${name}** → ${pathValue}` } content: { text: `✅ 已添加预设路径:**${name}** → ${pathValue}` }
}); });
} else if (subCommand === 'remove' || subCommand === 'del') { } else if (subCommand === 'remove' || subCommand === 'del') {
if (args.length < 2) { if (!paramsText) {
throw new Error('用法:/path remove <名称>'); throw new Error('用法:/path remove <名称>\n示例/path remove my path');
} }
const name = args[1]; // 整个 paramsText 就是名称 (支持空格)
const name = paramsText;
if (!fullConfig.uploadPaths || !fullConfig.uploadPaths[name]) { if (!fullConfig.uploadPaths || !fullConfig.uploadPaths[name]) {
throw new Error(`预设路径 "${name}" 不存在,可用:${Object.keys(fullConfig.uploadPaths || {}).join(', ') || '无'}`); const availablePaths = Object.keys(fullConfig.uploadPaths || {}).join(', ');
throw new Error(`预设路径 "${name}" 不存在\n可用路径:${availablePaths || '无'}`);
} }
// 检查是否有上传配置引用此路径 // 检查是否有上传配置引用此路径
@@ -686,8 +706,14 @@ async function handlePathCommandV2(message, content, feishu) {
async function handleProfileCommandV2(message, content, feishu) { async function handleProfileCommandV2(message, content, feishu) {
const chatId = message.chat_id; const chatId = message.chat_id;
const text = content.text || ''; const text = content.text || '';
const args = text.replace(/^\/profile\s*/i, '').trim().split(/\s+/);
const subCommand = args[0]; // 提取命令后的剩余文本
const remainingText = text.replace(/^\/profile\s*/i, '').trim();
// 先提取子命令
const spaceIndex = remainingText.indexOf(' ');
const subCommand = spaceIndex === -1 ? remainingText : remainingText.substring(0, spaceIndex);
const paramsText = spaceIndex === -1 ? '' : remainingText.substring(spaceIndex + 1).trim();
const configPath = path.join(process.cwd(), 'config', 'qiniu-config.json'); const configPath = path.join(process.cwd(), 'config', 'qiniu-config.json');
@@ -700,12 +726,17 @@ async function handleProfileCommandV2(message, content, feishu) {
await feishu.sendCard(chatId, createProfilesListCard(profiles, uploadPaths)); await feishu.sendCard(chatId, createProfilesListCard(profiles, uploadPaths));
} else if (subCommand === 'add') { } else if (subCommand === 'add') {
// /profile add <名称> <存储桶> [路径键名] // /profile add <名称> <存储桶> [路径键名]
if (args.length < 3) { // 支持带空格的名称,从后往前解析:最后一个是路径 (可选),倒数第二个是存储桶,其余是名称
const addParams = paramsText.split(/\s+/).filter(p => p);
if (addParams.length < 2) {
throw new Error('用法:/profile add <名称> <存储桶> [路径键名]\n示例/profile add IPA 上传 default ipa'); throw new Error('用法:/profile add <名称> <存储桶> [路径键名]\n示例/profile add IPA 上传 default ipa');
} }
const name = args[1];
const bucket = args[2]; // 从后往前解析:最后一个参数是路径 (可选),倒数第二个是存储桶,其余是名称
const pathKey = args[3] || ''; const pathKey = addParams.length >= 3 ? addParams[addParams.length - 1] : '';
const bucket = addParams[addParams.length - (pathKey ? 2 : 1)];
const name = addParams.slice(0, addParams.length - (pathKey ? 2 : 1)).join(' ');
// 验证存储桶是否存在 // 验证存储桶是否存在
if (!fullConfig.buckets[bucket]) { if (!fullConfig.buckets[bucket]) {
@@ -732,13 +763,15 @@ async function handleProfileCommandV2(message, content, feishu) {
content: { text: `✅ 已添加上传配置:**${name}**\n存储桶:${bucket}\n路径:${pathDisplay}` } content: { text: `✅ 已添加上传配置:**${name}**\n存储桶:${bucket}\n路径:${pathDisplay}` }
}); });
} else if (subCommand === 'remove' || subCommand === 'del') { } else if (subCommand === 'remove' || subCommand === 'del') {
if (args.length < 2) { if (!paramsText) {
throw new Error('用法:/profile remove <名称>'); throw new Error('用法:/profile remove <名称>\n示例/profile remove IPA 上传');
} }
const name = args[1]; // 整个 paramsText 就是名称 (支持空格)
const name = paramsText;
if (!fullConfig.uploadProfiles || !fullConfig.uploadProfiles[name]) { if (!fullConfig.uploadProfiles || !fullConfig.uploadProfiles[name]) {
throw new Error(`上传配置 "${name}" 不存在`); const availableProfiles = Object.keys(fullConfig.uploadProfiles || {}).join(', ');
throw new Error(`上传配置 "${name}" 不存在\n可用配置:${availableProfiles || '无'}`);
} }
delete fullConfig.uploadProfiles[name]; delete fullConfig.uploadProfiles[name];