From d6ba24ae331bbd5bf351ebb79e7fdf3fbea5c4b0 Mon Sep 17 00:00:00 2001 From: zhangtao Date: Fri, 1 Aug 2025 18:23:53 +0800 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20=E5=AE=9E=E7=8E=B0=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=99=BB=E5=BD=95=E5=92=8C=E9=A1=B9=E7=9B=AE=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增用户登录页面和相关 API - 实现项目列表展示和基本交互 - 添加全局布局组件和路由守卫 - 优化首页界面,增加未登录状态展示 --- src/App.vue | 63 +----- src/api/deploy.js | 12 +- src/api/index.js | 35 ++-- src/api/user.js | 33 +-- src/components/AppLayout.vue | 212 +++++++++++++++++++ src/components/ProjectCard.vue | 178 ++++++++++++++++ src/router/index.js | 45 ++++- src/utils/auth.js | 63 ++++++ src/utils/format.js | 3 + src/views/Home.vue | 358 ++++++++++++++++++++++++--------- src/views/Login.vue | 164 +++++++++++++++ test-build.js | 26 --- vite.config.js | 4 +- 13 files changed, 977 insertions(+), 219 deletions(-) create mode 100644 src/components/AppLayout.vue create mode 100644 src/components/ProjectCard.vue create mode 100644 src/utils/auth.js create mode 100644 src/views/Login.vue delete mode 100644 test-build.js diff --git a/src/App.vue b/src/App.vue index c420305..78168d5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,66 +1,19 @@ - \ No newline at end of file diff --git a/src/components/ProjectCard.vue b/src/components/ProjectCard.vue new file mode 100644 index 0000000..370fe15 --- /dev/null +++ b/src/components/ProjectCard.vue @@ -0,0 +1,178 @@ + + + + + \ No newline at end of file diff --git a/src/router/index.js b/src/router/index.js index 44b22af..a2699b1 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,39 +1,52 @@ import { createRouter, createWebHistory } from 'vue-router' import Home from '@/views/Home.vue' +import Login from '@/views/Login.vue' import Deploy from '@/views/Deploy.vue' import Files from '@/views/Files.vue' import Logs from '@/views/Logs.vue' import Users from '@/views/Users.vue' +import auth from '@/utils/auth' const routes = [ { path: '/', redirect: '/home' }, + { + path: '/login', + name: 'Login', + component: Login, + meta: { requiresAuth: false } + }, { path: '/home', name: 'Home', - component: Home + component: Home, + meta: { requiresAuth: false } // 首页不需要登录 }, { path: '/deploy', name: 'Deploy', - component: Deploy + component: Deploy, + meta: { requiresAuth: true } }, { path: '/files', name: 'Files', - component: Files + component: Files, + meta: { requiresAuth: true } }, { path: '/logs', name: 'Logs', - component: Logs + component: Logs, + meta: { requiresAuth: true } }, { path: '/users', name: 'Users', - component: Users + component: Users, + meta: { requiresAuth: true } } ] @@ -42,4 +55,26 @@ const router = createRouter({ routes }) +// 路由守卫 +router.beforeEach((to, from, next) => { + const isLoggedIn = auth.isLoggedIn() + + // 如果路由需要认证 + if (to.meta.requiresAuth === true) { + // 未登录,跳转到登录页 + if (!isLoggedIn) { + next('/login') + return + } + } + + // 已登录用户访问登录页,跳转到首页 + if (to.path === '/login' && isLoggedIn) { + next('/home') + return + } + + next() +}) + export default router \ No newline at end of file diff --git a/src/utils/auth.js b/src/utils/auth.js new file mode 100644 index 0000000..22c4516 --- /dev/null +++ b/src/utils/auth.js @@ -0,0 +1,63 @@ +import { localStorage } from './storage' + +// Token 相关常量 +const TOKEN_KEY = 'auth_token' +const USER_INFO_KEY = 'user_info' + +// 认证工具类 +class Auth { + // 设置 token + setToken(token) { + localStorage.set(TOKEN_KEY, token) + } + + // 获取 token + getToken() { + return localStorage.get(TOKEN_KEY) + } + + // 移除 token + removeToken() { + localStorage.remove(TOKEN_KEY) + } + + // 设置用户信息 + setUserInfo(userInfo) { + localStorage.set(USER_INFO_KEY, userInfo) + } + + // 获取用户信息 + getUserInfo() { + return localStorage.get(USER_INFO_KEY) + } + + // 移除用户信息 + removeUserInfo() { + localStorage.remove(USER_INFO_KEY) + } + + // 检查是否已登录 + isLoggedIn() { + return !!this.getToken() + } + + // 登出 + logout() { + this.removeToken() + this.removeUserInfo() + } + + // 获取用户权限 + getUserPermissions() { + const userInfo = this.getUserInfo() + return userInfo?.permissions || [] + } + + // 检查用户是否有某个权限 + hasPermission(permission) { + const permissions = this.getUserPermissions() + return permissions.includes(permission) + } +} + +export default new Auth() \ No newline at end of file diff --git a/src/utils/format.js b/src/utils/format.js index 94131e7..2b827e1 100644 --- a/src/utils/format.js +++ b/src/utils/format.js @@ -76,6 +76,9 @@ export function formatRelativeTime(date) { } } +// 别名函数,与ProjectCard组件中的引用保持一致 +export const formatDistanceToNow = formatRelativeTime + /** * 格式化数字 * @param {number} num 数字 diff --git a/src/views/Home.vue b/src/views/Home.vue index 620c4da..4a1fa58 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -1,84 +1,154 @@ \ No newline at end of file diff --git a/src/views/Login.vue b/src/views/Login.vue new file mode 100644 index 0000000..d90ed40 --- /dev/null +++ b/src/views/Login.vue @@ -0,0 +1,164 @@ + + + + + \ No newline at end of file diff --git a/test-build.js b/test-build.js deleted file mode 100644 index ae46068..0000000 --- a/test-build.js +++ /dev/null @@ -1,26 +0,0 @@ -const { execSync } = require('child_process'); - -console.log('🧪 开始测试 DeployHelper 前端项目...\n'); - -try { - // 检查依赖是否安装 - console.log('📦 检查依赖...'); - execSync('npm list --depth=0', { stdio: 'inherit' }); - console.log('✅ 依赖检查通过\n'); - - // 检查构建 - console.log('🔨 测试构建...'); - execSync('npm run build', { stdio: 'inherit' }); - console.log('✅ 构建测试通过\n'); - - console.log('🎉 所有测试通过!项目可以正常运行。'); - console.log('\n📝 使用说明:'); - console.log('1. 开发模式:npm run dev'); - console.log('2. 构建生产版本:npm run build'); - console.log('3. 预览构建结果:npm run preview'); - console.log('\n🌐 访问地址:http://localhost:3000'); - -} catch (error) { - console.error('❌ 测试失败:', error.message); - process.exit(1); -} \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 9f1fc1b..183cb54 100644 --- a/vite.config.js +++ b/vite.config.js @@ -11,11 +11,11 @@ export default defineConfig({ } }, server: { - port: 3000, + port: 8080, open: true, proxy: { '/api': { - target: 'http://localhost:8080', + target: 'http://localhost:3000', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') }