mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-11 21:06:56 +08:00
feat: 在 ClientAutoAction 组件中新增操作历史标签页和相关功能
- 引入 ActionHistoryViewer 组件,展示执行历史。 - 更新主标签页逻辑,调整为操作管理和执行历史两个标签。 - 在自动操作逻辑中增加弹幕和私信发送历史记录功能,提升操作追踪能力。
This commit is contained in:
@@ -11,6 +11,7 @@ import { buildExecutionContext, getRandomTemplate } from './utils';
|
||||
import { evaluateTemplateExpressions } from './expressionEvaluator';
|
||||
import { evaluateExpression } from './utils';
|
||||
import { useBiliCookie } from '../useBiliCookie';
|
||||
import { logDanmakuHistory, logPrivateMsgHistory, logCommandHistory } from './utils/historyLogger';
|
||||
|
||||
/**
|
||||
* 过滤有效的自动操作项
|
||||
@@ -223,11 +224,57 @@ export function executeActions(
|
||||
if (action.actionConfig.delaySeconds && action.actionConfig.delaySeconds > 0) {
|
||||
setTimeout(() => {
|
||||
handlers.sendLiveDanmaku!(roomId, message)
|
||||
.catch(err => console.error(`[AutoAction] 发送弹幕失败 (${action.name || action.id}):`, err));
|
||||
.then(success => {
|
||||
// 记录弹幕发送历史
|
||||
logDanmakuHistory(
|
||||
action.id,
|
||||
action.name || '未命名操作',
|
||||
message,
|
||||
roomId,
|
||||
success,
|
||||
success ? undefined : '发送失败'
|
||||
).catch(err => console.error('记录弹幕历史失败:', err));
|
||||
return success;
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(`[AutoAction] 发送弹幕失败 (${action.name || action.id}):`, err);
|
||||
// 记录失败的发送
|
||||
logDanmakuHistory(
|
||||
action.id,
|
||||
action.name || '未命名操作',
|
||||
message,
|
||||
roomId,
|
||||
false,
|
||||
err.toString()
|
||||
).catch(e => console.error('记录弹幕历史失败:', e));
|
||||
});
|
||||
}, action.actionConfig.delaySeconds * 1000);
|
||||
} else {
|
||||
handlers.sendLiveDanmaku(roomId, message)
|
||||
.catch(err => console.error(`[AutoAction] 发送弹幕失败 (${action.name || action.id}):`, err));
|
||||
.then(success => {
|
||||
// 记录弹幕发送历史
|
||||
logDanmakuHistory(
|
||||
action.id,
|
||||
action.name || '未命名操作',
|
||||
message,
|
||||
roomId,
|
||||
success,
|
||||
success ? undefined : '发送失败'
|
||||
).catch(err => console.error('记录弹幕历史失败:', err));
|
||||
return success;
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(`[AutoAction] 发送弹幕失败 (${action.name || action.id}):`, err);
|
||||
// 记录失败的发送
|
||||
logDanmakuHistory(
|
||||
action.id,
|
||||
action.name || '未命名操作',
|
||||
message,
|
||||
roomId,
|
||||
false,
|
||||
err.toString()
|
||||
).catch(e => console.error('记录弹幕历史失败:', e));
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -249,6 +296,16 @@ export function executeActions(
|
||||
const sendPmPromise = (uid: number, msg: string) => {
|
||||
return handlers.sendPrivateMessage!(uid, msg)
|
||||
.then(success => {
|
||||
// 记录私信发送历史
|
||||
logPrivateMsgHistory(
|
||||
action.id,
|
||||
action.name || '未命名操作',
|
||||
msg,
|
||||
uid,
|
||||
success,
|
||||
success ? undefined : '发送失败'
|
||||
).catch(err => console.error('记录私信历史失败:', err));
|
||||
|
||||
if (success && options?.onSuccess) {
|
||||
// 发送成功后调用 onSuccess 回调
|
||||
options.onSuccess(action, context);
|
||||
@@ -257,6 +314,15 @@ export function executeActions(
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(`[AutoAction] 发送私信失败 (${action.name || action.id}):`, err);
|
||||
// 记录失败的发送
|
||||
logPrivateMsgHistory(
|
||||
action.id,
|
||||
action.name || '未命名操作',
|
||||
msg,
|
||||
uid,
|
||||
false,
|
||||
err.toString()
|
||||
).catch(e => console.error('记录私信历史失败:', e));
|
||||
return false; // 明确返回 false 表示失败
|
||||
});
|
||||
};
|
||||
@@ -276,8 +342,22 @@ export function executeActions(
|
||||
break;
|
||||
|
||||
case ActionType.EXECUTE_COMMAND:
|
||||
// 执行自定义命令(未实现)
|
||||
console.warn(`[AutoAction] 暂不支持执行自定义命令: ${action.name || action.id}`);
|
||||
// 执行自定义命令
|
||||
const command = processTemplate(action, context);
|
||||
if (command) {
|
||||
// 更新冷却时间
|
||||
runtimeState.lastExecutionTime[action.id] = Date.now();
|
||||
|
||||
// 目前只记录执行历史,具体实现可在未来扩展
|
||||
logCommandHistory(
|
||||
action.id,
|
||||
action.name || '未命名操作',
|
||||
command,
|
||||
true
|
||||
).catch(err => console.error('记录命令执行历史失败:', err));
|
||||
|
||||
console.warn(`[AutoAction] 暂不支持执行自定义命令: ${action.name || action.id}`);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
145
src/client/store/autoAction/utils/historyLogger.ts
Normal file
145
src/client/store/autoAction/utils/historyLogger.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import { get, set, del, update } from 'idb-keyval';
|
||||
import { ActionType } from '../types';
|
||||
|
||||
// 历史记录类型常量
|
||||
export enum HistoryType {
|
||||
DANMAKU = 'danmaku',
|
||||
PRIVATE_MSG = 'privateMsg',
|
||||
COMMAND = 'command',
|
||||
}
|
||||
|
||||
// 历史记录项结构
|
||||
export interface HistoryItem {
|
||||
id: string; // 唯一ID
|
||||
actionId: string; // 操作ID
|
||||
actionName: string; // 操作名称
|
||||
actionType: ActionType; // 操作类型
|
||||
timestamp: number; // 执行时间戳
|
||||
content: string; // 发送的内容
|
||||
target?: string; // 目标(如UID或房间ID)
|
||||
success: boolean; // 是否成功
|
||||
error?: string; // 错误信息(如果有)
|
||||
}
|
||||
|
||||
// 每种类型的历史记录容量
|
||||
const HISTORY_CAPACITY = 1000;
|
||||
|
||||
// 使用IDB存储的键名
|
||||
const HISTORY_KEYS = {
|
||||
[HistoryType.DANMAKU]: 'autoAction_history_danmaku',
|
||||
[HistoryType.PRIVATE_MSG]: 'autoAction_history_privateMsg',
|
||||
[HistoryType.COMMAND]: 'autoAction_history_command',
|
||||
};
|
||||
|
||||
// 环形队列添加记录
|
||||
async function addToCircularQueue(key: string, item: HistoryItem, capacity: number): Promise<void> {
|
||||
await update<HistoryItem[]>(key, (history = []) => {
|
||||
// 添加到队列末尾
|
||||
history.push(item);
|
||||
|
||||
// 如果超出容量,移除最旧的记录
|
||||
if (history.length > capacity) {
|
||||
history.splice(0, history.length - capacity);
|
||||
}
|
||||
return history;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录弹幕发送历史
|
||||
*/
|
||||
export async function logDanmakuHistory(
|
||||
actionId: string,
|
||||
actionName: string,
|
||||
content: string,
|
||||
roomId: number,
|
||||
success: boolean,
|
||||
error?: string
|
||||
): Promise<void> {
|
||||
const historyItem: HistoryItem = {
|
||||
id: `d_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`,
|
||||
actionId,
|
||||
actionName,
|
||||
actionType: ActionType.SEND_DANMAKU,
|
||||
timestamp: Date.now(),
|
||||
content,
|
||||
target: roomId.toString(),
|
||||
success,
|
||||
error
|
||||
};
|
||||
|
||||
await addToCircularQueue(HISTORY_KEYS[HistoryType.DANMAKU], historyItem, HISTORY_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录私信发送历史
|
||||
*/
|
||||
export async function logPrivateMsgHistory(
|
||||
actionId: string,
|
||||
actionName: string,
|
||||
content: string,
|
||||
userId: number,
|
||||
success: boolean,
|
||||
error?: string
|
||||
): Promise<void> {
|
||||
const historyItem: HistoryItem = {
|
||||
id: `p_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`,
|
||||
actionId,
|
||||
actionName,
|
||||
actionType: ActionType.SEND_PRIVATE_MSG,
|
||||
timestamp: Date.now(),
|
||||
content,
|
||||
target: userId.toString(),
|
||||
success,
|
||||
error
|
||||
};
|
||||
|
||||
await addToCircularQueue(HISTORY_KEYS[HistoryType.PRIVATE_MSG], historyItem, HISTORY_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录命令执行历史
|
||||
*/
|
||||
export async function logCommandHistory(
|
||||
actionId: string,
|
||||
actionName: string,
|
||||
content: string,
|
||||
success: boolean,
|
||||
error?: string
|
||||
): Promise<void> {
|
||||
const historyItem: HistoryItem = {
|
||||
id: `c_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`,
|
||||
actionId,
|
||||
actionName,
|
||||
actionType: ActionType.EXECUTE_COMMAND,
|
||||
timestamp: Date.now(),
|
||||
content,
|
||||
success,
|
||||
error
|
||||
};
|
||||
|
||||
await addToCircularQueue(HISTORY_KEYS[HistoryType.COMMAND], historyItem, HISTORY_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取历史记录
|
||||
*/
|
||||
export async function getHistoryByType(type: HistoryType): Promise<HistoryItem[]> {
|
||||
return await get<HistoryItem[]>(HISTORY_KEYS[type]) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除历史记录
|
||||
*/
|
||||
export async function clearHistory(type: HistoryType): Promise<void> {
|
||||
await del(HISTORY_KEYS[type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有历史记录
|
||||
*/
|
||||
export async function clearAllHistory(): Promise<void> {
|
||||
await Promise.all(
|
||||
Object.values(HistoryType).map(type => clearHistory(type as HistoryType))
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user