feat: 更新组件和配置,增强功能和用户体验, 添加签到功能

- 在 .editorconfig 中调整文件格式设置,统一代码风格。
- 在 default.d.ts 中为 naive-ui 添加 TabPaneSlots 接口声明,增强类型支持。
- 在多个组件中优化了模板和样式,提升用户交互体验。
- 在 ClientAutoAction.vue 中新增签到设置标签页,丰富功能选项。
- 在 Utils.ts 中增强 GUID 处理逻辑,增加输入验证和错误处理。
- 更新多个组件的逻辑,简化代码结构,提升可读性和维护性。
This commit is contained in:
2025-04-26 01:35:59 +08:00
parent e48b3df236
commit 8bed5bbc1a
24 changed files with 2004 additions and 328 deletions

View File

@@ -117,7 +117,7 @@ export function checkCooldown(action: AutoActionItem, runtimeState: RuntimeState
*/
export function processTemplate(
action: AutoActionItem,
context: any,
context: ExecutionContext,
options?: {
useRandomTemplate?: boolean; // 是否随机选择模板默认true
defaultValue?: string; // 如果模板为空或格式化失败时的默认值

View File

@@ -0,0 +1,436 @@
import { ref, Ref, computed } from 'vue';
import { EventModel, EventDataTypes } from '@/api/api-models';
import { ActionType, AutoActionItem, RuntimeState, TriggerType, Priority, KeywordMatchType } from '../types';
import { usePointStore } from '@/store/usePointStore';
import { processTemplate } from '../actionUtils';
import { buildExecutionContext } from '../utils';
import { v4 as uuidv4 } from 'uuid';
import { useIDBKeyval } from '@vueuse/integrations/useIDBKeyval';
import { GuidUtils } from '@/Utils';
// 签到配置接口
export interface CheckInConfig {
enabled: boolean;
command: string;
points: number;
cooldownSeconds: number;
onlyDuringLive: boolean; // 仅在直播时可签到
sendReply: boolean; // 是否发送签到回复消息
successAction: AutoActionItem; // 使用 AutoActionItem 替代字符串
cooldownAction: AutoActionItem; // 使用 AutoActionItem 替代字符串
earlyBird: {
enabled: boolean;
windowMinutes: number;
bonusPoints: number;
successAction: AutoActionItem; // 使用 AutoActionItem 替代字符串
};
}
// 创建默认配置
function createDefaultCheckInConfig(): CheckInConfig { return {
enabled: false,
command: '签到',
points: 10,
cooldownSeconds: 3600, // 1小时
onlyDuringLive: true, // 默认仅在直播时可签到
sendReply: true, // 默认发送回复消息
successAction: {
id: uuidv4(),
name: '签到成功回复',
enabled: true,
triggerType: TriggerType.DANMAKU,
actionType: ActionType.SEND_DANMAKU,
template: '@{{user.name}} 签到成功,获得 {{checkin.totalPoints}} 积分。',
priority: Priority.NORMAL,
logicalExpression: '',
ignoreCooldown: false,
executeCommand: '',
triggerConfig: {},
actionConfig: {}
},
cooldownAction: {
id: uuidv4(),
name: '签到冷却回复',
enabled: true,
triggerType: TriggerType.DANMAKU,
actionType: ActionType.SEND_DANMAKU,
template: '{{user.name}} 你今天已经签到过了,明天再来吧~',
priority: Priority.NORMAL,
logicalExpression: '',
ignoreCooldown: false,
executeCommand: '',
triggerConfig: {},
actionConfig: {}
},
earlyBird: {
enabled: false,
windowMinutes: 30,
bonusPoints: 5,
successAction: {
id: uuidv4(),
name: '早鸟签到回复',
enabled: true,
triggerType: TriggerType.DANMAKU,
actionType: ActionType.SEND_DANMAKU,
template: '恭喜 {{user.name}} 完成早鸟签到!额外获得 {{bonusPoints}} 积分,共获得 {{totalPoints}} 积分!',
priority: Priority.NORMAL,
logicalExpression: '',
ignoreCooldown: false,
executeCommand: '',
triggerConfig: {},
actionConfig: {}
}
}
};
}
// 签到记录存储
interface CheckInStorage {
lastCheckIn: Record<string, number>; // ouid -> timestamp
users: Record<string, UserCheckInData>; // 用户签到详细数据
}
// 用户签到数据
export interface UserCheckInData {
ouid: string; // 用户ID
username: string; // 用户名称
totalCheckins: number; // 累计签到次数
streakDays: number; // 连续签到天数
lastCheckInTime: number; // 上次签到时间
earlyBirdCount: number; // 早鸟签到次数
firstCheckInTime: number; // 首次签到时间
}
/**
* 签到功能核心逻辑
*/
export function useCheckIn(
isLive: Ref<boolean>,
roomId: Ref<number | undefined>,
liveStartTime: Ref<number | null>,
isTianXuanActive: Ref<boolean>,
sendDanmaku: (roomId: number, message: string) => Promise<boolean>
) {
const pointStore = usePointStore();
// 使用 IndexedDB 持久化存储签到配置
const { data: checkInConfig, isFinished: isConfigLoaded } = useIDBKeyval<CheckInConfig>(
'autoAction.checkin.config',
createDefaultCheckInConfig(),
{
onError: (err) => {
console.error('[CheckIn] IDB 错误 (配置):', err);
}
}
); // 使用 IndexedDB 持久化存储签到记录
const { data: checkInStorage, isFinished: isStorageLoaded } = useIDBKeyval<CheckInStorage>(
'autoAction.checkin.storage',
{
lastCheckIn: {},
users: {}
},
{
onError: (err) => {
console.error('[CheckIn] IDB 错误 (记录):', err);
}
}
);
// 处理签到弹幕
async function processCheckIn(
event: EventModel,
runtimeState: RuntimeState
) {
// 确保配置和存储已加载
if (!isConfigLoaded.value || !isStorageLoaded.value) {
console.log('[CheckIn] 配置或存储尚未加载完成,跳过处理');
return;
}
if (!roomId.value || !checkInConfig.value.enabled) {
return;
}
// 检查是否仅在直播时可签到
if (checkInConfig.value.onlyDuringLive && !isLive.value) {
return;
}
// 跳过非弹幕事件
if (event.type !== EventDataTypes.Message) {
return;
}
// 检查弹幕内容是否匹配签到指令
if (event.msg?.trim() !== checkInConfig.value.command) {
return;
}
const userId = event.ouid;
const username = event.uname || '用户';
const currentTime = Date.now();
// 检查是否已经在今天签到过
const lastCheckInTime = checkInStorage.value.lastCheckIn[userId] || 0;
// 判断上次签到时间是否为今天
const lastCheckInDate = new Date(lastCheckInTime);
const currentDate = new Date(currentTime);
// 比较日期部分是否相同(年、月、日)
const isSameDay = lastCheckInDate.getFullYear() === currentDate.getFullYear() &&
lastCheckInDate.getMonth() === currentDate.getMonth() &&
lastCheckInDate.getDate() === currentDate.getDate();
// 检查是否发送冷却提示
if (lastCheckInTime > 0 && isSameDay) {
// 用户今天已经签到过,发送提示
if (checkInConfig.value.sendReply) {
// 使用buildExecutionContext构建上下文
const cooldownContext = buildExecutionContext(event, roomId.value, TriggerType.DANMAKU, {
user: { name: username, uid: userId }
});
const message = processTemplate(checkInConfig.value.cooldownAction, cooldownContext);
if (roomId.value && message) {
sendDanmaku(roomId.value, message).catch(err =>
console.error('[CheckIn] 发送已签到提示失败:', err)
);
}
}
window.$notification.info({
title: '签到提示',
description: `${username} 重复签到, 已忽略`,
duration: 5000
});
return;
}
// 计算积分奖励
let pointsEarned = checkInConfig.value.points;
let bonusPoints = 0;
let isEarlyBird = false;
// 检查是否符合早鸟奖励条件
if (checkInConfig.value.earlyBird.enabled && liveStartTime.value) {
const earlyBirdWindowMs = checkInConfig.value.earlyBird.windowMinutes * 60 * 1000;
const timeSinceLiveStart = currentTime - liveStartTime.value;
if (timeSinceLiveStart <= earlyBirdWindowMs) {
bonusPoints = checkInConfig.value.earlyBird.bonusPoints;
pointsEarned += bonusPoints;
isEarlyBird = true;
}
}
// 更新用户积分
try {
// 调用积分系统添加积分
const point = await pointStore.addPoints(userId, pointsEarned, `签到奖励 (${format(new Date(), 'yyyy-MM-dd')})`, `${username} 完成签到`); // 更新签到记录
if (checkInStorage.value) {
// 确保 lastCheckIn 对象存在
if (!checkInStorage.value.lastCheckIn) {
checkInStorage.value.lastCheckIn = {};
}
// 确保 users 对象存在
if (!checkInStorage.value.users) {
checkInStorage.value.users = {};
}
// 获取用户当前的签到数据
let userData = checkInStorage.value.users[userId];
// 如果是新用户,创建用户数据
if (!userData) {
userData = {
ouid: userId,
username: username,
totalCheckins: 0,
streakDays: 0,
lastCheckInTime: 0,
earlyBirdCount: 0,
firstCheckInTime: currentTime
};
}
// 计算连续签到天数
const lastCheckInDate = new Date(userData.lastCheckInTime);
const currentDate = new Date(currentTime);
// 如果上次签到不是昨天(隔了一天以上),则重置连续签到天数
const isYesterday =
lastCheckInDate.getFullYear() === currentDate.getFullYear() &&
lastCheckInDate.getMonth() === currentDate.getMonth() &&
lastCheckInDate.getDate() === currentDate.getDate() - 1;
// 如果上次签到不是今天(防止重复计算)
if (!isSameDay) {
// 更新连续签到天数
if (isYesterday) {
// 昨天签到过,增加连续签到天数
userData.streakDays += 1;
} else if (userData.lastCheckInTime > 0) {
// 不是昨天签到且不是首次签到重置连续签到天数为1
userData.streakDays = 1;
} else {
// 首次签到
userData.streakDays = 1;
}
// 更新累计签到次数
userData.totalCheckins += 1;
// 更新早鸟签到次数
if (isEarlyBird) {
userData.earlyBirdCount += 1;
}
}
// 更新最后签到时间
userData.lastCheckInTime = currentTime;
// 更新用户名(以防用户改名)
userData.username = username;
// 保存用户数据
checkInStorage.value.users[userId] = userData;
// 更新lastCheckIn记录
checkInStorage.value.lastCheckIn[userId] = currentTime;
}
// 发送成功消息
if (roomId.value) {
// 构建签到上下文数据
const checkInData = {
checkin: {
points: checkInConfig.value.points,
bonusPoints: isEarlyBird ? bonusPoints : 0,
totalPoints: pointsEarned,
userPoints: point,
isEarlyBird: isEarlyBird,
time: new Date(currentTime),
cooldownSeconds: checkInConfig.value.cooldownSeconds
}
};
// 根据配置决定是否发送回复消息
if (checkInConfig.value.sendReply) {
// 使用buildExecutionContext构建完整上下文
const successContext = buildExecutionContext(event, roomId.value, TriggerType.DANMAKU, checkInData);
let message;
if (isEarlyBird) {
// 使用早鸟签到模板
message = processTemplate(checkInConfig.value.earlyBird.successAction, successContext);
} else {
// 使用普通签到模板
message = processTemplate(checkInConfig.value.successAction, successContext);
}
if (message) {
sendDanmaku(roomId.value, message).catch(err =>
console.error('[CheckIn] 发送签到成功消息失败:', err)
);
}
}
window.$notification.success({
title: '签到成功',
description: `${username} 完成签到, 获得 ${pointsEarned} 积分, 累计签到 ${checkInStorage.value.users[userId].totalCheckins}`,
duration: 5000
});
}
} catch (error) {
console.error('[CheckIn] 处理签到失败:', error);
}
}
// 监听直播开始事件
function onLiveStart() {
// 直播开始时记录开始时间,用于早鸟奖励计算
if (isLive.value && !liveStartTime.value) {
liveStartTime.value = Date.now();
}
}
// 监听直播结束事件
function onLiveEnd() {
// 直播结束时清空早鸟奖励的时间记录
liveStartTime.value = null;
}
return {
checkInConfig,
checkInStorage,
processCheckIn,
onLiveStart,
onLiveEnd
};
}
/**
* 创建默认的签到相关 AutoActionItem 配置
* 这些配置可以在管理界面中显示和编辑
*/
export function createCheckInAutoActions(): AutoActionItem[] {
return [
// 普通签到成功响应
{
id: uuidv4(),
name: '签到成功响应',
enabled: true,
triggerType: TriggerType.DANMAKU,
actionType: ActionType.SEND_DANMAKU,
template: '@{{user.name}} 签到成功,获得 {{points}} 积分',
priority: Priority.NORMAL,
logicalExpression: '',
ignoreCooldown: false,
executeCommand: '',
triggerConfig: {
keywords: ['签到'],
keywordMatchType: KeywordMatchType.Full
},
actionConfig: {
cooldownSeconds: 86400 // 24小时确保每天只能签到一次
}
},
// 早鸟签到成功响应
{
id: uuidv4(),
name: '早鸟签到成功响应',
enabled: true,
triggerType: TriggerType.DANMAKU,
actionType: ActionType.SEND_DANMAKU,
template: '@{{user.name}} 早鸟签到成功,获得 {{totalPoints}} 积分',
priority: Priority.HIGH,
logicalExpression: '',
ignoreCooldown: false,
executeCommand: '',
triggerConfig: {
keywords: ['签到'],
keywordMatchType: KeywordMatchType.Full
},
actionConfig: {
cooldownSeconds: 86400 // 24小时
}
},
// 签到冷却期提示
{
id: uuidv4(),
name: '签到冷却提示',
enabled: true,
triggerType: TriggerType.DANMAKU,
actionType: ActionType.SEND_DANMAKU,
template: '@{{user.name}} 你今天已经签到过了,明天再来吧~',
priority: Priority.LOW,
logicalExpression: '',
ignoreCooldown: true,
executeCommand: '',
triggerConfig: {
keywords: ['签到'],
keywordMatchType: KeywordMatchType.Full
},
actionConfig: {}
}
];
}

View File

@@ -269,12 +269,14 @@ export function checkUserFilter(config: { userFilterEnabled: boolean; requireMed
* @param event 事件对象
* @param roomId 房间ID
* @param triggerType 触发类型
* @param additionalContext 附加的上下文数据,将被合并到上下文中
* @returns 标准化的执行上下文
*/
export function buildExecutionContext(
event: any,
roomId: number | undefined,
triggerType?: TriggerType
triggerType?: TriggerType,
additionalContext?: Record<string, any>
): ExecutionContext {
const now = Date.now();
const dateObj = new Date(now);
@@ -432,5 +434,13 @@ export function buildExecutionContext(
}
}
// 合并附加的上下文数据(如果存在)
if (additionalContext) {
context.variables = {
...context.variables,
...additionalContext
};
}
return context;
}

View File

@@ -1,48 +1,45 @@
// 导入 Vue 和 Pinia 相关函数
import { ref, computed, watch } from 'vue';
import { defineStore, acceptHMRUpdate } from 'pinia';
import { acceptHMRUpdate, defineStore } from 'pinia';
import { computed, ref, watch } from 'vue';
// 导入 API 模型和类型
import { EventModel, GuardLevel, EventDataTypes } from '@/api/api-models.js';
import { useAccount } from '@/api/account.js';
import { EventDataTypes, EventModel } from '@/api/api-models.js';
import { useDanmakuClient } from '@/store/useDanmakuClient.js';
import { useBiliFunction } from './useBiliFunction.js';
import { useAccount } from '@/api/account.js';
// 导入 VueUse 工具库
import { useStorage } from '@vueuse/core';
import { useIDBKeyval } from '@vueuse/integrations/useIDBKeyval';
// 导入自动操作相关的类型和工具函数
import { evaluateTemplateExpressions } from './autoAction/expressionEvaluator';
import {
TriggerType,
ActionType,
KeywordMatchType,
Priority,
RuntimeState,
type AutoActionItem,
ExecutionContext,
KeywordMatchType
TriggerType,
type AutoActionItem
} from './autoAction/types.js';
import {
getRandomTemplate,
buildExecutionContext,
evaluateExpression,
shouldProcess,
createDefaultAutoAction,
createDefaultRuntimeState
createDefaultRuntimeState,
getRandomTemplate
} from './autoAction/utils';
import { evaluateTemplateExpressions } from './autoAction/expressionEvaluator';
// 导入 actionUtils 工具函数
import { filterValidActions, checkUserFilters, checkCooldown, processTemplate, executeActions } from './autoAction/actionUtils';
// 导入 nanoid 用于生成唯一 ID
import { nanoid } from 'nanoid';
// 导入开发环境判断标志
import { isDev } from '@/data/constants.js';
// 导入所有自动操作子模块
import { usePointStore } from '@/store/usePointStore'; // 修正导入路径
import { useAutoReply } from './autoAction/modules/autoReply';
import { useEntryWelcome } from './autoAction/modules/entryWelcome';
import { useFollowThank } from './autoAction/modules/followThank';
import { useGiftThank } from './autoAction/modules/giftThank';
import { useGuardPm } from './autoAction/modules/guardPm';
import { useFollowThank } from './autoAction/modules/followThank';
import { useEntryWelcome } from './autoAction/modules/entryWelcome';
import { useAutoReply } from './autoAction/modules/autoReply';
import { useScheduledDanmaku } from './autoAction/modules/scheduledDanmaku';
import { useSuperChatThank } from './autoAction/modules/superChatThank';
import { useCheckIn } from './autoAction/modules/checkin';
// 定义名为 'autoAction' 的 Pinia store
export const useAutoAction = defineStore('autoAction', () => {
@@ -50,11 +47,13 @@ export const useAutoAction = defineStore('autoAction', () => {
const danmakuClient = useDanmakuClient(); // 弹幕客户端
const biliFunc = useBiliFunction(); // B站相关功能函数
const account = useAccount(); // 账户信息用于获取房间ID和直播状态
const pointStore = usePointStore(); // 积分 Store
// --- 共享状态 ---
const isLive = computed(() => account.value.streamerInfo?.isStreaming ?? false); // 获取直播状态
const roomId = computed(() => isDev ? 1294406 : account.value.streamerInfo?.roomId); // 获取房间ID (开发环境使用固定ID)
const isTianXuanActive = ref(false); // 天选时刻活动状态
const liveStartTime = ref<number | null>(null); // 直播开始时间戳
// --- 存储所有自动操作项 (使用 IndexedDB 持久化) ---
const { data: autoActions, isFinished: isActionsLoaded } = useIDBKeyval<AutoActionItem[]>('autoAction.items', [], {
@@ -393,28 +392,29 @@ export const useAutoAction = defineStore('autoAction', () => {
if (action.triggerConfig.schedulingMode === undefined) action.triggerConfig.schedulingMode = 'random';
}
});
// 确保全局顺序索引已初始化 (以防 IDB 返回 null/undefined)
if (lastGlobalActionIndex.value === null || lastGlobalActionIndex.value === undefined) {
lastGlobalActionIndex.value = -1;
}
// 确保触发类型启用状态已初始化
if (!enabledTriggerTypes.value) {
enabledTriggerTypes.value = {
[TriggerType.DANMAKU]: true,
[TriggerType.GIFT]: true,
[TriggerType.GUARD]: true,
[TriggerType.FOLLOW]: true,
[TriggerType.ENTER]: true,
[TriggerType.SCHEDULED]: true,
[TriggerType.SUPER_CHAT]: true
};
}
checkTianXuanStatus(); // 检查天选状态
startIndividualScheduledActions(); // 启动独立定时任务
startGlobalTimer(); // 启动全局定时器 (如果需要)
registerEventListeners(); // 注册弹幕事件监听器
// 启动定时器 (如果有需要)
startGlobalTimer();
startIndividualScheduledActions();
}
}, { immediate: true }); // 立即执行一次检查
}, { immediate: true });
// 监听直播状态变化,处理签到模块的生命周期事件
watch(isLive, (currentState, prevState) => {
// 直播开始
if (currentState && !prevState) {
console.log('[AutoAction] 检测到直播开始,更新签到模块状态');
checkInModule.onLiveStart();
}
// 直播结束
else if (!currentState && prevState) {
console.log('[AutoAction] 检测到直播结束,更新签到模块状态');
checkInModule.onLiveEnd();
}
}, { immediate: true });
// 注册事件监听器
registerEventListeners();
}
// 初始化模块
@@ -429,6 +429,7 @@ export const useAutoAction = defineStore('autoAction', () => {
const autoReplyModule = useAutoReply(isLive, roomId, biliFunc.sendLiveDanmaku);
const scheduledDanmakuModule = useScheduledDanmaku(isLive, roomId, biliFunc.sendLiveDanmaku);
const superChatThankModule = useSuperChatThank(isLive, roomId, isTianXuanActive, biliFunc.sendLiveDanmaku);
const checkInModule = useCheckIn(isLive, roomId, liveStartTime, isTianXuanActive, biliFunc.sendLiveDanmaku);
/**
* 向弹幕客户端注册事件监听器
@@ -556,6 +557,8 @@ export const useAutoAction = defineStore('autoAction', () => {
case TriggerType.DANMAKU:
// 调用弹幕自动回复模块
autoReplyModule.onDanmaku(event, autoActions.value, runtimeState.value);
// 处理签到功能
checkInModule.processCheckIn(event, runtimeState.value);
break;
case TriggerType.GIFT:
// 调用礼物感谢模块
@@ -710,42 +713,34 @@ export const useAutoAction = defineStore('autoAction', () => {
* @param actionId 要设置为下一个执行的操作ID
*/
function setNextGlobalAction(actionId: string) {
const targetAction = autoActions.value.find(a => a.id === actionId);
if (!targetAction || targetAction.triggerType !== TriggerType.SCHEDULED || !targetAction.triggerConfig.useGlobalTimer) {
console.warn(`[AutoAction] setNextGlobalAction: 无法设置 ID 为 ${actionId} 的操作为下一个全局操作 (不存在、类型错误或未使用全局定时器)`);
return;
}
if (globalSchedulingMode.value !== 'sequential') {
console.warn('[AutoAction] 只能在顺序模式下手动指定下一个操作。');
console.warn(`[AutoAction] setNextGlobalAction: 只有在顺序模式下才能手动指定下一个操作。当前模式: ${globalSchedulingMode.value}`);
return;
}
// 筛选出当前符合条件的活动操作 (与 nextScheduledAction 逻辑一致)
const eligibleActions = autoActions.value.filter(action =>
action.triggerType === TriggerType.SCHEDULED &&
action.enabled &&
action.enabled && // 这里需要检查启用状态,只在启用的里面找
action.triggerConfig.useGlobalTimer &&
(!action.triggerConfig.onlyDuringLive || isLive.value) &&
(!action.triggerConfig.ignoreTianXuan || !isTianXuanActive.value)
);
if (eligibleActions.length === 0) {
console.warn('[AutoAction] 没有符合条件的活动操作可供指定。');
return;
}
// 找到目标操作在当前合格列表中的索引
const targetIndex = eligibleActions.findIndex(action => action.id === actionId);
const targetIndex = eligibleActions.findIndex(a => a.id === actionId);
if (targetIndex === -1) {
console.warn(`[AutoAction] 指定的操作ID ${actionId} 不存在或不符合当前执行条件。`);
console.warn(`[AutoAction] setNextGlobalAction: 指定的操作 ID ${actionId} 当前不符合执行条件,无法设置为下一个`);
return;
}
// 设置 lastGlobalActionIndex 为目标索引的前一个索引
// 这样,在下一次 handleGlobalTimerTick 中计算 (lastGlobalActionIndex + 1) % length 时,就会得到 targetIndex
// 如果目标是列表中的第一个 (index 0),则将 lastGlobalActionIndex 设置为列表最后一个元素的索引
lastGlobalActionIndex.value = (targetIndex === 0) ? eligibleActions.length - 1 : targetIndex - 1;
console.log(`[AutoAction] 手动指定下一个执行的操作为: ${eligibleActions[targetIndex].name} (ID: ${actionId}), 将在下一个计时周期执行。`);
// 重启全局计时器,以便立即应用更改并在下一个周期执行指定的操作
// (如果不重启,则会在当前周期结束后,按新的索引执行)
// 设置索引,使其下一次执行 targetIndex
lastGlobalActionIndex.value = (targetIndex - 1 + eligibleActions.length) % eligibleActions.length;
// 立即重置并重新安排计时器以便下次tick时执行新指定的任务
restartGlobalTimer();
}
@@ -885,6 +880,7 @@ export const useAutoAction = defineStore('autoAction', () => {
isLive, // 直播状态 (计算属性)
isTianXuanActive, // 天选状态 (ref)
enabledTriggerTypes, // 触发类型启用状态
checkInModule,
init, // 初始化函数
addAutoAction, // 添加操作
removeAutoAction, // 移除操作
@@ -899,7 +895,7 @@ export const useAutoAction = defineStore('autoAction', () => {
stopIndividualTimer,
stopAllIndividualScheduledActions,
startIndividualScheduledActions,
triggerTestActionByType // 新的 action
triggerTestActionByType, // 新的 action
};
});// HMR (热模块替换) 支持
if (import.meta.hot) {
@@ -907,5 +903,5 @@ if (import.meta.hot) {
}
// 重新导出类型,方便外部使用
export { AutoActionItem, TriggerType, ActionType, Priority, KeywordMatchType };
export { ActionType, AutoActionItem, KeywordMatchType, Priority, TriggerType };

View File

@@ -371,7 +371,7 @@ export const useBiliCookie = defineStore('biliCookie', () => {
info('[BiliCookie] 检测到已存储的 Bilibili Cookie');
// 检查 Cookie 有效性,除非用户信息缓存有效且未过期
if (!_cachedUserInfo.value) { // 只有在没有有效缓存时才立即检查
debug('[BiliCookie] 无有效缓存,立即检查 Cookie 有效性...');
info('[BiliCookie] 无有效缓存,立即检查 Cookie 有效性...');
const { valid } = await _checkCookieValidity(storedCookieData.cookie);
_updateCookieState(true, valid); // 更新状态
}

View File

@@ -153,7 +153,7 @@ export const useBiliFunction = defineStore('biliFunction', () => {
justifyContent: 'space-between',
width: '100%',
},
}, () => `错误: ${json.code} - ${json.message || json.msg}`),
}, `错误: ${json.code} - ${json.message || json.msg}`),
duration: 0,
});
console.error(`发送弹幕API失败 to: ${roomId} ${uid.value} [${message}] - ${json.code} - ${json.message || json.msg}`);