拒绝过度封装!GoWind Admin:基于Element Plus重塑中后台CRUD开发范式

Source: Juejin Frontend Hottest

#🖥 前端

拒绝过度封装!GoWind Admin:基于Element Plus重塑中后台CRUD开发范式

前言:为什么越来越多人厌倦传统Admin脚手架?

在 Golang + Vue 中后台开发领域,成熟一体化脚手架早已成为企业项目开发的首选方案。标准化脚手架能够完成项目初始化、权限封装、基础页面搭建等重复性工作,大幅提升项目落地速度。但在实际业务迭代过程中,不少开发者都会遇到同一个普遍性痛点:部分脚手架过度封装底层组件,固化编码范式,变相约束开发者的编码自由度

这类脚手架为了统一团队编码规范、降低入门门槛,对页面布局、请求逻辑、弹窗交互、表格渲染等底层能力做深层次封装。该方案对简单标准化CRUD页面十分友好,但适配复杂企业级业务时,弊端会逐步凸显:

  1. 定制改造成本高:非标准布局、特殊表格交互、定制化弹窗逻辑,无法通过简单配置实现,需要深入破解上层封装、重写底层内部方法;

  2. 黑盒问题难以排查:底层逻辑完全封闭,开发者无法感知内部运行机制,线上渲染异常、状态联动报错等问题排查难度大幅增加;

  3. 编码范式强制绑定:项目强依赖框架私有API与定制组件,开发者必须适配框架固定写法,无法根据团队技术习惯自由调整;

  4. 进阶学习成本偏高:基础上手简单,但深度定制门槛高,开发者除UI框架基础语法外,还需要熟记框架大量私有配置项与内部规则。

基于此,**GoWind Admin(风行)**脚手架针对行业痛点,重构了中后台页面开发逻辑。依托原生Element Plus,自研一套渐进式Pro业务组件库,摒弃过度封装思维,打造「配置优先、自由兜底、层级可选」的全新CRUD开发模式,从根源解决传统脚手架的束缚问题。

本文将从技术底层、设计理念、分层用法、落地价值四个维度,深度拆解这套适配企业级项目的开发方案。

一、GoWind Admin 整体技术底座

GoWind Admin(风行)是一款开箱即用的前后端一体化企业级脚手架,后端基于Golang微服务框架go-kratos开发,完美支持单体/微服务双模式部署,适配从小型团队单体项目到中大型企业微服务集群各类场景;为适配不同技术栈偏好、不同团队选型需求,前端内置三套完整且独立的版本,覆盖主流中后台技术方案:

  • Vue3 Vben版:基于Vue3 + TypeScript + Vite + Ant Design Vue打造,适配习惯配置化高阶封装、追求极速开发的团队;

  • Vue3 Element Plus版:轻量化纯净版本,依托原生Element Plus开发,低侵入无黑盒封装,兼顾效率与自由度,也是本文核心讲解版本;

  • React版:基于React19 + TypeScript + Ant Design V6,无UMI框架绑定,轻量化架构,适配React技术栈开发团队。

本次重点解析的Vue3 Element Plus版,主打轻量化、低侵入、无黑盒封装,核心技术栈如下:

  • 基础框架:Vue3 + TypeScript + Vite(原生语法,无额外语法糖)

  • UI底座:Element Plus(100%原生组件,无二次深层封装)

  • 表格双引擎:内置vxe-table/原生el-table,一键自由切换

  • 状态管理:TanStack Vue Store(轻量化全局状态,替代冗余Pinia模块)

区别于其他脚手架,该版本最大核心亮点:所有Pro业务组件均基于原生Element Plus原子组件封装,不隐藏底层API,所有Props、事件、插槽完全对外开放。开发者随时可以放弃配置化写法,回归原生Element Plus编码。

二、Pro组件库核心设计理念:渐进式开发

市面上绝大多数配置化组件库只有两种极端模式:要么纯模板编写(重复冗余代码),要么全配置化(高度封装、无法定制)。GoWind Pro组件库打破二元对立,提出四级渐进式开发模型,让开发者根据业务复杂度,自由选择编码层级,适配100%中后台业务场景。

核心设计思想:用一份配置对象,描述完整CRUD页面生命周期(搜索-工具栏-表格-分页-弹窗);配置解决标准化场景,插槽/原生组件兜底复杂场景

组件库整体目录结构清晰,职责单一,无无效冗余模块:

