diff --git a/.gitignore b/.gitignore index 924db5e..efa49ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules/ out/ dist/ +electron-dist/ *.log npm-debug.log* yarn-debug.log* diff --git a/AGENTS.md b/AGENTS.md index 6c8dd4c..2962a84 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,9 +6,10 @@ Fork of [AnotherRedisDesktopManager](https://github.com/qishibo/AnotherRedisDesk ## Stack -- **Shell:** Electron 33 (`src/main/index.ts`) -- **Preload:** `src/preload/index.ts` (contextBridge, typed API) +- **Shell:** Electron 43 (`electron/main/index.ts`) +- **Preload:** `electron/preload/index.ts` (contextBridge, typed API) - **Renderer:** Vue 3 + Pinia + Element Plus + Vue Router (`src/renderer/`) +- **Shared:** `electron/shared/types.ts` (cross-process types) - **Build:** electron-vite + Vite 6 + TypeScript 5 - **Redis client:** ioredis 5 (main process only) - **Persistence:** electron-store + safeStorage (credentials) @@ -17,7 +18,7 @@ Fork of [AnotherRedisDesktopManager](https://github.com/qishibo/AnotherRedisDesk ```bash npm run dev # electron-vite dev (HMR, renderer on :5173) -npm run build # production build → out/ +npm run build # production build → electron-dist/ npm start # preview built app npm run build:unpack # build + electron-builder --dir npm run build:win # build + electron-builder --win @@ -28,18 +29,31 @@ npm run build:linux # build + electron-builder --linux ## Architecture ``` -Electron main (src/main/) +Electron main (electron/main/) ├── index.ts # Window creation, app lifecycle - ├── redis-service.ts # ioredis wrapper (connect, scan, CRUD, stream) + ├── redis/ # Redis service modules + │ ├── index.ts # Unified export + │ ├── connection.ts # connect, disconnect, isClientConnected + │ ├── keys.ts # scan, delete, rename, ttl, batchDelete + │ ├── string.ts # get, set + │ ├── hash.ts # hscan, hset, hdel + │ ├── list.ts # range, push, set, remove + │ ├── set.ts # members, add, remove + │ ├── zset.ts # range, add, remove + │ ├── stream.ts # info, range, add, trim + │ └── server.ts # info, select, ping, slowlog ├── store.ts # electron-store (connections, settings) ├── credential.ts # safeStorage encrypt/decrypt ├── win-state.ts # window position persistence └── ipc-handlers.ts # all IPC channel handlers -Preload (src/preload/) +Preload (electron/preload/) ├── index.ts # contextBridge.exposeInMainWorld └── index.d.ts # ElectronAPI type declarations +Shared (electron/shared/) + └── types.ts # Cross-process type definitions + Renderer (src/renderer/src/) ├── main.ts # Vue 3 bootstrap (Pinia, Element Plus) ├── App.vue # Shell layout (TitleBar + Sidebar + MainArea + StatusBar) diff --git a/electron.vite.config.ts b/electron.vite.config.ts index b8fa1b9..f9be677 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -6,10 +6,10 @@ export default defineConfig({ main: { plugins: [externalizeDepsPlugin()], build: { - outDir: 'out/main', + outDir: 'electron-dist/main', rollupOptions: { input: { - index: resolve(__dirname, 'src/main/index.ts') + index: resolve(__dirname, 'electron/main/index.ts') } } } @@ -17,27 +17,28 @@ export default defineConfig({ preload: { plugins: [externalizeDepsPlugin()], build: { - outDir: 'out/preload', + outDir: 'electron-dist/preload', rollupOptions: { input: { - index: resolve(__dirname, 'src/preload/index.ts') + index: resolve(__dirname, 'electron/preload/index.ts') } } } }, renderer: { - root: 'src/renderer', + root: 'src', build: { - outDir: 'out/renderer', + outDir: resolve(__dirname, 'electron-dist/renderer'), rollupOptions: { input: { - index: resolve(__dirname, 'src/renderer/index.html') + index: resolve(__dirname, 'src/index.html') } } }, resolve: { alias: { - '@renderer': resolve(__dirname, 'src/renderer/src') + '@renderer': resolve(__dirname, 'src'), + '@shared': resolve(__dirname, 'electron/shared') } }, plugins: [vue()], diff --git a/src/main/credential.ts b/electron/main/credential.ts similarity index 100% rename from src/main/credential.ts rename to electron/main/credential.ts diff --git a/src/main/index.ts b/electron/main/index.ts similarity index 100% rename from src/main/index.ts rename to electron/main/index.ts diff --git a/src/main/ipc-handlers.ts b/electron/main/ipc-handlers.ts similarity index 73% rename from src/main/ipc-handlers.ts rename to electron/main/ipc-handlers.ts index 53f82be..84cc8e7 100644 --- a/src/main/ipc-handlers.ts +++ b/electron/main/ipc-handlers.ts @@ -1,8 +1,9 @@ // src/main/ipc-handlers.ts +// IPC 通道处理器 import { ipcMain, BrowserWindow, nativeTheme, dialog } from 'electron' import store, { ConnectionConfig } from './store' import { encrypt, decrypt } from './credential' -import * as redisService from './redis-service' +import * as redis from './redis' export function registerIpcHandlers(): void { // Window @@ -67,152 +68,152 @@ export function registerIpcHandlers(): void { store.set('settings', settings) }) - // Redis + // Redis - 连接 ipcMain.handle('redis:connect', async (_e, id: string, opts) => { try { - console.log(`[IPC] redis:connect id=${id}`, opts) - await redisService.connect(id, opts) + await redis.connect(id, opts) return { success: true } } catch (err: any) { - console.error(`[IPC] redis:connect error:`, err.message) - return { success: false, error: err.message || String(err) } + return { success: false, error: err.message } } }) ipcMain.handle('redis:disconnect', async (_e, id: string) => { - await redisService.disconnect(id) - }) - ipcMain.handle('redis:execute', async (_e, id: string, command: string, args: string[]) => { - return redisService.execute(id, command, args) - }) - ipcMain.handle('redis:getInfo', async (_e, id: string) => { - return redisService.getServerInfo(id) - }) - ipcMain.handle('redis:scanKeys', async (_e, id: string, cursor: string, pattern: string, count: number) => { - return redisService.scanKeys(id, cursor, pattern, count) - }) - ipcMain.handle('redis:getKeyType', async (_e, id: string, key: string) => { - return redisService.getKeyType(id, key) - }) - ipcMain.handle('redis:getKeyTTL', async (_e, id: string, key: string) => { - return redisService.getKeyTTL(id, key) - }) - ipcMain.handle('redis:getString', async (_e, id: string, key: string) => { - return redisService.getStringValue(id, key) - }) - ipcMain.handle('redis:setString', async (_e, id: string, key: string, value: string) => { - await redisService.setStringValue(id, key, value) - }) - ipcMain.handle('redis:deleteKey', async (_e, id: string, key: string) => { - await redisService.deleteKey(id, key) - }) - ipcMain.handle('redis:hashScan', async (_e, id: string, key: string, cursor: string, count: number) => { - return redisService.getHashFields(id, key, cursor, count) - }) - ipcMain.handle('redis:hashSet', async (_e, id: string, key: string, field: string, value: string) => { - await redisService.setHashField(id, key, field, value) - }) - ipcMain.handle('redis:hashDel', async (_e, id: string, key: string, field: string) => { - await redisService.deleteHashField(id, key, field) - }) - ipcMain.handle('redis:setTTL', async (_e, id: string, key: string, ttl: number) => { - await redisService.setKeyTTL(id, key, ttl) - }) - ipcMain.handle('redis:selectDb', async (_e, id: string, db: number) => { - await redisService.selectDb(id, db) - }) - ipcMain.handle('redis:dbSize', async (_e, id: string) => { - return redisService.dbSize(id) - }) - - // List - ipcMain.handle('redis:listRange', async (_e, id: string, key: string, start: number, stop: number) => { - return redisService.listRange(id, key, start, stop) - }) - ipcMain.handle('redis:listLength', async (_e, id: string, key: string) => { - return redisService.listLength(id, key) - }) - ipcMain.handle('redis:listPush', async (_e, id: string, key: string, values: string[]) => { - return redisService.listPush(id, key, ...values) - }) - ipcMain.handle('redis:listSet', async (_e, id: string, key: string, index: number, value: string) => { - await redisService.listSet(id, key, index, value) - }) - ipcMain.handle('redis:listRemove', async (_e, id: string, key: string, count: number, value: string) => { - return redisService.listRemove(id, key, count, value) - }) - - // Set - ipcMain.handle('redis:setMembers', async (_e, id: string, key: string) => { - return redisService.setMembers(id, key) - }) - ipcMain.handle('redis:setSize', async (_e, id: string, key: string) => { - return redisService.setSize(id, key) - }) - ipcMain.handle('redis:setAdd', async (_e, id: string, key: string, members: string[]) => { - return redisService.setAdd(id, key, ...members) - }) - ipcMain.handle('redis:setRemove', async (_e, id: string, key: string, members: string[]) => { - return redisService.setRemove(id, key, ...members) - }) - - // Sorted set - ipcMain.handle('redis:zsetRange', async (_e, id: string, key: string, start: number, stop: number, withScores: boolean) => { - return redisService.zsetRange(id, key, start, stop, withScores) - }) - ipcMain.handle('redis:zsetSize', async (_e, id: string, key: string) => { - return redisService.zsetSize(id, key) - }) - ipcMain.handle('redis:zsetAdd', async (_e, id: string, key: string, score: number, member: string) => { - return redisService.zsetAdd(id, key, score, member) - }) - ipcMain.handle('redis:zsetRemove', async (_e, id: string, key: string, members: string[]) => { - return redisService.zsetRemove(id, key, ...members) - }) - - // Slow log - ipcMain.handle('redis:slowLogGet', async (_e, id: string, count: number) => { - return redisService.slowLogGet(id, count) - }) - ipcMain.handle('redis:slowLogLen', async (_e, id: string) => { - return redisService.slowLogLen(id) - }) - - // Memory - ipcMain.handle('redis:memoryUsage', async (_e, id: string, key: string) => { - return redisService.memoryUsage(id, key) - }) - ipcMain.handle('redis:batchDelete', async (_e, id: string, keys: string[]) => { - return redisService.batchDelete(id, keys) - }) - - // Stream - ipcMain.handle('redis:streamInfo', async (_e, id: string, key: string) => { - return redisService.streamInfo(id, key) - }) - ipcMain.handle('redis:streamRange', async (_e, id: string, key: string, start: string, end: string, count: number) => { - return redisService.streamRange(id, key, start, end, count) - }) - ipcMain.handle('redis:streamAdd', async (_e, id: string, key: string, streamId: string, fieldValues: string[]) => { - return redisService.streamAdd(id, key, streamId, fieldValues) - }) - ipcMain.handle('redis:streamTrim', async (_e, id: string, key: string, maxLen: number) => { - return redisService.streamTrim(id, key, maxLen) - }) - ipcMain.handle('redis:streamDel', async (_e, id: string, key: string, ids: string[]) => { - return redisService.streamDel(id, key, ...ids) - }) - - // Key ops - ipcMain.handle('redis:renameKey', async (_e, id: string, oldKey: string, newKey: string) => { - await redisService.renameKey(id, oldKey, newKey) - }) - ipcMain.handle('redis:existsKey', async (_e, id: string, key: string) => { - return redisService.existsKey(id, key) + await redis.disconnect(id) }) ipcMain.handle('redis:ping', async (_e, id: string) => { - return redisService.ping(id) + return redis.ping(id) }) ipcMain.handle('redis:isConnected', (_e, id: string) => { - return redisService.isConnected(id) + return redis.isClientConnected(id) + }) + + // Redis - 服务器 + ipcMain.handle('redis:execute', async (_e, id: string, command: string, args: string[]) => { + return redis.execute(id, command, args) + }) + ipcMain.handle('redis:getInfo', async (_e, id: string) => { + return redis.getServerInfo(id) + }) + ipcMain.handle('redis:selectDb', async (_e, id: string, db: number) => { + await redis.selectDb(id, db) + }) + ipcMain.handle('redis:dbSize', async (_e, id: string) => { + return redis.dbSize(id) + }) + ipcMain.handle('redis:slowLogGet', async (_e, id: string, count: number) => { + return redis.slowLogGet(id, count) + }) + ipcMain.handle('redis:slowLogLen', async (_e, id: string) => { + return redis.slowLogLen(id) + }) + + // Redis - Key 操作 + ipcMain.handle('redis:scanKeys', async (_e, id: string, cursor: string, pattern: string, count: number) => { + return redis.scanKeys(id, cursor, pattern, count) + }) + ipcMain.handle('redis:getKeyType', async (_e, id: string, key: string) => { + return redis.getKeyType(id, key) + }) + ipcMain.handle('redis:getKeyTTL', async (_e, id: string, key: string) => { + return redis.getKeyTTL(id, key) + }) + ipcMain.handle('redis:setTTL', async (_e, id: string, key: string, ttl: number) => { + await redis.setKeyTTL(id, key, ttl) + }) + ipcMain.handle('redis:deleteKey', async (_e, id: string, key: string) => { + await redis.deleteKey(id, key) + }) + ipcMain.handle('redis:renameKey', async (_e, id: string, oldKey: string, newKey: string) => { + await redis.renameKey(id, oldKey, newKey) + }) + ipcMain.handle('redis:existsKey', async (_e, id: string, key: string) => { + return redis.existsKey(id, key) + }) + ipcMain.handle('redis:batchDelete', async (_e, id: string, keys: string[]) => { + return redis.batchDelete(id, keys) + }) + ipcMain.handle('redis:memoryUsage', async (_e, id: string, key: string) => { + return redis.memoryUsage(id, key) + }) + + // Redis - String + ipcMain.handle('redis:getString', async (_e, id: string, key: string) => { + return redis.getStringValue(id, key) + }) + ipcMain.handle('redis:setString', async (_e, id: string, key: string, value: string) => { + await redis.setStringValue(id, key, value) + }) + + // Redis - Hash + ipcMain.handle('redis:hashScan', async (_e, id: string, key: string, cursor: string, count: number) => { + return redis.getHashFields(id, key, cursor, count) + }) + ipcMain.handle('redis:hashSet', async (_e, id: string, key: string, field: string, value: string) => { + await redis.setHashField(id, key, field, value) + }) + ipcMain.handle('redis:hashDel', async (_e, id: string, key: string, field: string) => { + await redis.deleteHashField(id, key, field) + }) + + // Redis - List + ipcMain.handle('redis:listRange', async (_e, id: string, key: string, start: number, stop: number) => { + return redis.listRange(id, key, start, stop) + }) + ipcMain.handle('redis:listLength', async (_e, id: string, key: string) => { + return redis.listLength(id, key) + }) + ipcMain.handle('redis:listPush', async (_e, id: string, key: string, values: string[]) => { + return redis.listPush(id, key, ...values) + }) + ipcMain.handle('redis:listSet', async (_e, id: string, key: string, index: number, value: string) => { + await redis.listSet(id, key, index, value) + }) + ipcMain.handle('redis:listRemove', async (_e, id: string, key: string, count: number, value: string) => { + return redis.listRemove(id, key, count, value) + }) + + // Redis - Set + ipcMain.handle('redis:setMembers', async (_e, id: string, key: string) => { + return redis.setMembers(id, key) + }) + ipcMain.handle('redis:setSize', async (_e, id: string, key: string) => { + return redis.setSize(id, key) + }) + ipcMain.handle('redis:setAdd', async (_e, id: string, key: string, members: string[]) => { + return redis.setAdd(id, key, ...members) + }) + ipcMain.handle('redis:setRemove', async (_e, id: string, key: string, members: string[]) => { + return redis.setRemove(id, key, ...members) + }) + + // Redis - Zset + ipcMain.handle('redis:zsetRange', async (_e, id: string, key: string, start: number, stop: number, withScores: boolean) => { + return redis.zsetRange(id, key, start, stop, withScores) + }) + ipcMain.handle('redis:zsetSize', async (_e, id: string, key: string) => { + return redis.zsetSize(id, key) + }) + ipcMain.handle('redis:zsetAdd', async (_e, id: string, key: string, score: number, member: string) => { + return redis.zsetAdd(id, key, score, member) + }) + ipcMain.handle('redis:zsetRemove', async (_e, id: string, key: string, members: string[]) => { + return redis.zsetRemove(id, key, ...members) + }) + + // Redis - Stream + ipcMain.handle('redis:streamInfo', async (_e, id: string, key: string) => { + return redis.streamInfo(id, key) + }) + ipcMain.handle('redis:streamRange', async (_e, id: string, key: string, start: string, end: string, count: number) => { + return redis.streamRange(id, key, start, end, count) + }) + ipcMain.handle('redis:streamAdd', async (_e, id: string, key: string, streamId: string, fieldValues: string[]) => { + return redis.streamAdd(id, key, streamId, fieldValues) + }) + ipcMain.handle('redis:streamTrim', async (_e, id: string, key: string, maxLen: number) => { + return redis.streamTrim(id, key, maxLen) + }) + ipcMain.handle('redis:streamDel', async (_e, id: string, key: string, ids: string[]) => { + return redis.streamDel(id, key, ...ids) }) } diff --git a/electron/main/redis/connection.ts b/electron/main/redis/connection.ts new file mode 100644 index 0000000..2962fe8 --- /dev/null +++ b/electron/main/redis/connection.ts @@ -0,0 +1,85 @@ +// src/main/redis/connection.ts +// Redis 连接管理 +import Redis, { RedisOptions } from 'ioredis' +import type { ConnectionOptions } from '../../shared/types' + +export type RedisClient = Redis + +const clients = new Map() + +function buildRedisOptions(opts: ConnectionOptions): RedisOptions { + const options: RedisOptions = { + host: opts.host, + port: opts.port, + username: opts.username || undefined, + password: opts.password || undefined, + stringNumbers: true, + enableReadyCheck: true, + family: 0, + connectTimeout: 10000, + retryStrategy(times: number) { + if (times > 3) return null + return Math.min(times * 200, 1000) + }, + maxRetriesPerRequest: 3, + } + + if (opts.tls) { + options.tls = { + rejectUnauthorized: false, + checkServerIdentity: () => undefined, + } + } + + return options +} + +export function getClient(id: string): RedisClient | undefined { + return clients.get(id) +} + +export function isClientConnected(id: string): boolean { + const client = clients.get(id) + return client?.status === 'ready' +} + +export async function connect(id: string, opts: ConnectionOptions): Promise { + if (clients.has(id)) { + await disconnect(id) + } + + return new Promise((resolve, reject) => { + const redis = new Redis(buildRedisOptions(opts)) + + redis.once('ready', () => { + clients.set(id, redis) + resolve() + }) + + redis.once('error', (err: Error) => { + redis.disconnect() + reject(err) + }) + + setTimeout(() => { + if (!clients.has(id)) { + redis.disconnect() + reject(new Error('连接超时,请检查主机和端口')) + } + }, 12000) + }) +} + +export async function disconnect(id: string): Promise { + const client = clients.get(id) + if (client) { + client.disconnect() + clients.delete(id) + } +} + +export function disconnectAll(): void { + for (const [id] of clients) { + disconnect(id) + } +} diff --git a/electron/main/redis/hash.ts b/electron/main/redis/hash.ts new file mode 100644 index 0000000..9cb9fc3 --- /dev/null +++ b/electron/main/redis/hash.ts @@ -0,0 +1,30 @@ +// src/main/redis/hash.ts +// Hash 操作 +import { getClient } from './connection' + +export async function getHashFields( + id: string, key: string, cursor: string, count: number +): Promise<{ cursor: string; fields: [string, string][] }> { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + const [nextCursor, raw] = await client.hscan(key, cursor, 'COUNT', count) + const fields: [string, string][] = [] + for (let i = 0; i < raw.length; i += 2) { + fields.push([raw[i], raw[i + 1]]) + } + return { cursor: nextCursor, fields } +} + +export async function setHashField( + id: string, key: string, field: string, value: string +): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + await client.hset(key, field, value) +} + +export async function deleteHashField(id: string, key: string, field: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + await client.hdel(key, field) +} diff --git a/electron/main/redis/index.ts b/electron/main/redis/index.ts new file mode 100644 index 0000000..bba73d7 --- /dev/null +++ b/electron/main/redis/index.ts @@ -0,0 +1,11 @@ +// src/main/redis/index.ts +// Redis 服务统一导出 +export * from './connection' +export * from './keys' +export * from './string' +export * from './hash' +export * from './list' +export * from './set' +export * from './zset' +export * from './stream' +export * from './server' diff --git a/electron/main/redis/keys.ts b/electron/main/redis/keys.ts new file mode 100644 index 0000000..dc5f3a2 --- /dev/null +++ b/electron/main/redis/keys.ts @@ -0,0 +1,73 @@ +// src/main/redis/keys.ts +// Key 操作 +import { getClient } from './connection' + +export async function getKeyType(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.type(key) +} + +export async function getKeyTTL(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.ttl(key) +} + +export async function deleteKey(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + await client.del(key) +} + +export async function setKeyTTL(id: string, key: string, ttl: number): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + if (ttl < 0) { + await client.persist(key) + } else { + await client.expire(key, ttl) + } +} + +export async function renameKey(id: string, oldKey: string, newKey: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + await client.rename(oldKey, newKey) +} + +export async function existsKey(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return (await client.exists(key)) === 1 +} + +export async function batchDelete(id: string, keys: string[]): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + if (keys.length === 0) return 0 + const pipeline = client.pipeline() + for (const key of keys) { + pipeline.del(key) + } + const results = await pipeline.exec() + return results?.filter(([err]) => !err).length ?? 0 +} + +export async function memoryUsage(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.memory('USAGE', key) as Promise +} + +export async function scanKeys( + id: string, + cursor: string, + pattern: string, + count: number +): Promise<{ cursor: string; keys: string[] }> { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + const [nextCursor, keys] = await client.scan(cursor, 'MATCH', pattern, 'COUNT', count) + return { cursor: nextCursor, keys } +} diff --git a/electron/main/redis/list.ts b/electron/main/redis/list.ts new file mode 100644 index 0000000..86ab442 --- /dev/null +++ b/electron/main/redis/list.ts @@ -0,0 +1,33 @@ +// src/main/redis/list.ts +// List 操作 +import { getClient } from './connection' + +export async function listRange(id: string, key: string, start: number, stop: number): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.lrange(key, start, stop) +} + +export async function listLength(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.llen(key) +} + +export async function listPush(id: string, key: string, ...values: string[]): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.rpush(key, ...values) +} + +export async function listSet(id: string, key: string, index: number, value: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + await client.lset(key, index, value) +} + +export async function listRemove(id: string, key: string, count: number, value: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.lrem(key, count, value) +} diff --git a/electron/main/redis/server.ts b/electron/main/redis/server.ts new file mode 100644 index 0000000..ea4cbd0 --- /dev/null +++ b/electron/main/redis/server.ts @@ -0,0 +1,45 @@ +// src/main/redis/server.ts +// 服务器操作 +import { getClient } from './connection' + +export async function execute(id: string, command: string, args: string[]): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.call(command, ...args) +} + +export async function getServerInfo(id: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.info() as Promise +} + +export async function selectDb(id: string, db: number): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + await client.select(db) +} + +export async function dbSize(id: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.dbsize() as Promise +} + +export async function ping(id: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.ping() +} + +export async function slowLogGet(id: string, count: number): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.slowlog('GET', count) as Promise +} + +export async function slowLogLen(id: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.slowlog('LEN') as Promise +} diff --git a/electron/main/redis/set.ts b/electron/main/redis/set.ts new file mode 100644 index 0000000..3a6cb3a --- /dev/null +++ b/electron/main/redis/set.ts @@ -0,0 +1,27 @@ +// src/main/redis/set.ts +// Set 操作 +import { getClient } from './connection' + +export async function setMembers(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.smembers(key) +} + +export async function setSize(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.scard(key) +} + +export async function setAdd(id: string, key: string, ...members: string[]): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.sadd(key, ...members) +} + +export async function setRemove(id: string, key: string, ...members: string[]): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.srem(key, ...members) +} diff --git a/electron/main/redis/stream.ts b/electron/main/redis/stream.ts new file mode 100644 index 0000000..7cf8115 --- /dev/null +++ b/electron/main/redis/stream.ts @@ -0,0 +1,37 @@ +// src/main/redis/stream.ts +// Stream 操作 +import { getClient } from './connection' + +export async function streamInfo(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.xinfo('STREAM', key) +} + +export async function streamRange( + id: string, key: string, start: string, end: string, count: number +): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.xrange(key, start, end, 'COUNT', count) +} + +export async function streamAdd( + id: string, key: string, streamId: string, fieldValues: string[] +): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.xadd(key, streamId, ...fieldValues) +} + +export async function streamTrim(id: string, key: string, maxLen: number): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.xtrim(key, 'MAXLEN', maxLen) +} + +export async function streamDel(id: string, key: string, ...ids: string[]): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.xdel(key, ...ids) +} diff --git a/electron/main/redis/string.ts b/electron/main/redis/string.ts new file mode 100644 index 0000000..16d3d7b --- /dev/null +++ b/electron/main/redis/string.ts @@ -0,0 +1,15 @@ +// src/main/redis/string.ts +// String 操作 +import { getClient } from './connection' + +export async function getStringValue(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.get(key) +} + +export async function setStringValue(id: string, key: string, value: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + await client.set(key, value) +} diff --git a/electron/main/redis/zset.ts b/electron/main/redis/zset.ts new file mode 100644 index 0000000..2526130 --- /dev/null +++ b/electron/main/redis/zset.ts @@ -0,0 +1,28 @@ +// src/main/redis/zset.ts +// Sorted Set 操作 +import { getClient } from './connection' + +export async function zsetRange(id: string, key: string, start: number, stop: number, withScores: boolean): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + if (withScores) return client.zrange(key, start, stop, 'WITHSCORES') + return client.zrange(key, start, stop) +} + +export async function zsetSize(id: string, key: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.zcard(key) +} + +export async function zsetAdd(id: string, key: string, score: number, member: string): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.zadd(key, score, member) +} + +export async function zsetRemove(id: string, key: string, ...members: string[]): Promise { + const client = getClient(id) + if (!client) throw new Error(`Client ${id} not found`) + return client.zrem(key, ...members) +} diff --git a/src/main/store.ts b/electron/main/store.ts similarity index 100% rename from src/main/store.ts rename to electron/main/store.ts diff --git a/src/main/win-state.ts b/electron/main/win-state.ts similarity index 100% rename from src/main/win-state.ts rename to electron/main/win-state.ts diff --git a/src/preload/index.d.ts b/electron/preload/index.d.ts similarity index 100% rename from src/preload/index.d.ts rename to electron/preload/index.d.ts diff --git a/src/preload/index.ts b/electron/preload/index.ts similarity index 100% rename from src/preload/index.ts rename to electron/preload/index.ts diff --git a/electron/shared/types.ts b/electron/shared/types.ts new file mode 100644 index 0000000..77d9124 --- /dev/null +++ b/electron/shared/types.ts @@ -0,0 +1,95 @@ +// src/shared/types.ts +// 共享类型定义 + +// 连接配置 +export interface ConnectionConfig { + id: string + name: string + host: string + port: number + auth: string + username: string + tls: boolean + tlsCaPath: string + tlsCertPath: string + tlsKeyPath: string + sshEnabled: boolean + sshHost: string + sshPort: number + sshUsername: string + sshPassword: string + sshPrivateKeyPath: string + cluster: boolean + sentinelMasterName: string + separator: string + order: number + createdAt: number + color?: string +} + +// 连接选项(用于 Redis 连接) +export interface ConnectionOptions { + host: string + port: number + password?: string + username?: string + tls?: boolean +} + +// IPC 响应 +export interface IpcResponse { + success: boolean + data?: T + error?: string +} + +// Key 类型 +export type RedisKeyType = 'string' | 'hash' | 'list' | 'set' | 'zset' | 'stream' | 'none' + +// Key 项 +export interface KeyItem { + name: string + type: RedisKeyType | string + ttl: number + level: number + children?: KeyItem[] + isLeaf: boolean +} + +// Scan 结果 +export interface ScanResult { + cursor: string + keys: string[] +} + +// Hash 字段 +export interface HashField { + field: string + value: string +} + +// Stream Entry +export interface StreamEntry { + id: string + fields: Record +} + +// Zset Item +export interface ZsetItem { + member: string + score: number +} + +// 慢日志条目 +export interface SlowLogEntry { + id: number + timestamp: number + duration: number + command: string +} + +// INFO 段 +export interface InfoSection { + title: string + items: { key: string; value: string }[] +} diff --git a/src/renderer/src/App.vue b/src/App.vue similarity index 100% rename from src/renderer/src/App.vue rename to src/App.vue diff --git a/src/renderer/src/components/CliView.vue b/src/components/CliView.vue similarity index 100% rename from src/renderer/src/components/CliView.vue rename to src/components/CliView.vue diff --git a/src/renderer/src/components/ConnectionCard.vue b/src/components/ConnectionCard.vue similarity index 100% rename from src/renderer/src/components/ConnectionCard.vue rename to src/components/ConnectionCard.vue diff --git a/src/renderer/src/components/ConnectionList.vue b/src/components/ConnectionList.vue similarity index 100% rename from src/renderer/src/components/ConnectionList.vue rename to src/components/ConnectionList.vue diff --git a/src/renderer/src/components/DbSelector.vue b/src/components/DbSelector.vue similarity index 100% rename from src/renderer/src/components/DbSelector.vue rename to src/components/DbSelector.vue diff --git a/src/renderer/src/components/HashEditor.vue b/src/components/HashEditor.vue similarity index 100% rename from src/renderer/src/components/HashEditor.vue rename to src/components/HashEditor.vue diff --git a/src/renderer/src/components/KeyBrowser.vue b/src/components/KeyBrowser.vue similarity index 100% rename from src/renderer/src/components/KeyBrowser.vue rename to src/components/KeyBrowser.vue diff --git a/src/renderer/src/components/KeyDetail.vue b/src/components/KeyDetail.vue similarity index 100% rename from src/renderer/src/components/KeyDetail.vue rename to src/components/KeyDetail.vue diff --git a/src/renderer/src/components/KeyList.vue b/src/components/KeyList.vue similarity index 100% rename from src/renderer/src/components/KeyList.vue rename to src/components/KeyList.vue diff --git a/src/renderer/src/components/ListEditor.vue b/src/components/ListEditor.vue similarity index 100% rename from src/renderer/src/components/ListEditor.vue rename to src/components/ListEditor.vue diff --git a/src/renderer/src/components/MainArea.vue b/src/components/MainArea.vue similarity index 100% rename from src/renderer/src/components/MainArea.vue rename to src/components/MainArea.vue diff --git a/src/renderer/src/components/NewConnectionDialog.vue b/src/components/NewConnectionDialog.vue similarity index 100% rename from src/renderer/src/components/NewConnectionDialog.vue rename to src/components/NewConnectionDialog.vue diff --git a/src/renderer/src/components/SetEditor.vue b/src/components/SetEditor.vue similarity index 100% rename from src/renderer/src/components/SetEditor.vue rename to src/components/SetEditor.vue diff --git a/src/renderer/src/components/SettingsView.vue b/src/components/SettingsView.vue similarity index 100% rename from src/renderer/src/components/SettingsView.vue rename to src/components/SettingsView.vue diff --git a/src/renderer/src/components/Sidebar.vue b/src/components/Sidebar.vue similarity index 100% rename from src/renderer/src/components/Sidebar.vue rename to src/components/Sidebar.vue diff --git a/src/renderer/src/components/SlowLogView.vue b/src/components/SlowLogView.vue similarity index 100% rename from src/renderer/src/components/SlowLogView.vue rename to src/components/SlowLogView.vue diff --git a/src/renderer/src/components/StatusBar.vue b/src/components/StatusBar.vue similarity index 100% rename from src/renderer/src/components/StatusBar.vue rename to src/components/StatusBar.vue diff --git a/src/renderer/src/components/StatusView.vue b/src/components/StatusView.vue similarity index 100% rename from src/renderer/src/components/StatusView.vue rename to src/components/StatusView.vue diff --git a/src/renderer/src/components/StreamEditor.vue b/src/components/StreamEditor.vue similarity index 100% rename from src/renderer/src/components/StreamEditor.vue rename to src/components/StreamEditor.vue diff --git a/src/renderer/src/components/StringEditor.vue b/src/components/StringEditor.vue similarity index 100% rename from src/renderer/src/components/StringEditor.vue rename to src/components/StringEditor.vue diff --git a/src/renderer/src/components/TitleBar.vue b/src/components/TitleBar.vue similarity index 100% rename from src/renderer/src/components/TitleBar.vue rename to src/components/TitleBar.vue diff --git a/src/renderer/src/components/ZsetEditor.vue b/src/components/ZsetEditor.vue similarity index 100% rename from src/renderer/src/components/ZsetEditor.vue rename to src/components/ZsetEditor.vue diff --git a/src/renderer/src/composables/useKeyboard.ts b/src/composables/useKeyboard.ts similarity index 100% rename from src/renderer/src/composables/useKeyboard.ts rename to src/composables/useKeyboard.ts diff --git a/src/renderer/src/i18n/index.ts b/src/i18n/index.ts similarity index 100% rename from src/renderer/src/i18n/index.ts rename to src/i18n/index.ts diff --git a/src/renderer/src/i18n/locales/en.ts b/src/i18n/locales/en.ts similarity index 100% rename from src/renderer/src/i18n/locales/en.ts rename to src/i18n/locales/en.ts diff --git a/src/renderer/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts similarity index 100% rename from src/renderer/src/i18n/locales/zh-CN.ts rename to src/i18n/locales/zh-CN.ts diff --git a/src/renderer/index.html b/src/index.html similarity index 81% rename from src/renderer/index.html rename to src/index.html index cb1f0d5..5dda43e 100644 --- a/src/renderer/index.html +++ b/src/index.html @@ -7,6 +7,6 @@
- + diff --git a/src/renderer/src/main.ts b/src/main.ts similarity index 81% rename from src/renderer/src/main.ts rename to src/main.ts index d2db1de..b4894fb 100644 --- a/src/renderer/src/main.ts +++ b/src/main.ts @@ -1,16 +1,13 @@ -// src/renderer/src/main.ts +// src/renderer/main.ts import { createApp } from 'vue' import { createPinia } from 'pinia' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import * as ElementPlusIconsVue from '@element-plus/icons-vue' import App from './App.vue' -import router from './router' -import './styles/global.css' const app = createApp(App) app.use(createPinia()) -app.use(router) app.use(ElementPlus, { size: 'small' }) for (const [key, component] of Object.entries(ElementPlusIconsVue)) { diff --git a/src/main/redis-service.ts b/src/main/redis-service.ts deleted file mode 100644 index 72185fc..0000000 --- a/src/main/redis-service.ts +++ /dev/null @@ -1,373 +0,0 @@ -// src/main/redis-service.ts -import Redis, { RedisOptions, Cluster, ClusterNode } from 'ioredis' - -export type RedisClient = Redis | Cluster - -interface ConnectionOptions { - id: string - host: string - port: number - password?: string - username?: string - tls?: boolean - tlsCa?: string - tlsCert?: string - tlsKey?: string -} - -const clients = new Map() - -function buildRedisOptions(opts: ConnectionOptions): RedisOptions { - const options: RedisOptions = { - host: opts.host, - port: opts.port, - username: opts.username || undefined, - password: opts.password || undefined, - stringNumbers: true, - enableReadyCheck: true, - family: 0, - connectTimeout: 10000, - retryStrategy(times: number) { - if (times > 3) return null - return Math.min(times * 200, 1000) - }, - maxRetriesPerRequest: 3, - } - - if (opts.tls) { - options.tls = { - rejectUnauthorized: false, - checkServerIdentity: () => undefined, - } - if (opts.tlsCa) options.tls.ca = opts.tlsCa - if (opts.tlsCert) options.tls.cert = opts.tlsCert - if (opts.tlsKey) options.tls.key = opts.tlsKey - } - - return options -} - -export async function connect(id: string, opts: ConnectionOptions): Promise { - if (clients.has(id)) { - await disconnect(id) - } - - return new Promise((resolve, reject) => { - console.log(`[Redis] Connecting to ${opts.host}:${opts.port}...`) - const redis = new Redis(buildRedisOptions(opts)) - - redis.once('ready', () => { - console.log(`[Redis] Connected to ${opts.host}:${opts.port}`) - clients.set(id, redis) - resolve() - }) - - redis.once('error', (err: Error) => { - console.error(`[Redis] Connection error:`, err.message) - redis.disconnect() - reject(err) - }) - - // Timeout - setTimeout(() => { - if (!clients.has(id)) { - console.error(`[Redis] Connection timeout`) - redis.disconnect() - reject(new Error('连接超时,请检查主机和端口')) - } - }, 12000) - }) -} - -export async function disconnect(id: string): Promise { - const client = clients.get(id) - if (client) { - client.disconnect() - clients.delete(id) - } -} - -export function getClient(id: string): RedisClient | undefined { - return clients.get(id) -} - -export function disconnectAll(): void { - for (const [id] of clients) { - disconnect(id) - } -} - -export async function execute(id: string, command: string, args: string[]): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.call(command, ...args) -} - -export async function getServerInfo(id: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.info() as Promise -} - -export async function scanKeys( - id: string, - cursor: string, - pattern: string, - count: number -): Promise<{ cursor: string; keys: string[] }> { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - const [nextCursor, keys] = await client.scan(cursor, 'MATCH', pattern, 'COUNT', count) - return { cursor: nextCursor, keys } -} - -export async function getKeyType(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.type(key) -} - -export async function getKeyTTL(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.ttl(key) -} - -export async function getStringValue(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.get(key) -} - -export async function setStringValue(id: string, key: string, value: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - await client.set(key, value) -} - -export async function deleteKey(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - await client.del(key) -} - -export async function getHashFields( - id: string, key: string, cursor: string, count: number -): Promise<{ cursor: string; fields: [string, string][] }> { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - const [nextCursor, raw] = await client.hscan(key, cursor, 'COUNT', count) - const fields: [string, string][] = [] - for (let i = 0; i < raw.length; i += 2) { - fields.push([raw[i], raw[i + 1]]) - } - return { cursor: nextCursor, fields } -} - -export async function setHashField( - id: string, key: string, field: string, value: string -): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - await client.hset(key, field, value) -} - -export async function deleteHashField(id: string, key: string, field: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - await client.hdel(key, field) -} - -export async function setKeyTTL(id: string, key: string, ttl: number): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - if (ttl < 0) { - await client.persist(key) - } else { - await client.expire(key, ttl) - } -} - -export async function selectDb(id: string, db: number): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - await client.select(db) -} - -export async function dbSize(id: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.dbsize() as Promise -} - -// List operations -export async function listRange(id: string, key: string, start: number, stop: number): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.lrange(key, start, stop) -} - -export async function listLength(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.llen(key) -} - -export async function listPush(id: string, key: string, ...values: string[]): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.rpush(key, ...values) -} - -export async function listSet(id: string, key: string, index: number, value: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - await client.lset(key, index, value) -} - -export async function listRemove(id: string, key: string, count: number, value: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.lrem(key, count, value) -} - -// Set operations -export async function setMembers(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.smembers(key) -} - -export async function setSize(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.scard(key) -} - -export async function setAdd(id: string, key: string, ...members: string[]): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.sadd(key, ...members) -} - -export async function setRemove(id: string, key: string, ...members: string[]): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.srem(key, ...members) -} - -// Sorted set operations -export async function zsetRange(id: string, key: string, start: number, stop: number, withScores: boolean): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - if (withScores) return client.zrange(key, start, stop, 'WITHSCORES') - return client.zrange(key, start, stop) -} - -export async function zsetSize(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.zcard(key) -} - -export async function zsetAdd(id: string, key: string, score: number, member: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.zadd(key, score, member) -} - -export async function zsetRemove(id: string, key: string, ...members: string[]): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.zrem(key, ...members) -} - -// Slow log -export async function slowLogGet(id: string, count: number): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.slowlog('GET', count) as Promise -} - -export async function slowLogLen(id: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.slowlog('LEN') as Promise -} - -// Memory info -export async function memoryUsage(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.memory('USAGE', key) as Promise -} - -export async function batchDelete(id: string, keys: string[]): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - if (keys.length === 0) return 0 - const pipeline = client.pipeline() - for (const key of keys) { - pipeline.del(key) - } - const results = await pipeline.exec() - return results?.filter(([err]) => !err).length ?? 0 -} - -// Stream operations -export async function streamInfo(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.xinfo('STREAM', key) -} - -export async function streamRange( - id: string, key: string, start: string, end: string, count: number -): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.xrange(key, start, end, 'COUNT', count) -} - -export async function streamAdd( - id: string, key: string, streamId: string, fieldValues: string[] -): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.xadd(key, streamId, ...fieldValues) -} - -export async function streamTrim(id: string, key: string, maxLen: number): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.xtrim(key, 'MAXLEN', maxLen) -} - -export async function streamDel(id: string, key: string, ...ids: string[]): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.xdel(key, ...ids) -} - -export async function renameKey(id: string, oldKey: string, newKey: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - await client.rename(oldKey, newKey) -} - -export async function existsKey(id: string, key: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return (await client.exists(key)) === 1 -} - -export async function ping(id: string): Promise { - const client = clients.get(id) - if (!client) throw new Error(`Client ${id} not found`) - return client.ping() -} - -export function isConnected(id: string): boolean { - const client = clients.get(id) - return client?.status === 'ready' -} diff --git a/src/renderer/src/env.d.ts b/src/renderer/src/env.d.ts deleted file mode 100644 index 65c7311..0000000 --- a/src/renderer/src/env.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -declare module '*.vue' { - import type { DefineComponent } from 'vue' - const component: DefineComponent - export default component -} diff --git a/src/renderer/src/router/index.ts b/src/renderer/src/router/index.ts deleted file mode 100644 index f391e5c..0000000 --- a/src/renderer/src/router/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -// src/renderer/src/router/index.ts -import { createRouter, createMemoryHistory } from 'vue-router' -import App from '@renderer/App.vue' - -const router = createRouter({ - history: createMemoryHistory(), - routes: [ - { - path: '/', - name: 'home', - component: App, - }, - ], -}) - -export default router diff --git a/src/renderer/src/styles/global.css b/src/renderer/src/styles/global.css deleted file mode 100644 index 67fc5e7..0000000 --- a/src/renderer/src/styles/global.css +++ /dev/null @@ -1,26 +0,0 @@ -/* src/renderer/src/styles/global.css */ -@import './variables.css'; - -*, *::before, *::after { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -html, body, #app { - height: 100%; - width: 100%; - overflow: hidden; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; - background: var(--bg-primary); - color: var(--text-primary); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -::-webkit-scrollbar { width: 6px; height: 6px; } -::-webkit-scrollbar-track { background: transparent; } -::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 3px; } diff --git a/src/renderer/src/styles/variables.css b/src/renderer/src/styles/variables.css deleted file mode 100644 index 365bd88..0000000 --- a/src/renderer/src/styles/variables.css +++ /dev/null @@ -1,42 +0,0 @@ -/* src/renderer/src/styles/variables.css */ -:root { - --bg-primary: #0f0f1a; - --bg-secondary: #1a1a2e; - --bg-card: rgba(255, 255, 255, 0.03); - --bg-card-hover: rgba(255, 255, 255, 0.06); - --bg-card-active: rgba(99, 102, 241, 0.08); - --border-color: rgba(255, 255, 255, 0.06); - --border-accent: rgba(99, 102, 241, 0.2); - --text-primary: #e2e8f0; - --text-secondary: #94a3b8; - --text-muted: #64748b; - --accent: #6366f1; - --accent-light: #a5b4fc; - --success: #22c55e; - --warning: #eab308; - --danger: #ef4444; - --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.2); - --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.3); - --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.4); - --shadow-glow: 0 0 14px rgba(99, 102, 241, 0.2); - --radius-sm: 8px; - --radius-md: 12px; - --radius-lg: 16px; -} - -:root.light { - --bg-primary: #f8fafc; - --bg-secondary: #f1f5f9; - --bg-card: #ffffff; - --bg-card-hover: #f1f5f9; - --bg-card-active: rgba(99, 102, 241, 0.06); - --border-color: rgba(0, 0, 0, 0.06); - --border-accent: rgba(99, 102, 241, 0.15); - --text-primary: #1e293b; - --text-secondary: #64748b; - --text-muted: #94a3b8; - --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.04); - --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.06); - --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.08); - --shadow-glow: 0 0 12px rgba(99, 102, 241, 0.1); -} diff --git a/src/renderer/src/stores/app.ts b/src/stores/app.ts similarity index 100% rename from src/renderer/src/stores/app.ts rename to src/stores/app.ts diff --git a/src/renderer/src/stores/connection.ts b/src/stores/connection.ts similarity index 100% rename from src/renderer/src/stores/connection.ts rename to src/stores/connection.ts diff --git a/src/renderer/src/stores/key.ts b/src/stores/key.ts similarity index 100% rename from src/renderer/src/stores/key.ts rename to src/stores/key.ts diff --git a/tsconfig.node.json b/tsconfig.node.json index 5c13ee2..a73d3fe 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -6,9 +6,9 @@ "strict": true, "esModuleInterop": true, "skipLibCheck": true, - "outDir": "./out", + "outDir": "./electron-dist", "types": ["node"], "composite": true }, - "include": ["src/main/**/*", "src/preload/**/*", "electron.vite.config.ts"] + "include": ["electron/main/**/*", "electron/preload/**/*", "electron/shared/**/*", "electron.vite.config.ts"] } diff --git a/tsconfig.web.json b/tsconfig.web.json index c2184a1..17b9d82 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -11,8 +11,9 @@ "composite": true, "baseUrl": ".", "paths": { - "@renderer/*": ["src/renderer/src/*"] + "@renderer/*": ["src/*"], + "@shared/*": ["electron/shared/*"] } }, - "include": ["src/renderer/**/*", "src/renderer/src/**/*.d.ts", "src/preload/index.d.ts"] + "include": ["src/**/*", "electron/preload/index.d.ts"] }