feat: 添加快捷指令功能
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
Reference in New Issue
Block a user