update
This commit is contained in:
@@ -12,7 +12,7 @@ export const settingsRepository = {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.all('SELECT key, value FROM settings', (err: any, rows: Setting[]) => { // 添加 err 类型
|
||||
if (err) {
|
||||
console.error('获取所有设置时出错:', err); // 更新日志为中文
|
||||
console.error('[Repository] 获取所有设置时出错:', err); // 更新日志为中文
|
||||
reject(new Error('获取设置失败')); // 更新错误消息为中文
|
||||
} else {
|
||||
resolve(rows);
|
||||
@@ -23,11 +23,13 @@ export const settingsRepository = {
|
||||
|
||||
async getSetting(key: string): Promise<string | null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(`[Repository] Attempting to get setting with key: ${key}`); // +++ 添加日志 +++
|
||||
db.get('SELECT value FROM settings WHERE key = ?', [key], (err: any, row: { value: string } | undefined) => { // 添加 err 类型
|
||||
if (err) {
|
||||
console.error(`获取设置项 ${key} 时出错:`, err); // 更新日志为中文
|
||||
console.error(`[Repository] 获取设置项 ${key} 时出错:`, err); // 更新日志为中文
|
||||
reject(new Error(`获取设置项 ${key} 失败`)); // 更新错误消息为中文
|
||||
} else {
|
||||
console.log(`[Repository] Found value for key ${key}:`, row ? row.value : null); // +++ 添加日志 +++
|
||||
resolve(row ? row.value : null);
|
||||
}
|
||||
});
|
||||
@@ -37,18 +39,26 @@ export const settingsRepository = {
|
||||
async setSetting(key: string, value: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const now = Math.floor(Date.now() / 1000); // 获取当前 Unix 时间戳
|
||||
db.run(
|
||||
`INSERT INTO settings (key, value, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(key) DO UPDATE SET
|
||||
const sql = `INSERT INTO settings (key, value, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(key) DO UPDATE SET
|
||||
value = excluded.value,
|
||||
updated_at = excluded.updated_at`,
|
||||
[key, value, now, now],
|
||||
function (err: any) { // 添加 err 类型
|
||||
updated_at = excluded.updated_at`;
|
||||
const params = [key, value, now, now];
|
||||
|
||||
console.log(`[Repository] Attempting to set setting. Key: ${key}, Value: ${value}`); // +++ 添加日志 +++
|
||||
console.log(`[Repository] Executing SQL: ${sql} with params: ${JSON.stringify(params)}`); // +++ 添加日志 +++
|
||||
|
||||
db.run(
|
||||
sql,
|
||||
params,
|
||||
function (this: any, err: any) { // 使用 this 需要 function 声明, 添加 err 类型
|
||||
if (err) {
|
||||
console.error(`设置设置项 ${key} 时出错:`, err); // 更新日志为中文
|
||||
console.error(`[Repository] 设置设置项 ${key} 时出错:`, err); // 更新日志为中文
|
||||
reject(new Error(`设置设置项 ${key} 失败`)); // 更新错误消息为中文
|
||||
} else {
|
||||
// this.changes 提供了受影响的行数 (对于 INSERT/UPDATE)
|
||||
console.log(`[Repository] Successfully set setting for key: ${key}. Rows affected: ${this.changes}`); // +++ 添加日志 +++
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
@@ -58,11 +68,13 @@ export const settingsRepository = {
|
||||
|
||||
async deleteSetting(key: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run('DELETE FROM settings WHERE key = ?', [key], function (err: any) { // 添加 err 类型
|
||||
console.log(`[Repository] Attempting to delete setting with key: ${key}`); // +++ 添加日志 +++
|
||||
db.run('DELETE FROM settings WHERE key = ?', [key], function (this: any, err: any) { // 添加 err 类型
|
||||
if (err) {
|
||||
console.error(`删除设置项 ${key} 时出错:`, err); // 更新日志为中文
|
||||
console.error(`[Repository] 删除设置项 ${key} 时出错:`, err); // 更新日志为中文
|
||||
reject(new Error(`删除设置项 ${key} 失败`)); // 更新错误消息为中文
|
||||
} else {
|
||||
console.log(`[Repository] Successfully deleted setting for key: ${key}. Rows affected: ${this.changes}`); // +++ 添加日志 +++
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
@@ -70,9 +82,11 @@ export const settingsRepository = {
|
||||
},
|
||||
|
||||
async setMultipleSettings(settings: Record<string, string>): Promise<void> {
|
||||
console.log('[Repository] setMultipleSettings called with:', JSON.stringify(settings)); // +++ 添加日志 +++
|
||||
const promises = Object.entries(settings).map(([key, value]) =>
|
||||
this.setSetting(key, value)
|
||||
this.setSetting(key, value) // this 指向 settingsRepository 对象
|
||||
);
|
||||
await Promise.all(promises);
|
||||
console.log('[Repository] setMultipleSettings finished.'); // +++ 添加日志 +++
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { settingsRepository, Setting } from '../repositories/settings.repository';
|
||||
|
||||
// +++ 定义默认的焦点切换顺序 +++
|
||||
const DEFAULT_FOCUS_SEQUENCE = ["quickCommandsSearch", "commandHistorySearch", "fileManagerSearch", "commandInput", "terminalSearch"];
|
||||
const FOCUS_SEQUENCE_KEY = 'focusSwitcherSequence'; // +++ 定义设置键常量 +++
|
||||
|
||||
export const settingsService = {
|
||||
// ... (getAllSettings, getSetting, setSetting, setMultipleSettings, deleteSetting, getIpWhitelistSettings, updateIpWhitelistSettings, getFocusSwitcherSequence 保持不变) ...
|
||||
|
||||
/**
|
||||
* 获取所有设置项
|
||||
* @returns 返回包含所有设置项的数组
|
||||
@@ -76,4 +82,57 @@ export const settingsService = {
|
||||
settingsRepository.setSetting('ipWhitelist', whitelist),
|
||||
]);
|
||||
},
|
||||
|
||||
// +++ 新增:获取焦点切换顺序 +++
|
||||
/**
|
||||
* 获取焦点切换顺序
|
||||
* @returns 返回存储的焦点切换顺序数组,如果未设置或无效则返回默认顺序
|
||||
*/
|
||||
async getFocusSwitcherSequence(): Promise<string[]> {
|
||||
console.log(`[Service] Attempting to get setting for key: ${FOCUS_SEQUENCE_KEY}`); // +++ 添加日志 +++
|
||||
try {
|
||||
const sequenceJson = await settingsRepository.getSetting(FOCUS_SEQUENCE_KEY);
|
||||
console.log(`[Service] Raw value from repository for ${FOCUS_SEQUENCE_KEY}:`, sequenceJson); // +++ 添加日志 +++
|
||||
if (sequenceJson) {
|
||||
const sequence = JSON.parse(sequenceJson);
|
||||
// 基本验证:确保它是一个数组并且包含字符串
|
||||
if (Array.isArray(sequence) && sequence.every(item => typeof item === 'string')) {
|
||||
console.log('[Service] Fetched and validated focus switcher sequence:', JSON.stringify(sequence)); // +++ 更新日志 +++
|
||||
return sequence;
|
||||
} else {
|
||||
console.warn('[Service] Invalid focus switcher sequence format found in settings. Returning default.');
|
||||
}
|
||||
} else {
|
||||
console.log('[Service] No focus switcher sequence found in settings. Returning default.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[Service] Error parsing focus switcher sequence from settings (key: ${FOCUS_SEQUENCE_KEY}):`, error); // +++ 更新日志 +++
|
||||
}
|
||||
// 如果发生错误或未找到/无效,返回默认值
|
||||
console.log('[Service] Returning default focus sequence:', JSON.stringify(DEFAULT_FOCUS_SEQUENCE)); // +++ 添加日志 +++
|
||||
return [...DEFAULT_FOCUS_SEQUENCE]; // 返回默认值的副本
|
||||
},
|
||||
|
||||
// +++ 新增:设置焦点切换顺序 +++
|
||||
/**
|
||||
* 设置焦点切换顺序
|
||||
* @param sequence 要保存的焦点切换顺序数组
|
||||
*/
|
||||
async setFocusSwitcherSequence(sequence: string[]): Promise<void> {
|
||||
console.log('[Service] setFocusSwitcherSequence called with:', JSON.stringify(sequence)); // +++ 添加日志 +++
|
||||
// 基本验证
|
||||
if (!Array.isArray(sequence) || !sequence.every(item => typeof item === 'string')) {
|
||||
console.error('[Service] Attempted to save invalid focus switcher sequence format:', sequence);
|
||||
throw new Error('Invalid sequence format provided.'); // 抛出错误阻止保存无效数据
|
||||
}
|
||||
try {
|
||||
const sequenceJson = JSON.stringify(sequence);
|
||||
console.log(`[Service] Attempting to save setting. Key: ${FOCUS_SEQUENCE_KEY}, Value: ${sequenceJson}`); // +++ 添加日志 +++
|
||||
await settingsRepository.setSetting(FOCUS_SEQUENCE_KEY, sequenceJson);
|
||||
console.log(`[Service] Successfully saved setting for key: ${FOCUS_SEQUENCE_KEY}`); // +++ 添加日志 +++
|
||||
} catch (error) {
|
||||
console.error(`[Service] Error calling settingsRepository.setSetting for key ${FOCUS_SEQUENCE_KEY}:`, error); // +++ 更新日志 +++
|
||||
throw new Error('Failed to save focus switcher sequence.'); // 重新抛出错误
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -6,6 +6,8 @@ import { ipBlacklistService } from '../services/ip-blacklist.service'; // 引入
|
||||
const auditLogService = new AuditLogService(); // 实例化 AuditLogService
|
||||
|
||||
export const settingsController = {
|
||||
// ... (getAllSettings, updateSettings, getFocusSwitcherSequence 保持不变) ...
|
||||
|
||||
/**
|
||||
* 获取所有设置项
|
||||
*/
|
||||
@@ -31,11 +33,11 @@ export const settingsController = {
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 过滤掉外观设置相关的键 ---
|
||||
// --- 过滤掉外观设置和焦点切换顺序相关的键 ---
|
||||
const allowedSettingsKeys = [
|
||||
'language', 'ipWhitelist', 'maxLoginAttempts', 'loginBanDuration',
|
||||
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled' // 添加 ipWhitelistEnabled
|
||||
// 在这里添加其他允许的通用设置键
|
||||
'showPopupFileEditor', 'shareFileEditorTabs', 'ipWhitelistEnabled'
|
||||
// 不在此处处理 'focusSwitcherSequence'
|
||||
];
|
||||
const filteredSettings: Record<string, string> = {};
|
||||
for (const key in settingsToUpdate) {
|
||||
@@ -51,29 +53,75 @@ export const settingsController = {
|
||||
}
|
||||
|
||||
// 记录审计日志
|
||||
// 区分 IP 白名单更新和其他设置更新
|
||||
// 注意:现在审计日志可能需要更精细的逻辑,因为它只记录了实际更新的通用设置
|
||||
const updatedKeys = Object.keys(filteredSettings); // 使用过滤后的键
|
||||
if (updatedKeys.length > 0) { // 只有实际更新了才记录
|
||||
const updatedKeys = Object.keys(filteredSettings);
|
||||
if (updatedKeys.length > 0) {
|
||||
if (updatedKeys.includes('ipWhitelist') || updatedKeys.includes('ipWhitelistEnabled')) {
|
||||
auditLogService.logAction('IP_WHITELIST_UPDATED', { updatedKeys });
|
||||
} else {
|
||||
auditLogService.logAction('SETTINGS_UPDATED', { updatedKeys });
|
||||
}
|
||||
}
|
||||
res.status(200).json({ message: '设置已成功更新' }); // 即使没有更新通用设置也返回成功
|
||||
res.status(200).json({ message: '设置已成功更新' });
|
||||
} catch (error: any) {
|
||||
console.error('更新设置时出错:', error);
|
||||
res.status(500).json({ message: '更新设置失败', error: error.message });
|
||||
}
|
||||
},
|
||||
|
||||
// 注意:通常不直接通过 API 提供单个设置项的获取、设置或删除,
|
||||
// 而是通过批量获取/更新来管理。如果需要单独操作,可以添加相应方法。
|
||||
// 例如:
|
||||
// async getSetting(req: Request, res: Response): Promise<void> { ... }
|
||||
// async setSetting(req: Request, res: Response): Promise<void> { ... }
|
||||
// async deleteSetting(req: Request, res: Response): Promise<void> { ... }
|
||||
// +++ 新增:获取焦点切换顺序 +++
|
||||
/**
|
||||
* 获取焦点切换顺序
|
||||
*/
|
||||
async getFocusSwitcherSequence(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
console.log('[Controller] Received request to get focus switcher sequence.'); // +++ 添加日志 +++
|
||||
const sequence = await settingsService.getFocusSwitcherSequence();
|
||||
console.log('[Controller] Sending focus switcher sequence to client:', JSON.stringify(sequence)); // +++ 添加日志 +++
|
||||
res.json(sequence);
|
||||
} catch (error: any) {
|
||||
console.error('[Controller] 获取焦点切换顺序时出错:', error); // +++ 更新日志前缀 +++
|
||||
res.status(500).json({ message: '获取焦点切换顺序失败', error: error.message });
|
||||
}
|
||||
},
|
||||
|
||||
// +++ 新增:设置焦点切换顺序 +++
|
||||
/**
|
||||
* 设置焦点切换顺序
|
||||
*/
|
||||
async setFocusSwitcherSequence(req: Request, res: Response): Promise<void> {
|
||||
console.log('[Controller] Received request to set focus switcher sequence.'); // +++ 添加日志 +++
|
||||
try {
|
||||
const { sequence } = req.body;
|
||||
console.log('[Controller] Request body sequence:', JSON.stringify(sequence)); // +++ 添加日志 +++
|
||||
|
||||
// 输入验证
|
||||
if (!Array.isArray(sequence) || !sequence.every(item => typeof item === 'string')) {
|
||||
console.warn('[Controller] Invalid sequence format received:', sequence); // +++ 添加日志 +++
|
||||
res.status(400).json({ message: '无效的请求体,"sequence" 必须是一个字符串数组' });
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[Controller] Calling settingsService.setFocusSwitcherSequence...'); // +++ 添加日志 +++
|
||||
await settingsService.setFocusSwitcherSequence(sequence);
|
||||
console.log('[Controller] settingsService.setFocusSwitcherSequence completed successfully.'); // +++ 添加日志 +++
|
||||
|
||||
// 记录审计日志 (可选)
|
||||
console.log('[Controller] Logging audit action: FOCUS_SWITCHER_SEQUENCE_UPDATED'); // +++ 添加日志 +++
|
||||
auditLogService.logAction('FOCUS_SWITCHER_SEQUENCE_UPDATED', { sequence });
|
||||
|
||||
console.log('[Controller] Sending success response.'); // +++ 添加日志 +++
|
||||
res.status(200).json({ message: '焦点切换顺序已成功更新' });
|
||||
} catch (error: any) {
|
||||
console.error('[Controller] 设置焦点切换顺序时出错:', error); // +++ 更新日志前缀 +++
|
||||
// 区分是服务层抛出的验证错误还是其他错误
|
||||
if (error.message === 'Invalid sequence format provided.') {
|
||||
res.status(400).json({ message: '设置焦点切换顺序失败: 无效的格式', error: error.message });
|
||||
} else {
|
||||
res.status(500).json({ message: '设置焦点切换顺序失败', error: error.message });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 获取 IP 黑名单列表 (分页)
|
||||
|
||||
@@ -11,6 +11,13 @@ router.use(isAuthenticated);
|
||||
router.get('/', settingsController.getAllSettings); // GET /api/v1/settings
|
||||
router.put('/', settingsController.updateSettings); // PUT /api/v1/settings
|
||||
|
||||
// +++ 新增:焦点切换顺序路由 +++
|
||||
// GET /api/v1/settings/focus-switcher-sequence - 获取焦点切换顺序
|
||||
router.get('/focus-switcher-sequence', settingsController.getFocusSwitcherSequence);
|
||||
// PUT /api/v1/settings/focus-switcher-sequence - 更新焦点切换顺序
|
||||
router.put('/focus-switcher-sequence', settingsController.setFocusSwitcherSequence);
|
||||
|
||||
|
||||
// --- IP 黑名单管理路由 ---
|
||||
// GET /api/v1/settings/ip-blacklist - 获取 IP 黑名单列表 (需要认证)
|
||||
router.get('/ip-blacklist', settingsController.getIpBlacklist);
|
||||
|
||||
@@ -31,6 +31,7 @@ export type AuditLogActionType =
|
||||
// Settings
|
||||
| 'SETTINGS_UPDATED' // General settings update
|
||||
| 'IP_WHITELIST_UPDATED' // Specific setting update
|
||||
| 'FOCUS_SWITCHER_SEQUENCE_UPDATED' // +++ 新增:焦点切换顺序更新 +++
|
||||
|
||||
// Notifications
|
||||
| 'NOTIFICATION_SETTING_CREATED'
|
||||
|
||||
@@ -102,9 +102,8 @@ const saveConfiguration = () => {
|
||||
// 从本地副本提取 ID 序列
|
||||
const newSequenceIds = localSequence.value.map(item => item.id);
|
||||
console.log('[FocusSwitcherConfigurator] Saving configuration. Sequence IDs to save:', newSequenceIds); // +++ Log: Saving IDs +++
|
||||
focusSwitcherStore.updateSequence(newSequenceIds); // 更新 Store 中的序列
|
||||
focusSwitcherStore.saveConfiguration(); // 持久化保存
|
||||
console.log('[FocusSwitcherConfigurator] Configuration save process completed.'); // +++ Log: Save completed +++
|
||||
focusSwitcherStore.updateSequence(newSequenceIds); // 更新 Store 中的序列 (这会触发保存到后端)
|
||||
console.log('[FocusSwitcherConfigurator] Configuration save process triggered via updateSequence.'); // +++ Log: Save triggered +++
|
||||
hasChanges.value = false;
|
||||
emit('close'); // 保存后关闭
|
||||
};
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, computed, nextTick } from 'vue'; // +++ 将 nextTick 导入移到这里 +++
|
||||
import { ref, computed, nextTick } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
// 假设有一个 API 客户端或辅助函数,这里我们直接使用 fetch
|
||||
// import apiClient from '@/services/api'; // 理想情况下
|
||||
|
||||
// 定义输入框的接口
|
||||
export interface FocusableInput {
|
||||
id: string; // 唯一标识符
|
||||
label: string; // 用户友好的名称
|
||||
// 可以添加其他元数据,例如组件路径或选择器,以便将来查找元素
|
||||
componentPath?: string;
|
||||
selector?: string;
|
||||
}
|
||||
@@ -17,155 +18,185 @@ interface FocusSwitcherState {
|
||||
configuredSequence: string[]; // 只存储 ID 序列
|
||||
isConfiguratorVisible: boolean;
|
||||
activateFileManagerSearchTrigger: number;
|
||||
activateTerminalSearchTrigger: number; // +++ 新增:终端搜索触发器 +++
|
||||
activateTerminalSearchTrigger: number;
|
||||
}
|
||||
|
||||
const LOCAL_STORAGE_KEY = 'focusSwitcherSequence';
|
||||
// --- 移除 localStorage Key ---
|
||||
// const LOCAL_STORAGE_KEY = 'focusSwitcherSequence';
|
||||
|
||||
export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
|
||||
const { t } = useI18n(); // 在 store setup 中获取 t 函数
|
||||
const { t } = useI18n();
|
||||
|
||||
// --- State ---
|
||||
// 所有可供配置的输入框列表
|
||||
// 注意:label 使用 t() 函数获取初始值
|
||||
const availableInputs = ref<FocusableInput[]>([
|
||||
{ id: 'commandHistorySearch', label: t('focusSwitcher.input.commandHistorySearch', '命令历史搜索'), componentPath: 'CommandHistoryView.vue', selector: 'input[placeholder*="搜索历史记录"]' },
|
||||
{ id: 'quickCommandsSearch', label: t('focusSwitcher.input.quickCommandsSearch', '快捷指令搜索'), componentPath: 'QuickCommandsView.vue', selector: 'input[placeholder*="搜索名称或指令"]' },
|
||||
{ id: 'fileManagerSearch', label: t('focusSwitcher.input.fileManagerSearch', '文件管理器搜索'), componentPath: 'FileManager.vue', selector: '.search-input' }, // FileManager 的搜索框 class 是 search-input
|
||||
{ id: 'fileManagerSearch', label: t('focusSwitcher.input.fileManagerSearch', '文件管理器搜索'), componentPath: 'FileManager.vue', selector: '.search-input' },
|
||||
{ id: 'commandInput', label: t('focusSwitcher.input.commandInput', '命令输入'), componentPath: 'CommandInputBar.vue', selector: '.command-input' },
|
||||
{ id: 'terminalSearch', label: t('focusSwitcher.input.terminalSearch', '终端内搜索'), componentPath: 'CommandInputBar.vue', selector: '.search-input' }, // CommandInputBar 的搜索框 class 也是 search-input
|
||||
// 注意:CommandInputBar 和 FileManager 都有 .search-input,需要更精确的选择器或逻辑来区分,暂时先这样
|
||||
{ id: 'terminalSearch', label: t('focusSwitcher.input.terminalSearch', '终端内搜索'), componentPath: 'CommandInputBar.vue', selector: '.search-input' },
|
||||
]);
|
||||
|
||||
// 用户配置的切换顺序 (存储 ID)
|
||||
const configuredSequence = ref<string[]>([]);
|
||||
|
||||
// 控制配置弹窗可见性
|
||||
// 控制配置弹窗可见性
|
||||
const isConfiguratorVisible = ref(false);
|
||||
// +++ 触发器状态 +++
|
||||
const activateFileManagerSearchTrigger = ref(0);
|
||||
const activateTerminalSearchTrigger = ref(0); // +++ 终端搜索触发器状态 +++
|
||||
const activateTerminalSearchTrigger = ref(0);
|
||||
|
||||
// --- Actions ---
|
||||
// +++ 新增:触发终端搜索激活的 Action +++
|
||||
|
||||
// +++ 新增:从后端加载配置 +++
|
||||
async function loadSequenceFromBackend() {
|
||||
const apiUrl = '/api/v1/settings/focus-switcher-sequence'; // +++ 定义 API URL +++
|
||||
console.log(`[FocusSwitcherStore] Attempting to load sequence from backend via: ${apiUrl}`); // +++ 更新日志 +++
|
||||
try {
|
||||
// 注意:需要根据实际项目配置调整 API 路径和认证处理
|
||||
const response = await fetch(apiUrl); // +++ 使用变量 +++
|
||||
console.log(`[FocusSwitcherStore] Received response from ${apiUrl}. Status: ${response.status}`); // +++ 添加日志:响应状态 +++
|
||||
|
||||
if (!response.ok) {
|
||||
// +++ 添加日志:记录非 OK 状态 +++
|
||||
console.error(`[FocusSwitcherStore] HTTP error from ${apiUrl}. Status: ${response.status}`);
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const sequence = await response.json();
|
||||
// +++ 添加日志:记录原始 JSON 数据 +++
|
||||
console.log(`[FocusSwitcherStore] Raw JSON received from backend for sequence:`, JSON.stringify(sequence));
|
||||
|
||||
if (Array.isArray(sequence) && sequence.every(item => typeof item === 'string')) {
|
||||
console.log('[FocusSwitcherStore] Sequence format is valid (string array). Filtering against available inputs...'); // +++ 添加日志 +++
|
||||
// 验证加载的 ID 是否仍然存在于 availableInputs 中
|
||||
const availableIds = new Set(availableInputs.value.map(input => input.id));
|
||||
const filteredSequence = sequence.filter((id: string) => {
|
||||
const isValid = availableIds.has(id);
|
||||
if (!isValid) {
|
||||
console.warn(`[FocusSwitcherStore] Filtered out invalid ID during load from backend: ${id}`);
|
||||
}
|
||||
return isValid;
|
||||
});
|
||||
configuredSequence.value = filteredSequence;
|
||||
// +++ 更新日志:显示最终设置的值 +++
|
||||
console.log('[FocusSwitcherStore] Successfully loaded and set configuredSequence:', JSON.stringify(configuredSequence.value));
|
||||
} else {
|
||||
console.error('[FocusSwitcherStore] Invalid sequence format received from backend:', sequence);
|
||||
configuredSequence.value = []; // 使用空数组作为回退
|
||||
console.log('[FocusSwitcherStore] Set configuredSequence to empty array due to invalid format.'); // +++ 添加日志 +++
|
||||
}
|
||||
} catch (error) {
|
||||
// +++ 添加日志:记录 fetch 或 JSON 解析错误 +++
|
||||
console.error(`[FocusSwitcherStore] Failed to load or parse sequence from backend (${apiUrl}):`, error);
|
||||
// 加载失败时可以考虑使用默认值或保持为空
|
||||
configuredSequence.value = [];
|
||||
console.log('[FocusSwitcherStore] Set configuredSequence to empty array due to loading error.'); // +++ 添加日志 +++
|
||||
}
|
||||
}
|
||||
|
||||
// +++ 新增:保存配置到后端 +++
|
||||
async function saveSequenceToBackend() {
|
||||
const apiUrl = '/api/v1/settings/focus-switcher-sequence'; // +++ 定义 API URL +++
|
||||
console.log(`[FocusSwitcherStore] Attempting to save sequence to backend via PUT: ${apiUrl}`); // +++ 更新日志 +++
|
||||
try {
|
||||
const sequenceToSave = configuredSequence.value;
|
||||
console.log('[FocusSwitcherStore] Sequence data to save:', JSON.stringify(sequenceToSave)); // +++ 添加日志 +++
|
||||
// 注意:需要根据实际项目配置调整 API 路径和认证处理
|
||||
const response = await fetch(apiUrl, { // +++ 使用变量 +++
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
// 如果需要认证,添加 Authorization header
|
||||
// 'Authorization': `Bearer ${your_token}`
|
||||
},
|
||||
body: JSON.stringify({ sequence: sequenceToSave }),
|
||||
});
|
||||
console.log(`[FocusSwitcherStore] Received response from PUT ${apiUrl}. Status: ${response.status}`); // +++ 添加日志 +++
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({})); // 尝试解析错误体
|
||||
console.error(`[FocusSwitcherStore] Save failed. Status: ${response.status}, Error data:`, errorData); // +++ 添加日志 +++
|
||||
throw new Error(`HTTP error! status: ${response.status}, message: ${errorData.message || 'Unknown error'}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log('[FocusSwitcherStore] Configuration successfully saved to backend. Response message:', result.message); // +++ 更新日志 +++
|
||||
} catch (error) {
|
||||
console.error(`[FocusSwitcherStore] Failed to save sequence to backend (${apiUrl}):`, error); // +++ 更新日志 +++
|
||||
// 可以在这里触发 UI 通知用户保存失败
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function triggerTerminalSearchActivation() {
|
||||
activateTerminalSearchTrigger.value++;
|
||||
console.log('[FocusSwitcherStore] Triggering Terminal search activation.');
|
||||
}
|
||||
|
||||
// +++ 新增:触发文件管理器搜索激活的 Action +++
|
||||
function triggerFileManagerSearchActivation() {
|
||||
activateFileManagerSearchTrigger.value++; // 简单地增加计数器来触发监听
|
||||
activateFileManagerSearchTrigger.value++;
|
||||
console.log('[FocusSwitcherStore] Triggering FileManager search activation.');
|
||||
}
|
||||
|
||||
// 控制配置器显示/隐藏
|
||||
function toggleConfigurator(visible?: boolean) {
|
||||
isConfiguratorVisible.value = visible === undefined ? !isConfiguratorVisible.value : visible;
|
||||
console.log(`[FocusSwitcherStore] Configurator visibility set to: ${isConfiguratorVisible.value}`);
|
||||
}
|
||||
|
||||
// 从 localStorage 加载配置
|
||||
// --- 移除旧的 loadConfiguration ---
|
||||
/*
|
||||
function loadConfiguration() {
|
||||
console.log('[FocusSwitcherStore] Attempting to load configuration...'); // +++ Log: Start loading +++
|
||||
const savedSequence = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
console.log(`[FocusSwitcherStore] Raw data from localStorage ('${LOCAL_STORAGE_KEY}'):`, savedSequence); // +++ Log: Raw data +++
|
||||
if (savedSequence) {
|
||||
try {
|
||||
const parsedSequence = JSON.parse(savedSequence);
|
||||
console.log('[FocusSwitcherStore] Parsed sequence from localStorage:', parsedSequence); // +++ Log: Parsed data +++
|
||||
// 验证加载的 ID 是否仍然存在于 availableInputs 中
|
||||
const availableIds = new Set(availableInputs.value.map(input => input.id)); // +++ Get available IDs +++
|
||||
const filteredSequence = parsedSequence.filter((id: string) => { // +++ Filter and log +++
|
||||
const isValid = availableIds.has(id);
|
||||
if (!isValid) {
|
||||
console.warn(`[FocusSwitcherStore] Filtered out invalid ID during load: ${id}`);
|
||||
}
|
||||
return isValid;
|
||||
});
|
||||
configuredSequence.value = filteredSequence;
|
||||
console.log('[FocusSwitcherStore] Final loaded & filtered configuration:', configuredSequence.value); // +++ Log: Final loaded value +++
|
||||
} catch (error) {
|
||||
console.error('[FocusSwitcherStore] Failed to parse saved configuration:', error);
|
||||
configuredSequence.value = []; // 解析失败则重置
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY); // 移除损坏的数据
|
||||
}
|
||||
} else {
|
||||
// 如果没有保存的配置,可以设置一个默认顺序
|
||||
// configuredSequence.value = ['commandInput', 'terminalSearch']; // 例如
|
||||
configuredSequence.value = []; // 或者默认为空
|
||||
console.log('[FocusSwitcherStore] No saved configuration found, using default (empty).');
|
||||
}
|
||||
// ... localStorage logic ...
|
||||
}
|
||||
*/
|
||||
|
||||
// 保存配置到 localStorage
|
||||
// --- 移除旧的 saveConfiguration ---
|
||||
/*
|
||||
function saveConfiguration() {
|
||||
try {
|
||||
const sequenceToSave = configuredSequence.value; // +++ Get value to save +++
|
||||
const jsonStringToSave = JSON.stringify(sequenceToSave); // +++ Stringify +++
|
||||
console.log(`[FocusSwitcherStore] Attempting to save sequence to localStorage ('${LOCAL_STORAGE_KEY}'):`, sequenceToSave); // +++ Log: Value being saved +++
|
||||
console.log(`[FocusSwitcherStore] JSON string being saved:`, jsonStringToSave); // +++ Log: String being saved +++
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, jsonStringToSave);
|
||||
console.log('[FocusSwitcherStore] Configuration successfully saved.'); // +++ Log: Success +++
|
||||
} catch (error) {
|
||||
console.error('[FocusSwitcherStore] Failed to save configuration:', error);
|
||||
}
|
||||
// ... localStorage logic ...
|
||||
}
|
||||
*/
|
||||
|
||||
// 更新切换顺序
|
||||
// 更新切换顺序 (现在也触发保存到后端)
|
||||
function updateSequence(newSequence: string[]) {
|
||||
console.log('[FocusSwitcherStore] updateSequence called with:', newSequence); // +++ Log: Action called +++
|
||||
// 确保新序列中的 ID 都是有效的
|
||||
const availableIds = new Set(availableInputs.value.map(input => input.id)); // +++ Get available IDs +++
|
||||
const filteredSequence = newSequence.filter(id => availableIds.has(id)); // +++ Filter +++
|
||||
console.log('[FocusSwitcherStore] updateSequence called with:', JSON.stringify(newSequence)); // +++ 更新日志 +++
|
||||
const availableIds = new Set(availableInputs.value.map(input => input.id));
|
||||
const filteredSequence = newSequence.filter(id => availableIds.has(id));
|
||||
configuredSequence.value = filteredSequence;
|
||||
console.log('[FocusSwitcherStore] configuredSequence updated to:', configuredSequence.value); // +++ Log: State updated +++
|
||||
// 可以在这里直接保存,或者让用户点击保存按钮再调用 saveConfiguration
|
||||
// saveConfiguration(); // 取决于设计
|
||||
console.log('[FocusSwitcherStore] configuredSequence updated locally to:', JSON.stringify(configuredSequence.value)); // +++ 更新日志 +++
|
||||
// 更新后立即保存到后端
|
||||
saveSequenceToBackend();
|
||||
}
|
||||
|
||||
// --- Getters ---
|
||||
// 获取已配置的输入框完整信息 (按顺序)
|
||||
const getConfiguredInputs = computed((): FocusableInput[] => {
|
||||
return configuredSequence.value
|
||||
.map(id => availableInputs.value.find(input => input.id === id))
|
||||
.filter((input): input is FocusableInput => input !== undefined); // 类型守卫确保过滤掉 undefined
|
||||
.filter((input): input is FocusableInput => input !== undefined);
|
||||
});
|
||||
|
||||
// 获取在配置器中可用的输入框 (未被配置的)
|
||||
const getAvailableInputsForConfigurator = computed((): FocusableInput[] => {
|
||||
const configuredIds = new Set(configuredSequence.value);
|
||||
return availableInputs.value.filter(input => !configuredIds.has(input.id));
|
||||
});
|
||||
|
||||
// 获取下一个要聚焦的输入框 ID (用于实际切换逻辑)
|
||||
function getNextFocusTargetId(currentFocusedId: string | null): string | null {
|
||||
if (configuredSequence.value.length === 0) {
|
||||
return null; // 没有配置顺序
|
||||
return null;
|
||||
}
|
||||
if (currentFocusedId === null) {
|
||||
// 如果当前没有焦点在配置列表内,返回第一个
|
||||
return configuredSequence.value[0];
|
||||
}
|
||||
|
||||
const currentIndex = configuredSequence.value.indexOf(currentFocusedId);
|
||||
if (currentIndex === -1) {
|
||||
// 如果当前焦点不在配置列表内,返回第一个
|
||||
return configuredSequence.value[0];
|
||||
}
|
||||
|
||||
// 返回下一个,如果到末尾则循环回第一个
|
||||
const nextIndex = (currentIndex + 1) % configuredSequence.value.length;
|
||||
return configuredSequence.value[nextIndex];
|
||||
}
|
||||
|
||||
|
||||
// --- Initialization ---
|
||||
// Store 创建时自动加载配置 (使用 nextTick 确保响应式系统就绪)
|
||||
// --- import { nextTick } from 'vue'; // --- 移除这里的导入 ---
|
||||
// Store 创建时自动从后端加载配置
|
||||
console.log('[FocusSwitcherStore] Initializing store and scheduling loadSequenceFromBackend...'); // +++ 添加日志 +++
|
||||
nextTick(() => {
|
||||
loadConfiguration();
|
||||
console.log('[FocusSwitcherStore] nextTick triggered, calling loadSequenceFromBackend.'); // +++ 添加日志 +++
|
||||
loadSequenceFromBackend(); // +++ 调用新的加载函数 +++
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -174,13 +205,13 @@ export const useFocusSwitcherStore = defineStore('focusSwitcher', () => {
|
||||
configuredSequence,
|
||||
isConfiguratorVisible,
|
||||
activateFileManagerSearchTrigger,
|
||||
activateTerminalSearchTrigger, // +++ 导出终端搜索触发器状态 +++
|
||||
activateTerminalSearchTrigger,
|
||||
// Actions
|
||||
toggleConfigurator,
|
||||
triggerFileManagerSearchActivation,
|
||||
triggerTerminalSearchActivation, // +++ 确保导出终端搜索触发器 Action +++
|
||||
loadConfiguration,
|
||||
saveConfiguration,
|
||||
triggerTerminalSearchActivation,
|
||||
loadSequenceFromBackend, // +++ 导出新的加载函数 +++
|
||||
saveSequenceToBackend, // +++ 导出新的保存函数 +++
|
||||
updateSequence,
|
||||
// Getters
|
||||
getConfiguredInputs,
|
||||
|
||||
Reference in New Issue
Block a user