initial: LAN IM desktop app (Electron 32 + Vue 3 + TS + SQLite)

This commit is contained in:
2026-07-15 18:31:13 +08:00
commit 07c7260a3c
43 changed files with 12320 additions and 0 deletions
+64
View File
@@ -0,0 +1,64 @@
// preload: 把主进程能力通过 contextBridge 暴露给渲染进程
import { contextBridge, ipcRenderer, webUtils } from 'electron'
contextBridge.exposeInMainWorld('api', {
platform: process.platform,
versions: process.versions,
// self / 设备
self: () => ipcRenderer.invoke('self:info'),
listDevices: () => ipcRenderer.invoke('device:list'),
triggerScan: () => ipcRenderer.invoke('device:triggerScan'),
// 消息
listMessages: (peerId: string) => ipcRenderer.invoke('message:list', peerId),
sendText: (toDeviceId: string, content: string) => ipcRenderer.invoke('message:sendText', { toDeviceId, content }),
sendFile: (toDeviceId: string, localPath: string, opts?: { name?: string; mime?: string; asImage?: boolean; withProgress?: boolean }) =>
ipcRenderer.invoke('message:sendFile', { toDeviceId, localPath, ...(opts || {}) }),
sendBuffer: (toDeviceId: string, dataBase64: string, name: string, mime: string) =>
ipcRenderer.invoke('message:sendBuffer', { toDeviceId, dataBase64, name, mime }),
recall: (messageId: string) => ipcRenderer.invoke('message:recall', messageId),
retry: (messageId: string) => ipcRenderer.invoke('message:retry', messageId),
typing: (toDeviceId: string) => ipcRenderer.invoke('message:typing', toDeviceId),
// 未读
unreadList: () => ipcRenderer.invoke('unread:list'),
clearUnread: (deviceId: string) => ipcRenderer.invoke('unread:clear', deviceId),
// 设置
getSettings: () => ipcRenderer.invoke('settings:get'),
setSettings: (patch: any) => ipcRenderer.invoke('settings:set', patch),
chooseDownloadDir: () => ipcRenderer.invoke('settings:chooseDownloadDir'),
// 文件
openInFolder: (p: string) => ipcRenderer.invoke('file:openInFolder', p),
open: (p: string) => ipcRenderer.invoke('file:open', p),
readBase64: (p: string) => ipcRenderer.invoke('file:readBase64', p),
pickFile: (opts?: { image?: boolean }) => ipcRenderer.invoke('file:pick', opts),
// 拖拽文件 -> 真实磁盘路径 (Electron 32+ 必须用 webUtils.getPathForFile)
getPathForFile: (file: File): string => {
try { return webUtils.getPathForFile(file) || '' } catch { return '' }
},
// 应用
hide: () => ipcRenderer.invoke('app:hide'),
appVersion: () => ipcRenderer.invoke('app:version'),
// 开机自启
getAutoStart: () => ipcRenderer.invoke('autostart:get'),
setAutoStart: (enabled: boolean) => ipcRenderer.invoke('autostart:set', enabled),
// 网络接口 (只读)
listInterfaces: () => ipcRenderer.invoke('network:listInterfaces'),
// 事件订阅: 主进程 webContents.send('xxx', payload) 会在此处派发
on(channel: string, cb: (payload: any) => void) {
const listener = (_e: any, payload: any) => cb(payload)
ipcRenderer.on(channel, listener)
return () => ipcRenderer.removeListener(channel, listener)
},
// 离线消息: 启动后让主进程把 pending 重新尝试一遍
flushPending: () => ipcRenderer.invoke('message:flushPending'),
})