diff --git a/frontend/package.json b/frontend/package.json
index f3c0b5e..23e073c 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
- "version": "0.0.1",
+ "version": "1.0.1",
"main": "dist-electron/main.js",
"scripts": {
"dev": "concurrently \"vite\" \"yarn watch:main\" \"yarn electron-dev\"",
diff --git a/frontend/src/components/TitleBar.vue b/frontend/src/components/TitleBar.vue
index 05e0af8..ef20330 100644
--- a/frontend/src/components/TitleBar.vue
+++ b/frontend/src/components/TitleBar.vue
@@ -7,6 +7,12 @@
AUTO-MAS
+
+ v{{ version }}
+
+ 检测到更新 {{ updateInfo.latest_version }} 请尽快更新
+
+
@@ -16,26 +22,18 @@
-
@@ -47,10 +45,47 @@
import { ref, onMounted } from 'vue'
import { MinusOutlined, BorderOutlined, CopyOutlined, CloseOutlined } from '@ant-design/icons-vue'
import { useTheme } from '@/composables/useTheme'
+import { Service } from '@/api'
+import type { UpdateCheckOut } from '@/api'
const { isDark } = useTheme()
const isMaximized = ref(false)
+// 使用 import.meta.env 或直接定义版本号,确保打包后可用
+const version = import.meta.env.VITE_APP_VERSION || '获取版本失败!'
+const updateInfo = ref
(null)
+
+// 获取是否有更新
+const getAppVersion = async () => {
+ try {
+ const ver = await Service.checkUpdateApiUpdateCheckPost({
+ current_version: version,
+ })
+ updateInfo.value = ver
+ return ver || '获取版本失败!'
+ } catch (error) {
+ console.error('Failed to get app version:', error)
+ return '获取版本失败!'
+ }
+}
+
+// 生成更新提示的详细信息
+const getUpdateTooltip = () => {
+ if (!updateInfo.value?.update_info) return ''
+
+ const updateDetails = []
+ for (const [category, items] of Object.entries(updateInfo.value.update_info)) {
+ if (items && items.length > 0) {
+ updateDetails.push(`${category}:`)
+ items.forEach(item => {
+ updateDetails.push(`• ${item}`)
+ })
+ updateDetails.push('')
+ }
+ }
+ return updateDetails.join('\n')
+}
+
const minimizeWindow = async () => {
try {
await window.electronAPI?.windowMinimize()
@@ -62,7 +97,7 @@ const minimizeWindow = async () => {
const toggleMaximize = async () => {
try {
await window.electronAPI?.windowMaximize()
- isMaximized.value = await window.electronAPI?.windowIsMaximized() || false
+ isMaximized.value = (await window.electronAPI?.windowIsMaximized()) || false
} catch (error) {
console.error('Failed to toggle maximize:', error)
}
@@ -78,10 +113,11 @@ const closeWindow = async () => {
onMounted(async () => {
try {
- isMaximized.value = await window.electronAPI?.windowIsMaximized() || false
+ isMaximized.value = (await window.electronAPI?.windowIsMaximized()) || false
} catch (error) {
console.error('Failed to get window state:', error)
}
+ await getAppVersion()
})
@@ -124,11 +160,11 @@ onMounted(async () => {
left: 55px; /* 调整:更贴近图标 */
top: 50%;
transform: translate(-50%, -50%);
- width: 200px; /* 缩小尺寸以适配 32px 高度 */
+ width: 200px; /* 缩小尺寸以适配 32px 高度 */
height: 100px;
pointer-events: none;
border-radius: 50%;
- background: radial-gradient(circle at 50% 50%, var(--ant-color-primary) 0%, rgba(0,0,0,0) 70%);
+ background: radial-gradient(circle at 50% 50%, var(--ant-color-primary) 0%, rgba(0, 0, 0, 0) 70%);
filter: blur(24px); /* 降低模糊避免越界过多 */
opacity: 0.4;
z-index: 0;
@@ -153,10 +189,23 @@ onMounted(async () => {
z-index: 1;
}
+.version-text {
+ font-size: 13px;
+ font-weight: 400;
+ opacity: 0.8;
+ position: relative;
+ z-index: 1;
+ margin-left: 4px;
+}
+
.title-bar-dark .title-text {
color: #fff;
}
+.title-bar-dark .version-text {
+ color: #ffffff;
+}
+
.title-bar-center {
flex: 1;
height: 100%;
@@ -218,4 +267,79 @@ onMounted(async () => {
.title-bar-dark .maximize-button:hover {
background: rgba(255, 255, 255, 0.15);
}
-
\ No newline at end of file
+
+.update-hint {
+ font-weight: 500;
+ margin-left: 4px;
+ cursor: help;
+ background: linear-gradient(45deg, #ff0000, #ff7f00, #ffff00, #00ff00, #8b00ff, #ff0000);
+ background-size: 400% 400%;
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+ animation:
+ rainbow-flow 3s ease-in-out infinite,
+ glow-pulse 2s ease-in-out infinite;
+ position: relative;
+}
+
+.update-hint::before {
+ content: '';
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ background: linear-gradient(45deg, #ff0000, #ff7f00, #ffff00, #00ff00, #8b00ff, #ff0000);
+ background-size: 400% 400%;
+ border-radius: 4px;
+ z-index: -1;
+ opacity: 0.3;
+ filter: blur(8px);
+ animation: rainbow-flow 3s ease-in-out infinite;
+}
+
+.title-bar-dark .update-hint::before {
+ opacity: 0.5;
+ filter: blur(10px);
+}
+
+@keyframes rainbow-flow {
+ 0% {
+ background-position: 0% 50%;
+ }
+ 50% {
+ background-position: 100% 50%;
+ }
+ 100% {
+ background-position: 0% 50%;
+ }
+}
+
+@keyframes glow-pulse {
+ 0% {
+ filter: brightness(1) saturate(1);
+ transform: scale(1);
+ }
+ 50% {
+ filter: brightness(1.2) saturate(1.3);
+ transform: scale(1.02);
+ }
+ 100% {
+ filter: brightness(1) saturate(1);
+ transform: scale(1);
+ }
+}
+
+@keyframes pulse {
+ 0% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0.7;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
diff --git a/frontend/src/types/electron.ts b/frontend/src/types/electron.ts
index 11f134f..571c95c 100644
--- a/frontend/src/types/electron.ts
+++ b/frontend/src/types/electron.ts
@@ -5,9 +5,18 @@ export interface ElectronAPI {
selectFolder: () => Promise
selectFile: (filters?: Array<{ name: string; extensions: string[] }>) => Promise
+ // 窗口控制
+ windowMinimize: () => Promise
+ windowMaximize: () => Promise
+ windowClose: () => Promise
+ windowIsMaximized: () => Promise
+
// 管理员权限检查
checkAdmin: () => Promise
+ // 重启为管理员
+ restartAsAdmin: () => Promise
+
// 环境检查
checkEnvironment: () => Promise<{
pythonExists: boolean
@@ -53,7 +62,6 @@ export interface ElectronAPI {
callback: (progress: { progress: number; status: string; message: string }) => void
) => void
removeDownloadProgressListener: () => void
- restartAsAdmin: () => Promise
}
declare global {
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index 0611bc6..aedce55 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -2,6 +2,9 @@ import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
+// 读取package.json中的版本号
+const packageJson = require('./package.json')
+
// https://vite.dev/config/
export default defineConfig({
plugins: [vue()],
@@ -12,4 +15,8 @@ export default defineConfig({
'@': path.resolve(__dirname, './src'),
},
},
+ define: {
+ // 在编译时将版本号注入到环境变量中
+ 'import.meta.env.VITE_APP_VERSION': JSON.stringify(packageJson.version)
+ }
})