🚧 Refactor backup service
This commit is contained in:
@@ -19,37 +19,45 @@ export class Document {
|
||||
"id"?: number;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
* UUID for cross-device sync (UUIDv7)
|
||||
*/
|
||||
"uuid": string;
|
||||
|
||||
/**
|
||||
* creation time
|
||||
*/
|
||||
"created_at": string;
|
||||
|
||||
/**
|
||||
* 最后更新时间
|
||||
* update time
|
||||
*/
|
||||
"updated_at": string;
|
||||
|
||||
/**
|
||||
* 删除时间,NULL表示未删除
|
||||
* deleted at
|
||||
*/
|
||||
"deleted_at"?: string | null;
|
||||
|
||||
/**
|
||||
* 文档标题
|
||||
* document title
|
||||
*/
|
||||
"title": string;
|
||||
|
||||
/**
|
||||
* 文档内容
|
||||
* document content
|
||||
*/
|
||||
"content": string;
|
||||
|
||||
/**
|
||||
* 是否锁定
|
||||
* document locked status
|
||||
*/
|
||||
"locked": boolean;
|
||||
|
||||
/** Creates a new Document instance. */
|
||||
constructor($$source: Partial<Document> = {}) {
|
||||
if (!("uuid" in $$source)) {
|
||||
this["uuid"] = "";
|
||||
}
|
||||
if (!("created_at" in $$source)) {
|
||||
this["created_at"] = "";
|
||||
}
|
||||
@@ -88,37 +96,45 @@ export class Extension {
|
||||
"id"?: number;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
* UUID for cross-device sync (UUIDv7)
|
||||
*/
|
||||
"uuid": string;
|
||||
|
||||
/**
|
||||
* creation time
|
||||
*/
|
||||
"created_at": string;
|
||||
|
||||
/**
|
||||
* 最后更新时间
|
||||
* update time
|
||||
*/
|
||||
"updated_at": string;
|
||||
|
||||
/**
|
||||
* 删除时间,NULL表示未删除
|
||||
* deleted at
|
||||
*/
|
||||
"deleted_at"?: string | null;
|
||||
|
||||
/**
|
||||
* 扩展标识符
|
||||
* extension key
|
||||
*/
|
||||
"key": string;
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
* extension enabled or not
|
||||
*/
|
||||
"enabled": boolean;
|
||||
|
||||
/**
|
||||
* 扩展配置
|
||||
* extension config
|
||||
*/
|
||||
"config": { [_: string]: any };
|
||||
|
||||
/** Creates a new Extension instance. */
|
||||
constructor($$source: Partial<Extension> = {}) {
|
||||
if (!("uuid" in $$source)) {
|
||||
this["uuid"] = "";
|
||||
}
|
||||
if (!("created_at" in $$source)) {
|
||||
this["created_at"] = "";
|
||||
}
|
||||
@@ -142,10 +158,10 @@ export class Extension {
|
||||
* Creates a new Extension instance from a string or object.
|
||||
*/
|
||||
static createFrom($$source: any = {}): Extension {
|
||||
const $$createField6_0 = $$createType0;
|
||||
const $$createField7_0 = $$createType0;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("config" in $$parsedSource) {
|
||||
$$parsedSource["config"] = $$createField6_0($$parsedSource["config"]);
|
||||
$$parsedSource["config"] = $$createField7_0($$parsedSource["config"]);
|
||||
}
|
||||
return new Extension($$parsedSource as Partial<Extension>);
|
||||
}
|
||||
@@ -161,42 +177,50 @@ export class KeyBinding {
|
||||
"id"?: number;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
* UUID for cross-device sync (UUIDv7)
|
||||
*/
|
||||
"uuid": string;
|
||||
|
||||
/**
|
||||
* creation time
|
||||
*/
|
||||
"created_at": string;
|
||||
|
||||
/**
|
||||
* 最后更新时间
|
||||
* update time
|
||||
*/
|
||||
"updated_at": string;
|
||||
|
||||
/**
|
||||
* 删除时间,NULL表示未删除
|
||||
* deleted at
|
||||
*/
|
||||
"deleted_at"?: string | null;
|
||||
|
||||
/**
|
||||
* 快捷键标识符
|
||||
* key binding key
|
||||
*/
|
||||
"key": string;
|
||||
|
||||
/**
|
||||
* 快捷键命令
|
||||
* key binding command
|
||||
*/
|
||||
"command": string;
|
||||
|
||||
/**
|
||||
* 所属扩展标识符
|
||||
* key binding extension
|
||||
*/
|
||||
"extension"?: string;
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
* key binding enabled
|
||||
*/
|
||||
"enabled": boolean;
|
||||
|
||||
/** Creates a new KeyBinding instance. */
|
||||
constructor($$source: Partial<KeyBinding> = {}) {
|
||||
if (!("uuid" in $$source)) {
|
||||
this["uuid"] = "";
|
||||
}
|
||||
if (!("created_at" in $$source)) {
|
||||
this["created_at"] = "";
|
||||
}
|
||||
@@ -235,37 +259,45 @@ export class Theme {
|
||||
"id"?: number;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
* UUID for cross-device sync (UUIDv7)
|
||||
*/
|
||||
"uuid": string;
|
||||
|
||||
/**
|
||||
* creation time
|
||||
*/
|
||||
"created_at": string;
|
||||
|
||||
/**
|
||||
* 最后更新时间
|
||||
* update time
|
||||
*/
|
||||
"updated_at": string;
|
||||
|
||||
/**
|
||||
* 删除时间,NULL表示未删除
|
||||
* deleted at
|
||||
*/
|
||||
"deleted_at"?: string | null;
|
||||
|
||||
/**
|
||||
* 主题标识符
|
||||
* theme key
|
||||
*/
|
||||
"key": string;
|
||||
|
||||
/**
|
||||
* 主题类型
|
||||
* theme type
|
||||
*/
|
||||
"type": theme$0.Type;
|
||||
|
||||
/**
|
||||
* 主题颜色配置
|
||||
* theme colors
|
||||
*/
|
||||
"colors": { [_: string]: any };
|
||||
|
||||
/** Creates a new Theme instance. */
|
||||
constructor($$source: Partial<Theme> = {}) {
|
||||
if (!("uuid" in $$source)) {
|
||||
this["uuid"] = "";
|
||||
}
|
||||
if (!("created_at" in $$source)) {
|
||||
this["created_at"] = "";
|
||||
}
|
||||
@@ -289,10 +321,10 @@ export class Theme {
|
||||
* Creates a new Theme instance from a string or object.
|
||||
*/
|
||||
static createFrom($$source: any = {}): Theme {
|
||||
const $$createField6_0 = $$createType0;
|
||||
const $$createField7_0 = $$createType0;
|
||||
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||
if ("colors" in $$parsedSource) {
|
||||
$$parsedSource["colors"] = $$createField6_0($$parsedSource["colors"]);
|
||||
$$parsedSource["colors"] = $$createField7_0($$parsedSource["colors"]);
|
||||
}
|
||||
return new Theme($$parsedSource as Partial<Theme>);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
/**
|
||||
* BackupService 提供基于Git的备份功能
|
||||
* BackupService 提供基于Git的备份同步功能
|
||||
* @module
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,7 @@ import * as application$0 from "../../../github.com/wailsapp/wails/v3/pkg/applic
|
||||
import * as models$0 from "../models/models.js";
|
||||
|
||||
/**
|
||||
* HandleConfigChange 处理备份配置变更
|
||||
* HandleConfigChange 处理配置变更
|
||||
*/
|
||||
export function HandleConfigChange(config: models$0.GitBackupConfig | null): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(395287784, config) as any;
|
||||
@@ -34,15 +34,7 @@ export function Initialize(): Promise<void> & { cancel(): void } {
|
||||
}
|
||||
|
||||
/**
|
||||
* PushToRemote 推送本地更改到远程仓库
|
||||
*/
|
||||
export function PushToRemote(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(262644139) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinitialize 重新初始化备份服务,用于响应配置变更
|
||||
* Reinitialize 重新初始化
|
||||
*/
|
||||
export function Reinitialize(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(301562543) as any;
|
||||
@@ -50,7 +42,7 @@ export function Reinitialize(): Promise<void> & { cancel(): void } {
|
||||
}
|
||||
|
||||
/**
|
||||
* ServiceShutdown 服务关闭时的清理工作
|
||||
* ServiceShutdown 服务关闭
|
||||
*/
|
||||
export function ServiceShutdown(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(422131801) as any;
|
||||
@@ -63,7 +55,7 @@ export function ServiceStartup(options: application$0.ServiceOptions): Promise<v
|
||||
}
|
||||
|
||||
/**
|
||||
* StartAutoBackup 启动自动备份定时器
|
||||
* StartAutoBackup 启动自动备份
|
||||
*/
|
||||
export function StartAutoBackup(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3035755449) as any;
|
||||
@@ -77,3 +69,11 @@ export function StopAutoBackup(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(2641894021) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync 执行完整的同步流程:导出 -> commit -> pull -> 解决冲突 -> push -> 导入
|
||||
*/
|
||||
export function Sync(): Promise<void> & { cancel(): void } {
|
||||
let $resultPromise = $Call.ByID(3420383211) as any;
|
||||
return $resultPromise;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export default {
|
||||
keybindings: {
|
||||
headers: {
|
||||
shortcut: 'Shortcut',
|
||||
category: 'Category',
|
||||
extension: 'Extension',
|
||||
description: 'Description'
|
||||
},
|
||||
commands: {
|
||||
@@ -227,14 +227,10 @@ export default {
|
||||
sshKeyPassphrase: 'SSH Key Passphrase',
|
||||
sshKeyPassphrasePlaceholder: 'Enter SSH key passphrase',
|
||||
backupOperations: 'Backup Operations',
|
||||
pushToRemote: 'Push to Remote',
|
||||
pushing: 'Pushing...',
|
||||
syncToRemote: 'Sync to Remote',
|
||||
syncing: 'Syncing...',
|
||||
actions: {
|
||||
push: 'Push',
|
||||
},
|
||||
status: {
|
||||
success: 'Success',
|
||||
failed: 'Failed'
|
||||
sync: 'Sync',
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -46,7 +46,7 @@ export default {
|
||||
keybindings: {
|
||||
headers: {
|
||||
shortcut: '快捷键',
|
||||
category: '分类',
|
||||
extension: '扩展',
|
||||
description: '描述'
|
||||
},
|
||||
commands: {
|
||||
@@ -229,14 +229,10 @@ export default {
|
||||
sshKeyPassphrase: 'SSH密钥密码',
|
||||
sshKeyPassphrasePlaceholder: '请输入SSH密钥密码',
|
||||
backupOperations: '备份操作',
|
||||
pushToRemote: '推送到远程',
|
||||
pushing: '推送中...',
|
||||
syncToRemote: '同步到远程',
|
||||
syncing: '同步中...',
|
||||
actions: {
|
||||
push: '推送',
|
||||
},
|
||||
status: {
|
||||
success: '成功',
|
||||
failed: '失败'
|
||||
sync: '同步',
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,49 +1,31 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, onScopeDispose } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { BackupService } from '@/../bindings/voidraft/internal/services';
|
||||
import { useConfigStore } from '@/stores/configStore';
|
||||
import { createTimerManager } from '@/common/utils/timerUtils';
|
||||
|
||||
export const useBackupStore = defineStore('backup', () => {
|
||||
const isPushing = ref(false);
|
||||
const message = ref<string | null>(null);
|
||||
const isError = ref(false);
|
||||
|
||||
const timer = createTimerManager();
|
||||
const configStore = useConfigStore();
|
||||
const isSyncing = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
onScopeDispose(() => timer.clear());
|
||||
|
||||
const pushToRemote = async () => {
|
||||
const isConfigured = Boolean(configStore.config.backup.repo_url?.trim());
|
||||
|
||||
if (isPushing.value || !isConfigured) {
|
||||
const sync = async (): Promise<void> => {
|
||||
if (isSyncing.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
isSyncing.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
isPushing.value = true;
|
||||
message.value = null;
|
||||
timer.clear();
|
||||
|
||||
await BackupService.PushToRemote();
|
||||
|
||||
isError.value = false;
|
||||
message.value = 'push successful';
|
||||
timer.set(() => { message.value = null; }, 3000);
|
||||
} catch (error) {
|
||||
isError.value = true;
|
||||
message.value = error instanceof Error ? error.message : 'backup operation failed';
|
||||
timer.set(() => { message.value = null; }, 5000);
|
||||
await BackupService.Sync();
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : String(e);
|
||||
} finally {
|
||||
isPushing.value = false;
|
||||
isSyncing.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
isPushing,
|
||||
message,
|
||||
isError,
|
||||
pushToRemote
|
||||
isSyncing,
|
||||
error,
|
||||
sync
|
||||
};
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Extension } from '@codemirror/state';
|
||||
import { useKeybindingStore } from '@/stores/keybindingStore';
|
||||
import { useExtensionStore } from '@/stores/extensionStore';
|
||||
import { Manager } from './manager';
|
||||
|
||||
/**
|
||||
@@ -8,24 +7,13 @@ import { Manager } from './manager';
|
||||
*/
|
||||
export const createDynamicKeymapExtension = async (): Promise<Extension> => {
|
||||
const keybindingStore = useKeybindingStore();
|
||||
const extensionStore = useExtensionStore();
|
||||
|
||||
// 确保快捷键配置已加载
|
||||
if (keybindingStore.keyBindings.length === 0) {
|
||||
await keybindingStore.loadKeyBindings();
|
||||
}
|
||||
|
||||
// 确保扩展配置已加载
|
||||
if (extensionStore.extensions.length === 0) {
|
||||
await extensionStore.loadExtensions();
|
||||
}
|
||||
|
||||
// 获取启用的扩展key列表
|
||||
const enabledExtensionKeys = extensionStore.enabledExtensions
|
||||
.map(ext => ext.key)
|
||||
.filter((key): key is string => key !== undefined);
|
||||
|
||||
return Manager.createKeymapExtension(keybindingStore.keyBindings, enabledExtensionKeys);
|
||||
return Manager.createKeymapExtension(keybindingStore.keyBindings);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -34,14 +22,7 @@ export const createDynamicKeymapExtension = async (): Promise<Extension> => {
|
||||
*/
|
||||
export const updateKeymapExtension = (view: any): void => {
|
||||
const keybindingStore = useKeybindingStore();
|
||||
const extensionStore = useExtensionStore();
|
||||
|
||||
// 获取启用的扩展key列表
|
||||
const enabledExtensionKeys = extensionStore.enabledExtensions
|
||||
.map(ext => ext.key)
|
||||
.filter((key): key is string => key !== undefined);
|
||||
|
||||
Manager.updateKeymap(view, keybindingStore.keyBindings, enabledExtensionKeys);
|
||||
Manager.updateKeymap(view, keybindingStore.keyBindings);
|
||||
};
|
||||
|
||||
// 导出相关模块
|
||||
|
||||
@@ -14,10 +14,9 @@ export class Manager {
|
||||
/**
|
||||
* 将后端快捷键配置转换为CodeMirror快捷键绑定
|
||||
* @param keyBindings 后端快捷键配置列表
|
||||
* @param enabledExtensions 启用的扩展key列表,如果不提供则使用所有启用的快捷键
|
||||
* @returns 转换结果
|
||||
*/
|
||||
static convertToKeyBindings(keyBindings: KeyBindingConfig[], enabledExtensions?: string[]): KeymapResult {
|
||||
static convertToKeyBindings(keyBindings: KeyBindingConfig[]): KeymapResult {
|
||||
const result: KeyBinding[] = [];
|
||||
|
||||
for (const binding of keyBindings) {
|
||||
@@ -26,11 +25,6 @@ export class Manager {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果提供了扩展列表,则只处理启用扩展的快捷键
|
||||
if (enabledExtensions && binding.extension && !enabledExtensions.includes(binding.extension)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查命令是否已注册(使用 key 字段作为命令标识符)
|
||||
if (!binding.key || !isCommandRegistered(binding.key)) {
|
||||
continue;
|
||||
@@ -59,13 +53,10 @@ export class Manager {
|
||||
/**
|
||||
* 创建CodeMirror快捷键扩展
|
||||
* @param keyBindings 后端快捷键配置列表
|
||||
* @param enabledExtensions 启用的扩展key列表
|
||||
* @returns CodeMirror扩展
|
||||
*/
|
||||
static createKeymapExtension(keyBindings: KeyBindingConfig[], enabledExtensions?: string[]): Extension {
|
||||
const {keyBindings: cmKeyBindings} =
|
||||
this.convertToKeyBindings(keyBindings, enabledExtensions);
|
||||
|
||||
static createKeymapExtension(keyBindings: KeyBindingConfig[]): Extension {
|
||||
const {keyBindings: cmKeyBindings} = this.convertToKeyBindings(keyBindings);
|
||||
return this.compartment.of(keymap.of(cmKeyBindings));
|
||||
}
|
||||
|
||||
@@ -73,12 +64,9 @@ export class Manager {
|
||||
* 动态更新快捷键扩展
|
||||
* @param view 编辑器视图
|
||||
* @param keyBindings 后端快捷键配置列表
|
||||
* @param enabledExtensions 启用的扩展key列表
|
||||
*/
|
||||
static updateKeymap(view: any, keyBindings: KeyBindingConfig[], enabledExtensions: string[]): void {
|
||||
const {keyBindings: cmKeyBindings} =
|
||||
this.convertToKeyBindings(keyBindings, enabledExtensions);
|
||||
|
||||
static updateKeymap(view: any, keyBindings: KeyBindingConfig[]): void {
|
||||
const {keyBindings: cmKeyBindings} = this.convertToKeyBindings(keyBindings);
|
||||
view.dispatch({
|
||||
effects: this.compartment.reconfigure(keymap.of(cmKeyBindings))
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import {useConfigStore} from '@/stores/configStore';
|
||||
import {useBackupStore} from '@/stores/backupStore';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {computed} from 'vue';
|
||||
import {computed, ref, watch, onUnmounted} from 'vue';
|
||||
import SettingSection from '../components/SettingSection.vue';
|
||||
import SettingItem from '../components/SettingItem.vue';
|
||||
import ToggleSwitch from '../components/ToggleSwitch.vue';
|
||||
@@ -13,6 +13,37 @@ const {t} = useI18n();
|
||||
const configStore = useConfigStore();
|
||||
const backupStore = useBackupStore();
|
||||
|
||||
// 消息显示状态
|
||||
const message = ref<string | null>(null);
|
||||
const isError = ref(false);
|
||||
let messageTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
const clearMessage = () => {
|
||||
if (messageTimer) {
|
||||
clearTimeout(messageTimer);
|
||||
messageTimer = null;
|
||||
}
|
||||
message.value = null;
|
||||
};
|
||||
|
||||
// 监听同步完成,显示消息并自动消失
|
||||
watch(() => backupStore.isSyncing, (syncing, wasSyncing) => {
|
||||
if (wasSyncing && !syncing) {
|
||||
clearMessage();
|
||||
if (backupStore.error) {
|
||||
message.value = backupStore.error;
|
||||
isError.value = true;
|
||||
messageTimer = setTimeout(clearMessage, 5000);
|
||||
} else {
|
||||
message.value = 'Sync successful';
|
||||
isError.value = false;
|
||||
messageTimer = setTimeout(clearMessage, 3000);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(clearMessage);
|
||||
|
||||
const authMethodOptions = computed(() => [
|
||||
{value: AuthMethod.Token, label: t('settings.backup.authMethods.token')},
|
||||
{value: AuthMethod.SSHKey, label: t('settings.backup.authMethods.sshKey')},
|
||||
@@ -172,18 +203,18 @@ const selectSshKeyFile = async () => {
|
||||
<!-- 备份操作 -->
|
||||
<SettingSection :title="t('settings.backup.backupOperations')">
|
||||
<SettingItem
|
||||
:title="t('settings.backup.pushToRemote')"
|
||||
:description="backupStore.message || undefined"
|
||||
:descriptionType="backupStore.message ? (backupStore.isError ? 'error' : 'success') : 'default'"
|
||||
:title="t('settings.backup.syncToRemote')"
|
||||
:description="message || undefined"
|
||||
:descriptionType="message ? (isError ? 'error' : 'success') : 'default'"
|
||||
>
|
||||
<button
|
||||
class="push-button"
|
||||
@click="backupStore.pushToRemote"
|
||||
:disabled="!configStore.config.backup.enabled || !configStore.config.backup.repo_url || backupStore.isPushing"
|
||||
:class="{ 'backing-up': backupStore.isPushing }"
|
||||
class="sync-button"
|
||||
@click="backupStore.sync"
|
||||
:disabled="!configStore.config.backup.enabled || !configStore.config.backup.repo_url || backupStore.isSyncing"
|
||||
:class="{ 'syncing': backupStore.isSyncing }"
|
||||
>
|
||||
<span v-if="backupStore.isPushing" class="loading-spinner"></span>
|
||||
{{ backupStore.isPushing ? t('settings.backup.pushing') : t('settings.backup.actions.push') }}
|
||||
<span v-if="backupStore.isSyncing" class="loading-spinner"></span>
|
||||
{{ backupStore.isSyncing ? t('settings.backup.syncing') : t('settings.backup.actions.sync') }}
|
||||
</button>
|
||||
</SettingItem>
|
||||
</SettingSection>
|
||||
@@ -257,7 +288,7 @@ const selectSshKeyFile = async () => {
|
||||
}
|
||||
|
||||
// 按钮样式
|
||||
.push-button {
|
||||
.sync-button {
|
||||
padding: 8px 16px;
|
||||
background-color: var(--settings-input-bg);
|
||||
border: 1px solid var(--settings-input-border);
|
||||
@@ -294,7 +325,7 @@ const selectSshKeyFile = async () => {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
&.backing-up {
|
||||
&.syncing {
|
||||
background-color: #2196f3;
|
||||
border-color: #2196f3;
|
||||
color: white;
|
||||
|
||||
@@ -3,33 +3,27 @@ import { useI18n } from 'vue-i18n';
|
||||
import { onMounted, computed } from 'vue';
|
||||
import SettingSection from '../components/SettingSection.vue';
|
||||
import { useKeybindingStore } from '@/stores/keybindingStore';
|
||||
import { useExtensionStore } from '@/stores/extensionStore';
|
||||
import { useSystemStore } from '@/stores/systemStore';
|
||||
import { getCommandDescription } from '@/views/editor/keymap/commands';
|
||||
import { KeyBindingKey } from '@/../bindings/voidraft/internal/models/models';
|
||||
|
||||
const { t } = useI18n();
|
||||
const keybindingStore = useKeybindingStore();
|
||||
const extensionStore = useExtensionStore();
|
||||
const systemStore = useSystemStore();
|
||||
|
||||
// 加载数据
|
||||
onMounted(async () => {
|
||||
await keybindingStore.loadKeyBindings();
|
||||
await extensionStore.loadExtensions();
|
||||
});
|
||||
|
||||
// 从store中获取快捷键数据并转换为显示格式
|
||||
const keyBindings = computed(() => {
|
||||
// 只显示启用扩展的快捷键
|
||||
const enabledExtensionIds = new Set(extensionStore.enabledExtensionIds);
|
||||
|
||||
return keybindingStore.keyBindings
|
||||
.filter(kb => kb.enabled && (!kb.extension || enabledExtensionIds.has(kb.extension)))
|
||||
.filter(kb => kb.enabled)
|
||||
.map(kb => ({
|
||||
id: kb.key,
|
||||
keys: parseKeyBinding(kb.command || '', kb.key),
|
||||
category: kb.extension || '',
|
||||
key: kb.key,
|
||||
command: parseKeyBinding(kb.command || '', kb.key),
|
||||
extension: kb.extension || '',
|
||||
description: kb.key ? (getCommandDescription(kb.key) || kb.key) : ''
|
||||
}));
|
||||
});
|
||||
@@ -204,25 +198,25 @@ const parseKeyBinding = (keyStr: string, keyBindingKey?: string): string[] => {
|
||||
<div class="key-bindings-container">
|
||||
<div class="key-bindings-header">
|
||||
<div class="keybinding-col">{{ t('keybindings.headers.shortcut') }}</div>
|
||||
<div class="category-col">{{ t('keybindings.headers.category') }}</div>
|
||||
<div class="extension-col">{{ t('keybindings.headers.extension') }}</div>
|
||||
<div class="description-col">{{ t('keybindings.headers.description') }}</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="binding in keyBindings"
|
||||
:key="binding.id"
|
||||
:key="binding.key"
|
||||
class="key-binding-row"
|
||||
>
|
||||
<div class="keybinding-col">
|
||||
<span
|
||||
v-for="(key, index) in binding.keys"
|
||||
v-for="(key, index) in binding.command"
|
||||
:key="index"
|
||||
class="key-badge"
|
||||
>
|
||||
{{ key }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="category-col">{{ binding.category }}</div>
|
||||
<div class="extension-col">{{ binding.extension }}</div>
|
||||
<div class="description-col">{{ binding.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -276,7 +270,7 @@ const parseKeyBinding = (keyStr: string, keyBindingKey?: string): string[] => {
|
||||
}
|
||||
}
|
||||
|
||||
.category-col {
|
||||
.extension-col {
|
||||
width: 80px;
|
||||
padding: 0 10px 0 0;
|
||||
font-size: 13px;
|
||||
|
||||
Reference in New Issue
Block a user