系统文档结构

分析文档结构并简单说明

后台结构说明

1. 系统概述

1.1 项目简介

Wimoor ERP是国内首款100%开源、支持商用的亚马逊ERP系统,采用微服务+前后端分离+中央登录模式,支持新旧系统无缝对接。

技术栈

2. 项目根目录结构

2.1 核心配置文件

├── README.md                    # 项目说明文档
├── pom.xml                     # Maven父项目配置
├── nacos.env                   # Nacos环境变量配置
├── LICENSE                     # MIT开源协议
└── .gitignore                  # Git忽略配置

2.2 初始化配置目录 (init-config)

init-config/
├── mysql/                      # 数据库初始化脚本
│   ├── readme.txt             # 数据库说明
│   ├── 数据/                  # 基础数据SQL
│   └── 数据库结构/            # 表结构SQL
├── nacos/                     # Nacos配置中心
│   ├── DEFAULT_GROUP/         # 默认配置组
│   ├── install.txt            # 安装说明
│   └── nacos-seata-version-map.png
└── seata/                     # 分布式事务配置
    ├── readme.txt
    ├── seata-application.yml
    └── seataServer.properties

2.3 日志目录

logs/
└── wimoor-gen/                # 代码生成器日志
    ├── error.log              # 错误日志
    ├── info.log               # 信息日志
    └── 按日期分割的日志文件

3. 微服务模块架构

3.1 核心基础模块 (wimoor-common)

功能:提供公共组件和工具类

wimoor-common/
├── common-core/               # 核心工具类
├── common-core-ext/           # 扩展工具类
├── common-entity/             # 实体类定义
├── common-feishu/             # 飞书集成
├── common-mvc/                # MVC相关组件
├── common-mybatis/            # Mybatis配置
├── common-redis/              # Redis缓存
├── common-storage/            # 文件存储
├── common-swagger/            # API文档
└── pom.xml

3.2 网关服务 (wimoor-gateway)

功能:API网关,路由转发和负载均衡

wimoor-gateway/
├── src/main/java/            # 网关核心代码
├── src/main/resources/       # 配置文件
│   ├── bootstrap.yml         # 启动配置
│   ├── bootstrap-dev.yml     # 开发环境配置
│   └── bootstrap-prod.yml    # 生产环境配置
└── target/                   # 编译输出

3.3 管理系统 (wimoor-admin)

功能:系统管理和用户权限控制

wimoor-admin/
├── admin-api/                # API接口模块
├── admin-boot/               # 启动模块
└── pom.xml

3.4 亚马逊业务模块 (wimoor-amazon)

功能:亚马逊卖家业务核心功能

wimoor-amazon/
├── amazon-api/               # 亚马逊API接口
├── amazon-boot/              # 亚马逊启动模块
├── amazon-follow/            # 产品跟卖功能
├── amazon-sp-api/            # 亚马逊SP API集成
└── pom.xml

3.5 亚马逊广告模块 (wimoor-amazon-adv)

功能:亚马逊广告管理

wimoor-amazon-adv/
├── amazon-adv-api/           # 广告API接口
├── amazon-adv-boot/          # 广告启动模块
└── pom.xml

3.6 API接口模块 (wimoor-api)

功能:对外提供统一API接口

wimoor-api/
├── wimoor-api-admin/         # 管理API
├── wimoor-api-amazon/        # 亚马逊API
├── wimoor-api-quote/         # 报价API
└── pom.xml

3.7 功能模块 (wimoor-modules)

功能:业务功能模块集合

wimoor-modules/
├── wimoor-data/              # 数据处理模块
├── wimoor-finance/           # 财务管理模块
├── wimoor-gen/               # 代码生成器模块
├── wimoor-quote/             # 报价管理模块
└── pom.xml

3.8 ERP模块 (wimoor-erp)

功能:企业资源计划管理

4. 数据库架构设计

4.1 数据库划分

系统采用分库设计,按业务模块划分:

4.2 核心表结构

5. 微服务架构设计

5.1 服务发现与配置中心

