feat: 添加快捷指令的标签管理系统

Related to #5
This commit is contained in:
Baobhan Sith
2025-05-03 15:18:51 +08:00
parent 430aac8512
commit 026ed949fb
22 changed files with 1828 additions and 296 deletions
@@ -0,0 +1,118 @@
import * as QuickCommandTagRepository from '../repositories/quick-command-tag.repository';
import { QuickCommandTag } from '../repositories/quick-command-tag.repository';
/**
* 获取所有快捷指令标签
*/
export const getAllQuickCommandTags = async (): Promise<QuickCommandTag[]> => {
return QuickCommandTagRepository.findAllQuickCommandTags();
};
/**
* 根据 ID 获取单个快捷指令标签
*/
export const getQuickCommandTagById = async (id: number): Promise<QuickCommandTag | null> => {
return QuickCommandTagRepository.findQuickCommandTagById(id);
};
/**
* 添加新的快捷指令标签
* @param name 标签名称
* @returns 返回新标签的 ID
*/
export const addQuickCommandTag = async (name: string): Promise<number> => {
if (!name || name.trim().length === 0) {
throw new Error('标签名称不能为空');
}
const trimmedName = name.trim();
// 可以在这里添加更多验证逻辑,例如检查名称格式等
try {
const newId = await QuickCommandTagRepository.createQuickCommandTag(trimmedName);
return newId;
} catch (error: any) {
// Service 层可以重新抛出或处理 Repository 抛出的错误
console.error(`[Service] 添加快捷指令标签 "${trimmedName}" 失败:`, error.message);
throw error; // 重新抛出,让 Controller 处理 HTTP 响应
}
};
/**
* 更新快捷指令标签
* @param id 标签 ID
* @param name 新的标签名称
* @returns 返回是否成功更新
*/
export const updateQuickCommandTag = async (id: number, name: string): Promise<boolean> => {
if (!name || name.trim().length === 0) {
throw new Error('标签名称不能为空');
}
const trimmedName = name.trim();
// 可以在这里添加更多验证逻辑
try {
const success = await QuickCommandTagRepository.updateQuickCommandTag(id, trimmedName);
if (!success) {
// 可能需要检查标签是否存在,或者让 Repository 处理
console.warn(`[Service] 尝试更新不存在的快捷指令标签 ID: ${id}`);
}
return success;
} catch (error: any) {
console.error(`[Service] 更新快捷指令标签 ${id} 失败:`, error.message);
throw error;
}
};
/**
* 删除快捷指令标签
* @param id 标签 ID
* @returns 返回是否成功删除
*/
export const deleteQuickCommandTag = async (id: number): Promise<boolean> => {
try {
const success = await QuickCommandTagRepository.deleteQuickCommandTag(id);
if (!success) {
console.warn(`[Service] 尝试删除不存在的快捷指令标签 ID: ${id}`);
}
return success;
} catch (error: any) {
console.error(`[Service] 删除快捷指令标签 ${id} 失败:`, error.message);
throw error;
}
};
/**
* 设置指定快捷指令的标签关联
* @param commandId 快捷指令 ID
* @param tagIds 新的快捷指令标签 ID 数组
* @returns Promise<void>
*/
export const setCommandTags = async (commandId: number, tagIds: number[]): Promise<void> => {
// 验证 tagIds 是否为数字数组 (基本验证)
if (!Array.isArray(tagIds) || !tagIds.every(id => typeof id === 'number')) {
throw new Error('标签 ID 列表必须是一个数字数组');
}
// 可以在这里添加更复杂的验证,例如检查 tagIds 是否都存在于 quick_command_tags 表中
// 但 Repository 中的 setCommandTagAssociations 已包含基本的检查和错误处理
try {
// 直接调用 Repository 处理关联更新 (Repository 函数现在返回 void)
await QuickCommandTagRepository.setCommandTagAssociations(commandId, tagIds);
// Service 函数也返回 void,所以不需要 return
} catch (error: any) {
console.error(`[Service] 设置快捷指令 ${commandId} 的标签失败:`, error.message);
throw error;
}
};
/**
* 获取指定快捷指令的所有标签
* @param commandId 快捷指令 ID
* @returns 标签对象数组
*/
export const getTagsForCommand = async (commandId: number): Promise<QuickCommandTag[]> => {
try {
return await QuickCommandTagRepository.findTagsByCommandId(commandId);
} catch (error: any) {
console.error(`[Service] 获取快捷指令 ${commandId} 的标签失败:`, error.message);
throw error;
}
};
@@ -1,5 +1,6 @@
import * as QuickCommandsRepository from '../repositories/quick-commands.repository';
import { QuickCommand } from '../repositories/quick-commands.repository';
import { QuickCommandWithTags } from '../repositories/quick-commands.repository'; // Import the type with tags
import * as QuickCommandTagRepository from '../repositories/quick-command-tag.repository'; // Import the new tag repository
// 定义排序类型
export type QuickCommandSortBy = 'name' | 'usage_count';
@@ -8,15 +9,28 @@ export type QuickCommandSortBy = 'name' | 'usage_count';
* 添加快捷指令
* @param name - 指令名称 (可选)
* @param command - 指令内容
* @param tagIds - 关联的快捷指令标签 ID 数组 (可选)
* @returns 返回添加记录的 ID
*/
export const addQuickCommand = async (name: string | null, command: string): Promise<number> => {
export const addQuickCommand = async (name: string | null, command: string, tagIds?: number[]): Promise<number> => {
if (!command || command.trim().length === 0) {
throw new Error('指令内容不能为空');
}
// 如果 name 是空字符串,则视为 null
const finalName = name && name.trim().length > 0 ? name.trim() : null;
return QuickCommandsRepository.addQuickCommand(finalName, command.trim());
const commandId = await QuickCommandsRepository.addQuickCommand(finalName, command.trim());
// 添加成功后,设置标签关联
if (commandId > 0 && tagIds && Array.isArray(tagIds)) {
try {
await QuickCommandTagRepository.setCommandTagAssociations(commandId, tagIds);
} catch (tagError: any) {
// 如果标签关联失败,可以选择记录警告或回滚(但通常不回滚主记录)
console.warn(`[Service] 添加快捷指令 ${commandId} 成功,但设置标签关联失败:`, tagError.message);
// 可以考虑是否需要通知用户部分操作失败
}
}
return commandId;
};
/**
@@ -24,15 +38,27 @@ export const addQuickCommand = async (name: string | null, command: string): Pro
* @param id - 要更新的记录 ID
* @param name - 新的指令名称 (可选)
* @param command - 新的指令内容
* @param tagIds - 新的关联标签 ID 数组 (可选, undefined 表示不更新标签)
* @returns 返回是否成功更新 (更新行数 > 0)
*/
export const updateQuickCommand = async (id: number, name: string | null, command: string): Promise<boolean> => {
export const updateQuickCommand = async (id: number, name: string | null, command: string, tagIds?: number[]): Promise<boolean> => {
if (!command || command.trim().length === 0) {
throw new Error('指令内容不能为空');
}
const finalName = name && name.trim().length > 0 ? name.trim() : null;
const changes = await QuickCommandsRepository.updateQuickCommand(id, finalName, command.trim());
return changes;
const commandUpdated = await QuickCommandsRepository.updateQuickCommand(id, finalName, command.trim());
// 如果指令更新成功,并且提供了 tagIds (即使是空数组也表示要更新),则更新标签关联
if (commandUpdated && typeof tagIds !== 'undefined') {
try {
await QuickCommandTagRepository.setCommandTagAssociations(id, tagIds);
} catch (tagError: any) {
console.warn(`[Service] 更新快捷指令 ${id} 成功,但更新标签关联失败:`, tagError.message);
// 即使标签更新失败,主记录已更新,通常返回 true
}
}
// 返回主记录是否更新成功
return commandUpdated;
};
/**
@@ -48,9 +74,10 @@ export const deleteQuickCommand = async (id: number): Promise<boolean> => {
/**
* 获取所有快捷指令,并按指定方式排序
* @param sortBy - 排序字段 ('name' 或 'usage_count')
* @returns 返回排序后的快捷指令数组
* @returns 返回排序后的快捷指令数组 (包含 tagIds)
*/
export const getAllQuickCommands = async (sortBy: QuickCommandSortBy = 'name'): Promise<QuickCommand[]> => {
export const getAllQuickCommands = async (sortBy: QuickCommandSortBy = 'name'): Promise<QuickCommandWithTags[]> => {
// Repository 已返回带 tagIds 的数据
return QuickCommandsRepository.getAllQuickCommands(sortBy);
};
@@ -67,8 +94,38 @@ export const incrementUsageCount = async (id: number): Promise<boolean> => {
/**
* 根据 ID 获取单个快捷指令 (可能用于编辑)
* @param id - 记录 ID
* @returns 返回找到的快捷指令,或 undefined
* @returns 返回找到的快捷指令 (包含 tagIds),或 undefined
*/
export const getQuickCommandById = async (id: number): Promise<QuickCommand | undefined> => {
export const getQuickCommandById = async (id: number): Promise<QuickCommandWithTags | undefined> => {
// Repository 已返回带 tagIds 的数据
return QuickCommandsRepository.findQuickCommandById(id);
};
/**
* 将单个标签批量关联到多个快捷指令
* @param commandIds - 需要添加标签的快捷指令 ID 数组
* @param tagId - 要添加的标签 ID
* @returns Promise<void>
*/
export const assignTagToCommands = async (commandIds: number[], tagId: number): Promise<void> => {
try {
// 基本验证
if (!Array.isArray(commandIds) || commandIds.some(id => typeof id !== 'number' || isNaN(id))) {
throw new Error('无效的指令 ID 列表');
}
if (typeof tagId !== 'number' || isNaN(tagId)) {
throw new Error('无效的标签 ID');
}
// 调用 Repository 函数执行批量关联
// 注意:这里需要导入 QuickCommandTagRepository
console.log(`[Service] assignTagToCommands: Calling repo with commandIds: ${JSON.stringify(commandIds)}, tagId: ${tagId}`); // +++ 添加日志 +++
await QuickCommandTagRepository.addTagToCommands(commandIds, tagId);
console.log(`[Service] assignTagToCommands: Repo call finished for tag ${tagId}.`); // +++ 修改日志 +++
// 可以在这里添加额外的业务逻辑,例如发送事件通知等
} catch (error: any) {
console.error(`[Service] assignTagToCommands: 批量关联标签 ${tagId} 到指令时出错:`, error.message);
// 向上抛出错误,让 Controller 处理 HTTP 响应
throw error;
}
};