From 9838a7f0255230c19f77b5914cbe182e88997b96 Mon Sep 17 00:00:00 2001 From: zhaojisen <1301338853@qq.com> Date: Fri, 16 Jan 2026 17:39:45 +0800 Subject: [PATCH] perf: Optimize some details --- src-tauri/src/lib.rs | 28 +++++++++ ui/components/Header/ActionButtons.vue | 5 +- ui/composables/useAssetAction.ts | 67 ++++++++++++---------- ui/layouts/setting.vue | 79 ++++++++++++++++++++++++-- 4 files changed, 142 insertions(+), 37 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 0c30fc9..e49fdb3 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -30,11 +30,39 @@ use tauri::Manager; use tauri_plugin_deep_link::DeepLinkExt; use tauri_plugin_single_instance::init as single_instance; +fn raise_main_window_for_auth(handle: &tauri::AppHandle) { + let Some(win) = handle.get_webview_window("main") else { + warn!("main window not found, cannot raise for auth callback"); + return; + }; + + let _ = win.unminimize(); + let _ = win.show(); + let _ = win.set_focus(); + + let was_always_on_top = win.is_always_on_top().unwrap_or(false); + if let Err(e) = win.set_always_on_top(true) { + warn!("Failed to set main window always on top: {}", e); + return; + } + + if !was_always_on_top { + let app_handle = handle.clone(); + tauri::async_runtime::spawn(async move { + tokio::time::sleep(std::time::Duration::from_millis(1500)).await; + if let Some(win) = app_handle.get_webview_window("main") { + let _ = win.set_always_on_top(false); + } + }); + } +} + fn process_deep_link(handle: &tauri::AppHandle, raw: &str) -> bool { info!("deep link received: {}", raw); if is_auth_callback(raw) { info!("deep link is auth callback, handling in current instance"); + raise_main_window_for_auth(handle); let flow_state = handle.state::(); handle_auth_callback(&flow_state, raw); return false; diff --git a/ui/components/Header/ActionButtons.vue b/ui/components/Header/ActionButtons.vue index 3114703..5224ea5 100644 --- a/ui/components/Header/ActionButtons.vue +++ b/ui/components/Header/ActionButtons.vue @@ -195,6 +195,7 @@ const actionItems = computed(() => [ // 直接创建窗口 // eslint-disable-next-line no-new + const isMac = isMacOS.value; new useTauriWebviewWindowWebviewWindow(label, { title: t("Common.ConnectionSettings"), url: localePath({ path: "/setting" }), @@ -204,7 +205,9 @@ const actionItems = computed(() => [ maxHeight: 675, hiddenTitle: true, titleBarStyle: "overlay", - trafficLightPosition: new LogicalPosition(10, 22) + trafficLightPosition: new LogicalPosition(10, 22), + decorations: isMac, + shadow: isMac }); } } diff --git a/ui/composables/useAssetAction.ts b/ui/composables/useAssetAction.ts index 4e42e0a..fdf48be 100644 --- a/ui/composables/useAssetAction.ts +++ b/ui/composables/useAssetAction.ts @@ -58,8 +58,8 @@ export const useAssetAction = () => { const settingManager = useSettingManager(); // prettier-ignore const { currentSite, currentUser, currentConnectionInfoMap, currentRdpClientOption, orgId } = storeToRefs(userInfoStore); - const { charset, rdpResolution, backspaceAsCtrlH, keyboardLayout, rdpClientOption, rdpColorQuality, rdpSmartSize } - = settingManager; + const { charset, rdpResolution, backspaceAsCtrlH, keyboardLayout, rdpClientOption, rdpColorQuality, rdpSmartSize } = + settingManager; function buildLocalRdpParams() { const prefs = resolveGraphicsPreferences(); @@ -92,10 +92,10 @@ export const useAssetAction = () => { * @description 生成连接选项 */ function resolveGraphicsPreferences() { - const resolvedKeyboardLayout - = keyboardLayout.value || currentRdpClientOption.value.keyboard_layout || "en-us-qwerty"; - const resolvedClientOptions - = Array.isArray(rdpClientOption.value) && rdpClientOption.value.length > 0 + const resolvedKeyboardLayout = + keyboardLayout.value || currentRdpClientOption.value.keyboard_layout || "en-us-qwerty"; + const resolvedClientOptions = + Array.isArray(rdpClientOption.value) && rdpClientOption.value.length > 0 ? [...rdpClientOption.value] : [...(currentRdpClientOption.value.rdp_client_option || [])]; const resolvedColorQuality = rdpColorQuality.value || currentRdpClientOption.value.rdp_color_quality || "32"; @@ -152,8 +152,8 @@ export const useAssetAction = () => { // prettier-ignore const isManual = saved?.accountMode === "manual" || username === "手动输入" || username === "Manual input"; - const isDynamic - = saved?.accountMode === "dynamic" || username.includes("同名账号") || username.includes("Dynamic user"); + const isDynamic = + saved?.accountMode === "dynamic" || username.includes("同名账号") || username.includes("Dynamic user"); // 已保存过托管账号的 ID 则优先使用 if (!isManual && !isDynamic && saved?.accountId) { @@ -249,10 +249,10 @@ export const useAssetAction = () => { accounts?: PermedAccount[], protocolOverride?: string, ephemeral?: { - accountMode?: "hosted" | "dynamic" | "manual" - manualUsername?: string - manualPassword?: string - dynamicPassword?: string + accountMode?: "hosted" | "dynamic" | "manual"; + manualUsername?: string; + manualPassword?: string; + dynamicPassword?: string; } ) => { const saved = currentConnectionInfoMap.value[assetId]; @@ -377,8 +377,8 @@ export const useAssetAction = () => { try { unlistenGetTokenSuccess = await useTauriEventListen("get-token-success", (event) => { interface eventPayload { - status: number - data: TokenResponse + status: number; + data: TokenResponse; } const payload = event.payload as eventPayload; @@ -390,8 +390,8 @@ export const useAssetAction = () => { unlistenGetTokenFailure = await useTauriEventListen("get-token-failure", (event) => { interface eventPayload { - status: number - data: string + status: number; + data: string; } const payload = event.payload as eventPayload; @@ -421,7 +421,7 @@ export const useAssetAction = () => { unlistenFavoriteSuccess = await useTauriEventListen("set-favorite-success", (event) => { interface eventPayload { - status: string + status: string; } const payload = event.payload as eventPayload; @@ -438,7 +438,7 @@ export const useAssetAction = () => { unlistenFavoriteFailed = await useTauriEventListen("set-favorite-failure", (event) => { interface eventPayload { - status: string + status: string; } const payload = event.payload as eventPayload; @@ -455,7 +455,7 @@ export const useAssetAction = () => { unlistenUnfavoriteSuccess = await useTauriEventListen("unfavorite-success", (event) => { interface eventPayload { - status: string + status: string; } const payload = event.payload as eventPayload; @@ -473,7 +473,7 @@ export const useAssetAction = () => { unlistenUnfavoriteFailed = await useTauriEventListen("unfavorite-failure", (event) => { interface eventPayload { - status: string + status: string; } const payload = event.payload as eventPayload; @@ -490,9 +490,9 @@ export const useAssetAction = () => { unlistenGetAssetDetailSuccess = await useTauriEventListen("get-asset-detail-success", (event) => { interface eventPayload { - status: string - data: string - asset_id: string + status: string; + data: string; + asset_id: string; } const payload = event.payload as eventPayload; @@ -502,10 +502,15 @@ export const useAssetAction = () => { const permedAccounts = assetDetail.permed_accounts ?? []; const permedProtocols = assetDetail.permed_protocols ?? []; + // 不支持目录服务的 winrm 协议 + const filteredPermedProtocols = permedProtocols.filter( + (protocol: PermedProtocol) => protocol.name !== "winrm" + ); + useEventBus().emit("assetDetailUpdated", { assetId: payload.asset_id, permedAccounts, - permedProtocols + permedProtocols: filteredPermedProtocols }); } }); @@ -519,9 +524,9 @@ export const useAssetAction = () => { unlistenRenameSuccess = await useTauriEventListen("rename-success", (event) => { interface eventPayload { - success: boolean - status?: number - data?: string + success: boolean; + status?: number; + data?: string; } const payload = event.payload as eventPayload; @@ -546,9 +551,9 @@ export const useAssetAction = () => { unlistenRenameError = await useTauriEventListen("rename-error", (event) => { interface eventPayload { - success: boolean - status?: number - data?: string + success: boolean; + status?: number; + data?: string; } const payload = event.payload as eventPayload; @@ -570,7 +575,7 @@ export const useAssetAction = () => { unlistenPullUpFailure = await useTauriEventListen("pull-up-failure", (event) => { interface eventPayload { - error: string + error: string; } const payload = event.payload as eventPayload; diff --git a/ui/layouts/setting.vue b/ui/layouts/setting.vue index 19dd687..c680d91 100644 --- a/ui/layouts/setting.vue +++ b/ui/layouts/setting.vue @@ -4,9 +4,60 @@ import type { NavigationMenuItem } from "@nuxt/ui"; const localePath = useLocalePath(); const { t } = useI18n(); +const { isMacOS } = usePlatform(); const { theme } = useSettingManager(); const { initialTheme, listenOSThemeChange } = useThemeAdapter(); +const commonButtonProps = { + size: "sm" as const, + variant: "ghost" as const, + color: "neutral" as const +}; + +const windowControlButtons = computed(() => { + return [ + { + key: "minimize", + iconName: "i-lucide-minus", + tooltipLabel: t("ToolTips.Minimize"), + onClick: async () => { + await useTauriCoreInvoke("minimize_window"); + } + }, + { + key: "maximize", + iconName: "i-lucide-square", + tooltipLabel: t("ToolTips.Maximize"), + onClick: async () => { + await useTauriCoreInvoke("toggle_maximize_window"); + } + }, + { + key: "close", + iconName: "i-lucide-x", + tooltipLabel: t("ToolTips.Close"), + onClick: async () => { + await useTauriCoreInvoke("close_window"); + } + } + ]; +}); + +const getWindowControlButtonClass = (buttonKey: string) => { + const baseClass = "rounded-none w-12 h-13 p-1 flex items-center justify-center"; + + switch (buttonKey) { + case "minimize": + return `${baseClass} `; + case "maximize": + return `${baseClass} `; + case "close": + return `${baseClass} hover:bg-red-500 hover:text-white active:bg-red-600`; + default: + return baseClass; + } +}; + const settingMenu = computed(() => { return [ { @@ -50,14 +101,32 @@ onMounted(() => { >