5.2 分布式事务

5.3 API网关

6. 部署架构

6.1 依赖服务

必需服务:
├── MySQL 8.0                 # 数据库
├── Redis                     # 缓存和Session
├── Nacos                     # 服务注册配置中心
└── Seata                     # 分布式事务

可选服务:
└── Cas-Server               # 中央登录模块

6.2 启动顺序

  1. 启动Nacos服务
  2. 启动Seata服务
  3. 启动Gateway网关
  4. 启动各业务服务(admin, amazon, erp等)
  5. 启动前端UI服务

7. 开发环境配置

7.1 环境要求

7.2 配置步骤

  1. 导入数据库脚本
  2. 配置Nacos服务地址
  3. 配置Redis连接
  4. 配置各模块数据库连接
  5. 启动各微服务模块

8. 系统功能模块

8.1 核心业务功能

8.2 技术特性

9. 扩展与定制

9.1 模块扩展

系统采用模块化设计,支持:

9.2 定制服务

前段结构说明

1. 项目概述

Wimoor UI是一个基于 Vue 3 + Element Plus 的企业级前端应用,由深圳万墨信息技术有限公司开发。该系统提供了全面的业务管理功能,包括 ERP、Amazon 业务管理、财务管理和系统管理等模块,旨在为企业提供高效、便捷的业务运营解决方案。

2. 技术栈

2.1 核心技术

2.2 辅助技术

3. 目录结构

├── src/
│   ├── api/              # API 接口定义
│   │   ├── amazon/       # Amazon 业务相关接口
│   │   ├── erp/          # ERP 业务相关接口
│   │   ├── finance/      # 财务相关接口
│   │   └── sys/          # 系统管理相关接口
│   ├── assets/           # 静态资源
│   │   ├── css/          # 全局样式
│   │   ├── icons/        # SVG 图标
│   │   └── image/        # 图片资源
│   ├── components/       # 通用组件
│   │   ├── dialog/       # 对话框组件
│   │   ├── DictTag/      # 字典标签组件
│   │   ├── Editor/       # 富文本编辑器组件
│   │   ├── FileUpload/   # 文件上传组件
│   │   ├── ImageUpload/  # 图片上传组件
│   │   ├── Pagination/   # 分页组件
│   │   ├── RightToolbar/ # 右侧工具栏组件
│   │   ├── SvgIcon/      # SVG 图标组件
│   │   └── Table/        # 表格组件
│   ├── directive/        # 自定义指令
│   ├── filters/          # 全局过滤器
│   ├── hooks/            # 自定义 Hooks
│   ├── layout/           # 布局组件
│   ├── model/            # 数据模型
│   ├── plugins/          # 插件配置
│   ├── router/           # 路由配置
│   │   ├── modules/      # 路由模块
│   │   └── index.js      # 路由入口
│   ├── store/            # Vuex 状态管理
│   │   ├── modules/      # 状态模块
│   │   └── index.js      # 状态管理入口
│   ├── utils/            # 工具函数
│   ├── views/            # 页面视图
│   │   ├── amazon/       # Amazon 业务视图
│   │   ├── customized/   # 定制化视图
│   │   ├── dashboard/    # 仪表盘视图
│   │   ├── erp/          # ERP 业务视图
│   │   ├── finance/      # 财务视图
│   │   └── sys/          # 系统管理视图
│   ├── App.vue           # 根组件
│   └── main.js           # 应用入口
├── .gitignore            # Git 忽略配置
├── package.json          # 项目依赖
├── README.md             # 项目说明
└── vite.config.js        # Vite 配置

4. 核心功能模块

4.1 仪表盘 (Dashboard)

4.2 ERP 模块

4.3 Amazon 模块

4.4 财务管理

4.5 系统管理

5. 系统架构

5.1 前端架构

