11<template >
2- <div class =" menu-container" >
2+ <div class =" menu-container" style =" --wails-draggable :drag" @dblclick =" handleTitlebarDblClick" >
3+ <!-- 窗口控制按钮 -->
4+ <div class =" window-controls" :class =" isWindows ? 'windows-style' : 'mac-style'" >
5+ <template v-if =" isWindows " >
6+ <!-- Windows 风格 -->
7+ <button class =" window-btn windows-btn" @click =" windowMinimize" title =" 最小化" >
8+ <svg viewBox =" 0 0 10 10" class =" icon-minimize" ><path d =" M0 5h10" stroke =" currentColor" stroke-width =" 1" /></svg >
9+ </button >
10+ <button class =" window-btn windows-btn" @click =" windowMaximize" :title =" isMaximized ? '还原' : '最大化'" >
11+ <svg v-if =" !isMaximized" viewBox =" 0 0 10 10" class =" icon-maximize" ><rect x =" 0.5" y =" 0.5" width =" 9" height =" 9" stroke =" currentColor" fill =" none" stroke-width =" 1" /></svg >
12+ <svg v-else viewBox =" 0 0 10 10" class =" icon-restore" >
13+ <path d =" M3 1.5H8.5V7H7.5V2.5H3V1.5Z" fill =" currentColor" />
14+ <path d =" M1.5 3H7V8.5H1.5V3ZM2.5 4V7.5H6V4H2.5Z" fill =" currentColor" />
15+ </svg >
16+ </button >
17+ <button class =" window-btn windows-btn close-btn windows-close" @click =" windowClose" title =" 关闭" >
18+ <svg viewBox =" 0 0 10 10" class =" icon-close" ><path d =" M0 0L10 10M10 0L0 10" stroke =" currentColor" stroke-width =" 1" /></svg >
19+ </button >
20+ </template >
21+ <template v-else >
22+ <!-- macOS 风格 -->
23+ <button class =" window-btn mac-btn close-btn" @click =" windowClose" title =" 关闭" ></button >
24+ <button class =" window-btn mac-btn minimize-btn" @click =" windowMinimize" title =" 最小化" ></button >
25+ <button class =" window-btn mac-btn maximize-btn" @click =" windowMaximize" title =" 最大化" ></button >
26+ </template >
27+ </div >
28+
329 <el-menu router :default-active =" activeIndex" class =" el-menu" mode =" horizontal"
430 text-color =" var(--text-primary)"
531 active-text-color =" var(--accent-color)"
2551</template >
2652
2753<script lang="ts" setup>
28- import { ref , computed } from ' vue'
54+ import { ref , computed , onMounted } from ' vue'
2955import { useRouter , useRoute } from ' vue-router'
3056import { Moon , Sunny } from ' @element-plus/icons-vue'
3157import MenuItem from ' ./MenuItem.vue'
3258import { themeStore } from ' ../stores/theme'
59+ import { Environment , Quit , WindowIsMaximised , WindowMinimise , WindowToggleMaximise } from ' ../../wailsjs/runtime'
3360
3461const route = useRoute ()
3562const router = useRouter ()
@@ -44,6 +71,58 @@ const toggleDark = () => {
4471 console .log (' 切换后状态:' , store .isDark )
4572}
4673
74+ const isWindows = ref (false )
75+ const isMaximized = ref (false )
76+
77+ const initPlatform = async () => {
78+ try {
79+ const env = await Environment ()
80+ isWindows .value = env .platform === ' windows'
81+ if (isWindows .value ) {
82+ await syncMaximizedState ()
83+ }
84+ } catch {
85+ isWindows .value = false
86+ }
87+ }
88+
89+ const syncMaximizedState = async () => {
90+ try {
91+ isMaximized .value = await WindowIsMaximised ()
92+ } catch {
93+ isMaximized .value = false
94+ }
95+ }
96+
97+ onMounted (() => {
98+ initPlatform ()
99+ })
100+
101+ const windowClose = () => {
102+ Quit ()
103+ }
104+
105+ const windowMinimize = () => {
106+ WindowMinimise ()
107+ }
108+
109+ const windowMaximize = async () => {
110+ WindowToggleMaximise ()
111+ await syncMaximizedState ()
112+ }
113+
114+ const handleTitlebarDblClick = async (event : MouseEvent ) => {
115+ if (! isWindows .value ) {
116+ return
117+ }
118+ const target = event .target as HTMLElement | null
119+ const ignore = target ?.closest (' .window-controls, .theme-switch-container, .el-menu' )
120+ if (ignore ) {
121+ return
122+ }
123+ await windowMaximize ()
124+ }
125+
47126const allRoutes = router .options .routes .filter (route =>
48127 route .meta ?.name !== ' 主题' // 过滤掉主题页面
49128)
@@ -192,4 +271,85 @@ const handleSelect = (key: string, keyPath: string[]) => {
192271 background-color : var (--card-hover-bg ) !important ;
193272 border-bottom-color : var (--accent-color ) !important ;
194273}
195- </style >
274+
275+ /* 窗口控制按钮通用样式 */
276+ .window-controls {
277+ display : flex ;
278+ align-items : center ;
279+ padding : 0 12px ;
280+ margin-right : 16px ;
281+ -webkit-app-region : no-drag;
282+ }
283+
284+ .window-controls.mac-style {
285+ gap : 8px ;
286+ }
287+
288+ .window-controls.windows-style {
289+ gap : 4px ;
290+ }
291+
292+ .window-btn {
293+ border : none ;
294+ cursor : pointer ;
295+ transition : opacity 0.2s ease ;
296+ display : flex ;
297+ align-items : center ;
298+ justify-content : center ;
299+ }
300+
301+ /* macOS 风格按钮 */
302+ .mac-btn {
303+ width : 12px ;
304+ height : 12px ;
305+ border-radius : 50% ;
306+ }
307+
308+ .mac-btn :hover {
309+ opacity : 0.8 ;
310+ }
311+
312+ .mac-btn.close-btn {
313+ background-color : #ff5f57 ;
314+ }
315+
316+ .mac-btn.minimize-btn {
317+ background-color : #febc2e ;
318+ }
319+
320+ .mac-btn.maximize-btn {
321+ background-color : #28c840 ;
322+ }
323+
324+ /* Windows 风格按钮 */
325+ .windows-btn {
326+ width : 28px ;
327+ height : 28px ;
328+ background : transparent ;
329+ border-radius : 4px ;
330+ }
331+
332+ .windows-btn :hover {
333+ background-color : rgba (255 , 255 , 255 , 0.1 );
334+ }
335+
336+ .windows-btn .icon-minimize ,
337+ .windows-btn .icon-maximize ,
338+ .windows-btn .icon-close {
339+ width : 10px ;
340+ height : 10px ;
341+ color : var (--text-primary );
342+ }
343+
344+ .windows-btn.windows-close :hover {
345+ background-color : #e81123 ;
346+ }
347+
348+ .windows-btn.windows-close .icon-close {
349+ color : var (--text-primary );
350+ }
351+
352+ .windows-btn.windows-close :hover .icon-close {
353+ color : white ;
354+ }
355+ </style >
0 commit comments