feat: 添加快捷指令功能

This commit is contained in:
Baobhan Sith
2025-04-17 13:20:27 +08:00
parent b62982faa0
commit 747c9491c4
14 changed files with 1114 additions and 11 deletions
+2
View File
@@ -17,6 +17,7 @@ import settingsRoutes from './settings/settings.routes'; // 导入设置路由
import notificationRoutes from './notifications/notification.routes'; // 导入通知路由
import auditRoutes from './audit/audit.routes'; // 导入审计路由
import commandHistoryRoutes from './command-history/command-history.routes'; // 导入命令历史记录路由
import quickCommandsRoutes from './quick-commands/quick-commands.routes'; // 导入快捷指令路由
import { initializeWebSocket } from './websocket';
import { ipWhitelistMiddleware } from './auth/ipWhitelist.middleware'; // 导入 IP 白名单中间件
@@ -104,6 +105,7 @@ app.use('/api/v1/settings', settingsRoutes); // 挂载设置相关的路由
app.use('/api/v1/notifications', notificationRoutes); // 挂载通知相关的路由
app.use('/api/v1/audit-logs', auditRoutes); // 挂载审计日志相关的路由
app.use('/api/v1/command-history', commandHistoryRoutes); // 挂载命令历史记录相关的路由
app.use('/api/v1/quick-commands', quickCommandsRoutes); // 挂载快捷指令相关的路由
// 状态检查接口
app.get('/api/v1/status', (req: Request, res: Response) => {
+20
View File
@@ -139,6 +139,17 @@ CREATE TABLE IF NOT EXISTS command_history (
timestamp INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
);
`;
const createQuickCommandsTableSQL = `
CREATE TABLE IF NOT EXISTS quick_commands (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NULL, -- 名称可选
command TEXT NOT NULL, -- 指令必选
usage_count INTEGER NOT NULL DEFAULT 0, -- 使用频率
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
);
`;
// --- 结束新增表结构定义 ---
@@ -271,6 +282,15 @@ export const runMigrations = async (db: Database): Promise<void> => {
});
});
// 创建 quick_commands 表
await new Promise<void>((resolve, reject) => {
db.run(createQuickCommandsTableSQL, (err: Error | null) => {
if (err) return reject(new Error(`创建 quick_commands 表时出错: ${err.message}`));
console.log('Quick_Commands 表已检查/创建。');
resolve();
});
});
// --- 结束新增表创建逻辑 ---
@@ -0,0 +1,130 @@
import { Request, Response } from 'express';
import * as QuickCommandsService from '../services/quick-commands.service';
import { QuickCommandSortBy } from '../services/quick-commands.service';
/**
* 处理添加新快捷指令的请求
*/
export const addQuickCommand = async (req: Request, res: Response): Promise<void> => {
const { name, command } = req.body;
if (!command || typeof command !== 'string' || command.trim().length === 0) {
res.status(400).json({ message: '指令内容不能为空' });
return;
}
// 名称可以是 null 或 string
if (name !== null && typeof name !== 'string') {
res.status(400).json({ message: '名称必须是字符串或 null' });
return;
}
try {
const newId = await QuickCommandsService.addQuickCommand(name, command);
res.status(201).json({ id: newId, message: '快捷指令已添加' });
} catch (error: any) {
console.error('添加快捷指令控制器出错:', error);
res.status(500).json({ message: error.message || '无法添加快捷指令' });
}
};
/**
* 处理获取所有快捷指令的请求 (支持排序)
*/
export const getAllQuickCommands = async (req: Request, res: Response): Promise<void> => {
const sortBy = req.query.sortBy as QuickCommandSortBy | undefined;
// 验证 sortBy 参数
const validSortBy: QuickCommandSortBy = (sortBy === 'name' || sortBy === 'usage_count') ? sortBy : 'name';
try {
const commands = await QuickCommandsService.getAllQuickCommands(validSortBy);
res.status(200).json(commands);
} catch (error: any) {
console.error('获取快捷指令控制器出错:', error);
res.status(500).json({ message: error.message || '无法获取快捷指令' });
}
};
/**
* 处理更新快捷指令的请求
*/
export const updateQuickCommand = async (req: Request, res: Response): Promise<void> => {
const id = parseInt(req.params.id, 10);
const { name, command } = req.body;
if (isNaN(id)) {
res.status(400).json({ message: '无效的 ID' });
return;
}
if (!command || typeof command !== 'string' || command.trim().length === 0) {
res.status(400).json({ message: '指令内容不能为空' });
return;
}
if (name !== null && typeof name !== 'string') {
res.status(400).json({ message: '名称必须是字符串或 null' });
return;
}
try {
const success = await QuickCommandsService.updateQuickCommand(id, name, command);
if (success) {
res.status(200).json({ message: '快捷指令已更新' });
} else {
res.status(404).json({ message: '未找到要更新的快捷指令' });
}
} catch (error: any) {
console.error('更新快捷指令控制器出错:', error);
res.status(500).json({ message: error.message || '无法更新快捷指令' });
}
};
/**
* 处理删除快捷指令的请求
*/
export const deleteQuickCommand = async (req: Request, res: Response): Promise<void> => {
const id = parseInt(req.params.id, 10);
if (isNaN(id)) {
res.status(400).json({ message: '无效的 ID' });
return;
}
try {
const success = await QuickCommandsService.deleteQuickCommand(id);
if (success) {
res.status(200).json({ message: '快捷指令已删除' });
} else {
res.status(404).json({ message: '未找到要删除的快捷指令' });
}
} catch (error: any) {
console.error('删除快捷指令控制器出错:', error);
res.status(500).json({ message: error.message || '无法删除快捷指令' });
}
};
/**
* 处理增加快捷指令使用次数的请求
*/
export const incrementUsage = async (req: Request, res: Response): Promise<void> => {
const id = parseInt(req.params.id, 10);
if (isNaN(id)) {
res.status(400).json({ message: '无效的 ID' });
return;
}
try {
const success = await QuickCommandsService.incrementUsageCount(id);
if (success) {
res.status(200).json({ message: '使用次数已增加' });
} else {
// 即使没找到也可能返回成功,避免不必要的错误提示
console.warn(`尝试增加不存在的快捷指令 (ID: ${id}) 的使用次数`);
res.status(200).json({ message: '使用次数已记录 (或指令不存在)' });
// 或者严格一点返回 404:
// res.status(404).json({ message: '未找到要增加使用次数的快捷指令' });
}
} catch (error: any) {
console.error('增加快捷指令使用次数控制器出错:', error);
res.status(500).json({ message: error.message || '无法增加使用次数' });
}
};
@@ -0,0 +1,17 @@
import { Router } from 'express';
import * as QuickCommandsController from './quick-commands.controller';
import { isAuthenticated } from '../auth/auth.middleware'; // 引入认证中间件
const router = Router();
// 应用认证中间件到所有快捷指令相关的路由
router.use(isAuthenticated);
// 定义路由
router.post('/', QuickCommandsController.addQuickCommand); // POST /api/v1/quick-commands
router.get('/', QuickCommandsController.getAllQuickCommands); // GET /api/v1/quick-commands?sortBy=name|usage_count
router.put('/:id', QuickCommandsController.updateQuickCommand); // PUT /api/v1/quick-commands/:id
router.delete('/:id', QuickCommandsController.deleteQuickCommand); // DELETE /api/v1/quick-commands/:id
router.post('/:id/increment-usage', QuickCommandsController.incrementUsage); // POST /api/v1/quick-commands/:id/increment-usage
export default router;
@@ -0,0 +1,133 @@
import { getDb } from '../database';
// 定义快捷指令的接口
export interface QuickCommand {
id: number;
name: string | null; // 名称可选
command: string;
usage_count: number;
created_at: number; // Unix 时间戳 (秒)
updated_at: number; // Unix 时间戳 (秒)
}
/**
* 添加一条新的快捷指令
* @param name - 指令名称 (可选)
* @param command - 指令内容
* @returns 返回插入记录的 ID
*/
export const addQuickCommand = (name: string | null, command: string): Promise<number> => {
const db = getDb();
const sql = `INSERT INTO quick_commands (name, command, created_at, updated_at) VALUES (?, ?, strftime('%s', 'now'), strftime('%s', 'now'))`;
return new Promise((resolve, reject) => {
db.run(sql, [name, command], function (err) {
if (err) {
console.error('添加快捷指令时出错:', err);
return reject(new Error('无法添加快捷指令'));
}
resolve(this.lastID);
});
});
};
/**
* 更新指定的快捷指令
* @param id - 要更新的记录 ID
* @param name - 新的指令名称 (可选)
* @param command - 新的指令内容
* @returns 返回更新的行数 (通常是 1 或 0)
*/
export const updateQuickCommand = (id: number, name: string | null, command: string): Promise<number> => {
const db = getDb();
const sql = `UPDATE quick_commands SET name = ?, command = ?, updated_at = strftime('%s', 'now') WHERE id = ?`;
return new Promise((resolve, reject) => {
db.run(sql, [name, command, id], function (err) {
if (err) {
console.error('更新快捷指令时出错:', err);
return reject(new Error('无法更新快捷指令'));
}
resolve(this.changes);
});
});
};
/**
* 根据 ID 删除指定的快捷指令
* @param id - 要删除的记录 ID
* @returns 返回删除的行数 (通常是 1 或 0)
*/
export const deleteQuickCommand = (id: number): Promise<number> => {
const db = getDb();
const sql = `DELETE FROM quick_commands WHERE id = ?`;
return new Promise((resolve, reject) => {
db.run(sql, [id], function (err) {
if (err) {
console.error('删除快捷指令时出错:', err);
return reject(new Error('无法删除快捷指令'));
}
resolve(this.changes);
});
});
};
/**
* 获取所有快捷指令
* @param sortBy - 排序字段 ('name' 或 'usage_count')
* @returns 返回包含所有快捷指令条目的数组
*/
export const getAllQuickCommands = (sortBy: 'name' | 'usage_count' = 'name'): Promise<QuickCommand[]> => {
const db = getDb();
let orderByClause = 'ORDER BY name ASC'; // 默认按名称升序
if (sortBy === 'usage_count') {
orderByClause = 'ORDER BY usage_count DESC, name ASC'; // 按使用频率降序,同频率按名称升序
}
// SQLite 中 NULLS LAST/FIRST 的支持可能不一致,这里简单处理 NULL 名称排在前面
const sql = `SELECT id, name, command, usage_count, created_at, updated_at FROM quick_commands ${orderByClause}`;
return new Promise((resolve, reject) => {
db.all(sql, [], (err, rows: QuickCommand[]) => {
if (err) {
console.error('获取快捷指令时出错:', err);
return reject(new Error('无法获取快捷指令'));
}
resolve(rows);
});
});
};
/**
* 增加指定快捷指令的使用次数
* @param id - 要增加次数的记录 ID
* @returns 返回更新的行数 (通常是 1 或 0)
*/
export const incrementUsageCount = (id: number): Promise<number> => {
const db = getDb();
const sql = `UPDATE quick_commands SET usage_count = usage_count + 1, updated_at = strftime('%s', 'now') WHERE id = ?`;
return new Promise((resolve, reject) => {
db.run(sql, [id], function (err) {
if (err) {
console.error('增加快捷指令使用次数时出错:', err);
return reject(new Error('无法增加快捷指令使用次数'));
}
resolve(this.changes);
});
});
};
/**
* 根据 ID 查找快捷指令 (用于编辑前获取数据)
* @param id - 要查找的记录 ID
* @returns 返回找到的快捷指令条目,如果未找到则返回 undefined
*/
export const findQuickCommandById = (id: number): Promise<QuickCommand | undefined> => {
const db = getDb();
const sql = `SELECT id, name, command, usage_count, created_at, updated_at FROM quick_commands WHERE id = ?`;
return new Promise((resolve, reject) => {
db.get(sql, [id], (err, row: QuickCommand | undefined) => {
if (err) {
console.error('查找快捷指令时出错:', err);
return reject(new Error('无法查找快捷指令'));
}
resolve(row);
});
});
};
@@ -0,0 +1,74 @@
import * as QuickCommandsRepository from '../repositories/quick-commands.repository';
import { QuickCommand } from '../repositories/quick-commands.repository';
// 定义排序类型
export type QuickCommandSortBy = 'name' | 'usage_count';
/**
* 添加快捷指令
* @param name - 指令名称 (可选)
* @param command - 指令内容
* @returns 返回添加记录的 ID
*/
export const addQuickCommand = async (name: string | null, command: string): 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());
};
/**
* 更新快捷指令
* @param id - 要更新的记录 ID
* @param name - 新的指令名称 (可选)
* @param command - 新的指令内容
* @returns 返回是否成功更新 (更新行数 > 0)
*/
export const updateQuickCommand = async (id: number, name: string | null, command: string): 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 > 0;
};
/**
* 删除快捷指令
* @param id - 要删除的记录 ID
* @returns 返回是否成功删除 (删除行数 > 0)
*/
export const deleteQuickCommand = async (id: number): Promise<boolean> => {
const changes = await QuickCommandsRepository.deleteQuickCommand(id);
return changes > 0;
};
/**
* 获取所有快捷指令,并按指定方式排序
* @param sortBy - 排序字段 ('name' 或 'usage_count')
* @returns 返回排序后的快捷指令数组
*/
export const getAllQuickCommands = async (sortBy: QuickCommandSortBy = 'name'): Promise<QuickCommand[]> => {
return QuickCommandsRepository.getAllQuickCommands(sortBy);
};
/**
* 增加快捷指令的使用次数
* @param id - 记录 ID
* @returns 返回是否成功更新 (更新行数 > 0)
*/
export const incrementUsageCount = async (id: number): Promise<boolean> => {
const changes = await QuickCommandsRepository.incrementUsageCount(id);
return changes > 0;
};
/**
* 根据 ID 获取单个快捷指令 (可能用于编辑)
* @param id - 记录 ID
* @returns 返回找到的快捷指令,或 undefined
*/
export const getQuickCommandById = async (id: number): Promise<QuickCommand | undefined> => {
return QuickCommandsRepository.findQuickCommandById(id);
};