┌─────────────────────────────────────────────────────────┐
│                     页面层 (Views)                     │
├─────────────────────────────────────────────────────────┤
│                     组件层 (Components)                 │
├─────────────────────────────────────────────────────────┤
│                     路由层 (Router)                    │
├─────────────────────────────────────────────────────────┤
│                     状态层 (Vuex)                      │
├─────────────────────────────────────────────────────────┤
│                     API 层 (Axios)                     │
├─────────────────────────────────────────────────────────┤
│                     工具层 (Utils)                     │
└─────────────────────────────────────────────────────────┘

5.2 核心流程

5.2.1 路由加载流程

  1. 用户访问系统
  2. 检查是否为白名单路径
  3. 如非白名单路径,检查是否已加载动态路由
  4. 如未加载,从 API 获取动态路由配置
  5. 动态添加路由到 Vue Router
  6. 完成页面跳转

5.2.2 权限控制流程

  1. 用户登录后获取权限信息
  2. 将权限信息存储到 Vuex 中
  3. 使用自定义指令 (v-hasPerm, v-hasPermi) 控制页面元素显示
  4. 路由跳转时检查用户权限

6. 部署说明

6.1 环境要求

6.2 安装依赖

npm install

6.3 开发环境

npm run dev

6.4 生产构建

npm run build

6.5 预览生产构建

npm run preview

7. 开发指南

7.1 组件开发

7.2 API 接口

7.3 路由配置

7.4 状态管理

7.5 权限控制

8. 核心文件说明

8.1 main.js

应用入口文件,负责初始化 Vue 应用、注册全局组件、指令和插件。

8.2 App.vue

根组件,提供应用的基本结构。

8.3 router/index.js

路由配置文件,负责定义路由规则和路由拦截。

8.4 store/index.js

状态管理配置文件,负责组织 Vuex 模块。

8.5 src/api/

包含所有 API 接口定义,按业务模块组织。

8.6 src/components/

包含所有通用组件,如表格、分页、文件上传等。

8.7 src/views/

包含所有页面视图,按业务模块组织。

9. 技术特点

9.1 现代化技术栈

采用 Vue 3 + Composition API,提供更好的开发体验和性能。

9.2 模块化设计

按业务模块拆分代码,提高代码的可维护性和可扩展性。

9.3 组件化开发

封装通用组件,提高代码复用率和开发效率。

9.4 权限控制

提供完善的权限控制机制,确保系统安全。

9.5 响应式设计

适配不同屏幕尺寸,提供良好的用户体验。

9.6 数据可视化

集成 ECharts,提供丰富的数据可视化图表。

10. 总结

Wimoor UI3 是一个功能全面、架构清晰的企业级前端应用,采用现代化的技术栈和设计理念,为企业提供高效、便捷的业务管理解决方案。该系统具有良好的可扩展性和可维护性,能够满足企业不断发展的业务需求。

UI架构说明

1. 系统架构概述

Wimoor UI3 是一个基于 Vue 3 + Element Plus 构建的企业级前端应用框架,采用现代化的技术栈和架构设计理念。系统采用了组件化、模块化和分层架构,具有良好的可扩展性、可维护性和性能。

1.1 技术栈

技术 版本 用途
Vue 3.x 前端框架
Element Plus 2.x UI组件库
Vue Router 4.x 路由管理
Vuex 4.x 状态管理
Axios 0.27.x HTTP客户端
Vite 3.x 构建工具
SVG - 图标系统

1.2 系统分层

2. 核心架构组件

2.1 应用入口 (main.js)

应用入口文件负责初始化 Vue 应用,注册全局组件、指令、过滤器和方法。

核心功能

关键代码

// 创建Vue应用
const app = createApp(App);

// 注册核心依赖
app.use(store).use(router).use(ElementPlus).use(print).use(plugins);

// 注册全局组件
app.component('GlobalTable', GlobalTable);
app.component('Pagination', Pagination);

// 注册自定义指令
app.use(hasPerm).use(hasPermi).use(dataType);

// 挂载应用
app.mount('#app');

2.2 路由系统

路由系统采用 Vue Router 4,支持静态路由和动态路由结合的方式。

2.2.1 路由配置

路由配置分为静态路由和动态路由两部分:

路由模块划分

2.2.2 路由守卫

