64 lines
2.8 KiB
TypeScript
64 lines
2.8 KiB
TypeScript
// VaultService — 统筹库管理:默认库、切换、最近库(FR-V)
|
|
import nodePath from 'node:path';
|
|
import { promises as fs } from 'node:fs';
|
|
import { app, dialog } from 'electron';
|
|
import { DEFAULT_VAULT_NAME } from '@hunter/shared';
|
|
import type { VaultMeta } from '@hunter/shared';
|
|
import { ConfigStore } from './config-store.js';
|
|
import { FileService } from './file-service.js';
|
|
import { SearchService } from './search-service.js';
|
|
|
|
export class VaultService {
|
|
fileService: FileService | null = null;
|
|
searchService: SearchService | null = null;
|
|
private config: ConfigStore;
|
|
|
|
constructor() {
|
|
this.config = new ConfigStore(app.getPath('userData'));
|
|
}
|
|
|
|
// 启动时初始化:确保有当前库(无则创建默认库)
|
|
async init(): Promise<VaultMeta> {
|
|
let meta = await this.config.getVaultMeta();
|
|
if (!meta.currentRoot) {
|
|
const defaultRoot = nodePath.join(app.getPath('userData'), DEFAULT_VAULT_NAME);
|
|
await fs.mkdir(defaultRoot, { recursive: true });
|
|
meta = await this.config.setCurrentRoot(defaultRoot);
|
|
}
|
|
this.fileService = new FileService(meta.currentRoot);
|
|
this.searchService = new SearchService(meta.currentRoot, this.fileService);
|
|
return meta;
|
|
}
|
|
|
|
async getMeta(): Promise<VaultMeta> { return this.config.getVaultMeta(); }
|
|
|
|
// 通过系统对话框选择并切换库(FR-V3)
|
|
async pickAndSwitch(): Promise<VaultMeta | null> {
|
|
const result = await dialog.showOpenDialog({ properties: ['openDirectory'] });
|
|
if (result.canceled || result.filePaths.length === 0) return null;
|
|
return this.switch(result.filePaths[0]);
|
|
}
|
|
|
|
// 仅浏览选择目录路径,不切换(FR-V5 设置页浏览按钮)
|
|
async pickDirectory(): Promise<string | null> {
|
|
const result = await dialog.showOpenDialog({ properties: ['openDirectory'] });
|
|
if (result.canceled || result.filePaths.length === 0) return null;
|
|
return result.filePaths[0];
|
|
}
|
|
|
|
async switch(root: string): Promise<VaultMeta> {
|
|
// 校验是存在的目录
|
|
const stat = await fs.stat(root).catch(() => null);
|
|
if (!stat || !stat.isDirectory()) throw new Error('目标路径不是有效目录: ' + root);
|
|
const meta = await this.config.setCurrentRoot(root);
|
|
this.fileService = new FileService(root);
|
|
this.searchService = new SearchService(root, this.fileService);
|
|
return meta;
|
|
}
|
|
|
|
async setDefaultRoot(root: string): Promise<void> { await this.config.setDefaultRoot(root); }
|
|
getAppearance() { return this.config.getAppearance(); }
|
|
saveAppearance(data: { themeId: string; params: Record<string, unknown>; effect: string; bgImage: string | null }) { return this.config.saveAppearance(data); }
|
|
getKeymaps() { return this.config.getKeymaps(); }
|
|
saveKeymaps(data: { id: string; combo: string }[]) { return this.config.saveKeymaps(data); }
|
|
} |