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

@@ -1,16 +1,19 @@
import { ref, Ref } from 'vue';
import { EventModel, EventDataTypes } from '@/api/api-models';
import {
formatTemplate,
getRandomTemplate,
buildExecutionContext
} from '../utils';
import { evaluateTemplateExpressions } from '../expressionEvaluator';
import {
AutoActionItem,
TriggerType,
ExecutionContext,
RuntimeState
} from '../types';
import {
filterValidActions,
executeActions
} from '../actionUtils';
/**
* 礼物感谢模块
@@ -25,10 +28,6 @@ export function useGiftThank(
isTianXuanActive: Ref<boolean>,
sendLiveDanmaku: (roomId: number, message: string) => Promise<boolean>
) {
// 测试发送功能状态
const lastTestTime = ref(0);
const testCooldown = 5000; // 5秒冷却时间
const testLoading = ref(false);
/**
* 处理礼物事件
@@ -43,171 +42,52 @@ export function useGiftThank(
) {
if (!roomId.value) return;
// 过滤有效的礼物感谢操作
const giftActions = actions.filter(action =>
action.triggerType === TriggerType.GIFT &&
action.enabled &&
(!action.triggerConfig.onlyDuringLive || isLive.value) &&
(!action.triggerConfig.ignoreTianXuan || !isTianXuanActive.value)
);
// 使用通用函数过滤有效的礼物感谢操作
const giftActions = filterValidActions(actions, TriggerType.GIFT, isLive, isTianXuanActive);
if (giftActions.length === 0) return;
// 使用通用执行函数处理礼物事件
if (giftActions.length > 0 && roomId.value) {
// 礼物基本信息
const giftName = event.msg;
const giftPrice = event.price / 1000;
// 礼物基本信息
const giftName = event.msg;
const giftPrice = event.price / 1000;
const giftCount = event.num;
executeActions(
giftActions,
event,
TriggerType.GIFT,
roomId.value,
runtimeState,
{ sendLiveDanmaku },
{
customFilters: [
// 礼物过滤逻辑
(action, context) => {
// 黑名单模式
if (action.triggerConfig.filterMode === 'blacklist' &&
action.triggerConfig.filterGiftNames?.includes(giftName)) {
return false;
}
// 创建执行上下文
const context = buildExecutionContext(event, roomId.value, TriggerType.GIFT);
// 白名单模式
if (action.triggerConfig.filterMode === 'whitelist' &&
!action.triggerConfig.filterGiftNames?.includes(giftName)) {
return false;
}
// 处理每个符合条件的操作
for (const action of giftActions) {
// 跳过不符合用户过滤条件的
if (action.triggerConfig.userFilterEnabled) {
if (action.triggerConfig.requireMedal && !event.fans_medal_wearing_status) continue;
if (action.triggerConfig.requireCaptain && !event.guard_level) continue;
}
// 礼物价值过滤
if (action.triggerConfig.minValue && giftPrice < action.triggerConfig.minValue) {
return false;
}
// 礼物过滤逻辑
if (action.triggerConfig.filterMode === 'blacklist' &&
action.triggerConfig.filterGiftNames?.includes(giftName)) continue;
if (action.triggerConfig.filterMode === 'whitelist' &&
!action.triggerConfig.filterGiftNames?.includes(giftName)) continue;
if (action.triggerConfig.minValue && giftPrice < action.triggerConfig.minValue) continue;
// 检查冷却时间
const lastExecTime = runtimeState.lastExecutionTime[action.id] || 0;
if (!action.ignoreCooldown &&
Date.now() - lastExecTime < (action.actionConfig.cooldownSeconds || 0) * 1000) {
continue; // 仍在冷却中
}
// 选择并发送回复
const template = getRandomTemplate(action.templates);
if (template) {
// 更新冷却时间
runtimeState.lastExecutionTime[action.id] = Date.now();
// 格式化并发送
const formattedReply = formatTemplate(template, context);
// 延迟发送
if (action.actionConfig.delaySeconds && action.actionConfig.delaySeconds > 0) {
setTimeout(() => {
sendLiveDanmaku(roomId.value!, formattedReply);
}, (action.actionConfig.delaySeconds || 0) * 1000);
} else {
sendLiveDanmaku(roomId.value!, formattedReply);
return true;
}
]
}
}
}
}
/**
* 测试发送礼物感谢弹幕
*/
async function testSendThankMessage(
action?: AutoActionItem
): Promise<{ success: boolean; message: string }> {
// 检查是否在冷却期
const now = Date.now();
if (now - lastTestTime.value < testCooldown) {
return {
success: false,
message: `请等待${Math.ceil((testCooldown - (now - lastTestTime.value)) / 1000)}秒后再次测试发送`
};
}
if (!roomId.value) {
return {
success: false,
message: '未设置房间号'
};
}
if (!action) {
return {
success: false,
message: '未指定要测试的操作'
};
}
if (!action.templates || action.templates.length === 0) {
return {
success: false,
message: '请至少添加一条模板'
};
}
testLoading.value = true;
lastTestTime.value = now;
try {
// 构建测试事件对象
const testEvent: EventModel = {
type: EventDataTypes.Gift,
uname: '测试用户',
uface: 'https://i0.hdslb.com/bfs/face/member/noface.jpg',
uid: 123456,
open_id: '123456',
msg: '测试礼物',
time: Date.now(),
num: 1,
price: 100000, // 100元
guard_level: 0,
fans_medal_level: 0,
fans_medal_name: '',
fans_medal_wearing_status: false,
ouid: '123456'
};
// 创建测试上下文
const context = buildExecutionContext(testEvent, roomId.value, TriggerType.GIFT);
// 获取模板并格式化
const template = getRandomTemplate(action.templates);
if (!template) {
return {
success: false,
message: '无法获取模板'
};
}
const testMessage = formatTemplate(template, context);
// 发送测试弹幕
const success = await sendLiveDanmaku(roomId.value, testMessage);
if (success) {
return {
success: true,
message: '测试弹幕发送成功!'
};
} else {
return {
success: false,
message: '测试弹幕发送失败请检查B站登录状态和网络连接'
};
}
} catch (error) {
console.error('测试发送出错:', error);
return {
success: false,
message: '发送过程出错'
};
} finally {
testLoading.value = false;
);
}
}
return {
processGift,
testSendThankMessage,
testLoading,
lastTestTime,
testCooldown
};
}