使用 beforeEach 导航守卫实现权限控制和动态路由加载:

router.beforeEach(async (to, from, next) => {
  if (whitePath.includes(to.path)) {
    // 白名单路由直接放行
    next();
  } else {
    if (store.state.routerStore.router.length === 0) {
      // 动态加载路由
      await axios.get('/api/admin/api/v1/menus/route').then(res => {
        store.dispatch("routerStore/setRouter", res.data.data);
        addRoute(router, res.data.data);
      });
    }
    next();
  }
});

2.2.3 动态路由加载

通过 addRoute 函数实现动态路由的递归加载:

function addRoute(router, data) {
  data.forEach(v => {
    let item = {
      path: v.path,
      name: v.name,
      component: modules[`../views/${v.component}.vue`],
      meta: v.meta || { keepAlive: true }
    };
    // 过滤不需要缓存的页面
    if (['/sys/notepad', '/fin/voucher/create'].includes(item.path)) {
      item.meta.keepAlive = false;
    }
    router.addRoute('index', item);
    // 递归加载子路由
    if (v.children) {
      addRoute(router, v.children);
    }
  });
}

2.3 Layout 结构

Layout 采用了经典的三栏布局结构,使用 Element Plus 的 el-container 组件实现。

2.3.1 布局组件结构

<el-container>
  <el-aside>           <!-- 左侧菜单 -->
    <AsideMenu />
  </el-aside>
  <el-container>
    <el-header>        <!-- 顶部导航 -->
      <HeaderTab />
      <HeaderAvatar />
    </el-header>
    <el-main>          <!-- 主内容区 -->
      <router-view>
        <!-- 页面内容 -->
      </router-view>
    </el-main>
  </el-container>
</el-container>

2.3.2 布局组件说明

2.3.3 组件缓存机制

使用 Vue 的 keep-alive 组件实现页面缓存,提高用户体验:

<keep-alive ref="keepAlive" :exclude="excludes">
  <component :is="wrap($route.query.title, Component)" v-if="$route.meta.keepAlive" :key="$route.query.title" />
</keep-alive>
<component :is="wrap($route.query.title, Component)" v-if="!$route.meta.keepAlive" :key="$route.query.title" />

动态缓存控制

2.4 状态管理

采用 Vuex 4 实现状态管理,按功能模块划分为多个子模块。

2.4.1 Store 模块划分

2.4.2 核心状态管理

routerStore

permissionStore

2.5 权限控制

系统实现了基于指令的权限控制机制,通过 v-hasPermv-hasPermi 指令控制元素的显示。

2.5.1 权限指令

// v-hasPerm 指令:判断用户是否拥有特定权限
export const hasPerm = {
  install: (app) => {
    app.directive('hasPerm', {
      mounted(el, binding) {
        const permissions = store.state.permissionStore.permission;
        const value = binding.value;
        const hasPermission = permissions.has(value);
        if (!hasPermission) {
          el.parentNode.removeChild(el);
        }
      }
    });
  }
};

// v-hasPermi 指令:判断用户是否拥有任一指定权限
export const hasPermi = {
  install: (app) => {
    app.directive('hasPermi', {
      mounted(el, binding) {
        const permissions = Array.from(store.state.permissionStore.permission);
        const permissionFlag = binding.value;
        const hasPermissions = permissions.some(permission => {
          return "*:*:*" === permission || permissionFlag.includes(permission);
        });
        if (!hasPermissions) {
          el.parentNode.removeChild(el);
        }
      }
    });
  }
};

3. 公共组件与工具

3.1 全局组件

系统提供了一系列可复用的全局组件:

3.1.1 GlobalTable 组件

基于 Element Plus Table 封装的全局表格组件,提供了丰富的功能和配置选项。

核心功能

使用示例

<GlobalTable
  :table-data="tableData"
  :loading="loading"
  @row-click="handleRowClick"
  @selection-change="handleSelectionChange"
>
  <el-table-column prop="name" label="名称" />
  <el-table-column prop="status" label="状态" />
</GlobalTable>

