扫码
40.67M · 2026-04-17
这是一个面向中大型后台管理系统的 Vue3 工程化全套方案。
src
├── api # 接口请求统一封装
├── assets # 图片、样式资源
├── components # 公共组件
├── config # 全局常量、环境变量
├── hooks # 通用 hooks
├── layouts # 布局组件
├── router # 路由 + 权限路由
├── store # Pinia 模块化仓库
├── types // TS 类型声明
├── utils // 工具函数
├── views // 业务页面
├── App.vue
└── main.ts
import axios from 'axios'
import { ElMessage, ElLoading } from 'element-plus'
let loadingInstance: any = null
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
})
// 请求拦截器
request.interceptors.request.use(
(config) => {
loadingInstance = ElLoading.service({ fullscreen: true })
const token = localStorage.getItem('token')
if (token) config.headers.Authorization = `Bearer ${token}`
return config
},
(err) => Promise.reject(err)
)
// 响应拦截器
request.interceptors.response.use(
(res) => {
loadingInstance.close()
return res.data
},
(err) => {
loadingInstance.close()
ElMessage.error(err.response?.data?.message || '请求失败')
return Promise.reject(err)
}
)
export default request
import request from '@/utils/request'
export function getUserInfo() {
return request.get('/user/info')
}
export function login(data: any) {
return request.post('/login', data)
}
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
token: localStorage.getItem('token') || '',
userInfo: null as any,
}),
actions: {
setToken(token: string) {
this.token = token
localStorage.setItem('token', token)
},
async fetchUserInfo() {
const res = await getUserInfo()
this.userInfo = res.data
},
},
})
import { createRouter, createWebHistory } from 'vue-router'
import { useUserStore } from '@/store/user'
const routes = [
{
path: '/',
component: () => import('@/layouts/MainLayout.vue'),
meta: { requireAuth: true },
children: [
{ path: '', component: () => import('@/views/Home.vue') },
{ path: 'user', component: () => import('@/views/User.vue') },
],
},
{ path: '/login', component: () => import('@/views/Login.vue') },
]
const router = createRouter({
history: createWebHistory(),
routes,
})
// 全局路由守卫
router.beforeEach((to, from, next) => {
const userStore = useUserStore()
if (to.meta.requireAuth && !userStore.token) {
next('/login')
} else {
next()
}
})
export default router
component: () => import('@/views/Home.vue')
export default defineConfig({
build: {
rollupOptions: {
output: {
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
assetFileNames: '[ext]/[name]-[hash].[ext]',
},
},
},
})
npx eslint --fix .
npx husky install
npx husky add .husky/pre-commit "npm lint"
<template>
<el-table
:data="list"
:loading="loading"
>
<!-- 列 -->
</el-table>
<el-pagination
v-model:page-size="pageSize"
v-model:current-page="pageNum"
:total="total"
@change="fetchList"
/>
</template>
const ruleRef = ref()
const rules = {
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
}
——个人观点 · 仅供参考——