update
This commit is contained in:
@@ -521,27 +521,51 @@ watchEffect((onCleanup) => {
|
||||
});
|
||||
|
||||
// +++ 监听 Store 中的触发器以激活搜索 +++
|
||||
watch(() => focusSwitcherStore.activateFileManagerSearchTrigger, () => {
|
||||
// 确保只在触发器值大于 0 时执行(避免初始加载时触发)
|
||||
if (focusSwitcherStore.activateFileManagerSearchTrigger > 0) {
|
||||
console.log('[FileManager] Received search activation trigger from store.');
|
||||
watch(() => focusSwitcherStore.activateFileManagerSearchTrigger, (newValue, oldValue) => { // 修改监听器
|
||||
// 确保只在触发器值增加时执行(避免初始加载或重置时触发)
|
||||
// 并且当前组件的 sessionId 与活动 sessionId 匹配
|
||||
// 检查 newValue > oldValue 确保是递增触发,避免重复执行
|
||||
if (newValue > (oldValue ?? 0) && props.sessionId === sessionStore.activeSessionId) {
|
||||
console.log(`[FileManager ${props.sessionId}] Received search activation trigger for active session.`);
|
||||
activateSearch(); // 调用组件内部的激活搜索方法
|
||||
}
|
||||
});
|
||||
}, { immediate: false }); // 添加 immediate: false 避免初始值为 0 时触发
|
||||
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
console.log(`[FileManager ${props.sessionId}] 组件即将卸载。`);
|
||||
// 调用注入的 SFTP 管理器提供的清理函数
|
||||
cleanupSftpHandlers();
|
||||
});
|
||||
// onBeforeUnmount 中 cleanupSftpHandlers 的调用已移至新的 onBeforeUnmount 逻辑中
|
||||
|
||||
// +++ 注册/注销自定义聚焦动作 +++
|
||||
let unregisterFocusAction: (() => void) | null = null; // 用于存储注销函数
|
||||
|
||||
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(() => {
|
||||
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 => {
|
||||
// 检查当前会话是否激活,防止后台实例响应
|
||||
if (props.sessionId !== sessionStore.activeSessionId) {
|
||||
console.log(`[FileManager ${props.sessionId}] Ignoring focus request for inactive session.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isSearchActive.value) {
|
||||
activateSearch(); // Activate search first
|
||||
nextTick(() => { // Wait for DOM update
|
||||
// nextTick 确保 DOM 更新后再聚焦
|
||||
nextTick(() => {
|
||||
if (searchInputRef.value) {
|
||||
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) {
|
||||
searchInputRef.value.focus();
|
||||
console.log(`[FileManager ${props.sessionId}] Search already active, input focused.`);
|
||||
return true;
|
||||
}
|
||||
console.warn(`[FileManager ${props.sessionId}] Could not focus search input.`);
|
||||
return false;
|
||||
};
|
||||
defineExpose({ focusSearchInput });
|
||||
|
||||
@@ -221,18 +221,26 @@ const handleBlur = () => {
|
||||
}, 150); // 150ms 延迟可能更稳妥
|
||||
};
|
||||
|
||||
// 获取数据
|
||||
onMounted(() => {
|
||||
connectionsStore.fetchConnections();
|
||||
tagsStore.fetchTags();
|
||||
});
|
||||
// 获取数据的 onMounted 调用已移至新的 onMounted 逻辑中
|
||||
|
||||
// +++ 注册/注销自定义聚焦动作 +++
|
||||
let unregisterFocusAction: (() => void) | null = null; // 用于存储注销函数
|
||||
|
||||
onMounted(() => {
|
||||
focusSwitcherStore.registerFocusAction('connectionListSearch', focusSearchInput);
|
||||
// 调用新的 registerFocusAction 并存储返回的注销函数
|
||||
// focusSearchInput 返回 boolean,符合 () => boolean | Promise<boolean | undefined> 类型
|
||||
unregisterFocusAction = focusSwitcherStore.registerFocusAction('connectionListSearch', focusSearchInput);
|
||||
connectionsStore.fetchConnections(); // 移到 onMounted
|
||||
tagsStore.fetchTags(); // 移到 onMounted
|
||||
});
|
||||
|
||||
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
|
||||
// import apiClient from '@/services/api';
|
||||
|
||||
// 基础输入框接口 (保持不变)
|
||||
// 基础输入框接口 (移除 focusAction)
|
||||
export interface FocusableInput {
|
||||
id: string;
|
||||
label: string;
|
||||
focusAction: () => boolean | Promise<boolean>;
|
||||
// focusAction: () => boolean | Promise<boolean>; // 移除,动作将单独管理
|
||||
}
|
||||
|
||||
// --- 移除 ConfiguredFocusableInput ---
|
||||
@@ -28,12 +28,14 @@ export interface FocusSwitcherFullConfig {
|
||||
|
||||
// Store State 接口
|
||||
interface FocusSwitcherState {
|
||||
availableInputs: FocusableInput[]; // 所有可用项的基础信息
|
||||
availableInputs: FocusableInput[]; // 所有可用项的基础信息 (无 focusAction)
|
||||
sequenceOrder: string[]; // 顺序切换的 ID 列表
|
||||
itemConfigs: Record<string, FocusItemConfig>; // 所有项目的配置 (id -> config)
|
||||
isConfiguratorVisible: boolean;
|
||||
activateFileManagerSearchTrigger: number;
|
||||
activateTerminalSearchTrigger: number;
|
||||
// 新增:存储注册的聚焦动作
|
||||
registeredActions: Map<string, Array<() => boolean | Promise<boolean | undefined>>>;
|
||||
}
|
||||
|
||||
// --- 移除 localStorage Key ---
|
||||
@@ -44,14 +46,14 @@ export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
|
||||
|
||||
// --- State ---
|
||||
const availableInputs = ref<FocusableInput[]>([
|
||||
// 简化定义,移除 componentPath 和 selector,focusAction 将由组件注册
|
||||
{ id: 'commandHistorySearch', label: t('focusSwitcher.input.commandHistorySearch', '命令历史搜索'), focusAction: () => false },
|
||||
{ id: 'quickCommandsSearch', label: t('focusSwitcher.input.quickCommandsSearch', '快捷指令搜索'), focusAction: () => false },
|
||||
{ id: 'fileManagerSearch', label: t('focusSwitcher.input.fileManagerSearch', '文件管理器搜索'), focusAction: () => false },
|
||||
{ id: 'commandInput', label: t('focusSwitcher.input.commandInput', '命令输入'), focusAction: () => false },
|
||||
{ id: 'terminalSearch', label: t('focusSwitcher.input.terminalSearch', '终端内搜索'), focusAction: () => false },
|
||||
{ id: 'connectionListSearch', label: t('focusSwitcher.input.connectionListSearch', '连接列表搜索'), focusAction: () => false },
|
||||
{ id: 'fileEditorActive', label: t('focusSwitcher.input.fileEditorActive', '文件编辑器'), focusAction: () => false },
|
||||
// 移除 focusAction 初始化
|
||||
{ id: 'commandHistorySearch', label: t('focusSwitcher.input.commandHistorySearch', '命令历史搜索') },
|
||||
{ id: 'quickCommandsSearch', label: t('focusSwitcher.input.quickCommandsSearch', '快捷指令搜索') },
|
||||
{ id: 'fileManagerSearch', label: t('focusSwitcher.input.fileManagerSearch', '文件管理器搜索') },
|
||||
{ id: 'commandInput', label: t('focusSwitcher.input.commandInput', '命令输入') },
|
||||
{ id: 'terminalSearch', label: t('focusSwitcher.input.terminalSearch', '终端内搜索') },
|
||||
{ id: 'connectionListSearch', label: t('focusSwitcher.input.connectionListSearch', '连接列表搜索') },
|
||||
{ id: 'fileEditorActive', label: t('focusSwitcher.input.fileEditorActive', '文件编辑器') },
|
||||
]);
|
||||
const sequenceOrder = ref<string[]>([]); // +++ 新增:存储顺序 +++
|
||||
const itemConfigs = ref<Record<string, FocusItemConfig>>({}); // +++ 新增:存储所有配置 +++
|
||||
@@ -59,8 +61,8 @@ export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
|
||||
const activateFileManagerSearchTrigger = ref(0);
|
||||
const activateTerminalSearchTrigger = ref(0);
|
||||
|
||||
// 新增:存储自定义聚焦动作
|
||||
const focusActions = ref<Record<string, () => boolean | Promise<boolean>>>({});
|
||||
// 新增:存储注册的聚焦动作 (Map: id -> Array of actions)
|
||||
const registeredActions = ref<Map<string, Array<() => boolean | Promise<boolean | undefined>>>>(new Map());
|
||||
|
||||
// --- Actions ---
|
||||
|
||||
@@ -224,55 +226,92 @@ export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
|
||||
saveConfigurationToBackend();
|
||||
}
|
||||
|
||||
// 注册聚焦动作 (现在更新 availableInputs 中的 focusAction)
|
||||
function registerFocusAction(id: string, action: () => boolean | Promise<boolean>) {
|
||||
const targetInput = availableInputs.value.find(input => input.id === id);
|
||||
if (targetInput) {
|
||||
targetInput.focusAction = action;
|
||||
console.log(`[FocusSwitcherStore] Registered focus action for ID: ${id}`);
|
||||
} else {
|
||||
// 注册聚焦动作 (添加到 Map 中)
|
||||
// 返回一个注销函数,以便组件可以方便地注销自己添加的动作
|
||||
function registerFocusAction(id: string, action: () => boolean | Promise<boolean | undefined>): () => void {
|
||||
if (!availableInputs.value.some(input => input.id === id)) {
|
||||
console.warn(`[FocusSwitcherStore] Attempted to register focus action for unknown ID: ${id}`);
|
||||
return () => {}; // 返回一个无操作的注销函数
|
||||
}
|
||||
|
||||
const actions = registeredActions.value.get(id) || [];
|
||||
actions.push(action);
|
||||
registeredActions.value.set(id, actions);
|
||||
console.log(`[FocusSwitcherStore] Registered focus action for ID: ${id}. Total actions for this ID: ${actions.length}`);
|
||||
|
||||
// 返回一个用于注销此特定动作的函数
|
||||
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;
|
||||
}
|
||||
|
||||
// 注销聚焦动作 (重置为默认返回 false 的函数)
|
||||
function unregisterFocusAction(id: string) {
|
||||
const targetInput = availableInputs.value.find(input => input.id === id);
|
||||
if (targetInput) {
|
||||
targetInput.focusAction = () => false; // Reset to default non-functional action
|
||||
console.log(`[FocusSwitcherStore] Unregistered focus action for ID: ${id}`);
|
||||
}
|
||||
}
|
||||
// 注销聚焦动作 (现在由 registerFocusAction 返回的函数处理)
|
||||
// 保留一个空的 unregisterFocusAction 以防万一旧代码调用,但标记为废弃或移除
|
||||
// function unregisterFocusAction(id: string) {
|
||||
// console.warn("[FocusSwitcherStore] unregisterFocusAction(id) is deprecated. Use the function returned by registerFocusAction instead.");
|
||||
// }
|
||||
|
||||
// 新增:统一的聚焦目标 Action
|
||||
// 修改:统一的聚焦目标 Action,现在迭代 Map 中的动作数组
|
||||
async function focusTarget(id: string): Promise<boolean> {
|
||||
console.log(`[FocusSwitcherStore] Attempting to focus target ID: ${id}`);
|
||||
const targetInput = availableInputs.value.find(input => input.id === id);
|
||||
if (targetInput?.focusAction) {
|
||||
try {
|
||||
const result = await targetInput.focusAction();
|
||||
if (result) {
|
||||
console.log(`[FocusSwitcherStore] Successfully focused ${id} via action.`);
|
||||
return true;
|
||||
} else {
|
||||
console.log(`[FocusSwitcherStore] Focus action for ${id} returned false.`);
|
||||
// 尝试激活搜索框(如果适用)
|
||||
if (id === 'fileManagerSearch') {
|
||||
triggerFileManagerSearchActivation();
|
||||
// 激活后可能需要短暂延迟再尝试聚焦,但这部分逻辑移到 App.vue 或组件内部更合适
|
||||
} else if (id === 'terminalSearch') {
|
||||
triggerTerminalSearchActivation();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[FocusSwitcherStore] Error executing focus action for ${id}:`, error);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
console.warn(`[FocusSwitcherStore] No focus action registered for ID: ${id}`);
|
||||
const actions = registeredActions.value.get(id);
|
||||
|
||||
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 {
|
||||
// 执行动作,可能是同步或异步的
|
||||
const result = await action();
|
||||
|
||||
if (result === true) {
|
||||
// 如果动作返回 true,表示成功聚焦,停止迭代并返回 true
|
||||
console.log(`[FocusSwitcherStore] Successfully focused ${id} via one of its actions.`);
|
||||
return true;
|
||||
} else if (result === false) {
|
||||
// 如果动作返回 false,表示尝试但失败,记录日志并继续下一个动作
|
||||
console.log(`[FocusSwitcherStore] An action for ${id} returned false (failed). Trying next action if available.`);
|
||||
} else if (result === undefined) {
|
||||
// 如果动作返回 undefined,表示跳过(例如非活动实例),记录日志并继续下一个动作
|
||||
console.log(`[FocusSwitcherStore] An action for ${id} returned undefined (skipped). Trying next action if available.`);
|
||||
}
|
||||
// 如果 result 是其他值,也视为跳过或未处理
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[FocusSwitcherStore] Error executing a focus action for ${id}:`, error);
|
||||
// 即使出错,也继续尝试下一个动作
|
||||
}
|
||||
}
|
||||
|
||||
// 如果遍历完所有动作都没有成功聚焦 (没有返回 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 ---
|
||||
@@ -378,8 +417,8 @@ export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
|
||||
getAvailableInputsForConfigurator, // 已修改
|
||||
getNextFocusTargetId, // 已修改
|
||||
getFocusTargetIdByShortcut, // 已修改
|
||||
registerFocusAction,
|
||||
unregisterFocusAction,
|
||||
focusTarget,
|
||||
registerFocusAction, // 返回注销函数
|
||||
// unregisterFocusAction, // 废弃旧的注销函数
|
||||
focusTarget, // 已更新
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user