3.1.2 Pagination 组件

分页组件,与 GlobalTable 配合使用。

3.1.3 SvgIcon 组件

SVG 图标组件,支持动态加载和自定义样式。

3.1.4 DictTag 组件

字典标签组件,用于显示字典值对应的标签。

3.2 全局工具函数

系统提供了丰富的全局工具函数,挂载在 Vue 实例上:

3.3 自定义指令

4. 通信机制

4.1 组件通信

系统使用多种组件通信方式:

4.2 API 通信

使用 Axios 作为 HTTP 客户端,实现与后端 API 的通信。

API 请求流程

  1. 前端组件发起请求
  2. API 服务层处理请求参数
  3. Axios 拦截器处理请求头和响应
  4. 后端处理请求并返回数据
  5. 前端接收响应并处理

5. 性能优化

5.1 组件缓存

使用 keep-alive 缓存常用页面组件,减少重复渲染。

5.2 路由懒加载

采用动态导入方式实现路由懒加载:

component: () => import("@/views/dashboard/index.vue")

5.3 图片优化

使用 SVG 图标代替 PNG/JPG 图标,减少网络请求。

5.4 代码分割

利用 Vite 的代码分割功能,按需加载模块。

6. 开发规范

6.1 目录结构

src/
├── api/           # API服务
├── assets/        # 静态资源
├── components/    # 公共组件
├── directive/     # 自定义指令
├── filters/       # 过滤器
├── layout/        # 布局组件
├── router/        # 路由配置
├── store/         # 状态管理
├── styles/        # 样式文件
├── utils/         # 工具函数
├── views/         # 页面视图
├── App.vue        # 根组件
└── main.js        # 入口文件

6.2 命名规范

6.3 代码风格

7. 部署与维护

7.1 构建流程

# 安装依赖
npm install

# 开发环境
npm run dev

# 生产构建
npm run build

7.2 环境配置

7.3 常见问题

8. 总结

Wimoor UI3 是一个架构清晰、功能完善的企业级前端应用框架,采用了现代化的技术栈和设计理念。系统具有良好的可扩展性、可维护性和性能,能够满足企业不断发展的业务需求。

通过本架构说明文档,希望能帮助开发人员更好地理解系统架构和设计思想,提高开发效率和代码质量。


文档版本:1.0 更新日期:2023-07-01 编写人员:Wimoor UI3 开发团队

UI公共组件使用手册

1. Pagination 分页组件

Pagination 是一个基于 Element Plus 的分页组件封装,提供了丰富的功能和灵活的配置选项。

1.1 核心功能

1.2 基本使用

<template>
  <Pagination
    v-model:page="queryParams.pageNum"
    v-model:limit="queryParams.pageSize"
    :total="total"
    @pagination="getList"
  />
</template>

<script setup>
import { ref } from 'vue'
import Pagination from '@/components/Pagination/index.vue'

const queryParams = ref({
  pageNum: 1,
  pageSize: 20
})
const total = ref(0)

const getList = (pagination) => {
  queryParams.value = { ...queryParams.value, ...pagination }
  // 调用API获取数据
}
</script>

1.3 高级配置

1.3.1 自定义页面大小

<Pagination
  :page-sizes="[10, 20, 50, 100, 200]"
  :limit="10"
  @pagination="getList"
/>

1.3.2 自定义布局

<Pagination
  :layout="'total, sizes, prev, pager, next, jumper'
  @pagination="getList"
/>

1.3.3 禁用自动滚动

<Pagination
  :auto-scroll="false"
  @pagination="getList"
/>

1.4 响应式设计

组件会根据屏幕宽度自动调整页码按钮的数量:

2. GlobalTable 全局表格组件

GlobalTable 是一个功能强大的表格组件,基于 Element Plus Table 封装,提供了丰富的功能和灵活的配置选项。

2.1 核心功能

2.2 基本使用

