Skip to content

Latest commit

 

History

History
678 lines (589 loc) · 13.3 KB

File metadata and controls

678 lines (589 loc) · 13.3 KB

Mock API 文档

概述

Mock API是开发环境下的模拟接口系统,提供完整的后端API模拟功能,支持用户认证、权限管理、数据CRUD等操作。

文件位置: src/mock/api.js

主要功能

1. 认证相关API

  • 用户登录
  • 用户注册
  • 获取用户信息
  • 刷新Token
  • 用户登出

2. 用户管理API

  • 用户列表查询
  • 用户信息增删改查
  • 用户权限管理
  • 用户角色分配

3. 系统管理API

  • 菜单管理
  • 角色管理
  • 权限管理
  • 系统设置

API接口定义

1. 认证接口

用户登录

// POST /api/auth/login
{
  url: '/api/auth/login',
  method: 'post',
  response: (config) => {
    const { username, password } = JSON.parse(config.body)
    
    // 验证用户名密码
    const user = users.find(u => u.username === username && u.password === password)
    
    if (!user) {
      return {
        status: false,
        code: 401,
        msg: '用户名或密码错误'
      }
    }
    
    // 生成Token
    const token = generateToken(user)
    
    return {
      status: true,
      code: 200,
      msg: '登录成功',
      data: {
        token,
        userInfo: {
          id: user.id,
          username: user.username,
          realName: user.realName,
          email: user.email,
          avatar: user.avatar,
          roles: user.roles,
          permissions: user.permissions
        }
      }
    }
  }
}

获取用户信息

// GET /api/auth/userinfo
{
  url: '/api/auth/userinfo',
  method: 'get',
  response: (config) => {
    const token = getTokenFromHeader(config.headers)
    
    if (!token || !verifyToken(token)) {
      return {
        status: false,
        code: 401,
        msg: 'Token无效或已过期'
      }
    }
    
    const userId = getUserIdFromToken(token)
    const user = users.find(u => u.id === userId)
    
    if (!user) {
      return {
        status: false,
        code: 404,
        msg: '用户不存在'
      }
    }
    
    return {
      status: true,
      code: 200,
      data: {
        id: user.id,
        username: user.username,
        realName: user.realName,
        email: user.email,
        phone: user.phone,
        avatar: user.avatar,
        department: user.department,
        roles: user.roles,
        permissions: user.permissions,
        lastLoginTime: user.lastLoginTime,
        createTime: user.createTime
      }
    }
  }
}

2. 用户管理接口

用户列表查询

// GET /api/user/list
{
  url: '/api/user/list',
  method: 'get',
  response: (config) => {
    const { page = 1, size = 20, username, realName, status, departmentId } = config.query
    
    let filteredUsers = [...users]
    
    // 应用过滤条件
    if (username) {
      filteredUsers = filteredUsers.filter(user => 
        user.username.includes(username)
      )
    }
    
    if (realName) {
      filteredUsers = filteredUsers.filter(user => 
        user.realName.includes(realName)
      )
    }
    
    if (status !== undefined) {
      filteredUsers = filteredUsers.filter(user => 
        user.status === parseInt(status)
      )
    }
    
    if (departmentId) {
      filteredUsers = filteredUsers.filter(user => 
        user.departmentId === parseInt(departmentId)
      )
    }
    
    // 分页处理
    const total = filteredUsers.length
    const start = (page - 1) * size
    const end = start + parseInt(size)
    const list = filteredUsers.slice(start, end)
    
    return {
      status: true,
      code: 200,
      data: {
        list,
        total,
        page: parseInt(page),
        size: parseInt(size),
        pages: Math.ceil(total / size)
      }
    }
  }
}

创建用户

// POST /api/user/create
{
  url: '/api/user/create',
  method: 'post',
  response: (config) => {
    const userData = JSON.parse(config.body)
    
    // 验证用户名是否已存在
    const existingUser = users.find(u => u.username === userData.username)
    if (existingUser) {
      return {
        status: false,
        code: 400,
        msg: '用户名已存在'
      }
    }
    
    // 创建新用户
    const newUser = {
      id: generateId(),
      ...userData,
      password: hashPassword(userData.password),
      createTime: new Date().toISOString(),
      updateTime: new Date().toISOString(),
      status: 1
    }
    
    users.push(newUser)
    
    return {
      status: true,
      code: 200,
      msg: '用户创建成功',
      data: {
        id: newUser.id
      }
    }
  }
}

3. 菜单管理接口

获取菜单树

