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/, '') }