<template>
  <GlobalTable
    ref="globalTableRef"
    :table-data="tableData"
    :query-params="queryParams"
    @load-table="getList"
    @row-click="handleRowClick"
  >
    <template #field>
      <el-table-column prop="name" label="名称" />
      <el-table-column prop="status" label="状态" />
      <el-table-column prop="createTime" label="创建时间" width="180" />
      <el-table-column label="操作" width="150" fixed="right">
        <template #default="scope">
          <el-button type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
          <el-button type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </template>
  </GlobalTable>
</template>

<script setup>
import { ref } from 'vue'
import GlobalTable from '@/components/Table/GlobalTable/index.vue'

const globalTableRef = ref()
const tableData = ref({ records: [], total: 0 })
const queryParams = ref({})

const getList = (params, callback) => {
  // 调用API获取数据
  // 成功后调用callback
  callback({
    records: data.list,
    total: data.total
  })
}

const handleRowClick = (row) => {
  console.log('点击行:', row)
}
</script>

2.3 高级配置

2.3.1 树形表格

<GlobalTable
  :table-data="tableData"
  :lazy="true"
  :load="loadChild"
  :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
  @load-table="getList"
>
  <!-- 列定义 -->
</GlobalTable>

<script setup>
const loadChild = (tree, treeNode, resolve) => {
  // 加载子节点数据
  // 成功后调用resolve
  resolve(childData)
}
</script>

2.3.2 自定义排序

<GlobalTable
  :table-data="tableData"
  :default-sort="{ prop: 'createTime', order: 'descending' }"
  @load-table="getList"
  @table-sort="handleSort"
>
  <!-- 列定义 -->
</GlobalTable>

<script setup>
const handleSort = (option) => {
  queryParams.value.sort = option.prop
  queryParams.value.order = option.order.replace('ascending', 'asc').replace('descending', 'desc')
}
</script>

2.3.3 表格汇总

<GlobalTable
  :table-data="tableData"
  :show-summary="true"
  :summary-method="getSummaries"
  @load-table="getList"
>
  <!-- 列定义 -->
</GlobalTable>

<script setup>
const getSummaries = ({ columns, data }) => {
  const sums = []
  columns.forEach((column, index) => {
    if (index === 0) {
      sums[index] = '合计'
      return
    }
    const values = data.map(item => Number(item[column.property]))
    sums[index] = values.reduce((prev, curr) => prev + curr, 0)
  })
  return sums
}
</script>

2.3.4 动态字段配置

<GlobalTable
  :table-data="tableData"
  :field-type="'user_list'"
  @load-table="getList"
>
  <!-- 列定义 -->
</GlobalTable>

通过配置 field-type,GlobalTable 会自动从后端获取字段配置,并根据用户设置动态显示/隐藏列。

2.4 性能优化

2.4.1 浮动表头

当表格内容较长时,滚动时表头会固定在顶部:

<GlobalTable
  :table-data="tableData"
  @load-table="getList"
>
  <!-- 列定义 -->
</GlobalTable>

2.4.2 虚拟滚动

对于大数据量表格,可以启用虚拟滚动:

<GlobalTable
  :table-data="tableData"
  :height="500"
  :scrollbar-always-on="true"
  @load-table="getList"
>
  <!-- 列定义 -->
</GlobalTable>

2.5 常用方法

<script setup>
const globalTableRef = ref()

// 刷新表格
globalTableRef.value.refreshTable()

// 加载表格数据
globalTableRef.value.loadTable(queryParams)

// 切换行选中状态
globalTableRef.value.toggleRowSelection(row, true)

// 获取选中行
globalTableRef.value.getSelectionRows()

// 设置当前行
globalTableRef.value.setCurrentRow(row)
</script>

3. 字典树运用

字典树是系统中用于管理和展示字典数据的机制,包括字典数据的获取、缓存和展示。

3.1 核心功能

3.2 字典数据获取

使用 useDict hook 获取字典数据:

<script setup>
import { useDict } from '@/utils/dict'

// 获取单个字典类型
const { status } = useDict('sys_status')

// 获取多个字典类型
const { status, gender, userType } = useDict('sys_status', 'sys_user_gender', 'sys_user_type')
</script>

