当前位置: 首页 > article >正文

基于AVue的二次封装:快速构建后台管理系统的CRUD方案


基于AVue的二次封装:快速构建后台管理系统的CRUD方案

在开发后台管理系统时,表格是常见的组件之一。然而,使用原生的Element Plus实现CRUD(增删改查)功能往往需要编写大量重复代码,过程繁琐。即使借助类似AVue这样的数据驱动视图框架,虽然能简化开发,但配置和使用上仍不够简洁。因此,我对AVue进行了二次封装,打造了一个更高效的CRUD组件——f-crud,以提升开发效率。

本文将详细介绍封装思路、实现代码以及使用方法,并附上效果图和建议。


一、封装目标

  1. 简化配置:通过统一的接口和配置项,减少开发者重复编写CRUD逻辑的负担。
  2. 功能完整:支持表格展示、搜索、分页、增删改查等核心功能。
  3. 灵活扩展:支持插槽自定义列渲染,适配不同业务场景。
  4. 快速上手:只需简单配置即可实现完整的CRUD功能。

二、实现方案

1. 使用层代码 (f-crud 使用示例)

以下是基于f-crud组件的使用示例,直接实现一个日志管理页面:

<template>
  <div class="app-log-page flex pt-[10px]">
    <f-crud
      ref="fcrud"
      :option="option"
      :operate="operate"
      :formProps="formProps"
      v-model="form"
      class="p-[12px] w-full"
    >
      <!-- 自定义列渲染:显示应用Logo -->
      <template #appLogoUrl="{ row }">
        <img v-if="row.appLogoUrl" :src="row.appLogoUrl" alt="" width="60px" height="60px">
      </template>
      <!-- 可选插槽:自定义操作按钮 -->
      <template #menuLeft="{ row }"></template>
      <template #menu="{ row }"></template>
      <template #search-menu="{ row }"></template>
    </f-crud>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted } from "vue";

// 搜索表单数据
const form = ref({ status: "", userName: "", includedSub: true });

// CRUD 接口配置
const operate = ref({
  getList: "/getItalentSyncLogList",
  postUrl: "/admin/data/area",
  putUrl: "/admin/data/area",
  delUrl: "/admin/data/area/",
});

const fcrud = ref(null);

// 分页等基础属性
const formProps = ref({ pageSize: 10 });

// 表格及表单配置
const option = () => ({
  border: true,
  searchSpan: 4,
  searchLabelWidth: 1,
  searchIcon: true,
  searchGutter: 20,
  searchMenuSpan: 7,
  searchIndex: 5,
  indexWidth: 60,
  emptyBtnText: "重置",
  columnBtn: false,
  index: true,
  align: "center",
  column: [
    { label: "北森修改人", prop: "operatorName" },
    { label: "动作", prop: "actionTypeName" },
    { label: "类型", prop: "typeName" },
    { label: "同步前组织名称", prop: "name" },
    { label: "同步前信息", prop: "beforeUpdate", showOverflowTooltip: true, overHidden: true, width: 250 },
    { label: "同步后信息", prop: "afterUpdate", showOverflowTooltip: true, overHidden: true, width: 250 },
    { label: "创建时间", prop: "createTime", width: 200, align: "center" },
    // 搜索字段(隐藏在表格中)
    { prop: "beforeUpdate", search: true, hide: true, placeholder: "修改前信息搜索", width: 250 },
    { prop: "afterUpdate", search: true, hide: true, placeholder: "修改后信息搜索" },
    {
      prop: "actionType",
      placeholder: "操作类型",
      search: true,
      hide: true,
      type: "select",
      dicData: [
        { label: "新增", value: "1" },
        { label: "修改", value: "2" },
        { label: "禁用", value: "3" },
      ],
    },
  ],
});

// 初始化加载数据
onMounted(() => {
  fcrud.value.getList();
});
</script>

<style lang="scss" scoped></style>

效果图

效果图

通过以上代码,只需配置option(表格和表单结构)、operate(接口地址)和formProps(分页参数),即可实现完整的增删改查功能。


2. 封装层代码 (f-crud.vue)