Pro/
├── ProForm/          # 动态配置化表单
├── ProSearch/        # 自适应搜索栏
├── ProToolbar/       # 页面工具栏
├── ProTable/         # 双引擎自适应表格
├── ProPagination/    # 智能分页组件
├── ProModal/         # 弹窗/抽屉通用组件
├── ProPage/          # 一站式页面编排入口
├── composables/      # 可复用状态hooks
├── constants/        # 全局默认常量
└── index.ts          # 统一导出入口

三、四级开发层级:按需选型,拒绝强制绑定

我们将页面开发划分为四个层级,从低代码配置到原生原子组件自由组合,层层递进,覆盖简单/常规/复杂/定制化四类业务页面,下面结合实际业务场景逐一讲解。

Level 1:ProPage 零模板配置(标准CRUD场景)

适用场景:租户管理、用户管理、字典管理、菜单管理等90%标准化后台页面

核心逻辑:仅通过一份ProPageConfig配置对象,自动生成搜索栏、工具栏、数据表格、新增/编辑弹窗、分页组件,全程无需编写任何模板代码,纯声明式开发。

相较于传统固化模板的开发模式,该方案能减少70%以上重复模板代码,同时所有配置字段均有完善TS类型提示,规避拼写错误、参数不匹配等问题。下面给出一份完整版可直接上线的租户管理页面,包含搜索、标签状态、时间格式化、操作按钮、新增/编辑抽屉全套能力:

<template>
  <!-- 一行标签,完成完整CRUD页面:搜索+表格+分页+弹窗 -->
  <ProPage :config="pageConfig" />
</template>

<script setup lang="ts">
import { ProPage, type ProPageConfig } from "@/components/Pro";
// 项目内置统一请求封装
import { fetchListTenants, createTenant, updateTenant, useDeleteTenant } from "@/api/composables";

// 删除接口
const { mutateAsync: deleteTenant } = useDeleteTenant();

const pageConfig: ProPageConfig = {
  // 切换表格引擎:vxe / element
  engine: "element",
  // 搜索区域配置
  search: {
    grid: true,
    showNumber: 4,
    fields: [
      {
        type: "input",
        label: "租户名称",
        field: "name",
        attrs: { clearable: true, placeholder: "请输入租户名称" }
      },
      {
        type: "input",
        label: "租户编码",
        field: "code",
        attrs: { clearable: true }
      },
      {
        type: "select",
        label: "状态",
        field: "status",
        attrs: { clearable: true },
        options: [
          { label: "启用", value: 1 },
          { label: "禁用", value: 0 }
        ]
      },
      {
        type: "date-picker",
        label: "创建时间",
        field: "createdAt",
        attrs: { type: "daterange", rangeSeparator: "~" }
      }
    ]
  },
  // 表格核心配置
  table: {
    // 数据源请求
    listAction: async (query) => {
      const { page, pageSize, ...params } = query;
      const res = await fetchListTenants({ page, pageSize, ...params });
      return { items: res.items || [], total: res.total || 0 };
    },
    // 单行删除
    deleteAction: async (ids) => await deleteTenant({ id: ids as number }),
    // 左侧工具栏
    toolbar: ["add", "delete"],
    // 右侧默认工具:刷新、列筛选
    defaultToolbar: ["refresh", "filter"],
    columns: [
      { type: "selection", label: "", width: 50 },
      { type: "index", label: "序号", width: 60 },
      { prop: "name", label: "租户名称", minWidth: 140 },
      { prop: "code", label: "租户编码", minWidth: 120 },
      // 内置 cellType:tag 自动渲染状态标签,无需插槽
      {
        prop: "status",
        label: "状态",
        width: 100,
        cellType: "tag",
        labelMap: { 1: "启用", 0: "禁用" },
        tagType: { 1: "success", 0: "danger" }
      },
      // 内置日期格式化
      {
        prop: "createdAt",
        label: "创建时间",
        minWidth: 180,
        cellType: "date",
        dateFormat: "YYYY-MM-DD HH:mm:ss"
      },
      // 全自动操作列
      {
        prop: "action",
        label: "操作",
        fixed: "right",
        width: 180,
        cellType: "tool",
        buttons: [
          { name: "edit", text: "编辑" },
          { name: "delete", text: "删除", attrs: { type: "danger" } }
        ]
      }
    ]
  },
  // 内置新增/编辑抽屉弹窗(开箱即用)
  modal: {
    component: "drawer",
    drawer: { title: "租户维护", size: "520px" },
    fields: [
      { type: "input", label: "租户名称", field: "name", rules: [{ required: true, message: "请输入租户名称" }] },
      { type: "input", label: "租户编码", field: "code", rules: [{ required: true, message: "请输入租户编码" }] },
      { type: "switch", label: "启用状态", field: "status" },
      { type: "textarea", label: "备注", field: "remark", attrs: { rows: 4 } }
    ],
    submitAction: async (data, mode) => {
      if (mode === "add") {
        await createTenant(data);
      } else {
        await updateTenant(data);
      }
    }
  }
};
</script>