3.3 字典数据展示

使用 DictTag 组件展示字典标签:

<template>
  <DictTag :options="status" :value="record.status" />
</template>

<script setup>
import { useDict } from '@/utils/dict'
import DictTag from '@/components/DictTag/index.vue'

const { status } = useDict('sys_status')
</script>

3.4 字典数据转换

使用工具函数转换字典值:

<script setup>
import { selectDictLabel } from '@/utils/wimoor'
import { useDict } from '@/utils/dict'

const { status } = useDict('sys_status')

// 将字典值转换为标签
const statusLabel = selectDictLabel(status.value, record.status)
</script>

3.5 字典数据缓存

字典数据会自动缓存到 Vuex 的 dictStore 中,避免重复请求:

// 手动获取字典数据
import useDictStore from '@/hooks/store/useDictStore'

// 获取字典数据
const statusDict = useDictStore.getDict('sys_status')

// 手动设置字典数据
useDictStore.setDict('sys_status', dictData)

// 清除字典数据
useDictStore.removeDict('sys_status')

// 清除所有字典数据
useDictStore.cleanDict()

4. 权限控制

系统提供了基于指令的权限控制机制,使用 v-hasPermv-hasPermi 指令动态显示/隐藏元素。

4.1 核心功能

4.2 权限指令使用

4.2.1 v-hasPerm 单个权限控制

<el-button type="primary" v-hasPerm="'user:add'">新增用户</el-button>

当用户拥有 user:add 权限时,按钮会显示;否则会隐藏。

4.2.2 v-hasPermi 多个权限控制

<el-button type="danger" v-hasPermi="['user:edit', 'user:delete']">批量操作</el-button>

当用户拥有 user:edituser:delete 权限时,按钮会显示;否则会隐藏。

4.3 权限控制原理

权限控制的核心逻辑在 permission.js 中实现:

export const hasPerm = {
  install: (app) => {
    app.directive('hasPerm', {
      mounted(el, binding) {
        const permissions = store.state.permissionStore.permission;
        const value = binding.value;
        const flag = permissions.has(value);
        if (!flag) {
          el.parentNode.removeChild(el);
        }
      }
    });
  }
};

4.4 权限数据来源

用户权限数据从后端 API 获取,并存储在 Vuex 的 permissionStore 中:

// 从后端获取权限数据
avoid axios.get('/api/admin/api/v1/menus/route').then(res => {
  // 存储权限数据
  store.dispatch("permissionStore/setPermission", res.data.data[0].meta.permissions);
});

4.5 高级使用场景

4.5.1 权限控制在表格操作列

<GlobalTable
  :table-data="tableData"
  @load-table="getList"
>
  <el-table-column label="操作" width="150" fixed="right">
    <template #default="scope">
      <el-button type="primary" size="small" v-hasPerm="'user:edit'" @click="handleEdit(scope.row)">编辑</el-button>
      <el-button type="danger" size="small" v-hasPerm="'user:delete'" @click="handleDelete(scope.row)">删除</el-button>
    </template>
  </el-table-column>
</GlobalTable>

4.5.2 权限控制在表单字段

<el-form-item label="角色" prop="roleId" v-hasPerm="'user:assignRole'">
  <el-select v-model="form.roleId" placeholder="请选择角色">
    <el-option v-for="role in roles" :key="role.roleId" :label="role.roleName" :value="role.roleId" />
  </el-select>
</el-form-item>

4.5.3 权限控制在菜单

<el-menu-item v-for="menu in menus" :key="menu.path" :index="menu.path" v-hasPerm="menu.permission">
  <template #title>
    <span>{{ menu.name }}</span>
  </template>
</el-menu-item>

5. 其他公共组件

5.1 SvgIcon 图标组件

<svg-icon icon-class="user" />
<svg-icon icon-class="edit" class="icon-large" />

5.2 FileUpload 文件上传组件

<FileUpload
  v-model="form.fileUrl"
  :limit="1"
  :file-list="fileList"
  @success="handleUploadSuccess"
