vue3搭建一个后台管理系统

我爱海鲸 2026-01-30 14:24:18 暂无标签

简介Vite 5 、Vue 3 、TypeScript 、Element Plus 、Vue Router 4 、Pinia 、Axios

Element Plus(最主流、上手最简单)

  • 官网:https://element-plus.org/
  • 依赖:element-plus@^2.5.0+@element-plus/icons-vue(配套图标库,后台系统必备)

1、创建项目

npm create vite@latest

核心业务依赖(生产环境,pnpm add 直接安装 latest)

pnpm add vue@latest vue-router@latest pinia@latest axios@latest element-plus@latest

 辅助业务依赖(生产环境,配套工具也用 latest)

pnpm add @element-plus/icons-vue@latest pinia-plugin-persistedstate@latest

开发环境依赖(仅开发 / 构建使用,同样指定 latest)

pnpm add typescript@latest vue-tsc@latest @vitejs/plugin-vue@latest @types/node@latest -D

清除包:

pnpm store prune

安装pnpm:

npm install -g pnpm

安装rimraf

pnpm add rimraf@latest -D

2、运行相关命令:

"scripts": {
  "dev": "vite --host 0.0.0.0",
  "build": "vue-tsc && vite build",
  "preview": "vite preview",
  "preview:port": "vite preview --port 8080",
  "type-check": "vue-tsc --noEmit",
  "clean:dist": "rimraf dist 2>nul",
  "clean:packages": "rimraf node_modules 2>nul && rimraf pnpm-lock.yaml 2>nul",
  "clean:all": "rimraf dist node_modules pnpm-lock.yaml 2>nul",
  "reinstall": "pnpm run clean:packages && pnpm install"
}

3、vite.config.ts:

import { defineConfig, ConfigEnv, UserConfig } from 'vite' // 导入vite的类型定义
import vue from '@vitejs/plugin-vue'
import path from 'path'

// 生成唯一时间戳(精确到毫秒,确保每次打包都不同)
const buildTimestamp = new Date().getTime()

// https://vitejs.dev/config/
export default defineConfig(({ command, mode }: ConfigEnv): UserConfig => {
  return {
    plugins: [vue()],
    base: './', // 保持相对路径,无需关心CDN地址
    resolve: {
      alias: {
        // 明确指定路径别名的类型,避免TS类型提示警告
        '@': path.resolve(__dirname, 'src')
      }
    },
    build: {
      assetsDir: 'assets',
      outDir: 'dist',
      assetsInlineLimit: 4096,
      // 禁用打包缓存,确保每次打包重新计算哈希/时间戳
      cache: false,
      rollupOptions: {
        output: {
          // 方案1:时间戳 + hash(推荐,双重保证唯一性)
          assetFileNames: `assets/[name].${buildTimestamp}.[hash:8].[ext]`,
          chunkFileNames: `assets/[name].${buildTimestamp}.[hash:8].js`,
          entryFileNames: `assets/[name].${buildTimestamp}.[hash:8].js`,
          
          // 方案2:仅时间戳(极简,绝对唯一,可选)
          // assetFileNames: `assets/[name].${buildTimestamp}.[ext]`,
          // chunkFileNames: `assets/[name].${buildTimestamp}.js`,
          // entryFileNames: `assets/[name].${buildTimestamp}.js`
        }
      },
      sourcemap: false
    },
    server: {
      allowedHosts: ['www.test.com'],
      proxy: {
        '/api': {
          target: 'http://localhost:8967',
          changeOrigin: true,
          rewrite: (path) => path.replace('/api', '/api') // 修复代理路径
        }
      }
    }
  }
})

4、tsconfig.app.json:

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "types": ["vite/client"],
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    },

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "erasableSyntaxOnly": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}

5、在src目录下建立router文件夹 在router文件夹下创建router.js:

import { createRouter, createWebHistory, type RouteLocationNormalized } from 'vue-router'
import { useUserStore } from '@/stores/user'

// 路由懒加载
const Login = () => import('@/views/Login.vue')
const Home = () => import('@/views/Home.vue')

// 创建 Router 实例(基础配置,后续可扩展)
const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/login',
      name: 'login',
      component: Login,
      meta: {
        title: '登录',
        requiresAuth: false // 登录页不需要认证
      }
    },
    {
      path: '/',
      name: 'home',
      component: Home,
      meta: {
        title: '首页',
        requiresAuth: true // 需要登录
      }
    },
    {
      path: '/:pathMatch(.*)*',
      redirect: '/'
    }
  ]
})

// 路由守卫
router.beforeEach((to: RouteLocationNormalized, from: RouteLocationNormalized, next) => {
  const userStore = useUserStore()
  const isLoggedIn = userStore.checkLogin()

  // 设置页面标题
  if (to.meta.title) {
    document.title = `${to.meta.title} - CMS 系统`
  }

  // 检查路由是否需要登录
  if (to.meta.requiresAuth) {
    if (!isLoggedIn) {
      // 未登录,跳转到登录页,并保存当前路径用于登录后跳转
      next({
        path: '/login',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    // 如果已登录,访问登录页时重定向到首页
    if (to.path === '/login' && isLoggedIn) {
      next('/')
    } else {
      next()
    }
  }
})

export default router

types.d.ts:

import 'vue-router'

declare module 'vue-router' {
  interface RouteMeta {
    title?: string
    requiresAuth?: boolean
  }
}

6、在src目录下创建stores/user.ts

pina:

import { defineStore } from 'pinia'
import { ref } from 'vue'

export interface UserInfo {
  username: string
  token: string
}

export const useUserStore = defineStore(
  'user',
  () => {
    // 用户信息
    const userInfo = ref<UserInfo | null>(null)
    const isLoggedIn = ref(false)

    // 登录
    const login = async (username: string, password: string) => {
      // TODO: 这里应该调用实际的登录 API
      // 模拟登录请求
      return new Promise<boolean>((resolve) => {
        setTimeout(() => {
          if (username && password) {
            userInfo.value = {
              username,
              token: `token_${Date.now()}`
            }
            isLoggedIn.value = true
            resolve(true)
          } else {
            resolve(false)
          }
        }, 500)
      })
    }

    // 登出
    const logout = () => {
      userInfo.value = null
      isLoggedIn.value = false
    }

    // 检查登录状态
    const checkLogin = () => {
      // 从持久化存储中恢复登录状态
      return isLoggedIn.value && userInfo.value !== null
    }

    return {
      userInfo,
      isLoggedIn,
      login,
      logout,
      checkLogin
    }
  },
  {
    persist: true // 启用持久化存储
  }
)

 

 

你好:我的2025