Level 2:useProPage 命令式控制(外部联动场景)

适用场景:左侧组织树+右侧表格、Tab切换联动、定时器刷新、跨组件通信等需要外部控制页面的场景

传统脚手架中,开发者只能通过ref绑定组件,再调用内部方法,不仅写法冗余,还容易出现挂载时序报错问题。

GoWind 提供 useProPage 组合式函数,抛弃ref绑定组件的传统写法,以命令式API统一管理页面状态、表格刷新、弹窗开关、查询参数。该方案非常适合左侧组织树+右侧表格、Tab联动、按钮刷新等联动场景,下方为可直接复用的「树+表格」完整实战代码:

<template>
  <div class="flex gap-4 h-full">
    <!-- 左侧部门树 -->
    <el-card class="w-64 shrink-0" shadow="never">
      <el-tree :data="deptTree" node-key="id" @node-click="handleNodeClick" />
    </el-card>
    <!-- 右侧ProPage表格 -->
    <div class="flex-1 min-w-0">
      <Page />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import { ElCard, ElTree } from "element-plus";
import { useProPage, type ProPageConfig } from "@/components/Pro";
import { fetchUserList } from "@/api/composables";

const deptTree = ref([]);

// 1. 通过 useProPage 创建页面组件与全局API
const [Page, pageApi] = useProPage({
  search: {
    fields: [
      { type: "input", label: "账号", field: "username" },
      { type: "input", label: "昵称", field: "nickname" }
    ]
  },
  table: {
    listAction: async (params) => {
      const res = await fetchUserList(params);
      return { items: res.items || [], total: res.total || 0 };
    },
    columns: [
      { type: "index", label: "序号", width: 60 },
      { prop: "username", label: "账号", minWidth: 120 },
      { prop: "nickname", label: "昵称", minWidth: 120 },
      { prop: "createdAt", label: "创建时间", cellType: "date" }
    ]
  }
});

// 2. 树节点点击,命令式追加部门ID并重载第一页
function handleNodeClick(node: any) {
  // reload:重置页码+追加参数,最适合侧边栏联动
  pageApi.reload({ deptId: node.id });
}

// 3. 常用API汇总(业务高频)
const handleRefresh = () => pageApi.refresh(); // 刷新当前页
const openAddUser = () => pageApi.openAdd(); // 打开新增弹窗
const getSelectedIds = () => pageApi.getSelectionIds(); // 获取选中ID
</script>

Level 3:插槽定制化(复杂单元格/交互场景)

适用场景:单元格自定义渲染(Switch、图标、渐变标签)、工具栏拓展按钮、自定义弹窗、行内特殊交互

配置化无法覆盖高度个性化单元格,例如状态开关、彩色标签、操作权限按钮等场景。ProPage 支持配置为主、插槽补强的混合写法,所有列、工具栏、弹窗都支持插槽重写。下面示例展示:自定义Tag、Switch开关、展开行详情、工具栏拓展按钮四类高频用法:

<template>
  <ProPage :config="pageConfig" @edit="handleEdit">
    <!-- 自定义状态标签插槽 -->
    <template #status="scope">
      <el-tag :type="scope.row.status === 1 ? 'success' : 'danger'" size="small">
        {{ scope.row.status === 1 ? "正常" : "停用" }}
      </el-tag>
    </template>

    <!-- 行内开关插槽,直接修改状态 -->
    <template #switchStatus="scope">
      <el-switch v-model="scope.row.status" @change="handleSwitchChange(scope.row)" />
    </template>

    <!-- 工具栏左侧拓展插槽 -->
    <template #toolbar-left>
      <el-button type="warning" plain @click="batchExport">批量导出</el-button>
    </template>
  </ProPage>
</template>

<script setup lang="ts">
import { ProPage, type ProPageConfig } from "@/components/Pro";
import { ElTag, ElSwitch, ElButton } from "element-plus";
import { updateUserStatus } from "@/api/composables";

const pageConfig: ProPageConfig = {
  table: {
    toolbar: ["add"],
    columns: [
      { type: "index", label: "序号", width: 60 },
      { prop: "username", label: "账号", minWidth: 120 },
      // 绑定自定义插槽
      { prop: "status", label: "账号状态", width: 120, slotName: "status" },
      { prop: "status", label: "快速开关", width: 120, slotName: "switchStatus" },
      { prop: "createdAt", label: "创建时间", cellType: "date" }
    ]
  }
};

