This commit is contained in:
Baobhan Sith
2025-04-22 09:13:54 +08:00
parent 66a39e9428
commit 8412be76d5
3 changed files with 160 additions and 78 deletions
@@ -521,27 +521,51 @@ watchEffect((onCleanup) => {
}); });
// +++ 监听 Store 中的触发器以激活搜索 +++ // +++ 监听 Store 中的触发器以激活搜索 +++
watch(() => focusSwitcherStore.activateFileManagerSearchTrigger, () => { watch(() => focusSwitcherStore.activateFileManagerSearchTrigger, (newValue, oldValue) => { // 修改监听器
// 确保只在触发器值大于 0 时执行(避免初始加载时触发) // 确保只在触发器值增加时执行(避免初始加载或重置时触发)
if (focusSwitcherStore.activateFileManagerSearchTrigger > 0) { // 并且当前组件的 sessionId 与活动 sessionId 匹配
console.log('[FileManager] Received search activation trigger from store.'); // 检查 newValue > oldValue 确保是递增触发,避免重复执行
if (newValue > (oldValue ?? 0) && props.sessionId === sessionStore.activeSessionId) {
console.log(`[FileManager ${props.sessionId}] Received search activation trigger for active session.`);
activateSearch(); // 调用组件内部的激活搜索方法 activateSearch(); // 调用组件内部的激活搜索方法
} }
}); }, { immediate: false }); // 添加 immediate: false 避免初始值为 0 时触发
onBeforeUnmount(() => { // onBeforeUnmount 中 cleanupSftpHandlers 的调用已移至新的 onBeforeUnmount 逻辑中
console.log(`[FileManager ${props.sessionId}] 组件即将卸载。`);
// 调用注入的 SFTP 管理器提供的清理函数
cleanupSftpHandlers();
});
// +++ 注册/注销自定义聚焦动作 +++ // +++ 注册/注销自定义聚焦动作 +++
let unregisterFocusAction: (() => void) | null = null; // 用于存储注销函数
onMounted(() => { onMounted(() => {
focusSwitcherStore.registerFocusAction('fileManagerSearch', focusSearchInput); // 注册一个包装函数,而不是直接注册 focusSearchInput
// 使其成为 async 函数以兼容 Promise 返回类型
const focusActionWrapper = async (): Promise<boolean | undefined> => {
if (props.sessionId === sessionStore.activeSessionId) {
// 如果是活动会话,调用原始聚焦函数并返回其结果
// 由于 focusSearchInput 是同步的,我们直接返回它的 boolean 结果
// async 函数会自动将其包装在 Promise 中(如果需要,但这里不需要)
return focusSearchInput();
}
// 如果不是活动会话,返回 undefined,表示跳过
// async 函数返回 undefined 会被包装成 Promise<undefined>
console.log(`[FileManager ${props.sessionId}] Focus action skipped (async undefined) for inactive session.`);
return undefined; // 返回 undefined 表示跳过
};
// 调用新的 registerFocusAction 并存储返回的注销函数
unregisterFocusAction = focusSwitcherStore.registerFocusAction('fileManagerSearch', focusActionWrapper);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
focusSwitcherStore.unregisterFocusAction('fileManagerSearch'); // 调用存储的注销函数
if (unregisterFocusAction) {
unregisterFocusAction();
console.log(`[FileManager ${props.sessionId}] Unregistered focus action on unmount.`);
}
// 清理对函数的引用
unregisterFocusAction = null;
// 调用注入的 SFTP 管理器提供的清理函数 (移到这里确保注销后清理)
cleanupSftpHandlers();
}); });
// --- 列宽调整逻辑 (保持不变) --- // --- 列宽调整逻辑 (保持不变) ---
@@ -663,19 +687,30 @@ const handleWheel = (event: WheelEvent) => {
// +++ 新增:聚焦搜索框的方法 +++ // +++ 新增:聚焦搜索框的方法 +++
const focusSearchInput = (): boolean => { const focusSearchInput = (): boolean => {
// 检查当前会话是否激活,防止后台实例响应
if (props.sessionId !== sessionStore.activeSessionId) {
console.log(`[FileManager ${props.sessionId}] Ignoring focus request for inactive session.`);
return false;
}
if (!isSearchActive.value) { if (!isSearchActive.value) {
activateSearch(); // Activate search first activateSearch(); // Activate search first
nextTick(() => { // Wait for DOM update // nextTick 确保 DOM 更新后再聚焦
nextTick(() => {
if (searchInputRef.value) { if (searchInputRef.value) {
searchInputRef.value.focus(); searchInputRef.value.focus();
console.log(`[FileManager ${props.sessionId}] Search activated and input focused.`);
} else {
console.warn(`[FileManager ${props.sessionId}] Search activated but input ref not found after nextTick.`);
} }
}); });
// Assume activation and focus will likely succeed return true; // 假设会成功
return true;
} else if (searchInputRef.value) { } else if (searchInputRef.value) {
searchInputRef.value.focus(); searchInputRef.value.focus();
console.log(`[FileManager ${props.sessionId}] Search already active, input focused.`);
return true; return true;
} }
console.warn(`[FileManager ${props.sessionId}] Could not focus search input.`);
return false; return false;
}; };
defineExpose({ focusSearchInput }); defineExpose({ focusSearchInput });
@@ -221,18 +221,26 @@ const handleBlur = () => {
}, 150); // 150ms 延迟可能更稳妥 }, 150); // 150ms 延迟可能更稳妥
}; };
// 获取数据 // 获取数据的 onMounted 调用已移至新的 onMounted 逻辑中
onMounted(() => {
connectionsStore.fetchConnections();
tagsStore.fetchTags();
});
// +++ 注册/注销自定义聚焦动作 +++ // +++ 注册/注销自定义聚焦动作 +++
let unregisterFocusAction: (() => void) | null = null; // 用于存储注销函数
onMounted(() => { onMounted(() => {
focusSwitcherStore.registerFocusAction('connectionListSearch', focusSearchInput); // 调用新的 registerFocusAction 并存储返回的注销函数
// focusSearchInput 返回 boolean,符合 () => boolean | Promise<boolean | undefined> 类型
unregisterFocusAction = focusSwitcherStore.registerFocusAction('connectionListSearch', focusSearchInput);
connectionsStore.fetchConnections(); // 移到 onMounted
tagsStore.fetchTags(); // 移到 onMounted
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
focusSwitcherStore.unregisterFocusAction('connectionListSearch'); // 调用存储的注销函数
if (unregisterFocusAction) {
unregisterFocusAction();
console.log(`[WkspConnList] Unregistered focus action on unmount.`);
}
unregisterFocusAction = null;
}); });
// 处理中键点击(在新标签页打开) // 处理中键点击(在新标签页打开)
@@ -4,11 +4,11 @@ import { useI18n } from 'vue-i18n';
// 假设有一个 API 客户端或辅助函数,这里我们直接使用 fetch // 假设有一个 API 客户端或辅助函数,这里我们直接使用 fetch
// import apiClient from '@/services/api'; // import apiClient from '@/services/api';
// 基础输入框接口 (保持不变) // 基础输入框接口 (移除 focusAction)
export interface FocusableInput { export interface FocusableInput {
id: string; id: string;
label: string; label: string;
focusAction: () => boolean | Promise<boolean>; // focusAction: () => boolean | Promise<boolean>; // 移除,动作将单独管理
} }
// --- 移除 ConfiguredFocusableInput --- // --- 移除 ConfiguredFocusableInput ---
@@ -28,12 +28,14 @@ export interface FocusSwitcherFullConfig {
// Store State 接口 // Store State 接口
interface FocusSwitcherState { interface FocusSwitcherState {
availableInputs: FocusableInput[]; // 所有可用项的基础信息 availableInputs: FocusableInput[]; // 所有可用项的基础信息 (无 focusAction)
sequenceOrder: string[]; // 顺序切换的 ID 列表 sequenceOrder: string[]; // 顺序切换的 ID 列表
itemConfigs: Record<string, FocusItemConfig>; // 所有项目的配置 (id -> config) itemConfigs: Record<string, FocusItemConfig>; // 所有项目的配置 (id -> config)
isConfiguratorVisible: boolean; isConfiguratorVisible: boolean;
activateFileManagerSearchTrigger: number; activateFileManagerSearchTrigger: number;
activateTerminalSearchTrigger: number; activateTerminalSearchTrigger: number;
// 新增:存储注册的聚焦动作
registeredActions: Map<string, Array<() => boolean | Promise<boolean | undefined>>>;
} }
// --- 移除 localStorage Key --- // --- 移除 localStorage Key ---
@@ -44,14 +46,14 @@ export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
// --- State --- // --- State ---
const availableInputs = ref<FocusableInput[]>([ const availableInputs = ref<FocusableInput[]>([
// 简化定义,移除 componentPath 和 selectorfocusAction 将由组件注册 // 移除 focusAction 初始化
{ id: 'commandHistorySearch', label: t('focusSwitcher.input.commandHistorySearch', '命令历史搜索'), focusAction: () => false }, { id: 'commandHistorySearch', label: t('focusSwitcher.input.commandHistorySearch', '命令历史搜索') },
{ id: 'quickCommandsSearch', label: t('focusSwitcher.input.quickCommandsSearch', '快捷指令搜索'), focusAction: () => false }, { id: 'quickCommandsSearch', label: t('focusSwitcher.input.quickCommandsSearch', '快捷指令搜索') },
{ id: 'fileManagerSearch', label: t('focusSwitcher.input.fileManagerSearch', '文件管理器搜索'), focusAction: () => false }, { id: 'fileManagerSearch', label: t('focusSwitcher.input.fileManagerSearch', '文件管理器搜索') },
{ id: 'commandInput', label: t('focusSwitcher.input.commandInput', '命令输入'), focusAction: () => false }, { id: 'commandInput', label: t('focusSwitcher.input.commandInput', '命令输入') },
{ id: 'terminalSearch', label: t('focusSwitcher.input.terminalSearch', '终端内搜索'), focusAction: () => false }, { id: 'terminalSearch', label: t('focusSwitcher.input.terminalSearch', '终端内搜索') },
{ id: 'connectionListSearch', label: t('focusSwitcher.input.connectionListSearch', '连接列表搜索'), focusAction: () => false }, { id: 'connectionListSearch', label: t('focusSwitcher.input.connectionListSearch', '连接列表搜索') },
{ id: 'fileEditorActive', label: t('focusSwitcher.input.fileEditorActive', '文件编辑器'), focusAction: () => false }, { id: 'fileEditorActive', label: t('focusSwitcher.input.fileEditorActive', '文件编辑器') },
]); ]);
const sequenceOrder = ref<string[]>([]); // +++ 新增:存储顺序 +++ const sequenceOrder = ref<string[]>([]); // +++ 新增:存储顺序 +++
const itemConfigs = ref<Record<string, FocusItemConfig>>({}); // +++ 新增:存储所有配置 +++ const itemConfigs = ref<Record<string, FocusItemConfig>>({}); // +++ 新增:存储所有配置 +++
@@ -59,8 +61,8 @@ export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
const activateFileManagerSearchTrigger = ref(0); const activateFileManagerSearchTrigger = ref(0);
const activateTerminalSearchTrigger = ref(0); const activateTerminalSearchTrigger = ref(0);
// 新增:存储自定义聚焦动作 // 新增:存储注册的聚焦动作 (Map: id -> Array of actions)
const focusActions = ref<Record<string, () => boolean | Promise<boolean>>>({}); const registeredActions = ref<Map<string, Array<() => boolean | Promise<boolean | undefined>>>>(new Map());
// --- Actions --- // --- Actions ---
@@ -224,55 +226,92 @@ export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
saveConfigurationToBackend(); saveConfigurationToBackend();
} }
// 注册聚焦动作 (现在更新 availableInputs 中的 focusAction) // 注册聚焦动作 (添加到 Map 中)
function registerFocusAction(id: string, action: () => boolean | Promise<boolean>) { // 返回一个注销函数,以便组件可以方便地注销自己添加的动作
const targetInput = availableInputs.value.find(input => input.id === id); function registerFocusAction(id: string, action: () => boolean | Promise<boolean | undefined>): () => void {
if (targetInput) { if (!availableInputs.value.some(input => input.id === id)) {
targetInput.focusAction = action;
console.log(`[FocusSwitcherStore] Registered focus action for ID: ${id}`);
} else {
console.warn(`[FocusSwitcherStore] Attempted to register focus action for unknown ID: ${id}`); console.warn(`[FocusSwitcherStore] Attempted to register focus action for unknown ID: ${id}`);
} return () => {}; // 返回一个无操作的注销函数
} }
// 注销聚焦动作 (重置为默认返回 false 的函数) const actions = registeredActions.value.get(id) || [];
function unregisterFocusAction(id: string) { actions.push(action);
const targetInput = availableInputs.value.find(input => input.id === id); registeredActions.value.set(id, actions);
if (targetInput) { console.log(`[FocusSwitcherStore] Registered focus action for ID: ${id}. Total actions for this ID: ${actions.length}`);
targetInput.focusAction = () => false; // Reset to default non-functional action
console.log(`[FocusSwitcherStore] Unregistered focus action for ID: ${id}`); // 返回一个用于注销此特定动作的函数
const unregister = () => {
const currentActions = registeredActions.value.get(id);
if (currentActions) {
const index = currentActions.indexOf(action);
if (index > -1) {
currentActions.splice(index, 1);
console.log(`[FocusSwitcherStore] Unregistered a focus action for ID: ${id}. Remaining actions: ${currentActions.length}`);
// 如果数组为空,可以从 Map 中移除该 ID
if (currentActions.length === 0) {
registeredActions.value.delete(id);
console.log(`[FocusSwitcherStore] Removed ID ${id} from registeredActions map as it has no more actions.`);
} }
} else {
console.warn(`[FocusSwitcherStore] Attempted to unregister an action for ID ${id} that was not found.`);
}
}
};
return unregister;
} }
// 新增:统一的聚焦目标 Action // 注销聚焦动作 (现在由 registerFocusAction 返回的函数处理)
// 保留一个空的 unregisterFocusAction 以防万一旧代码调用,但标记为废弃或移除
// function unregisterFocusAction(id: string) {
// console.warn("[FocusSwitcherStore] unregisterFocusAction(id) is deprecated. Use the function returned by registerFocusAction instead.");
// }
// 修改:统一的聚焦目标 Action,现在迭代 Map 中的动作数组
async function focusTarget(id: string): Promise<boolean> { async function focusTarget(id: string): Promise<boolean> {
console.log(`[FocusSwitcherStore] Attempting to focus target ID: ${id}`); console.log(`[FocusSwitcherStore] Attempting to focus target ID: ${id}`);
const targetInput = availableInputs.value.find(input => input.id === id); const actions = registeredActions.value.get(id);
if (targetInput?.focusAction) {
if (!actions || actions.length === 0) {
console.warn(`[FocusSwitcherStore] No focus actions registered for ID: ${id}`);
return false;
}
console.log(`[FocusSwitcherStore] Found ${actions.length} action(s) for ID: ${id}. Iterating...`);
for (const action of actions) {
try { try {
const result = await targetInput.focusAction(); // 执行动作,可能是同步或异步的
if (result) { const result = await action();
console.log(`[FocusSwitcherStore] Successfully focused ${id} via action.`);
if (result === true) {
// 如果动作返回 true,表示成功聚焦,停止迭代并返回 true
console.log(`[FocusSwitcherStore] Successfully focused ${id} via one of its actions.`);
return true; return true;
} else { } else if (result === false) {
console.log(`[FocusSwitcherStore] Focus action for ${id} returned false.`); // 如果动作返回 false,表示尝试但失败,记录日志并继续下一个动作
// 尝试激活搜索框(如果适用) console.log(`[FocusSwitcherStore] An action for ${id} returned false (failed). Trying next action if available.`);
if (id === 'fileManagerSearch') { } else if (result === undefined) {
triggerFileManagerSearchActivation(); // 如果动作返回 undefined,表示跳过(例如非活动实例),记录日志并继续下一个动作
// 激活后可能需要短暂延迟再尝试聚焦,但这部分逻辑移到 App.vue 或组件内部更合适 console.log(`[FocusSwitcherStore] An action for ${id} returned undefined (skipped). Trying next action if available.`);
} else if (id === 'terminalSearch') {
triggerTerminalSearchActivation();
}
return false;
} }
// 如果 result 是其他值,也视为跳过或未处理
} catch (error) { } catch (error) {
console.error(`[FocusSwitcherStore] Error executing focus action for ${id}:`, error); console.error(`[FocusSwitcherStore] Error executing a focus action for ${id}:`, error);
return false; // 即使出错,也继续尝试下一个动作
} }
} else {
console.warn(`[FocusSwitcherStore] No focus action registered for ID: ${id}`);
return false;
} }
// 如果遍历完所有动作都没有成功聚焦 (没有返回 true)
console.log(`[FocusSwitcherStore] All actions for ${id} executed, but none returned true. Focus failed.`);
// 尝试激活搜索框(如果适用),这里的逻辑可能需要重新审视,
// 因为激活应该由返回 false 的动作内部触发,或者由调用 focusTarget 的地方处理
if (id === 'fileManagerSearch') {
// triggerFileManagerSearchActivation(); // 考虑移除这里的触发,让组件内部处理失败后的激活
} else if (id === 'terminalSearch') {
// triggerTerminalSearchActivation(); // 同上
}
return false; // 返回聚焦失败
} }
// --- 修改 Getters --- // --- 修改 Getters ---
@@ -378,8 +417,8 @@ export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
getAvailableInputsForConfigurator, // 已修改 getAvailableInputsForConfigurator, // 已修改
getNextFocusTargetId, // 已修改 getNextFocusTargetId, // 已修改
getFocusTargetIdByShortcut, // 已修改 getFocusTargetIdByShortcut, // 已修改
registerFocusAction, registerFocusAction, // 返回注销函数
unregisterFocusAction, // unregisterFocusAction, // 废弃旧的注销函数
focusTarget, focusTarget, // 已更新
}; };
}); });