// GET /api/menu/tree
{
  url: '/api/menu/tree',
  method: 'get',
  response: (config) => {
    const token = getTokenFromHeader(config.headers)
    const userId = getUserIdFromToken(token)
    const user = users.find(u => u.id === userId)
    
    if (!user) {
      return {
        status: false,
        code: 401,
        msg: '用户未登录'
      }
    }
    
    // 根据用户权限过滤菜单
    const userMenus = menus.filter(menu => {
      if (!menu.permissions || menu.permissions.length === 0) {
        return true
      }
      
      return menu.permissions.some(permission => 
        user.permissions.includes(permission)
      )
    })
    
    // 构建菜单树
    const menuTree = buildMenuTree(userMenus)
    
    return {
      status: true,
      code: 200,
      data: menuTree
    }
  }
}

4. 角色管理接口

角色列表查询

// GET /api/role/list
{
  url: '/api/role/list',
  method: 'get',
  response: (config) => {
    const { page = 1, size = 20, name, code, status } = config.query
    
    let filteredRoles = [...roles]
    
    // 应用过滤条件
    if (name) {
      filteredRoles = filteredRoles.filter(role => 
        role.name.includes(name)
      )
    }
    
    if (code) {
      filteredRoles = filteredRoles.filter(role => 
        role.code.includes(code)
      )
    }
    
    if (status !== undefined) {
      filteredRoles = filteredRoles.filter(role => 
        role.status === parseInt(status)
      )
    }
    
    // 分页处理
    const total = filteredRoles.length
    const start = (page - 1) * size
    const end = start + parseInt(size)
    const list = filteredRoles.slice(start, end)
    
    return {
      status: true,
      code: 200,
      data: {
        list,
        total,
        page: parseInt(page),
        size: parseInt(size),
        pages: Math.ceil(total / size)
      }
    }
  }
}

工具函数

1. Token管理

/**
 * 生成Token
 * @param {Object} user - 用户对象
 * @returns {String} Token字符串
 */
function generateToken(user) {
  const payload = {
    userId: user.id,
    username: user.username,
    exp: Date.now() + 24 * 60 * 60 * 1000 // 24小时过期
  }
  
  return btoa(JSON.stringify(payload))
}

/**
 * 验证Token
 * @param {String} token - Token字符串
 * @returns {Boolean} 是否有效
 */
function verifyToken(token) {
  try {
    const payload = JSON.parse(atob(token))
    return payload.exp > Date.now()
  } catch (error) {
    return false
  }
}

/**
 * 从Token获取用户ID
 * @param {String} token - Token字符串
 * @returns {Number} 用户ID
 */
function getUserIdFromToken(token) {
  try {
    const payload = JSON.parse(atob(token))
    return payload.userId
  } catch (error) {
    return null
  }
}

/**
 * 从请求头获取Token
 * @param {Object} headers - 请求头对象
 * @returns {String} Token字符串
 */
function getTokenFromHeader(headers) {
  const authorization = headers.authorization || headers.Authorization
  if (authorization && authorization.startsWith('Bearer ')) {
    return authorization.slice(7)
  }
  return null
}

2. 数据处理

/**
 * 生成唯一ID
 * @returns {Number} 唯一ID
 */
function generateId() {
  return Date.now() + Math.floor(Math.random() * 1000)
}

/**
 * 密码哈希
 * @param {String} password - 原始密码
 * @returns {String} 哈希后的密码
 */
function hashPassword(password) {
  // 简单的哈希实现,实际项目中应使用更安全的方法
  return btoa(password + 'salt')
}

/**
 * 构建菜单树
 * @param {Array} menus - 菜单数组
 * @returns {Array} 菜单树
 */
function buildMenuTree(menus) {
  const tree = []
  const map = new Map()
  
  // 创建映射
  menus.forEach(menu => {
    map.set(menu.id, { ...menu, children: [] })
  })
  
  // 构建树结构
  menus.forEach(menu => {
    const node = map.get(menu.id)
    if (menu.parentId && map.has(menu.parentId)) {
      map.get(menu.parentId).children.push(node)
    } else {
      tree.push(node)
    }
  })
  
  return tree
}

/**
 * 分页处理
 * @param {Array} data - 数据数组
 * @param {Number} page - 页码
 * @param {Number} size - 页大小
 * @returns {Object} 分页结果
 */
function paginate(data, page = 1, size = 20) {
  const total = data.length
  const start = (page - 1) * size
  const end = start + parseInt(size)
  const list = data.slice(start, end)
  
  return {
    list,
    total,
    page: parseInt(page),
    size: parseInt(size),
    pages: Math.ceil(total / size)
  }
}

