Vue2管理系统一键配置crud提升效率300%

2,247 阅读9分钟

119411680772094_.pic.jpg

本文主要基于element-ui深度封装,旨在快速完成列表查询、增删改查、弹窗表单。可以看到下面完整示例中包含了 Vue2后台管理系统中日常基本功能,代码量却非常少,可复用性非常高,6点下班美滋滋。

github地址 不断更新维护,如果对你有帮助,帮忙加个star~

一、完整示例

在线访问地址: minxiang.site/crud/
http://114.132.248.143/crud/

image1.png

包含列表table、分页、搜索条件查询、新增、编辑、删除

<mx-crud
      :data="tableList"
      :option="listOption"
      :page="page"
      :table-loading="loading"
      @size-change="sizeChange"
      @current-change="currentChange"
      @search-change="searchChange"
      @row-save="addFun"
      @row-update="updateFun"
      @row-del="rowDel"
      @custom-add="rowCustomAdd"
      @custom-view="rowCustomView"
      @custom-edit="rowCustomEdit"
      @search-reset="resetList">
      <template v-slot:zdy="{ row }">
        {{ row.id }}
      </template>
      <template v-slot:menu="{ row }"> menu插槽{{row}} </template>
</mx-crud>
listOption() {
      return {
        isShowmenu: true, // 操作栏配置-是否显示操作栏
        isViewBtn: true, // 操作栏配置-是否显示查看
        isEditBtn: true, // 操作栏配置-是否显示编辑
        isDelBtn: true, // 操作栏配置-是否显示删除
        exportBtn: true, // 操作栏配置-导出
        exportRecordBtn: true, // 操作栏配置-导出记录
        align: "center", // 表格列配置-对齐方式
        index: true, // 表格列配置-索引
        customAdd: false, // 自定义新增
        customView: true, // 自定义查看
        customEdit: false, // 自定义编辑
        titleAliasEdit: "自定义title",
        column: [
          {
            label: "姓名1",
            labelAlias: "自定义label别名", // 弹窗表单配置 - 自定义label别名
            prop: "name",
            search: true, // 表格列配置-是否搜索
            width: 200, // 表格列配置-宽度
            rules: {
              required: true,
              message: "请输入",
              trigger: ["blur", "change"],
            },
          },
          {
            label: "自定义列",
            prop: "zdy",
            slot: true, // 表格列配置-自定义列
            viewDisplay: false, // 弹窗表单配置-查看是否显示
            editDisplay: false, // 弹窗表单配置-编辑是否显示
            addDisplay: false, // 弹窗表单配置-新增是否显示
          },
          {
            label: "多选框",
            prop: "selectType",
            // multiple: true,
            search: true,
            type: "select", // 搜索-定义类型
            rules: {
              required: true,
              message: "请选择",
              trigger: ["blur", "change"],
            },
            dicData: [
              {
                label: "紧急公告",
                value: 1,
              },
              {
                label: "上线公告",
                value: 2,
              },
              {
                label: "业务公告",
                value: 3,
              },
            ],
            formatter: (row) => {
              // 表格列配置-筛选
              const map = new Map([
                [1, `紧急公告`],
                [2, `上线公告`],
                [3, `业务公告`],
              ]);
              return map.get(row.selectType);
            },
          },
          {
            label: "时间",
            prop: "date",
            search: true,
            type: "date", // 搜索-定义类型
            format: "yyyy-MM-dd",
            valueFormat: "yyyy-MM-dd",
            rules: {
              required: true,
              message: "请选择",
              trigger: ["blur", "change"],
            },
          },
          {
            label: "状态formatter",
            prop: "status",
            viewDisplay: false, // 弹窗表单配置-查看是否显示
            editDisplay: false, // 弹窗表单配置-编辑是否显示
            addDisplay: false, // 弹窗表单配置-新增是否显示
            formatter: (row) => {
              // 表格列配置-筛选
              const map = new Map([
                [1, `<i class="class1"></i> 未开始`],
                [2, `<i class="class2"></i> 成功`],
                [3, `<i class="class3"></i> 已完成`],
              ]);
              return map.get(row.status);
            },
          },
          {
            label: "列隐藏",
            prop: "lyc",
            viewDisplay: false, // 弹窗表单配置-查看是否显示
            editDisplay: false, // 弹窗表单配置-编辑是否显示
            addDisplay: false, // 弹窗表单配置-新增是否显示
            hide: true, // 表格列配置-列隐藏
          },
          {
            label: "日期2",
            prop: "date2",
            hide: true,
            viewDisplay: false, // 弹窗表单配置-查看是否显示
            editDisplay: false, // 弹窗表单配置-编辑是否显示
            addDisplay: false, // 弹窗表单配置-新增是否显示
            align: "left", // 表格列配置-对齐方式
          },
          {
            label: "地址3",
            prop: "address",
            overHidden: true, // 表格列配置-内容超出隐藏
            width: 100, // 表格列配置-宽度
            rules: {
              required: true,
              message: "请输入",
              trigger: ["blur", "change"],
            },
          },
        ],
      };
    },

