项目大家到现在肯定有人注意到了前端模块scaffold-admin-ui,但是这个项目是如何搭建的,代码内容现在还没有展示,现在就把admin-ui 这个模块的搭建过程及代码结构整体展示一下,便于直接复制应用。
scaffold-admin-ui
搭建详细步骤# 使用Vite创建Vue3项目
npm create vite@latest scaffold-admin-ui -- --template vue
cd scaffold-admin-ui
# 安装核心依赖
npm install vue-router@4 pinia element-plus axios
npm install sass --save-dev # 可选(支持SCSS)
scaffold-admin-ui/
├── public/ # 静态资源
├── src/
│ ├── api/ # 接口定义
│ │ └── auth.ts # 登录/权限接口
│ │ └── user.ts # 用户管理接口
│ ├── assets/ # 静态资源(图片、样式)
│ ├── components/ # 公共组件
│ │ └── PageHeader.vue # 页面头部
│ ├── layouts/ # 布局组件
│ │ └── MainLayout.vue # 主布局(包含侧边栏和头部)
│ ├── router/ # 路由配置
│ │ └── index.ts # 路由定义和权限守卫
│ ├── store/ # Pinia状态管理
│ │ └── user.ts # 用户状态(Token、权限信息)
│ ├── utils/ # 工具类
│ │ └── request.ts # Axios请求封装
│ ├── views/ # 页面组件
│ │ ├── login/ # 登录页
│ │ │ └── Login.vue
│ │ └── user/ # 用户管理
│ │ ├── UserList.vue # 用户列表
│ │ └── UserForm.vue # 用户表单(新增/编辑)
│ ├── App.vue # 根组件
│ └── main.ts # 入口文件
├── .env.development # 开发环境配置
├── .env.production # 生产环境配置
├── vite.config.ts # Vite配置
└── package.json
.env.development
)# 后端API基础地址
VITE_API_BASE_URL = http://localhost:8888
src/utils/request.ts
)import axios from 'axios'
import { useUserStore } from '@/store/user'
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 5000
})
// 请求拦截器(添加Token)
service.interceptors.request.use((config) => {
const userStore = useUserStore()
if (userStore.token) {
config.headers.Authorization = `Bearer ${userStore.token}`
}
return config
})
// 响应拦截器(处理错误)
service.interceptors.response.use(
(response) => {
const res = response.data
if (res.code !== 200) {
return Promise.reject(new Error(res.message || 'Error'))
}
return res.data
},
(error) => {
// Token过期处理
if (error.response.status === 401) {
const userStore = useUserStore()
userStore.logout()
window.location.href = '/login'
}
return Promise.reject(error)
}
)
export default service
src/store/user.ts
)import { defineStore } from 'pinia'
import { login } from '@/api/auth'
interface UserState {
token: string | null
username: string | null
}
export const useUserStore = defineStore('user', {
state: (): UserState => ({
token: localStorage.getItem('token'),
username: null
}),
actions: {
async login(username: string, password: string) {
const res = await login({ username, password })
this.token = res.token
this.username = username
localStorage.setItem('token', res.token)
},
logout() {
this.token = null
this.username = null
localStorage.removeItem('token')
}
}
})
src/views/login/Login.vue
)<template>
<div class="login-container">
<el-form :model="form" @submit.prevent="handleLogin">
<h2>后台管理系统</h2>
<el-form-item label="用户名">
<el-input v-model="form.username" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" type="password" />
</el-form-item>
<el-button type="primary" native-type="submit">登录</el-button>
</el-form>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useUserStore } from '@/store/user'
import { useRouter } from 'vue-router'
const form = ref({
username: '',
password: ''
})
const userStore = useUserStore()
const router = useRouter()
const handleLogin = async () => {
try {
await userStore.login(form.value.username, form.value.password)
router.push('/')
} catch (error) {
ElMessage.error(error.message)
}
}
</script>
src/router/index.ts
)import { createRouter, createWebHistory } from 'vue-router'
import { useUserStore } from '@/store/user'
const routes = [
{
path: '/login',
name: 'Login',
component: () => import('@/views/login/Login.vue')
},
{
path: '/',
component: () => import('@/layouts/MainLayout.vue'),
meta: { requiresAuth: true },
children: [
{
path: '/user',
name: 'User',
component: () => import('@/views/user/UserList.vue')
}
]
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
// 路由守卫(检查登录状态)
router.beforeEach((to) => {
const userStore = useUserStore()
if (to.meta.requiresAuth && !userStore.token) {
return '/login'
}
})
export default router
src/views/user/UserList.vue
)<template>
<div>
<el-button @click="handleAdd">新增用户</el-button>
<el-table :data="userList">
<el-table-column prop="id" label="ID" />
<el-table-column prop="username" label="用户名" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button @click="handleEdit(row)">编辑</el-button>
<el-button @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { getUserList, deleteUser } from '@/api/user'
interface User {
id: number
username: string
}
const userList = ref<User[]>([])
const loadData = async () => {
userList.value = await getUserList()
}
const handleDelete = async (id: number) => {
await deleteUser(id)
ElMessage.success('删除成功')
loadData()
}
onMounted(() => {
loadData()
})
</script>
src/api/user.ts
)import request from '@/utils/request'
export interface User {
id: number
username: string
}
export const getUserList = () => {
return request.get<User[]>('/api/user/list')
}
export const deleteUser = (id: number) => {
return request.delete(`/api/user/${id}`)
}
在 vite.config.ts
中配置代理:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
'/api': {
target: 'http://localhost:8888', // 网关地址
changeOrigin: true
}
}
}
})
构建静态文件:
npm run build
生成 dist
目录。
编写Dockerfile:
# 使用Nginx镜像托管静态文件
FROM nginx:alpine
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
Nginx配置(nginx.conf
):
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://gateway:8888; # 后端网关地址
}
}
# 开发环境启动
npm run dev
# 生产环境构建
docker build -t scaffold-admin-ui:1.0.0 .
docker run -p 80:80 scaffold-admin-ui:1.0.0
访问 http://localhost
,可看到登录页并与后端接口交互。
通过此模板,开发人员可快速扩展其他业务模块(如订单管理、权限配置)。
本篇的分享就到这里了,感谢观看,如果对你有帮助,别忘了点赞+收藏+关注。