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

news/2025/2/23 4:03:37

基于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.niftyadmin.cn/n/5862948.html

相关文章

Spring AI + Ollama 实现调用DeepSeek-R1模型API

一、前言 随着人工智能技术的飞速发展&#xff0c;大语言模型&#xff08;LLM&#xff09;在各个领域的应用越来越广泛。DeepSeek 作为一款备受瞩目的国产大语言模型&#xff0c;凭借其强大的自然语言处理能力和丰富的知识储备&#xff0c;迅速成为业界关注的焦点。无论是文本生…

大数据SQL调优专题——引擎优化

引入 通过前面对目前大数据领域常见数据处理技术执行原理的梳理&#xff0c;我们会发现一条SQL语句&#xff0c;想要最终转换成集群可执行的物理计划&#xff0c;通常会经过如下图所示的一系列过程&#xff1a; 通常这些数据处理技术都会抽象一个执行器&#xff08;Driver&…

docker的mysql容器修改数据库root的登录密码后,navicat依然能用旧密码访问

1. docker进入mysql。 2.修改及查看账户。 USE mysql; SELECT User, Host, plugin FROM user WHERE User root; 3. 更新账户密码。 -- 更新 rootlocalhost 密码 ALTER USER rootlocalhost IDENTIFIED WITH caching_sha2_password BY 新密码; -- 更新 root% 密码&#xff…

模拟实现分布式文件存储

Q1:如何解决海量数据存的下的问题 传统做法是在单机存储。但是随着数据变多&#xff0c;会遇到存储瓶颈。 单机纵向扩展&#xff1a;内存不够加内存&#xff0c;磁盘不够加磁盘。有上限限制&#xff0c;不能无限制加下去。 多机横向扩展&#xff1a;采用多台机器存储&#x…

Vue 3 生命周期和生命周期函数

Vue.js 是一个用于构建用户界面的渐进式框架。随着 Vue 3 的发布&#xff0c;它引入了许多新的功能和改进&#xff0c;包括更灵活和性能更高的生命周期管理。在这份文档中&#xff0c;我们将详细介绍 Vue 3 的生命周期和相关生命周期函数。 一、生命周期概述 Vue 实例在其生命…

Python 入门教程(2)搭建环境 | 2.3、VSCode配置Python开发环境

文章目录 一、VSCode配置Python开发环境1、软件安装2、安装Python插件3、配置Python环境4、包管理5、调试程序 前言 Visual Studio Code&#xff08;简称VSCode&#xff09;以其强大的功能和灵活的扩展性&#xff0c;成为了许多开发者的首选。本文将详细介绍如何在VSCode中配置…

同程旅行对象存储实践:架构演进与未来展望

在数字化转型的浪潮中&#xff0c;同程旅行作为旅游行业的佼佼者&#xff0c;面临着海量数据存储与管理的挑战。为了应对这一挑战&#xff0c;同程旅行研发中心架构师周祝群及其团队开展了一系列对象存储实践&#xff0c;旨在构建一个可扩展、高可用、高性能且低成本的存储解决…

【ISO 14229-1:2023 UDS诊断(ECU复位0x11服务)测试用例CAPL代码全解析⑫】

ISO 14229-1:2023 UDS诊断【ECU复位0x11服务】_TestCase12 作者&#xff1a;车端域控测试工程师 更新日期&#xff1a;2025年02月18日 关键词&#xff1a;UDS诊断协议、ECU复位服务、0x11服务、ISO 14229-1:2023 TC11-012测试用例 用例ID测试场景验证要点参考条款预期结果TC…