3. 响应格式化

/**
 * 成功响应
 * @param {Any} data - 响应数据
 * @param {String} msg - 响应消息
 * @returns {Object} 响应对象
 */
function successResponse(data, msg = '操作成功') {
  return {
    status: true,
    code: 200,
    msg,
    data
  }
}

/**
 * 错误响应
 * @param {String} msg - 错误消息
 * @param {Number} code - 错误码
 * @returns {Object} 响应对象
 */
function errorResponse(msg = '操作失败', code = 400) {
  return {
    status: false,
    code,
    msg
  }
}

/**
 * 延迟响应(模拟网络延迟)
 * @param {Function} responseFunc - 响应函数
 * @param {Number} delay - 延迟时间(毫秒)
 * @returns {Promise} 响应Promise
 */
function delayResponse(responseFunc, delay = 500) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(responseFunc())
    }, delay)
  })
}

数据模型

1. 用户模型

const userModel = {
  id: 1,
  username: 'admin',
  password: 'hashed_password',
  realName: '管理员',
  email: 'admin@example.com',
  phone: '13800138000',
  avatar: '/avatars/admin.jpg',
  departmentId: 1,
  department: {
    id: 1,
    name: '技术部'
  },
  roles: ['admin'],
  permissions: ['*'],
  status: 1, // 1-启用 0-禁用
  lastLoginTime: '2025-01-15T10:30:00Z',
  createTime: '2025-01-01T00:00:00Z',
  updateTime: '2025-01-15T10:30:00Z'
}

2. 菜单模型

const menuModel = {
  id: 1,
  parentId: 0,
  name: 'Dashboard',
  title: '仪表盘',
  path: '/dashboard',
  component: 'Dashboard',
  icon: 'Dashboard',
  sort: 1,
  type: 1, // 1-菜单 2-按钮
  permissions: ['dashboard:view'],
  hidden: false,
  keepAlive: true,
  status: 1,
  createTime: '2025-01-01T00:00:00Z',
  updateTime: '2025-01-01T00:00:00Z'
}

3. 角色模型

const roleModel = {
  id: 1,
  name: '管理员',
  code: 'ADMIN',
  description: '系统管理员角色',
  permissions: ['*'],
  userCount: 1,
  sort: 1,
  status: 1,
  isSystem: true,
  createTime: '2025-01-01T00:00:00Z',
  updateTime: '2025-01-01T00:00:00Z'
}

配置选项

1. Mock配置

const mockConfig = {
  // 是否启用Mock
  enabled: process.env.NODE_ENV === 'development',
  
  // 响应延迟时间
  delay: 500,
  
  // 是否记录请求日志
  logging: true,
  
  // 数据持久化(localStorage)
  persistence: true,
  
  // 错误模拟概率
  errorRate: 0.1
}

2. 数据初始化

/**
 * 初始化Mock数据
 */
function initMockData() {
  // 从localStorage恢复数据
  if (mockConfig.persistence) {
    const savedUsers = localStorage.getItem('mock_users')
    if (savedUsers) {
      users.splice(0, users.length, ...JSON.parse(savedUsers))
    }
  }
  
  // 确保有默认管理员用户
  if (!users.find(u => u.username === 'admin')) {
    users.push({
      id: 1,
      username: 'admin',
      password: hashPassword('admin123'),
      realName: '系统管理员',
      email: 'admin@example.com',
      roles: ['admin'],
      permissions: ['*'],
      status: 1,
      createTime: new Date().toISOString()
    })
  }
}

使用示例

1. 启用Mock

// main.js
import { setupMock } from '@/mock'

if (process.env.NODE_ENV === 'development') {
  setupMock()
}

2. API调用

// 登录
const loginResponse = await request.post('/api/auth/login', {
  username: 'admin',
  password: 'admin123'
})

// 获取用户列表
const userListResponse = await request.get('/api/user/list', {
  params: {
    page: 1,
    size: 20,
    username: 'admin'
  }
})

3. 自定义Mock接口

// 添加自定义接口
Mock.mock('/api/custom/data', 'get', {
  status: true,
  code: 200,
  data: {
    message: 'Custom mock data'
  }
})

注意事项

  1. 数据持久化: Mock数据默认存储在localStorage中
  2. 权限验证: 所有接口都会验证Token和权限
  3. 错误模拟: 可以配置错误概率来测试错误处理
  4. 性能考虑: 大量数据时注意分页和过滤性能
  5. 生产环境: 确保生产环境不会加载Mock代码

相关文档


最后更新时间:2025-09-19