feat: 工具栏动态宽度 - 根据内容自动调整窗口宽度

This commit is contained in:
2026-07-16 09:35:11 +08:00
parent cc40cd5524
commit 499a55af77
4 changed files with 48 additions and 16 deletions
+5
View File
@@ -81,6 +81,11 @@ export function setupIpc(win: BrowserWindow): void {
win.setPosition(x, y) win.setPosition(x, y)
}) })
ipcMain.handle('window:resizeMain', (_event, width: number) => {
const [wx, wy] = win.getPosition()
win.setBounds({ x: wx, y: wy, width: Math.max(200, Math.min(width, 1200)), height: 64 })
})
ipcMain.handle('screenshot:start', () => { ipcMain.handle('screenshot:start', () => {
log.info('IPC: screenshot:start') log.info('IPC: screenshot:start')
startScreenshot(win) startScreenshot(win)
+2 -1
View File
@@ -3,7 +3,8 @@ import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', { contextBridge.exposeInMainWorld('electronAPI', {
window: { window: {
dragMove: (deltaX: number, deltaY: number) => ipcRenderer.invoke('window:dragMove', { deltaX, deltaY }), dragMove: (deltaX: number, deltaY: number) => ipcRenderer.invoke('window:dragMove', { deltaX, deltaY }),
dragEnd: (x: number, y: number) => ipcRenderer.invoke('window:dragEnd', { x, y }) dragEnd: (x: number, y: number) => ipcRenderer.invoke('window:dragEnd', { x, y }),
resizeMain: (width: number) => ipcRenderer.invoke('window:resizeMain', width)
}, },
screenshot: { screenshot: {
+40 -15
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="floating-toolbar" :class="{ 'is-hidden': !appStore.isToolbarVisible }"> <div ref="toolbarRef" class="floating-toolbar" :class="{ 'is-hidden': !appStore.isToolbarVisible }">
<div class="toolbar-buttons"> <div class="toolbar-buttons">
<el-button class="toolbar-btn" @click="startScreenshot" :loading="appStore.isGrading"> <el-button class="toolbar-btn" @click="startScreenshot" :loading="appStore.isGrading">
<span class="btn-icon">📷</span> <span class="btn-icon">📷</span>
@@ -11,19 +11,26 @@
<span class="btn-label">评分标准</span> <span class="btn-label">评分标准</span>
</el-button> </el-button>
<el-dropdown trigger="click" @command="handleMenu"> <template v-if="!showMenu">
<el-button class="toolbar-btn"> <el-button class="toolbar-btn" @click="showMenu = true">
<span class="btn-icon">📎</span> <span class="btn-icon">📎</span>
<span class="btn-label">其它</span> <span class="btn-label">其它</span>
</el-button> </el-button>
<template #dropdown> </template>
<el-dropdown-menu> <template v-else>
<el-dropdown-item command="image">📁 图片阅卷</el-dropdown-item> <el-button class="toolbar-btn sub-btn" @click="showMenu = false; selectImage()">
<el-dropdown-item command="templates">📚 模板</el-dropdown-item> <span class="btn-icon">📁</span>
<el-dropdown-item command="history">📜 历史</el-dropdown-item> <span class="btn-label">图片阅卷</span>
</el-dropdown-menu> </el-button>
</template> <el-button class="toolbar-btn sub-btn" @click="showMenu = false; openTemplates()">
</el-dropdown> <span class="btn-icon">📚</span>
<span class="btn-label">模板</span>
</el-button>
<el-button class="toolbar-btn sub-btn" @click="showMenu = false; openHistory()">
<span class="btn-icon">📜</span>
<span class="btn-label">历史</span>
</el-button>
</template>
<el-button class="toolbar-btn" @click="openSettings"> <el-button class="toolbar-btn" @click="openSettings">
<span class="btn-icon"></span> <span class="btn-icon"></span>
@@ -34,7 +41,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted } from 'vue' import { ref, nextTick, watch, onMounted, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { useAppStore } from '@/stores/app' import { useAppStore } from '@/stores/app'
import { useGradingStore } from '@/stores/grading' import { useGradingStore } from '@/stores/grading'
@@ -44,9 +51,23 @@ const appStore = useAppStore()
const gradingStore = useGradingStore() const gradingStore = useGradingStore()
const settingsStore = useSettingsStore() const settingsStore = useSettingsStore()
const showMenu = ref(false)
const toolbarRef = ref<HTMLElement | null>(null)
async function resizeWindow() {
await nextTick()
if (toolbarRef.value && window.electronAPI) {
const w = toolbarRef.value.scrollWidth + 2
window.electronAPI.window.resizeMain(w)
}
}
watch(showMenu, resizeWindow)
let cleanupScreenshotListener: (() => void) | null = null let cleanupScreenshotListener: (() => void) | null = null
onMounted(() => { onMounted(() => {
resizeWindow()
if (window.electronAPI) { if (window.electronAPI) {
cleanupScreenshotListener = window.electronAPI.screenshot.onCompleted((base64: string) => { cleanupScreenshotListener = window.electronAPI.screenshot.onCompleted((base64: string) => {
if (!appStore.isGrading) { if (!appStore.isGrading) {
@@ -157,7 +178,11 @@ function openSettings() { window.electronAPI?.dialog.open('settings') }
<style scoped> <style scoped>
.floating-toolbar { .floating-toolbar {
position: fixed; position: fixed;
inset: 0; top: 0;
left: 0;
width: fit-content;
min-width: 200px;
height: 64px;
z-index: 99999; z-index: 99999;
user-select: none; user-select: none;
-webkit-app-region: drag; -webkit-app-region: drag;
@@ -177,8 +202,8 @@ function openSettings() { window.electronAPI?.dialog.open('settings') }
height: 100%; height: 100%;
} }
.toolbar-buttons :deep(.el-dropdown) { .sub-btn {
-webkit-app-region: no-drag; padding: 4px 8px !important;
} }
.toolbar-btn { .toolbar-btn {
+1
View File
@@ -46,6 +46,7 @@ export interface ElectronAPI {
window: { window: {
dragMove: (deltaX: number, deltaY: number) => Promise<void> dragMove: (deltaX: number, deltaY: number) => Promise<void>
dragEnd: (x: number, y: number) => Promise<void> dragEnd: (x: number, y: number) => Promise<void>
resizeMain: (width: number) => Promise<void>
} }
screenshot: { screenshot: {
start: () => Promise<void> start: () => Promise<void>