// 行内开关回调
async function handleSwitchChange(row: any, val: number) {
  await updateUserStatus({ id: row.id, status: val });
}
function handleEdit(row: any) {}
function batchExport() {}
</script>

Level 4:原子组件自由组合(非标准布局场景)

适用场景:完全非标准页面、多表格嵌套、多搜索栏联动、特殊异形布局等极端复杂业务

这也是本框架区别于重度封装脚手架的核心亮点:当业务极度特殊、ProPage编排层无法满足布局时,你可以直接放弃顶层封装,单独导入 ProSearch / ProTable / ProToolbar / ProModal 原子组件,自由拼装页面。下方为「独立原子组件」最简示例,完整还原底层组装逻辑:

<template>
  <div class="custom-page p-4">
    <!-- 独立搜索栏 -->
    <ProSearch :fields="searchFields" grid @search="onSearch" @reset="onReset"/>

    <ProToolbar left-buttons="['add']" @button-click="onToolbarClick" class="mt-4"/>

    <!-- 完全自主控制表格 -->
    <ProTable
      class="mt-4"
      :columns="columns"
      :data="tableState.data.value"
      :loading="tableState.loading.value"
      :total="tableState.pagination.total"
      v-model:current-page="tableState.pagination.currentPage"
      v-model:page-size="tableState.pagination.pageSize"
      @selection-change="tableState.handleSelectionChange"
    />
  </div>
</template>

<script setup lang="ts">
import { reactive } from "vue";
import { ProSearch, ProTable, ProToolbar, useTableState } from "@/components/Pro";
import { fetchUserList } from "@/api/composables";

// 1. 搜索字段
const searchFields = [
  { type: "input", label: "账号", field: "username" }
];
const query = reactive<Record<string, any>>({});

// 2. 表格状态托管
const tableState = useTableState({
  indexAction: async (params) => await fetchUserList(params)
});

// 3. 表格列
const columns = [
  { type: "selection", width: 50 },
  { type: "index", label: "序号", width: 60 },
  { prop: "username", label: "账号", minWidth: 120 }
];

function onSearch(params: any) {
  Object.assign(query, params);
  tableState.fetch(query, true);
}
function onReset() {}
function onToolbarClick(name: string) {}
</script>

四、双表格引擎:一键切换,适配不同团队习惯

表格是中后台系统的核心组件,ProTable内置双渲染引擎,一行配置即可切换,无需修改业务代码:

  • vxe-table(默认):功能完整版,支持虚拟滚动、树形表格、行内编辑、批量导出,适配大数据量复杂表格;

  • el-table:Element Plus原生表格,轻量无额外依赖,适配中小型数据页面,降低项目打包体积。

框架内部已完成两套引擎的API自动映射,开发者无需适配差异化语法,仅需修改engine参数即可完成切换,大幅降低团队适配成本。

五、GoWind Admin 整体核心优势总结

1. 弱化封装理念,全权掌控代码逻辑

区别于深层封装的脚手架,Vue3 Element Plus版本采用弱封装设计理念,所有Pro业务组件均基于原生UI组件二次轻量化封装,底层API、组件Props、事件、插槽全部对外开放。开发者可自由切换配置化/原生编码模式,拥有100%代码控制权。

2. 降低进阶学习成本

无需记忆框架私有语法、私有组件属性,开发者仅需掌握Vue3+Element Plus原生知识即可上手;配置化语法贴合原生组件设计逻辑,零基础开发者1小时即可熟练使用。

3. 层级化适配全业务场景

摒弃“一刀切”开发模式,标准化页面用Level1零模板开发,复杂联动页面用Level2命令式控制,定制化页面用Level3/4插槽/原生组合,适配从简单CRUD到复杂异形页面的所有场景。

4. 前后端一体化协同

后端基于go-kratos微服务架构,内置完整的租户、权限、菜单、任务调度、日志管理等企业级能力;前端Pro组件字段结构、请求格式与后端接口完美适配,无需额外做数据适配,一站式完成项目开发。

六、写在最后

优质的中后台脚手架,核心定位应当是赋能开发者,而非限制开发者

市面上多数脚手架仅解决项目“从0到1”的初始化问题,固化的编码模式却会限制项目长期迭代;GoWind Admin 通过四级渐进式开发模型,完美平衡开发效率编码自由度,既能满足标准化页面低代码开发需求,也能支撑复杂定制化业务的原生编码开发。同时多版本前端架构,可全方位适配不同技术栈团队的选型需求。

如果你早已厌倦被框架束缚、反复破解深层封装,追求轻量化、透明化、高自由度的中后台开发体验,不妨尝试 GoWind Admin。

附:项目相关地址