# 管理后台架构文档 ## 版本历史 | 版本 | 日期 | 作者 | 变更说明 | |------|------|------|----------| | 1.0 | 2024-01-20 | 前端团队 | 初始版本 | ## 1. 管理后台架构概述 ### 1.1 项目背景 管理后台是养殖管理平台的Web端管理系统,主要面向系统管理员、运营人员和客服人员,提供用户管理、数据统计、系统配置等管理功能。 ### 1.2 架构目标 - **易用性**:直观的操作界面和良好的用户体验 - **功能完整**:覆盖所有业务管理需求 - **性能优化**:快速的页面加载和响应 - **可维护性**:清晰的代码结构和组件化开发 - **扩展性**:支持功能模块的快速扩展 - **安全性**:完善的权限控制和安全防护 ### 1.3 技术栈 - **前端框架**:Vue.js 3.x + Composition API - **开发语言**:TypeScript 5.x - **UI框架**:Element Plus 2.x - **状态管理**:Pinia 2.x - **路由管理**:Vue Router 4.x - **构建工具**:Vite 4.x - **HTTP客户端**:Axios - **图表库**:ECharts 5.x - **代码规范**:ESLint + Prettier - **CSS预处理**:Sass/SCSS ## 2. 系统架构设计 ### 2.1 整体架构 ``` ┌─────────────────────────────────────────────────────────────┐ │ 表现层 (View) │ │ Pages + Components │ ├─────────────────────────────────────────────────────────────┤ │ 状态层 (State) │ │ Pinia Stores │ ├─────────────────────────────────────────────────────────────┤ │ 服务层 (Service) │ │ API + Utils + Plugins │ ├─────────────────────────────────────────────────────────────┤ │ 数据层 (Data) │ │ HTTP + WebSocket + Storage │ └─────────────────────────────────────────────────────────────┘ ``` ### 2.2 目录结构 ``` admin-system/ ├── public/ # 静态资源 │ ├── favicon.ico │ └── index.html ├── src/ # 源代码 │ ├── api/ # API接口 │ │ ├── auth.ts # 认证接口 │ │ ├── user.ts # 用户接口 │ │ ├── farm.ts # 养殖接口 │ │ └── trade.ts # 交易接口 │ ├── assets/ # 静态资源 │ │ ├── images/ # 图片资源 │ │ ├── icons/ # 图标资源 │ │ └── styles/ # 样式文件 │ ├── components/ # 组件 │ │ ├── common/ # 通用组件 │ │ ├── business/ # 业务组件 │ │ └── layout/ # 布局组件 │ ├── composables/ # 组合式函数 │ │ ├── useAuth.ts # 认证逻辑 │ │ ├── useTable.ts # 表格逻辑 │ │ └── useChart.ts # 图表逻辑 │ ├── directives/ # 自定义指令 │ │ ├── permission.ts # 权限指令 │ │ └── loading.ts # 加载指令 │ ├── layouts/ # 布局 │ │ ├── DefaultLayout.vue # 默认布局 │ │ └── AuthLayout.vue # 认证布局 │ ├── pages/ # 页面 │ │ ├── dashboard/ # 仪表板 │ │ ├── user/ # 用户管理 │ │ ├── farm/ # 养殖管理 │ │ ├── trade/ # 交易管理 │ │ └── system/ # 系统管理 │ ├── plugins/ # 插件 │ │ ├── element-plus.ts # Element Plus │ │ └── echarts.ts # ECharts │ ├── router/ # 路由 │ │ ├── index.ts # 路由配置 │ │ └── guards.ts # 路由守卫 │ ├── stores/ # 状态管理 │ │ ├── auth.ts # 认证状态 │ │ ├── user.ts # 用户状态 │ │ └── app.ts # 应用状态 │ ├── types/ # 类型定义 │ │ ├── api.ts # API类型 │ │ ├── user.ts # 用户类型 │ │ └── common.ts # 通用类型 │ ├── utils/ # 工具函数 │ │ ├── request.ts # 请求封装 │ │ ├── auth.ts # 认证工具 │ │ ├── validator.ts # 验证工具 │ │ └── formatter.ts # 格式化工具 │ ├── App.vue # 根组件 │ └── main.ts # 应用入口 ├── .env # 环境变量 ├── .env.development # 开发环境变量 ├── .env.production # 生产环境变量 ├── vite.config.ts # Vite配置 ├── tsconfig.json # TypeScript配置 ├── package.json # 项目配置 └── README.md # 项目说明 ``` ## 3. 核心模块设计 ### 3.1 认证授权模块 **功能**: 用户登录、权限验证、角色管理 **核心组件**: - **登录页面**: 用户名密码登录 - **权限控制**: 基于RBAC的权限控制 - **角色管理**: 角色创建、编辑、权限分配 **状态管理**: ```typescript // 认证状态管理 export const useAuthStore = defineStore('auth', () => { const token = ref('') const userInfo = ref(null) const permissions = ref([]) // 登录 const login = async (credentials: LoginCredentials) => { const response = await authApi.login(credentials) if (response.success) { token.value = response.data.token userInfo.value = response.data.user permissions.value = response.data.permissions // 保存到本地存储 localStorage.setItem('token', token.value) localStorage.setItem('userInfo', JSON.stringify(userInfo.value)) } return response } // 登出 const logout = async () => { await authApi.logout() token.value = '' userInfo.value = null permissions.value = [] // 清除本地存储 localStorage.removeItem('token') localStorage.removeItem('userInfo') } // 检查权限 const hasPermission = (permission: string): boolean => { return permissions.value.includes(permission) } return { token, userInfo, permissions, login, logout, hasPermission } }) ``` ### 3.2 用户管理模块 **功能**: 用户列表、用户详情、用户操作 **核心页面**: - **用户列表**: 分页展示用户信息,支持搜索和筛选 - **用户详情**: 查看和编辑用户详细信息 - **用户操作**: 启用/禁用用户、重置密码等 **表格组件**: ```vue ``` ### 3.3 数据统计模块 **功能**: 数据可视化、报表生成、趋势分析 **核心组件**: - **仪表板**: 关键指标展示 - **图表组件**: 各类数据图表 - **报表页面**: 详细数据报表 **图表组件**: ```vue ``` ### 3.4 系统配置模块 **功能**: 系统参数配置、菜单管理、字典管理 **核心页面**: - **系统参数**: 系统基础配置 - **菜单管理**: 动态菜单配置 - **字典管理**: 数据字典维护 ## 4. 路由设计 ### 4.1 路由配置 ```typescript // 路由配置 import { createRouter, createWebHistory } from 'vue-router' import type { RouteRecordRaw } from 'vue-router' const routes: RouteRecordRaw[] = [ { path: '/login', name: 'Login', component: () => import('@/pages/auth/Login.vue'), meta: { title: '登录', requiresAuth: false } }, { path: '/', component: () => import('@/layouts/DefaultLayout.vue'), redirect: '/dashboard', children: [ { path: 'dashboard', name: 'Dashboard', component: () => import('@/pages/dashboard/Index.vue'), meta: { title: '仪表板', icon: 'dashboard' } }, { path: 'user', name: 'UserManagement', redirect: '/user/list', meta: { title: '用户管理', icon: 'user' }, children: [ { path: 'list', name: 'UserList', component: () => import('@/pages/user/List.vue'), meta: { title: '用户列表' } }, { path: 'detail/:id', name: 'UserDetail', component: () => import('@/pages/user/Detail.vue'), meta: { title: '用户详情', hidden: true } } ] } ] } ] const router = createRouter({ history: createWebHistory(), routes }) export default router ``` ### 4.2 路由守卫 ```typescript // 路由守卫 import { useAuthStore } from '@/stores/auth' router.beforeEach(async (to, from, next) => { const authStore = useAuthStore() // 设置页面标题 if (to.meta.title) { document.title = `${to.meta.title} - 养殖管理平台` } // 检查是否需要认证 if (to.meta.requiresAuth !== false) { if (!authStore.token) { next('/login') return } // 检查权限 if (to.meta.permission && !authStore.hasPermission(to.meta.permission)) { ElMessage.error('权限不足') next('/403') return } } next() }) ``` ## 5. 状态管理 ### 5.1 应用状态 ```typescript // 应用状态管理 export const useAppStore = defineStore('app', () => { const sidebar = ref({ opened: true, withoutAnimation: false }) const device = ref('desktop') const size = ref('default') // 切换侧边栏 const toggleSidebar = () => { sidebar.value.opened = !sidebar.value.opened sidebar.value.withoutAnimation = false } // 关闭侧边栏 const closeSidebar = (withoutAnimation: boolean) => { sidebar.value.opened = false sidebar.value.withoutAnimation = withoutAnimation } // 设置设备类型 const setDevice = (deviceType: string) => { device.value = deviceType } // 设置组件大小 const setSize = (sizeType: string) => { size.value = sizeType } return { sidebar, device, size, toggleSidebar, closeSidebar, setDevice, setSize } }) ``` ### 5.2 用户状态 ```typescript // 用户状态管理 export const useUserStore = defineStore('user', () => { const users = ref([]) const currentUser = ref(null) // 获取用户列表 const getUsers = async (params: UserListParams) => { const response = await userApi.getUsers(params) if (response.success) { users.value = response.data.items } return response } // 获取用户详情 const getUserDetail = async (id: string) => { const response = await userApi.getUserDetail(id) if (response.success) { currentUser.value = response.data } return response } // 创建用户 const createUser = async (userData: CreateUserData) => { const response = await userApi.createUser(userData) if (response.success) { users.value.push(response.data) } return response } // 更新用户 const updateUser = async (id: string, userData: UpdateUserData) => { const response = await userApi.updateUser(id, userData) if (response.success) { const index = users.value.findIndex(user => user.id === id) if (index !== -1) { users.value[index] = { ...users.value[index], ...response.data } } } return response } // 删除用户 const deleteUser = async (id: string) => { const response = await userApi.deleteUser(id) if (response.success) { const index = users.value.findIndex(user => user.id === id) if (index !== -1) { users.value.splice(index, 1) } } return response } return { users, currentUser, getUsers, getUserDetail, createUser, updateUser, deleteUser } }) ``` ## 6. 网络层设计 ### 6.1 HTTP请求封装 ```typescript // HTTP请求封装 import axios from 'axios' import type { AxiosRequestConfig, AxiosResponse } from 'axios' import { ElMessage } from 'element-plus' import { useAuthStore } from '@/stores/auth' // 创建axios实例 const service = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 10000 }) // 请求拦截器 service.interceptors.request.use( (config: AxiosRequestConfig) => { const authStore = useAuthStore() // 添加认证token if (authStore.token) { config.headers = { ...config.headers, Authorization: `Bearer ${authStore.token}` } } return config }, (error) => { return Promise.reject(error) } ) // 响应拦截器 service.interceptors.response.use( (response: AxiosResponse) => { const { data } = response // 统一处理响应 if (data.success) { return data } else { ElMessage.error(data.message || '请求失败') return Promise.reject(data) } }, (error) => { const { response } = error if (response) { switch (response.status) { case 401: ElMessage.error('登录已过期,请重新登录') const authStore = useAuthStore() authStore.logout() router.push('/login') break case 403: ElMessage.error('权限不足') break case 404: ElMessage.error('请求的资源不存在') break case 500: ElMessage.error('服务器内部错误') break default: ElMessage.error('网络错误') } } else { ElMessage.error('网络连接失败') } return Promise.reject(error) } ) export default service ``` ### 6.2 API接口定义 ```typescript // API接口定义 import request from '@/utils/request' import type { LoginCredentials, LoginResponse, UserListParams, UserListResponse, CreateUserData, UpdateUserData } from '@/types/api' // 认证相关接口 export const authApi = { // 登录 login: (data: LoginCredentials): Promise => { return request.post('/auth/login', data) }, // 登出 logout: (): Promise => { return request.post('/auth/logout') }, // 获取用户信息 getUserInfo: (): Promise => { return request.get('/auth/user-info') } } // 用户相关接口 export const userApi = { // 获取用户列表 getUsers: (params: UserListParams): Promise => { return request.get('/users', { params }) }, // 获取用户详情 getUserDetail: (id: string): Promise => { return request.get(`/users/${id}`) }, // 创建用户 createUser: (data: CreateUserData): Promise => { return request.post('/users', data) }, // 更新用户 updateUser: (id: string, data: UpdateUserData): Promise => { return request.put(`/users/${id}`, data) }, // 删除用户 deleteUser: (id: string): Promise => { return request.delete(`/users/${id}`) } } ``` ## 7. 组件化设计 ### 7.1 通用组件 ```vue ``` ### 7.2 业务组件 ```vue ``` ## 8. 性能优化 ### 8.1 代码分割 ```typescript // 路由懒加载 const routes = [ { path: '/user', component: () => import('@/pages/user/Index.vue') }, { path: '/farm', component: () => import('@/pages/farm/Index.vue') } ] // 组件懒加载 const LazyComponent = defineAsyncComponent(() => import('@/components/HeavyComponent.vue')) ``` ### 8.2 虚拟滚动 ```vue ``` ### 8.3 缓存策略 ```typescript // 请求缓存 class RequestCache { private cache = new Map() private ttl = 5 * 60 * 1000 // 5分钟 get(key: string): any { const item = this.cache.get(key) if (!item) return null if (Date.now() - item.timestamp > this.ttl) { this.cache.delete(key) return null } return item.data } set(key: string, data: any): void { this.cache.set(key, { data, timestamp: Date.now() }) } clear(): void { this.cache.clear() } } // 使用缓存的API请求 const requestWithCache = async (url: string, options?: any) => { const cacheKey = `${url}${JSON.stringify(options)}` // 尝试从缓存获取 const cachedData = requestCache.get(cacheKey) if (cachedData) { return cachedData } // 发起请求 const response = await request(url, options) // 缓存响应数据 requestCache.set(cacheKey, response) return response } ``` ## 9. 安全设计 ### 9.1 XSS防护 ```typescript // XSS防护工具 export const xssFilter = { // 转义HTML特殊字符 escapeHtml: (str: string): string => { const map: Record = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' } return str.replace(/[&<>"']/g, (match) => map[match]) }, // 过滤危险标签 filterTags: (str: string): string => { return str.replace(/]*>.*?<\/script>/gi, '') .replace(/]*>.*?<\/iframe>/gi, '') .replace(/javascript:/gi, '') } } // 在组件中使用 const safeContent = computed(() => { return xssFilter.escapeHtml(props.content) }) ``` ### 9.2 CSRF防护 ```typescript // CSRF Token处理 const csrfToken = ref('') // 获取CSRF Token const getCsrfToken = async () => { const response = await request.get('/csrf-token') csrfToken.value = response.data.token } // 在请求中添加CSRF Token service.interceptors.request.use((config) => { if (['post', 'put', 'delete'].includes(config.method?.toLowerCase() || '')) { config.headers['X-CSRF-Token'] = csrfToken.value } return config }) ``` ### 9.3 权限控制 ```typescript // 权限指令 const permissionDirective = { mounted(el: HTMLElement, binding: any) { const { value } = binding const authStore = useAuthStore() if (!authStore.hasPermission(value)) { el.style.display = 'none' } }, updated(el: HTMLElement, binding: any) { const { value } = binding const authStore = useAuthStore() if (!authStore.hasPermission(value)) { el.style.display = 'none' } else { el.style.display = '' } } } // 注册指令 app.directive('permission', permissionDirective) // 在模板中使用 // 删除 ``` ## 10. 测试策略 ### 10.1 单元测试 ```typescript // 组件测试 import { mount } from '@vue/test-utils' import { describe, it, expect } from 'vitest' import UserList from '@/pages/user/List.vue' describe('UserList', () => { it('renders user list correctly', () => { const wrapper = mount(UserList, { props: { users: [ { id: 1, username: 'test1', email: 'test1@example.com' }, { id: 2, username: 'test2', email: 'test2@example.com' } ] } }) expect(wrapper.find('.user-list').exists()).toBe(true) expect(wrapper.findAll('.user-item')).toHaveLength(2) }) it('emits edit event when edit button clicked', async () => { const wrapper = mount(UserList) await wrapper.find('.edit-btn').trigger('click') expect(wrapper.emitted('edit')).toBeTruthy() }) }) ``` ### 10.2 集成测试 ```typescript // API测试 import { describe, it, expect, beforeEach } from 'vitest' import { userApi } from '@/api/user' describe('User API', () => { beforeEach(() => { // 设置测试环境 }) it('should get user list', async () => { const response = await userApi.getUsers({ page: 1, limit: 10 }) expect(response.success).toBe(true) expect(response.data.items).toBeInstanceOf(Array) }) it('should create user', async () => { const userData = { username: 'testuser', email: 'test@example.com', password: 'password123' } const response = await userApi.createUser(userData) expect(response.success).toBe(true) expect(response.data.username).toBe(userData.username) }) }) ``` ## 11. 构建与部署 ### 11.1 构建配置 ```typescript // vite.config.ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { resolve } from 'path' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': resolve(__dirname, 'src') } }, build: { target: 'es2015', outDir: 'dist', assetsDir: 'assets', sourcemap: false, rollupOptions: { output: { chunkFileNames: 'js/[name]-[hash].js', entryFileNames: 'js/[name]-[hash].js', assetFileNames: '[ext]/[name]-[hash].[ext]' } } }, server: { port: 3000, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } } }) ``` ### 11.2 Docker部署 ```dockerfile # Dockerfile FROM node:18-alpine as builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/nginx.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` ### 11.3 CI/CD配置 ```yaml # .gitlab-ci.yml stages: - test - build - deploy test: stage: test script: - npm ci - npm run test - npm run lint build: stage: build script: - npm ci - npm run build artifacts: paths: - dist/ deploy: stage: deploy script: - docker build -t admin-system . - docker push $CI_REGISTRY_IMAGE - kubectl apply -f k8s/ ``` ## 12. 监控与运维 ### 12.1 性能监控 ```typescript // 性能监控 class PerformanceMonitor { // 监控页面加载时间 monitorPageLoad() { window.addEventListener('load', () => { const timing = performance.timing const loadTime = timing.loadEventEnd - timing.navigationStart this.reportMetric('page_load_time', loadTime) }) } // 监控API响应时间 monitorApiResponse(url: string, startTime: number, endTime: number) { const responseTime = endTime - startTime this.reportMetric('api_response_time', responseTime, { url }) } // 上报指标 reportMetric(name: string, value: number, tags?: Record) { // 发送到监控系统 fetch('/api/metrics', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, value, tags, timestamp: Date.now() }) }) } } ``` ### 12.2 错误监控 ```typescript // 错误监控 class ErrorMonitor { constructor() { this.setupGlobalErrorHandler() this.setupUnhandledRejectionHandler() this.setupVueErrorHandler() } // 全局错误处理 setupGlobalErrorHandler() { window.addEventListener('error', (event) => { this.reportError({ type: 'javascript', message: event.message, filename: event.filename, lineno: event.lineno, colno: event.colno, stack: event.error?.stack }) }) } // Promise错误处理 setupUnhandledRejectionHandler() { window.addEventListener('unhandledrejection', (event) => { this.reportError({ type: 'promise', message: event.reason?.message || 'Unhandled Promise Rejection', stack: event.reason?.stack }) }) } // Vue错误处理 setupVueErrorHandler() { app.config.errorHandler = (err, vm, info) => { this.reportError({ type: 'vue', message: err.message, stack: err.stack, componentName: vm?.$options.name, errorInfo: info }) } } // 上报错误 reportError(error: any) { fetch('/api/errors', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...error, url: window.location.href, userAgent: navigator.userAgent, timestamp: Date.now() }) }) } } ``` ## 13. 扩展性设计 ### 13.1 插件系统 ```typescript // 插件系统 interface Plugin { name: string version: string install: (app: App) => void } class PluginManager { private plugins: Map = new Map() register(plugin: Plugin) { this.plugins.set(plugin.name, plugin) } install(app: App, pluginName: string) { const plugin = this.plugins.get(pluginName) if (plugin) { plugin.install(app) } } installAll(app: App) { this.plugins.forEach(plugin => { plugin.install(app) }) } } // 使用插件 const pluginManager = new PluginManager() pluginManager.register({ name: 'chart', version: '1.0.0', install: (app) => { app.component('Chart', ChartComponent) } }) ``` ### 13.2 主题系统 ```typescript // 主题系统 interface Theme { name: string colors: Record fonts: Record } class ThemeManager { private themes: Map = new Map() private currentTheme = ref('default') register(theme: Theme) { this.themes.set(theme.name, theme) } setTheme(themeName: string) { const theme = this.themes.get(themeName) if (theme) { this.currentTheme.value = themeName this.applyTheme(theme) } } private applyTheme(theme: Theme) { const root = document.documentElement Object.entries(theme.colors).forEach(([key, value]) => { root.style.setProperty(`--color-${key}`, value) }) Object.entries(theme.fonts).forEach(([key, value]) => { root.style.setProperty(`--font-${key}`, value) }) } } ``` ## 14. 未来规划 ### 14.1 技术升级 - **Vue 3.4+**: 升级到最新版本Vue.js - **Vite 5.x**: 升级构建工具 - **TypeScript 5.x**: 使用最新TypeScript特性 - **微前端**: 考虑微前端架构 ### 14.2 功能扩展 - **国际化**: 支持多语言 - **PWA**: 渐进式Web应用 - **离线功能**: 支持离线操作 - **实时通信**: WebSocket实时更新