From 8b4ccc1e40449184d2bed22ce6a8a5206f4b8d28 Mon Sep 17 00:00:00 2001 From: Program Date: Thu, 10 Apr 2025 02:44:28 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E4=BE=A7=E8=BE=B9=E6=A0=8F?= =?UTF-8?q?=E5=9B=BE=E6=A0=87UI=E4=BB=A5=E5=8F=8A=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components.d.ts | 3 + electron-builder.json5 | 62 +- electron/ipc/window.ts | 615 +++++++++--------- electron/main.ts | 118 ++-- electron/preload.ts | 4 + package.json | 4 +- src/App.vue | 5 +- src/assets/icon.png | Bin 0 -> 8074 bytes src/assets/png/avatar.png.jpg | Bin 0 -> 60079 bytes src/assets/svg/administering_user_16.svg | 1 + src/assets/svg/administering_user_24.svg | 1 + src/assets/svg/arrow_down_16.svg | 1 + src/assets/svg/arrow_down_24.svg | 1 + src/assets/svg/arrow_down_mini_16.svg | 1 + src/assets/svg/arrow_down_small_16.svg | 1 + src/assets/svg/arrow_left_16.svg | 1 + src/assets/svg/arrow_left_24.svg | 1 + src/assets/svg/arrow_left_small_16.svg | 1 + src/assets/svg/arrow_right_16.svg | 1 + src/assets/svg/arrow_right_24.svg | 1 + src/assets/svg/arrow_right_small_16.svg | 1 + src/assets/svg/arrow_up_16.svg | 1 + src/assets/svg/arrow_up_24.svg | 1 + src/assets/svg/arrow_up_small_16.svg | 1 + src/assets/svg/arrows_16.svg | 1 + src/assets/svg/arrows_24.svg | 1 + src/assets/svg/caution_16.svg | 1 + src/assets/svg/caution_24.svg | 1 + src/assets/svg/channel_discover_friend_24.svg | 1 + src/assets/svg/channel_discover_star_24.svg | 1 + src/assets/svg/filelook_ai_16.svg | 1 + src/assets/svg/filelook_apk_16.svg | 1 + src/assets/svg/filelook_audio_16.svg | 1 + src/assets/svg/filelook_doc_16.svg | 1 + src/assets/svg/filelook_exe_16.svg | 1 + src/assets/svg/filelook_folder_16.svg | 1 + src/assets/svg/filelook_html_16.svg | 1 + src/assets/svg/filelook_image_16.svg | 1 + src/assets/svg/filelook_ipa_16.svg | 1 + src/assets/svg/filelook_link_16.svg | 1 + src/assets/svg/filelook_multi_files_16.svg | 1 + src/assets/svg/filelook_pdf_16.svg | 1 + src/assets/svg/filelook_ppt_16.svg | 1 + src/assets/svg/filelook_ps_16.svg | 1 + src/assets/svg/filelook_sketch_16.svg | 1 + src/assets/svg/filelook_txt_16.svg | 1 + src/assets/svg/filelook_unknown_16.svg | 1 + src/assets/svg/filelook_video_16.svg | 1 + src/assets/svg/filelook_xls_16.svg | 1 + src/assets/svg/filelook_zip_16.svg | 1 + src/assets/svg/files_16.svg | 1 + src/assets/svg/files_24.svg | 1 + src/assets/svg/filter_16.svg | 1 + src/assets/svg/filter_24.svg | 1 + src/assets/svg/finger_16.svg | 1 + src/assets/svg/finger_24.svg | 1 + src/assets/svg/full_screen_16.svg | 1 + src/assets/svg/full_screen_24.svg | 1 + src/assets/svg/full_screen_off_16.svg | 1 + src/assets/svg/full_screen_off_24.svg | 1 + src/assets/svg/gif_16.svg | 1 + src/assets/svg/gif_24.svg | 1 + src/assets/svg/group_16.svg | 1 + src/assets/svg/group_24.svg | 1 + src/assets/svg/home_16.svg | 1 + src/assets/svg/home_24.svg | 1 + src/assets/svg/image_16.svg | 1 + src/assets/svg/image_24.svg | 1 + src/assets/svg/like_filled_24.svg | 1 + src/assets/svg/like_outline_16.svg | 1 + src/assets/svg/like_outline_24.svg | 1 + src/assets/svg/link_16.svg | 1 + src/assets/svg/link_24.svg | 1 + src/assets/svg/lock_16.svg | 1 + src/assets/svg/lock_24.svg | 1 + src/assets/svg/long_screenshot_16.svg | 1 + src/assets/svg/long_screenshot_24.svg | 1 + src/assets/svg/nav/collection_24.svg | 1 + src/assets/svg/nav/download_16.svg | 1 + src/assets/svg/nav/download_24.svg | 1 + src/assets/svg/nav/folder_24.svg | 1 + src/assets/svg/nav/menu_24.svg | 1 + .../svg/nav/nav_application_normal_24.svg | 1 + src/assets/svg/nav/nav_contact_active_24.svg | 1 + src/assets/svg/nav/nav_contact_normal_24.svg | 1 + src/assets/svg/nav/nav_message_active_24.svg | 13 + src/assets/svg/nav/nav_message_normal_24.svg | 1 + src/assets/svg/nav/nav_setting_normal_16.svg | 1 + src/assets/svg/nav/update_16.svg | 1 + src/assets/svg/nav/update_24.svg | 1 + src/assets/svg/open_file_16.svg | 1 + src/assets/svg/open_file_24.svg | 1 + src/assets/svg/paste_16.svg | 1 + src/assets/svg/paste_24.svg | 1 + src/assets/svg/pause_16.svg | 1 + src/assets/svg/pause_24.svg | 1 + src/assets/svg/pause_circle_16.svg | 1 + src/assets/svg/pause_circle_24.svg | 1 + src/assets/svg/pause_circle_filled_16.svg | 1 + src/assets/svg/pause_circle_filled_24.svg | 1 + src/assets/svg/star_16.svg | 1 + src/assets/svg/star_24.svg | 1 + src/assets/svg/tick_16.svg | 1 + src/assets/svg/tick_24.svg | 1 + src/assets/svg/transmission_file_16.svg | 1 + src/assets/svg/transmission_file_24.svg | 1 + src/assets/svg/user.svg | 1 + src/assets/svg/user_24.svg | 1 + src/assets/svg/voice_high_16.svg | 1 + src/assets/svg/voice_high_24.svg | 1 + src/assets/svg/zoom_in_16.svg | 1 + src/assets/svg/zoom_in_24.svg | 1 + src/assets/svg/zoom_out_16.svg | 1 + src/assets/svg/zoom_out_24.svg | 1 + src/components/common/SvgIcon.vue | 51 ++ src/components/mainwindow/NavBar.vue | 93 +++ src/components/mainwindow/SideBar.vue | 102 +++ src/electron/window.ts | 210 +++--- src/route/index.ts | 18 + src/style.css | 68 +- src/types/ElectronRawApi.d.ts | 35 +- src/view/Login.vue | 4 +- src/view/MainWindow.vue | 72 +- src/view/mainwindow/ChatView.vue | 17 + src/view/mainwindow/ContactList.vue | 6 + src/view/mainwindow/ListView.vue | 19 + 126 files changed, 1086 insertions(+), 537 deletions(-) create mode 100644 src/assets/icon.png create mode 100644 src/assets/png/avatar.png.jpg create mode 100644 src/assets/svg/administering_user_16.svg create mode 100644 src/assets/svg/administering_user_24.svg create mode 100644 src/assets/svg/arrow_down_16.svg create mode 100644 src/assets/svg/arrow_down_24.svg create mode 100644 src/assets/svg/arrow_down_mini_16.svg create mode 100644 src/assets/svg/arrow_down_small_16.svg create mode 100644 src/assets/svg/arrow_left_16.svg create mode 100644 src/assets/svg/arrow_left_24.svg create mode 100644 src/assets/svg/arrow_left_small_16.svg create mode 100644 src/assets/svg/arrow_right_16.svg create mode 100644 src/assets/svg/arrow_right_24.svg create mode 100644 src/assets/svg/arrow_right_small_16.svg create mode 100644 src/assets/svg/arrow_up_16.svg create mode 100644 src/assets/svg/arrow_up_24.svg create mode 100644 src/assets/svg/arrow_up_small_16.svg create mode 100644 src/assets/svg/arrows_16.svg create mode 100644 src/assets/svg/arrows_24.svg create mode 100644 src/assets/svg/caution_16.svg create mode 100644 src/assets/svg/caution_24.svg create mode 100644 src/assets/svg/channel_discover_friend_24.svg create mode 100644 src/assets/svg/channel_discover_star_24.svg create mode 100644 src/assets/svg/filelook_ai_16.svg create mode 100644 src/assets/svg/filelook_apk_16.svg create mode 100644 src/assets/svg/filelook_audio_16.svg create mode 100644 src/assets/svg/filelook_doc_16.svg create mode 100644 src/assets/svg/filelook_exe_16.svg create mode 100644 src/assets/svg/filelook_folder_16.svg create mode 100644 src/assets/svg/filelook_html_16.svg create mode 100644 src/assets/svg/filelook_image_16.svg create mode 100644 src/assets/svg/filelook_ipa_16.svg create mode 100644 src/assets/svg/filelook_link_16.svg create mode 100644 src/assets/svg/filelook_multi_files_16.svg create mode 100644 src/assets/svg/filelook_pdf_16.svg create mode 100644 src/assets/svg/filelook_ppt_16.svg create mode 100644 src/assets/svg/filelook_ps_16.svg create mode 100644 src/assets/svg/filelook_sketch_16.svg create mode 100644 src/assets/svg/filelook_txt_16.svg create mode 100644 src/assets/svg/filelook_unknown_16.svg create mode 100644 src/assets/svg/filelook_video_16.svg create mode 100644 src/assets/svg/filelook_xls_16.svg create mode 100644 src/assets/svg/filelook_zip_16.svg create mode 100644 src/assets/svg/files_16.svg create mode 100644 src/assets/svg/files_24.svg create mode 100644 src/assets/svg/filter_16.svg create mode 100644 src/assets/svg/filter_24.svg create mode 100644 src/assets/svg/finger_16.svg create mode 100644 src/assets/svg/finger_24.svg create mode 100644 src/assets/svg/full_screen_16.svg create mode 100644 src/assets/svg/full_screen_24.svg create mode 100644 src/assets/svg/full_screen_off_16.svg create mode 100644 src/assets/svg/full_screen_off_24.svg create mode 100644 src/assets/svg/gif_16.svg create mode 100644 src/assets/svg/gif_24.svg create mode 100644 src/assets/svg/group_16.svg create mode 100644 src/assets/svg/group_24.svg create mode 100644 src/assets/svg/home_16.svg create mode 100644 src/assets/svg/home_24.svg create mode 100644 src/assets/svg/image_16.svg create mode 100644 src/assets/svg/image_24.svg create mode 100644 src/assets/svg/like_filled_24.svg create mode 100644 src/assets/svg/like_outline_16.svg create mode 100644 src/assets/svg/like_outline_24.svg create mode 100644 src/assets/svg/link_16.svg create mode 100644 src/assets/svg/link_24.svg create mode 100644 src/assets/svg/lock_16.svg create mode 100644 src/assets/svg/lock_24.svg create mode 100644 src/assets/svg/long_screenshot_16.svg create mode 100644 src/assets/svg/long_screenshot_24.svg create mode 100644 src/assets/svg/nav/collection_24.svg create mode 100644 src/assets/svg/nav/download_16.svg create mode 100644 src/assets/svg/nav/download_24.svg create mode 100644 src/assets/svg/nav/folder_24.svg create mode 100644 src/assets/svg/nav/menu_24.svg create mode 100644 src/assets/svg/nav/nav_application_normal_24.svg create mode 100644 src/assets/svg/nav/nav_contact_active_24.svg create mode 100644 src/assets/svg/nav/nav_contact_normal_24.svg create mode 100644 src/assets/svg/nav/nav_message_active_24.svg create mode 100644 src/assets/svg/nav/nav_message_normal_24.svg create mode 100644 src/assets/svg/nav/nav_setting_normal_16.svg create mode 100644 src/assets/svg/nav/update_16.svg create mode 100644 src/assets/svg/nav/update_24.svg create mode 100644 src/assets/svg/open_file_16.svg create mode 100644 src/assets/svg/open_file_24.svg create mode 100644 src/assets/svg/paste_16.svg create mode 100644 src/assets/svg/paste_24.svg create mode 100644 src/assets/svg/pause_16.svg create mode 100644 src/assets/svg/pause_24.svg create mode 100644 src/assets/svg/pause_circle_16.svg create mode 100644 src/assets/svg/pause_circle_24.svg create mode 100644 src/assets/svg/pause_circle_filled_16.svg create mode 100644 src/assets/svg/pause_circle_filled_24.svg create mode 100644 src/assets/svg/star_16.svg create mode 100644 src/assets/svg/star_24.svg create mode 100644 src/assets/svg/tick_16.svg create mode 100644 src/assets/svg/tick_24.svg create mode 100644 src/assets/svg/transmission_file_16.svg create mode 100644 src/assets/svg/transmission_file_24.svg create mode 100644 src/assets/svg/user.svg create mode 100644 src/assets/svg/user_24.svg create mode 100644 src/assets/svg/voice_high_16.svg create mode 100644 src/assets/svg/voice_high_24.svg create mode 100644 src/assets/svg/zoom_in_16.svg create mode 100644 src/assets/svg/zoom_in_24.svg create mode 100644 src/assets/svg/zoom_out_16.svg create mode 100644 src/assets/svg/zoom_out_24.svg create mode 100644 src/components/common/SvgIcon.vue create mode 100644 src/components/mainwindow/NavBar.vue create mode 100644 src/components/mainwindow/SideBar.vue create mode 100644 src/view/mainwindow/ChatView.vue create mode 100644 src/view/mainwindow/ContactList.vue create mode 100644 src/view/mainwindow/ListView.vue diff --git a/components.d.ts b/components.d.ts index 4dbba03..dab5622 100644 --- a/components.d.ts +++ b/components.d.ts @@ -13,7 +13,10 @@ declare module 'vue' { ElText: typeof import('element-plus/es')['ElText'] FluentCheckBox: typeof import('./src/components/fluent-ui/FluentCheckBox.vue')['default'] FluentInput: typeof import('./src/components/fluent-ui/FluentInput.vue')['default'] + NavBar: typeof import('./src/components/mainwindow/NavBar.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] + SideBar: typeof import('./src/components/mainwindow/SideBar.vue')['default'] + SvgIcon: typeof import('./src/components/common/SvgIcon.vue')['default'] } } diff --git a/electron-builder.json5 b/electron-builder.json5 index 71a15e8..1222b0e 100644 --- a/electron-builder.json5 +++ b/electron-builder.json5 @@ -1,37 +1,45 @@ // @see - https://www.electron.build/configuration/configuration { - $schema: "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json", - appId: "cn.programcx", - asar: true, - productName: "Flow Message", - directories: { - output: "release/${version}", + "$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json", + "appId": "cn.programcx", + "asar": true, + "productName": "Flow Message", + "directories": { + "output": "release/${version}" }, - files: ["dist", "dist-electron"], - mac: { - target: ["dmg"], - artifactName: "${productName}-Mac-${version}-Installer.${ext}", + "files": [ + "dist", + "dist-electron" + ], + "mac": { + "target": [ + "dmg" + ], + "artifactName": "${productName}-Mac-${version}-Installer.${ext}", icon: "public/icon/icon.icns", }, - win: { - target: [ + "win": { + "target": [ { - target: "nsis", - arch: ["x64"], - }, + "target": "nsis", + "arch": [ + "x64" + ] + } ], - artifactName: "${productName}-Windows-${version}-Setup.${ext}", + "artifactName": "${productName}-Windows-${version}-Setup.${ext}", icon: "public/icon/icon.ico", }, - nsis: { - oneClick: false, - perMachine: false, - allowToChangeInstallationDirectory: true, - deleteAppDataOnUninstall: false, - }, - linux: { - target: ["AppImage"], - artifactName: "${productName}-Linux-${version}.${ext}", - "icon": "public/icon/icon.png", + "nsis": { + "oneClick": false, + "perMachine": false, + "allowToChangeInstallationDirectory": true, + "deleteAppDataOnUninstall": false }, -} + "linux": { + "target": [ + "AppImage" + ], + "artifactName": "${productName}-Linux-${version}.${ext}" + } +} \ No newline at end of file diff --git a/electron/ipc/window.ts b/electron/ipc/window.ts index abe81c5..cd13af7 100644 --- a/electron/ipc/window.ts +++ b/electron/ipc/window.ts @@ -1,318 +1,309 @@ import { BrowserWindow, ipcMain } from "electron"; export default function setupWindowIpcHandlers(win: BrowserWindow | null) { - //改变窗口大小 - ipcMain.on("resize-window", (_event, width: number, height: number) => { - if (win) { - win.setSize(width, height); - } - }); - //设置窗口边框是否可见 - ipcMain.on("set-window-frame-visible", (_event, isFrameVisible: boolean) => { - if (win) { - win.setMenuBarVisibility(isFrameVisible); - win.setResizable(isFrameVisible); - } - }); - - //设置窗口标题 - ipcMain.on("set-window-title", (_event, title: string) => { - if (win) { - win.setTitle(title); - } - }); - - //设置窗口图标 - ipcMain.on("set-window-central", (_event) => { - if (win) { - const { width, height } = win.getBounds(); - const { workAreaSize } = require("electron").screen.getPrimaryDisplay(); - const x = (workAreaSize.width - width) / 2; - const y = (workAreaSize.height - height) / 2; - win.setBounds({ x, y }); - } - }); - - //设置窗口是是否置顶 - ipcMain.on("set-window-always-on-top", (_event, alwaysOnTop: boolean) => { - if (win) { - win.setAlwaysOnTop(alwaysOnTop); - } - }); - - //设置窗口是否可见 - ipcMain.on("set-window-visible", (_event, visible: boolean) => { - if (win) { - visible ? win.show() : win.hide(); - } - }); - - //设置窗口菜单栏是否可见 - ipcMain.on("set-window-menu-bar-visible", (_event, visible: boolean) => { - if (win) { - win.setMenuBarVisibility(visible); - } - }); - - //设置窗口是否可改变大小 - ipcMain.on("set-window-resizable", (_event, resizable: boolean) => { - if (win) { - win.setResizable(resizable); - } - }); - - //设置窗口是否可移动 - ipcMain.on("set-window-movable", (_event, movable: boolean) => { - if (win) { - win.setMovable(movable); - } - }); - - //设置窗口最小化 - ipcMain.on("set-window-minimizable", (_event, minimizable: boolean) => { - if (win) { - win.setMinimizable(minimizable); - } - }); - - //设置窗口最大化 - ipcMain.on("set-window-maximizable", (_event, maximizable: boolean) => { - if (win) { - win.setMaximizable(maximizable); - } - }); - - //设置窗口是否全屏 - ipcMain.on("set-window-full-screen", (_event, fullScreen: boolean) => { - if (win) { - win.setFullScreen(fullScreen); - } - }); - - //设置窗口背景颜色 - ipcMain.on("set-window-background-color", (_event, color: string) => { - if (win) { - win.setBackgroundColor(color); - } - }); - - //设置窗口图标 - ipcMain.on("set-window-icon", (_event, iconPath: string) => { - if (win) { - win.setIcon(iconPath); - } - }); - - //设置窗口是否在所有工作区可见 - ipcMain.on( - "set-window-visible-on-all-workspaces", - (_event, visible: boolean) => { - if (win) { - win.setVisibleOnAllWorkspaces(visible); + // 判断窗口是否有效,返回 true 表示窗口可用 + const checkWindow = () => { + return win && !win.isDestroyed(); + }; + + // ----------------- Set 系列操作(使用 win.webContents 绑定) ----------------- + + if (checkWindow()) { + win.webContents.on("ipc-message", (event, channel, ...args) => { + // 根据 channel 处理 set 操作 + switch (channel) { + // 改变窗口大小 + case "resize-window": { + const [width, height] = args as number[]; + win.setSize(width, height); + break; + } + // 设置窗口边框是否可见 + case "set-window-frame-visible": { + const [isFrameVisible] = args as [boolean]; + win.setMenuBarVisibility(isFrameVisible); + win.setResizable(isFrameVisible); + break; + } + // 设置窗口标题 + case "set-window-title": { + const [title] = args as [string]; + win.setTitle(title); + break; + } + // 设置窗口图标(居中窗口) + case "set-window-central": { + const { width, height } = win.getBounds(); + const { workAreaSize } = require("electron").screen.getPrimaryDisplay(); + const x = (workAreaSize.width - width) / 2; + const y = (workAreaSize.height - height) / 2; + win.setBounds({ x, y }); + break; + } + // 设置窗口是否置顶 + case "set-window-always-on-top": { + const [alwaysOnTop] = args as [boolean]; + win.setAlwaysOnTop(alwaysOnTop); + break; + } + // 设置窗口是否可见 + case "set-window-visible": { + const [visible] = args as [boolean]; + visible ? win.show() : win.hide(); + break; + } + // 设置窗口菜单栏是否可见 + case "set-window-menu-bar-visible": { + const [visible] = args as [boolean]; + win.setMenuBarVisibility(visible); + break; + } + // 设置窗口是否可改变大小 + case "set-window-resizable": { + const [resizable] = args as [boolean]; + win.setResizable(resizable); + break; + } + // 设置窗口是否可移动 + case "set-window-movable": { + const [movable] = args as [boolean]; + win.setMovable(movable); + break; + } + // 设置窗口最小化 + case "set-window-minimizable": { + const [minimizable] = args as [boolean]; + win.setMinimizable(minimizable); + break; + } + // 设置窗口最大化 + case "set-window-maximizable": { + const [maximizable] = args as [boolean]; + win.setMaximizable(maximizable); + break; + } + // 设置窗口是否全屏 + case "set-window-full-screen": { + const [fullScreen] = args as [boolean]; + win.setFullScreen(fullScreen); + break; + } + // 设置窗口背景颜色 + case "set-window-background-color": { + const [color] = args as [string]; + win.setBackgroundColor(color); + break; + } + // 设置窗口图标 + case "set-window-icon": { + const [iconPath] = args as [string]; + win.setIcon(iconPath); + break; + } + // 设置窗口是否在所有工作区可见 + case "set-window-visible-on-all-workspaces": { + const [visible] = args as [boolean]; + win.setVisibleOnAllWorkspaces(visible); + break; + } + // 设置窗口大小 + case "set-window-size": { + const [width, height] = args as number[]; + win.setSize(width, height); + break; + } + // 设置窗口位置 + case "set-window-position": { + const [x, y] = args as number[]; + win.setPosition(x, y); + break; + } + // 设置窗口透明度 + case "set-window-opacity": { + const [opacity] = args as [number]; + win.setOpacity(opacity); + break; + } + // 设置窗口是否在任务栏中显示 + case "set-window-in-taskbar": { + const [inTaskbar] = args as [boolean]; + win.setSkipTaskbar(!inTaskbar); + break; + } + // 设置窗口最小化 + case "minimize-window": { + win.minimize(); + break; + } + // 设置窗口最大化 + case "maximize-window": { + win.maximize(); + break; + } + // 设置窗口还原 + case "restore-window": { + win.restore(); + break; + } + // 设置窗口最小大小 + case "set-window-min-size": { + const [minWidth, minHeight] = args as number[]; + win.setMinimumSize(minWidth, minHeight); + break; + } + // 关闭窗口(只触发一次) + case "close-window": { + win.close(); + break; + } + // 销毁窗口 + case "destroy-window": { + win.destroy(); + break; + } + default: { + console.warn("Unknown set-window ipc-message channel:", channel); + } } - } - ); - - //设置窗口大小 - ipcMain.on("set-window-size", (_event, width: number, height: number) => { - if (win) { - win.setSize(width, height); - } - }); - - //设置窗口位置 - ipcMain.on("set-window-position", (_event, x: number, y: number) => { - if (win) { - win.setPosition(x, y); - } - }); - - //设置窗口透明度 - ipcMain.on("set-window-opacity", (_event, opacity: number) => { - if (win) { - win.setOpacity(opacity); - } - }); - - //设置窗口是否在任务栏中显示 - ipcMain.on("set-window-in-taskbar", (_event, inTaskbar: boolean) => { - if (win) { - win.setSkipTaskbar(!inTaskbar); - } - }); - - //设置窗口最小化 - ipcMain.on("minimize-window", () => { - if (win) { - win.minimize(); - } - }); - - //设置窗口最大化 - ipcMain.on("maximize-window", () => { - if (win) { - win.maximize(); - } - }); - - //设置窗口还原 - ipcMain.on("restore-window", () => { - if (win) { - win.restore(); - } - }); - - //关闭窗口 - ipcMain.on("close-window", () => { - if (win) { - win.close(); - } - }); - - //销毁窗口 - ipcMain.on("destroy-window", () => { - if (win) { - win.destroy(); - } - }); - - //获取窗口位置 - ipcMain.on("get-window-position", (_event) => { - if (win) { - const [x, y] = win.getPosition(); - _event.reply("get-window-position-reply", { x, y }); - } - }); - - //获取窗口大小 - ipcMain.on("get-window-size", (_event) => { - if (win) { - const [width, height] = win.getSize(); - _event.reply("get-window-size-reply", { width, height }); - } - }); - - //获取窗口标题 - ipcMain.on("get-window-title", (_event) => { - if (win) { - const title = win.getTitle(); - _event.reply("get-window-title-reply", title); - } - }); - - //获取窗口背景色 - ipcMain.on("get-window-background-color", (_event) => { - if (win) { - const color = win.getBackgroundColor(); - _event.reply("get-window-background-color-reply", color); - } - }); - - //获取窗口透明度 - ipcMain.on("get-window-opacity", (_event) => { - if (win) { - const opacity = win.getOpacity(); - _event.reply("get-window-opacity-reply", opacity); - } - }); - - //获取窗口是否可见 - ipcMain.on("is-window-visible", (_event) => { - if (win) { - const visible = win.isVisible(); - _event.reply("is-window-visible-reply", visible); - } - }); - - //获取窗口是否最大化 - ipcMain.on("is-window-maximized", (_event) => { - if (win) { - const maximized = win.isMaximized(); - _event.reply("is-window-maximized-reply", maximized); - } - }); - - //获取窗口是否最小化 - ipcMain.on("is-window-minimized", (_event) => { - if (win) { - const minimized = win.isMinimized(); - _event.reply("is-window-minimized-reply", minimized); - } - }); - - //获取窗口是否全屏 - ipcMain.on("is-window-full-screen", (_event) => { - if (win) { - const fullScreen = win.isFullScreen(); - _event.reply("is-window-full-screen-reply", fullScreen); - } - }); - - //获取窗口是否可以改变大小 - ipcMain.on("is-window-resizable", (_event) => { - if (win) { - const resizable = win.isResizable(); - _event.reply("is-window-resizable-reply", resizable); - } - }); - - //获取窗口是否在所有工作区可见 - ipcMain.on("is-window-visible-on-all-workspaces", (_event) => { - if (win) { - const visibleOnAllWorkspaces = win.isVisibleOnAllWorkspaces(); - _event.reply( - "is-window-visible-on-all-workspaces-reply", - visibleOnAllWorkspaces - ); - } - }); - - //获取窗口是否置顶 - ipcMain.on("is-window-always-on-top", (_event) => { - if (win) { - const alwaysOnTop = win.isAlwaysOnTop(); - _event.reply("is-window-always-on-top-reply", alwaysOnTop); - } - }); - - //获取窗口是否可移动 - ipcMain.on("is-window-movable", (_event) => { - if (win) { - const movable = win.isMovable(); - _event.reply("is-window-movable-reply", movable); - } - }); - - //获取窗口是否可最小化 - ipcMain.on("is-window-minimizable", (_event) => { - if (win) { - const minimizable = win.isMinimizable(); - _event.reply("is-window-minimizable-reply", minimizable); - } - }); - - //获取窗口是否可最大化 - ipcMain.on("is-window-maximizable", (_event) => { - if (win) { - const maximizable = win.isMaximizable(); - _event.reply("is-window-maximizable-reply", maximizable); - } - }); - - //获取窗口是否可关闭 - ipcMain.on("is-window-closable", (_event) => { - if (win) { - const closable = win.isClosable(); - _event.reply("is-window-closable-reply", closable); - } - }); - - //获取窗口是否在任务栏中显示 - ipcMain.on("is-window-menu-bar-visible", (_event) => { - if (win) { - const menuBarVisible = win.isMenuBarVisible(); - _event.reply("is-window-menu-bar-visible-reply", menuBarVisible); - } - }); + }); + } } +// // ----------------- Get 系列操作(使用全局 ipcMain) ----------------- + +// // 获取窗口位置 +// ipcMain.on("get-window-position", (_event) => { +// if (checkWindow()) { +// const [x, y] = win.getPosition(); +// return { x, y }; +// } +// }); + +// // 获取窗口大小 +// ipcMain.on("get-window-size", (_event) => { +// if (checkWindow()) { +// const [width, height] = win.getSize(); +// return { width, height }; +// } +// }); + +// // 获取窗口标题 +// ipcMain.on("get-window-title", (_event) => { +// if (checkWindow()) { +// const title = win.getTitle(); +// return title; +// } +// }); + +// // 获取窗口背景色 +// ipcMain.on("get-window-background-color", (_event) => { +// if (checkWindow()) { +// const color = win.getBackgroundColor(); +// return color; +// } +// }); + +// // 获取窗口透明度 +// ipcMain.on("get-window-opacity", (_event) => { +// if (checkWindow()) { +// const opacity = win.getOpacity(); +// return opacity; +// } +// }); + +// // 获取窗口是否可见 +// ipcMain.on("is-window-visible", (_event) => { +// if (checkWindow()) { +// const visible = win.isVisible(); +// return visible; +// } +// }); + +// // 获取窗口是否最大化 +// ipcMain.on("is-window-maximized", (_event) => { +// if (checkWindow()) { +// const maximized = win.isMaximized(); +// return maximized; +// } +// }); + +// // 获取窗口是否最小化 +// ipcMain.on("is-window-minimized", (_event) => { +// if (checkWindow()) { +// const minimized = win.isMinimized(); +// return minimized; +// } +// }); + +// // 获取窗口是否全屏 +// ipcMain.on("is-window-full-screen", (_event) => { +// if (checkWindow()) { +// const fullScreen = win.isFullScreen(); +// return fullScreen; +// } +// }); + +// // 获取窗口是否可以改变大小 +// ipcMain.on("is-window-resizable", (_event) => { +// if (checkWindow()) { +// const resizable = win.isResizable(); +// return resizable; +// } +// }); + +// // 获取窗口是否在所有工作区可见 +// ipcMain.on("is-window-visible-on-all-workspaces", (_event) => { +// if (checkWindow()) { +// const visibleOnAllWorkspaces = win.isVisibleOnAllWorkspaces(); +// return visibleOnAllWorkspaces; +// } +// }); + +// // 获取窗口是否置顶 +// ipcMain.on("is-window-always-on-top", (_event) => { +// if (checkWindow()) { +// const alwaysOnTop = win.isAlwaysOnTop(); +// return alwaysOnTop; +// } +// }); + +// // 获取窗口是否可移动 +// ipcMain.on("is-window-movable", (_event) => { +// if (checkWindow()) { +// const movable = win.isMovable(); +// return movable; +// } +// }); + +// // 获取窗口是否可最小化 +// ipcMain.on("is-window-minimizable", (_event) => { +// if (checkWindow()) { +// const minimizable = win.isMinimizable(); +// return minimizable; +// } +// }); + +// // 获取窗口是否可最大化 +// ipcMain.on("is-window-maximizable", (_event) => { +// if (checkWindow()) { +// const maximizable = win.isMaximizable(); +// return maximizable; +// } +// }); + +// // 获取窗口是否可关闭 +// ipcMain.on("is-window-closable", (_event) => { +// if (checkWindow()) { +// const closable = win.isClosable(); +// return closable; +// } +// }); + +// // 获取窗口是否在任务栏中显示 +// ipcMain.on("is-window-menu-bar-visible", (_event) => { +// if (checkWindow()) { +// const menuBarVisible = win.isMenuBarVisible(); +// return menuBarVisible; +// } +// }); +// } diff --git a/electron/main.ts b/electron/main.ts index dd363e6..706db99 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -1,23 +1,11 @@ import { app, BrowserWindow, ipcMain } from "electron"; import { fileURLToPath } from "node:url"; import setupIpcHandlers from "./ipc"; - import path from "node:path"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -// The built directory structure -// -// ├─┬─┬ dist -// │ │ └── index.html -// │ │ -// │ ├─┬ dist-electron -// │ │ ├── main.js -// │ │ └── preload.mjs -// │ process.env.APP_ROOT = path.join(__dirname, ".."); - -// 🚧 Use ['ENV_NAME'] avoid vite:define plugin - Vite@2.x export const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"]; export const MAIN_DIST = path.join(process.env.APP_ROOT, "dist-electron"); export const RENDERER_DIST = path.join(process.env.APP_ROOT, "dist"); @@ -26,15 +14,9 @@ process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL ? path.join(process.env.APP_ROOT, "public") : RENDERER_DIST; -let wins: Array = []; // Store all windows +let wins: Array = []; -/** - * - * @param route 需要加载的URL路径 - * @param width 设置窗口宽度 - * @param height 设置窗口高度 - * @param frame 是否显示窗口边框 - */ +// 创建新窗口 function createNewWindow( route: string, width: number, @@ -73,7 +55,7 @@ function createNewWindow( const finalRoute = route.startsWith("/") ? route : "/" + route; - //加载html文件 + // 加载URL或者本地HTML if (VITE_DEV_SERVER_URL) { const fullUrl = `${VITE_DEV_SERVER_URL}#${finalRoute}`; newWin.loadURL(fullUrl); @@ -83,23 +65,27 @@ function createNewWindow( newWin.loadFile(indexPath, { hash: finalRoute }); } - // 等待加载完后再展示窗口 + // 窗口加载完成后显示并发送消息 newWin.webContents.on("did-finish-load", () => { - newWin.show(); - newWin.webContents.send( - "main-process-message", - new Date().toLocaleString() - ); + if (!newWin.isDestroyed()) { + newWin.show(); + newWin.webContents.send( + "main-process-message", + new Date().toLocaleString() + ); + } }); + // 窗口关闭时处理 newWin.on("closed", () => { const index = wins.indexOf(newWin); - //将销毁的窗口从数组中删除 - if (index !== -1) wins.splice(index, 1); + if (index !== -1) { + wins.splice(index, 1); + } + newWin.removeAllListeners(); }); - //设置IPC通信 - setupIpcHandlers(newWin); + setupIpcHandlers(newWin); // 设置IPC处理 wins.push(newWin); } @@ -109,7 +95,6 @@ app.on("window-all-closed", () => { app.quit(); wins.forEach((win) => { win.destroy(); - win = null; }); wins = []; } @@ -121,7 +106,7 @@ app.on("activate", () => { } }); -//打开应用程序时创建初始窗口 +// 应用程序准备好后创建初始窗口 app.whenReady().then(() => { createNewWindow( "/", @@ -140,38 +125,35 @@ app.whenReady().then(() => { ); }); -ipcMain.on( - "create-new-window", - ( - _event, - route: string, - width: number, - height: number, - frame: boolean = true, - hideMenuBar: boolean = true, - resizable: boolean = true, - movable: boolean = true, - minimizable: boolean = true, - maximizable: boolean = true, - fullScreen: boolean = false, - alwaysOnTop: boolean = false, - inTaskbar: boolean = true, - opacity: number = 1 - ) => { - createNewWindow( - route, - width, - height, - frame, - hideMenuBar, - resizable, - movable, - minimizable, - maximizable, - fullScreen, - alwaysOnTop, - inTaskbar, - opacity - ); - } -); +ipcMain.on("create-new-window", ( + _event, + route: string, + width: number, + height: number, + frame: boolean = true, + hideMenuBar: boolean = true, + resizable: boolean = true, + movable: boolean = true, + minimizable: boolean = true, + maximizable: boolean = true, + fullScreen: boolean = false, + alwaysOnTop: boolean = false, + inTaskbar: boolean = true, + opacity: number = 1 +) => { + createNewWindow( + route, + width, + height, + frame, + hideMenuBar, + resizable, + movable, + minimizable, + maximizable, + fullScreen, + alwaysOnTop, + inTaskbar, + opacity + ); +}); diff --git a/electron/preload.ts b/electron/preload.ts index 1d178c4..27943ff 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -86,6 +86,10 @@ contextBridge.exposeInMainWorld("electron", { setWindowInTaskbar: (inTaskbar: boolean) => ipcRenderer.send("set-window-in-taskbar", inTaskbar), + //设置窗口最小大小 + setMinimumSize: (width: number, height: number) => + ipcRenderer.send("set-window-min-size", width, height), + // 窗口操作 minimizeWindow: () => ipcRenderer.send("minimize-window"), maximizeWindow: () => ipcRenderer.send("maximize-window"), diff --git a/package.json b/package.json index eca68b7..f2ed27b 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,5 @@ "vue-tsc": "^2.0.26" }, "main": "dist-electron/main.js", - "build": { - "publish": null - } + "build-icon": "electron-icon-builder --input=./public/favicon.png --output=public --flatten" } \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index 1be21bf..dfded7c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,4 +1,6 @@ - + @@ -79,6 +79,7 @@ const props = defineProps<{ .message-list-item-right{ gap: 8px; + align-items: flex-end; #date{ font-size: 10px; color: var(--tip-grey-fore-color); diff --git a/src/components/mainwindow/SideBar.vue b/src/components/mainwindow/SideBar.vue index c408786..3ac5680 100644 --- a/src/components/mainwindow/SideBar.vue +++ b/src/components/mainwindow/SideBar.vue @@ -6,9 +6,9 @@ date: 2025-04-07