/>

5.3 Editor 富文本组件

<Editor
  v-model="form.content"
  :height="300"
  @change="handleContentChange"
/>

5.4 RightToolbar 表格工具栏组件

<RightToolbar @handleSizeChange="handleSizeChange">
  <el-button type="primary" @click="handleAdd">
    <i class="el-icon-plus"></i> 新增
  </el-button>
  <el-button type="danger" @click="handleDelete" :disabled="selectionList.length === 0">
    <i class="el-icon-delete"></i> 删除
  </el-button>
</RightToolbar>

6. 最佳实践

6.1 组件组合使用

表格 + 分页 + 字典 + 权限

<template>
  <div class="app-container">
    <RightToolbar @handleSizeChange="handleSizeChange">
      <el-button type="primary" v-hasPerm="'user:add'" @click="handleAdd">
        <i class="el-icon-plus"></i> 新增用户
      </el-button>
      <el-button type="danger" v-hasPerm="'user:delete'" @click="handleDelete" :disabled="selectionList.length === 0">
        <i class="el-icon-delete"></i> 批量删除
      </el-button>
    </RightToolbar>

    <GlobalTable
      ref="globalTableRef"
      :table-data="tableData"
      :query-params="queryParams"
      @load-table="getList"
      @selection-change="handleSelectionChange"
    >
      <template #field>
        <el-table-column type="selection" width="55" />
        <el-table-column prop="userName" label="用户名" />
        <el-table-column prop="gender" label="性别">
          <template #default="scope">
            <DictTag :options="gender" :value="scope.row.gender" />
          </template>
        </el-table-column>
        <el-table-column prop="status" label="状态">
          <template #default="scope">
            <DictTag :options="status" :value="scope.row.status" />
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150" fixed="right">
          <template #default="scope">
            <el-button type="primary" size="small" v-hasPerm="'user:edit'" @click="handleEdit(scope.row)">编辑</el-button>
            <el-button type="danger" size="small" v-hasPerm="'user:delete'" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </template>
    </GlobalTable>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import GlobalTable from '@/components/Table/GlobalTable/index.vue'
import RightToolbar from '@/components/RightToolbar/index.vue'
import DictTag from '@/components/DictTag/index.vue'
import { useDict } from '@/utils/dict'

const globalTableRef = ref()
const tableData = ref({ records: [], total: 0 })
const queryParams = ref({})
const selectionList = ref([])

const { gender, status } = useDict('sys_user_gender', 'sys_status')

const getList = (params, callback) => {
  // 调用API获取数据
  callback(data)
}

const handleSelectionChange = (selection) => {
  selectionList.value = selection
}

const handleAdd = () => {
  // 新增用户
}

const handleEdit = (row) => {
  // 编辑用户
}

const handleDelete = (row) => {
  // 删除用户
}

const handleSizeChange = (size) => {
  globalTableRef.value.changeSize(size)
}
</script>

6.2 性能优化建议

  1. 表格性能优化

    • 对于大数据量表格,使用 height 属性启用虚拟滚动
    • 合理设置 scrollbar-always-on 属性
    • 使用 stripeborder 属性时注意性能影响
  2. 字典数据优化

    • 尽量在组件初始化时获取所有需要的字典类型
    • 避免在循环中频繁调用 selectDictLabel 函数
  3. 权限控制优化

    • 避免在大量重复元素上使用权限指令
    • 可以在父组件层面进行权限判断,减少指令使用

6.3 代码规范建议

  1. 组件命名

    • 使用 PascalCase 命名组件
    • 组件文件使用 kebab-case 命名
  2. Props 定义

    • 明确 Props 类型和默认值
    • 使用 v-model 实现双向绑定
  3. 事件处理

    • 使用明确的事件名称
    • 避免在模板中编写复杂的事件处理逻辑
  4. 代码结构

    • 合理组织组件代码结构
    • 使用 setup script 语法
    • 避免组件过大,合理拆分组件

文档版本:1.0 更新日期:2023-07-01 编写人员:Wimoor UI 开发团队