feat: 更新项目配置和组件,增强功能和用户体验

- 在 .gitignore 中添加了 .specstory 文件的忽略规则。
- 更新 tsconfig.json,修正了 vue-vine/types/macros 的引用路径。
- 在组件声明中新增了 NInput 组件的类型支持。
- 优化了 EventModel 接口,调整了 guard_level 的类型为 GuardLevel。
- 增加了 Follow 事件类型到 EventDataTypes 枚举中。
- 在 ClientAutoAction.vue 中引入了新的 store 和组件,增强了功能。
- 更新了多个设置组件,添加了关键词匹配类型和过滤模式的支持。
- 改进了模板编辑器和测试器的功能,支持更灵活的模板管理。
- 在弹幕客户端中新增了关注事件的处理逻辑,提升了事件响应能力。
This commit is contained in:
2025-04-22 02:30:09 +08:00
parent 2fc8f7fcf8
commit 77cf0c5edc
39 changed files with 3955 additions and 1959 deletions

View File

@@ -7,6 +7,16 @@ import {
RuntimeState,
ExecutionContext
} from './types';
import { get, set, del, clear, keys as idbKeys, createStore } from 'idb-keyval'; // 导入 useIDBKeyval
// --- 定义用户持久化数据的自定义存储区 ---
const USER_DATA_DB_NAME = 'AutoActionUserDataDB';
const USER_DATA_STORE_NAME = 'userData';
const userDataStore = createStore(USER_DATA_DB_NAME, USER_DATA_STORE_NAME);
// ----------------------------------------
// --- 定义运行时数据的前缀 (避免与页面其他 sessionStorage 冲突) ---
const RUNTIME_STORAGE_PREFIX = 'autoaction_runtime_';
/**
* 创建默认的运行时状态
@@ -15,6 +25,8 @@ export function createDefaultRuntimeState(): RuntimeState {
return {
lastExecutionTime: {},
scheduledTimers: {},
timerStartTimes: {},
globalTimerStartTime: null,
sentGuardPms: new Set(),
aggregatedEvents: {}
};
@@ -28,14 +40,14 @@ export function createDefaultAutoAction(triggerType: TriggerType): AutoActionIte
const id = `auto-action-${nanoid(8)}`;
// 根据不同触发类型设置默认模板
const defaultTemplates: Record<TriggerType, string[]> = {
[TriggerType.DANMAKU]: ['收到 @{user.name} 的弹幕: {event.msg}'],
[TriggerType.GIFT]: ['感谢 @{user.name} 赠送的 {gift.summary}'],
[TriggerType.GUARD]: ['感谢 @{user.name} 开通了{guard.levelName}'],
[TriggerType.FOLLOW]: ['感谢 @{user.name} 的关注!'],
[TriggerType.ENTER]: ['欢迎 @{user.name} 进入直播间'],
[TriggerType.SCHEDULED]: ['这是一条定时消息,当前时间: {date.formatted}'],
[TriggerType.SUPER_CHAT]: ['感谢 @{user.name} 的SC: {sc.message}'],
const defaultTemplates: Record<TriggerType, string> = {
[TriggerType.DANMAKU]: '收到 {{user.name}} 的弹幕: {{danmaku.msg}}',
[TriggerType.GIFT]: '感谢 {{user.name}} 赠送的 {{gift.summary}}',
[TriggerType.GUARD]: '感谢 {{user.name}} 开通了{{danmaku.msg}}',
[TriggerType.FOLLOW]: '感谢 {{user.name}} 的关注!',
[TriggerType.ENTER]: '欢迎 {{user.name}} 进入直播间',
[TriggerType.SCHEDULED]: '这是一条定时消息,当前时间: {{date.formatted}}',
[TriggerType.SUPER_CHAT]: '感谢 {{user.name}} 的SC!',
};
// 根据不同触发类型设置默认名称
@@ -56,7 +68,7 @@ export function createDefaultAutoAction(triggerType: TriggerType): AutoActionIte
triggerType,
actionType: triggerType === TriggerType.GUARD ? ActionType.SEND_PRIVATE_MSG : ActionType.SEND_DANMAKU,
priority: Priority.NORMAL,
templates: defaultTemplates[triggerType] || ['默认模板'],
template: defaultTemplates[triggerType] || '默认模板',
logicalExpression: '',
executeCommand: '',
ignoreCooldown: false,
@@ -79,13 +91,12 @@ export function createDefaultAutoAction(triggerType: TriggerType): AutoActionIte
}
/**
* 从模板数组中随机选择一个
* @param templates 模板数组
* 处理模板字符串
* @param template 模板字符串
*/
export function getRandomTemplate(templates: string[]): string | null {
if (!templates || templates.length === 0) return null;
const index = Math.floor(Math.random() * templates.length);
return templates[index];
export function getRandomTemplate(template: string): string | null {
if (!template) return null;
return template;
}
/**
@@ -268,7 +279,6 @@ export function buildExecutionContext(
const now = Date.now();
const dateObj = new Date(now);
// 基础上下文
const context: ExecutionContext = {
event,
roomId,
@@ -295,6 +305,88 @@ export function buildExecutionContext(
if (hour < 22) return '晚上';
return '深夜';
}
},
// --- 实现运行时数据管理函数 (使用 sessionStorage) ---
getData: <T>(key: string, defaultValue?: T): T | undefined => {
const prefixedKey = RUNTIME_STORAGE_PREFIX + key;
try {
const storedValue = sessionStorage.getItem(prefixedKey);
if (storedValue === null) {
return defaultValue;
}
return JSON.parse(storedValue) as T;
} catch (error) {
console.error(`[Runtime SessionStorage] Error getting/parsing key '${key}':`, error);
return defaultValue;
}
},
setData: <T>(key: string, value: T): void => {
const prefixedKey = RUNTIME_STORAGE_PREFIX + key;
try {
// 不存储 undefined
if (value === undefined) {
sessionStorage.removeItem(prefixedKey);
return;
}
sessionStorage.setItem(prefixedKey, JSON.stringify(value));
} catch (error) {
console.error(`[Runtime SessionStorage] Error setting key '${key}':`, error);
// 如果序列化失败,可以选择移除旧键或保留
sessionStorage.removeItem(prefixedKey);
}
},
containsData: (key: string): boolean => {
const prefixedKey = RUNTIME_STORAGE_PREFIX + key;
return sessionStorage.getItem(prefixedKey) !== null;
},
removeData: (key: string): void => {
const prefixedKey = RUNTIME_STORAGE_PREFIX + key;
sessionStorage.removeItem(prefixedKey);
},
// --- 持久化数据管理函数 (不变,继续使用 userDataStore) ---
getStorageData: async <T>(key: string, defaultValue?: T): Promise<T | undefined> => {
try {
// 使用 userDataStore
const value = await get<T>(key, userDataStore);
return value === undefined ? defaultValue : value;
} catch (error) {
console.error(`[UserData IDB] getStorageData error for key '${key}':`, error);
return defaultValue;
}
},
setStorageData: async <T>(key: string, value: T): Promise<void> => {
try {
// 使用 userDataStore
await set(key, value, userDataStore);
} catch (error) {
console.error(`[UserData IDB] setStorageData error for key '${key}':`, error);
}
},
hasStorageData: async (key: string): Promise<boolean> => {
try {
// 使用 userDataStore
const value = await get(key, userDataStore);
return value !== undefined;
} catch (error) {
console.error(`[UserData IDB] hasStorageData error for key '${key}':`, error);
return false;
}
},
removeStorageData: async (key: string): Promise<void> => {
try {
// 使用 userDataStore
await del(key, userDataStore);
} catch (error) {
console.error(`[UserData IDB] removeStorageData error for key '${key}':`, error);
}
},
clearStorageData: async (): Promise<void> => {
try {
// 使用 userDataStore
await clear(userDataStore);
} catch (error) {
console.error('[UserData IDB] clearStorageData error:', error);
}
}
};
@@ -308,7 +400,7 @@ export function buildExecutionContext(
medalLevel: event.fans_medal_level,
medalName: event.fans_medal_name
};
context.variables.danmaku = event;
context.variables.message = event.msg;
// 根据不同触发类型添加特定变量