详情示例

二、属性方法介绍

这些属性方法使用频率较高,方法和属性都是在组件里抛出,当我们需要某些功能和配置 时,添加即可

Crud

参数说 明类型默认值
data列表数据array
option表单配置项 参考Option配置object
page分页变量 参考Page参数object
table-loading表格loadingbooleanboolean

Option

参数说 明类型默认值
index是否有序号boolean
align列表对齐方式string'center'
isShowmenu是否显示操作栏booleanfalse
isViewBtn是否显示查看按钮booleanfalse
isEditBtn是否显示编辑按钮booleanfalse
isDelBtn是否显示删除按钮booleanfalse
exportBtn是否显示导出按钮boolean
exportRecordBtn是否显示导出记录按钮boolean
customAdd是否自定义新增回调boolean
customView是否自定义查看回调boolean
customEdit是否自定义编辑回调boolean
titleAliasEdit自定义新增编辑弹窗titlestring

Column属性

参数说 明类型默认值
label列标题string
prop列标题对应字段string
width对应列的宽度string
search是否为搜索项Boolean
rules弹窗表单校验规则object
hide列表项是否显示Booleanfalse
addDisplay表单新增时项是否显示Boolean
editDisplay表单编辑时项是否显示Boolean
viewDisplay表单查看时项是否显示Boolean
formatter用来格式化列内容function
dicData数据字典值array

Events

事件名称说 明类型
size-changepageSize 改变时会触发每页条数\
current-changecurrentPage 改变时会触发当前页\
search-change点击搜索触发该事件\
search-reset点击重置触发该事件\
row-save新增数据确定触发该事件\
row-update更新数据确定触发该事件\
row-del行数据删除时触发该事件\
custom-add自定义新增触发该事件\
custom-edit自定义编辑触发该事件\
custom-view自定义查看触发该事件

三、搜索 & 分页

控制column是否搜索

search变量控制列表项是否搜索

listOption:{
    column: [{
        label: '姓名',
        prop: 'name',
        search:true, // 控制column是否搜索
    }]
}

搜索方法

search-change:点击搜索触发该事件 search-reset: 点击重置触发该事件

<mx-crud
    :data="tableList"
    :option="listOption"
    :page="page"
    :table-loading="loading"
    @search-change="searchChange"
    @search-reset="resetList">
</mx-crud>

自定义列搜索

配置searchslot为true即可开启自定义,列的prop加Search作为卡槽的名称

<mx-crud :option="listOption" :data="tableList" >
     <!-- 搜索 自定义slot -->
      <template v-slot:ageSearch="{ column }"> {{ column.prop }} </template>
</mx-crud>

listOption:{
    column: [{
        label: "自定义列搜索",
        prop: "age",
        search: true,
        searchslot: true,
    }]
}

image2.png

页码和条数

currentPage当前页码,total总条数,pageSize每页多少条数据

四、操作栏设置 & 表格列配置

操作栏隐藏 & 其他属性

isShowmenu属性接受一个Boolean属性显示隐藏操作栏,默认为false menuWidth属性设置操作栏宽度

自定义操作栏