f-crud组件基于AVue的avue-crud,对其进行封装,统一处理数据请求、分页、表单等逻辑:

<template>
  <div>
    <avue-crud
      v-loading="data.listLoading"
      @search-reset="resetList"
      element-loading-text="Loading..."
      element-loading-spinner="svg"
      ref="crud"
      v-model:page="data.page"
      v-model:search="data.tForm"
      v-model="data.tForm"
      @row-update="rowEdit"
      @row-save="rowSave"
      @search-change="handleFilter"
      @size-change="sizeChange"
      @current-change="currentChange"
      @row-del="rowDelete"
      @refreshChange="handleRefreshChange"
      :data="data.list"
      :option="option()"
      :beforeOpen="beforeOpen"
      @selection-change="selectionChange"
    >
      <template #menu="{ row }">
        <slot name="menu" :row="row"></slot>
      </template>
      <template #menu-left="{ row }">
        <slot name="menuLeft" :row="row"></slot>
      </template>
      <template #search-menu="{ row }">
        <slot name="search-menu" :row="row"></slot>
      </template>
      <template #appLogoUrl="{ row }">
        <slot name="appLogoUrl" :row="row"></slot>
      </template>
    </avue-crud>
  </div>
</template>

<script setup lang="ts">
import { reactive, watch, ref, onMounted } from "vue";
import { useTable } from "@/utils/use-table";

interface Props<T = any> {
  operate: T;
  modelValue: T;
  formProps?: T;
  option: T;
}

const props = withDefaults(defineProps<Props>(), {
  operate: { getList: "", postUrl: "", putUrl: "", delUrl: "" },
  modelValue: {},
  formProps: {},
  option: () => {},
});

const crud = ref<any>(null);
const data = reactive({
  page: {
    total: 0,
    currentPage: 1,
    pageSize: props.formProps.pageSize || 20,
    isAsc: false,
  },
  listLoading: true,
  getList: props.operate.getList,
  postUrl: props.operate.postUrl,
  putUrl: props.operate.putUrl,
  delUrl: props.operate.delUrl,
  props: props.formProps,
  query: {},
  list: [],
  tForm: {},
});

const emit = defineEmits(["update:modelValue", "selectionChange"]);

const beforeOpen = (done: Function) => {
  crud.value.dicInit();
  done();
};

watch(() => data.tForm, (value) => emit("update:modelValue", value));

onMounted(() => {
  data.tForm = props.modelValue;
});

const selectionChange = (list) => emit("selectionChange", list);

const resetList = () => getList();

const { getList, rowSave, rowEdit, rowDelete, handleFilter, handleRefreshChange, currentChange, sizeChange } =
  useTable(data);

defineExpose({ getList, rowSave, rowEdit, rowDelete, handleFilter, handleRefreshChange, currentChange, sizeChange, data, crud });
</script>

3. 逻辑层代码 (use-table.ts)

use-table是一个独立的工具函数,封装了CRUD的核心逻辑,包括数据获取、分页处理和表单操作:

import { ElMessageBox, ElNotification } from "element-plus";
import Api from "@/api/common";