menu为操作栏自定义

<!-- 操作栏配置-自定义操作栏 -->
<template #menu="{ row }"> menu插槽 {{ row.name }}</template>

image3.png

操作栏查看、编辑、删除按钮设置

isViewBtn是否显示查看按钮,默认false; isEditBtn是否显示编辑按钮,默认false; isDelBtn 是否显示删除按钮,默认false;

列配置隐藏 & 其他属性

hide属性接受一个Boolean属性显示隐藏表格列,默认为false width属性控制每列的宽度 align属性控制每列的对齐方式 overHidden设置true超出列表宽度内容以省略号显示

自定义列

设置列的属性slot为true时,在卡槽中用prop作为卡槽的名字即可

<template v-slot:zdy="{ row }">
    {{ row.prop }}
</template>
{
  label: "自定义列",
  prop: "zdy",
  slot: true, // 表格列配置-自定义列
},

image4.png

列内容格式化

formatter方法格式化内容

{
label: "状态formatter",
prop: "status",
formatter: (row) => {
    const map = new Map([
    [1, `<i class="class1"></i> 未开始`],
    [2, `<i class="class2"></i> 成功`],
    [3, `<i class="class3"></i> 已完成`],
     ]);
    return map.get(row.status);
 }
}

image5.png

五、顶部按钮 & 自定义回调

顶部按钮控制

addBtn 属性设置是否显示新增按钮,默认true; 利用了menuLeft卡槽自定义顶部按钮

自定义回调

customAdd 自定义新增回调

<mx-crud
  ref="crud"
  :data="tableList"
  :option="listOption"
  @custom-add="rowCustomAdd">
</mx-crud>
listOption() {
  return {
      customAdd: true, // 自定义新增回调
  }
}

未设置时,默认打开新增弹窗表单;设置customAdd为ture时,增加custom-add回调,增加自定义处理。

customEdit 自定义编辑回调

<mx-crud
  ref="crud"
  :data="tableList"
  :option="listOption"
  @custom-edit="rowCustomEdit">
</mx-crud>
listOption() {
  return {
      customEdit: true, // 自定义编辑回调
  }
}

未设置时,默认打开编辑弹窗表单;设置customEdit为ture时,增加custom-edit回调,增加自定义处理。

customView 自定义查看回调

<mx-crud
  ref="crud"
  :data="tableList"
  :option="listOption"
  @custom-view="rowCustomView">
</mx-crud>
listOption() {
  return {
      customView: true, // 自定义查看回调
  }
}

未设置时,默认打开新增弹窗;设置customView为ture时,增加custom-view回调,增加自定义处理。

六、提取Mixins & 增删改查封装

公共Mixins

提取公共Mixins,减少各个业务页面重复代码,包含page、tableList、loading属性,sizeChange、currentChange、增删改查方法等。自此业务开发时,只需要配置对应的option,及crud接口即可完成基本业务开发,效率提升杠杠的,重复低质的工作大幅度较少。

配置接口 & 增删改查封装

crud逻辑相对固定,抽取到mixin做相应封装处理。业务页面配置接口,mixin中调用

  mixins: [mixin],
  data() {
    return {
      COM_HTTP: {  // 配置接口
        reqList: queryHomePageData, // 列表查询
        reqDel: deleteHomePageData, //删除
        reqAdd: addHomePageData, //新增
        reqUpdate: updateHomePageData, //编辑
      }
    }
  }

完整mixins

详情

export default {
  data() {
    return {
      COM_HTTP: {}, // 当前默认请求
      tableList: [], // 表格列表数据
      loading: false, // 加载控制
      page: {
        currentPage: 1,
        pageSize: 10,
        total: 0,
      },
    };
  },
  mounted() {
    this.searchFun();
  },
  methods: {
    // 选择分页条数
    sizeChange(val) {
      this.page.currentPage = 1;
      this.page.pageSize = val;
      this.searchFun();
    },
    // 跳转页码
    currentChange(val) {
      this.page.currentPage = val;
      this.searchFun();
    },
    // 触发按钮查询
    searchChange(params) {
      this.searchFun(params, 1);
    },
    /** 查询方法 */
    async searchFun(params, currentPage) {
      this.loading = true;
      // 传入参数有current
      if (currentPage) {
        this.page.currentPage = currentPage;
      }
      const filnalParams = this.searchFunParamsHandle(params);
      console.log('最后的请求参数filnalParams:', filnalParams);
      const { data: res } = await this.COM_HTTP.reqList(filnalParams);
      // 没做axios数据拦截 多一层结构
      if (res.code === RESPONSE_CODE.SUCCESS) {
        this.tableList = res.data.results || [];
        this.page.total = res.data.total || 0;
        this.page.currentPage = res.data.currentPage || 1;
      } else {
        this.$message.error(res.msg);
      }
      this.loading = false;
    },
    /** 列表查询参数处理 */
    searchFunParamsHandle(params) {
      let filnalParams = Object.assign(
        { page: this.page.currentPage, pageSize: this.page.pageSize },
        params
      );
      return filnalParams;
    },
    // 删除 - 提示弹窗
    rowDel(row, index) {
      const delTipMsg =
        this.customDelMsg || this.delTipMsg || '确定删除该条数据?';
      this.$confirm(delTipMsg, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        closeOnClickModal: false,
        type: 'warning',
      })
        .then(() => {
          // 开始删除
          this.deleteFun(row, index);
        })
        .catch(() => {});
    },
    /**
     * 增加方法
     * @param {*} item  新增数据
     * @param {*} doneCallback  执行完成回调
     */
    async addFun(item, doneCallback){
      const { data: res } = await this.COM_HTTP.reqAdd(item)
      // 没做axios数据拦截 多一层结构
        if (res.code === RESPONSE_CODE.SUCCESS) {
            this.$message.success('新增成功')
            this.searchFun()
            doneCallback()
        } else {
          this.$message.error(res.msg);
        }
    },
    /**
     * 编辑更新方法
     * @param {*} item  新增数据
     * @param {*} doneCallback  执行完成回调
     */
    async updateFun(item, doneCallback){
      const { data: res } = await this.COM_HTTP.reqUpdate(item)
      // 没做axios数据拦截 多一层结构
        if (res.code === RESPONSE_CODE.SUCCESS) {
            this.$message.success('新增成功')
            this.searchFun()
            doneCallback()
        } else {
          this.$message.error(res.msg);
        }
    },
    // 删除方法
    async deleteFun(item) {
      // 调接口
      const { data: res } = await this.COM_HTTP.reqDel(item)
       // 没做axios数据拦截 多一层结构
      if (res.code === RESPONSE_CODE.SUCCESS) {
        this.$message.success('删除成功')
      } else {
        this.$message.error(res.msg);
      }
   
    },
    // 搜索清空
    resetList() {
      console.log('resetList');
    },
  },
};

七、其他功能 & 后续

整个基本查询、列表、分页增删改查已基本完成。当然功能没有面面俱到,如很多table的属性配置和方法,到组件源码中增加对应的配置即可 如需请留言我会补上你所需的功能场景。后续:逐步完善功能,如果有人看,继续封装一个Vue3版本。

引入方法

初步发布了一个npm包,大家可下载使用,更建议下载整个项目,结合示例看懂源码

// 组件库
import mxCrud from "mx-crud";
import 'mx-crud/lib/mx-crud.css';
// 调试或者自定义crud
// import mxCrud from "../packages/src/index";

七、在.vscode下新增代码片段

在vue文件中输入crud, 回车便可出现配置好的代码碎片

企业微信截图_9bcaa0c9-2e12-4017-8c52-0715a90c6f09.png

八、最后

我更推荐的是屏幕前的你看懂封装的思路,几年前的我初次使用和浏览时,直呼666,算是小开了眼界;整个代码量不是很大,逻辑也比较简单,一两把游戏的时间足已;看懂之后增加日常业务开发需求的功能,信手拈来。将整体完全消化吸收,逐步拓展成公司组件库,妥妥的KPI,提高整体前端的开发效率。

github地址 不断更新维护,如果对你有帮助,帮忙加个star~