export function useTable(data: any) {
  const getList = (params: any = {}) => {
    params = Object.assign(params, data.tForm, data.props || {});
    data.listLoading = true;
    return Api.getList(
      { ...params, pageNum: data.page.currentPage, pageSize: data.page.pageSize },
      data
    ).then((response: any) => {
      data.list = response.data.resultData?.list || response.data.resultData;
      data.page.total = response.data.resultData?.total;
      data.listLoading = false;
    });
  };

  const handleFilter = (param: any, done: Function) => {
    data.page.currentPage = 1;
    getList(param);
    done && done();
  };

  const handleRefreshChange = (current?: number) => {
    if (current) data.page.currentPage = current;
    getList();
  };

  const sizeChange = (pageSize: number) => {
    data.page.pageSize = pageSize;
    handleRefreshChange();
  };

  const currentChange = (current: number) => {
    data.page.currentPage = current;
    handleRefreshChange();
  };

  const rowSave = async (form: any, done: Function, loading: Function) => {
    if (data.props) Object.assign(form, data.props);
    await Api.post(form, data).then(() => {
      ElNotification({ message: "操作成功", type: "success" });
      done();
      loading();
      handleRefreshChange();
    }).catch(loading);
  };

  const rowEdit = async (form: any, index: number, done: Function, loading: Function) => {
    if (data.props) Object.assign(form, data.props);
    await Api.put(form, data).then(() => {
      ElNotification({ message: "操作成功", type: "success" });
      done && done();
      loading && loading();
      handleRefreshChange();
    }).catch(loading);
  };

  const rowDelete = (form: any) => {
    ElMessageBox.confirm("此操作将永久删除该数据,是否继续?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    }).then(async () => {
      await Api.del(form.id, data);
      ElNotification({ message: "操作成功", type: "success" });
      handleRefreshChange();
    });
  };

  return { getList, rowSave, rowEdit, rowDelete, handleFilter, handleRefreshChange, currentChange, sizeChange };
}

4. 请求层代码 (common.ts)

封装Axios请求,提供统一的接口调用方法:

import request from "@/plugins/axios";

const common = {
  getList: (params: {}, { getList = "", id = "" }) =>
    request({ url: getList + id, method: "get", params }),
  post: (data: {}, { postUrl = "", postMethod = "post" }) =>
    request({ url: postUrl, method: postMethod, data }),
  del: (id: string, { delUrl = "", delMethod = "delete" }, params = {}) =>
    request({ url: delUrl + id, method: delMethod, params }),
  put: (data: {}, { putUrl = "", putMethod = "put" }) =>
    request({ url: putUrl, method: putMethod, data }),
};

export default common;

三、使用方法

  1. 引入组件:将f-crud.vue注册到项目中。
  2. 配置参数
    • option:定义表格列、搜索字段和样式。
    • operate:提供CRUD接口地址。
    • formProps:设置分页等额外参数。
  3. 绑定数据:通过v-model绑定搜索表单数据。
  4. 自定义扩展:通过插槽自定义列渲染或按钮。

四、优点与建议

优点

  • 高效开发:只需少量配置即可实现完整CRUD功能。
  • 代码复用:逻辑抽离到use-table,便于维护和复用。
  • 灵活性:支持插槽和AVue原生属性,满足复杂需求。

建议

如果对样式要求不高,可以考虑使用百度的AMIS低代码框架。AMIS提供更强大的CRUD功能和更高的开发效率,尤其适合快速原型开发。

  • AVue官网:https://avuejs.com/
  • AMIS官网:https://aisuda.bce.baidu.com/amis/zh-CN/docs/index

希望这个封装方案能帮助你更高效地构建后台管理系统!如果有其他需求,可以随时交流优化方案。


这篇文章基于xai进行重新编辑


http://www.kler.cn/a/556038.html

相关文章:

  • Amazon Lex:AI对话引擎重构企业服务新范式
  • 应用层的协议-http/https的状态码
  • OSPF | 理论 / 实验
  • ubuntu 守护进程
  • QSplashScreen --软件启动前的交互
  • 项目汇报PPT转视频制作 | 有字幕和配音版
  • 【知识】深度学习中,应该先zero_grad还是先backward?
  • 让浏览器AI起来:基于大模型Agent的浏览器自动化工具
  • 实现rolabelimg对于dota格式文件的直接加载和保存
  • 轻松美化双系统启动界面与同步时间设置(Windows + Ubuntu)
  • 每天设计者模式-1:基础面试题
  • AF3 _build_query_to_hit_index_mapping函数解读
  • windows 安装 stable diffusion
  • CPCI机箱 阿尔泰科技4槽2U CPCI测控机箱 后IO走线 CPCIC7604A
  • Java——列表(List)
  • org.mortbay.jetty和org.eclipse.jetty的区别
  • 第4章 信息系统架构(五)
  • CNN 卷积神经网络【更新中】
  • Web数据管理复习考点整理
  • PyTorch-基础(CUDA、Dataset、transforms、卷积神经网络、VGG16)