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

react + ant 封装Crud-根据配置生成对应的页面

在这里插入图片描述
在这里插入图片描述

后台管理系统中很多基础的页面的都是差不多都是crud这种,对于这种可以封装成一个crud组件页面通过配置来生成对应界面

页面配置项

主要是分为搜索条件、批量操作按钮、表格、crud接口等配置

const CurdConfig = (childRef) => {return {// 页面搜索条件pageSearch: {formConfig: {},formList: []},// 批量操作按钮pageBatchButtons: [],// 表格列pageTable: {},// 基础弹框配置dialogFormListConfig: {},// 页面接口pageApi: {// 查询getList: accessAuthorityList,// 删除delete: accessAuthorityDeleteBatch,// 新增add: accessAuthorityAdd,// 编辑edit: accessAuthorityUpdate,// 详情detail: accessAuthorityDetail}}
}export default CurdConfig

搜索条件

pageSearch主要是包括两个,

  • .formConfig主要form组件的配置
  • formList 就是每个表单控件的配置,每个对象就是一个表单控件
    • component 组件类型
    • formItemConfig formItem的配置
    • componentConfig: 每个表单组件的额外配置
pageSearch: {formConfig: {},formList: [{component: Select, // 组件类型formItemConfig: {label: '启用状态',name: 'enableFlag',},componentConfig: { // 配置项placeholder: '请选择',fieldNames: {label: 'text',value: 'id'},options: getDictOptions(DictEnum.ENABLE_FLAG)}},]
}

页面批量操作按钮

  • label: 按钮的名称
  • permission: 权限码
  • config: 按钮的一些配置
  • click: 按钮点击事件
pageBatchButtons:{{label: '新增',permission: '',config: {icon: <PlusOutlined />,iconPosition: 'start', // start | end},click: ($event) => {$event.addClick()}},
}

表格带分页

  • tableConfig: 表格的配置
  • paginationConfig: 分页的配置
  • columns: 每列表格的配置
pageTable: {tableConfig: {},paginationConfig:{},columns: [{{title: '序号',dataIndex: 'key',align: 'center',width: 70,render: (_, __, index) => index + 1},{title: '菜单名称',dataIndex: 'targetName',align: 'center',minWidth: 100,render: (_, row) => {return (<div>{`${row["targetName"]}[${row["target"]}]`}</div>);}},}]
}

基础新增 编辑 查看配置

  • modalConfig: 弹框的配置
  • formConfig: 弹框表单的form配置
  • formList: 每个表单控件的配置
dialogFormListConfig: {modalConfig: {},formConfig: {labelCol: { span: 6 },},formList: [{component: Input, // 组件类型formItemConfig: {label: '菜单代码',name: 'target',rules: [{ required: true, message: "目标菜单必填" },{ min: 1, max: 64, message: "不超过64个字符" }],},componentConfig: { // 配置项placeholder: '请输入',}},]
}

页面crud接口

主要是五项getList查询、delete删除、add新增、edit编辑、detial查询详情数据

    pageApi: {// 查询getList: accessAuthorityList,// 删除delete: accessAuthorityDeleteBatch,// 新增add: accessAuthorityAdd,// 编辑edit: accessAuthorityUpdate,// 详情detail: accessAuthorityDetail}

每个页面组件

import { useRef } from 'react';
import Crud from '@/components/Crud'
import CurdConfig from './util/crudConfig'
const Authority = () => {const childRef = useRef(null);const pageConfig = CurdConfig(childRef)return (<Crud { ...pageConfig } ref={childRef} />);
}export default Authority;

crud组件

import React, { forwardRef, useImperativeHandle, useEffect, useState, useCallback } from 'react';
import { Row, Col, Form, Button, Flex, Divider, Splitter, Table, Pagination, message, Modal } from 'antd';
import { DownOutlined, UpOutlined, ExclamationCircleFilled } from '@ant-design/icons';
import TreePage from './components/TreePage.tsx'
import DialogModal from './components/DialogModal.tsx';
import './index.scss'
import { DialogType } from '@/enums/commonEnum'
type ModelType = 'add' | 'edit' | 'view'
const Authority = (props, ref) => {const [ messageApi, contextHolder ] = message.useMessage();const { confirm } = Modal;const { pageLeftTree, pageSearch, pageBatchButtons, pageTable, dialogFormListConfig, pageApi } = props// 搜索表单数据源const { formList } = pageSearchconst [isExpand, setIsExpand] = useState(false)const [isExpandLength, setIsExpandLength] = useState(3)const [form] = Form.useForm();// 表格const [tableList, setTableList] = useState([])const [total, setTotal] = useState(0)const [pageNumber, setPageNumber] = useState(1)const [pageSize, setPageSize] = useState(10)// 弹框const [modelType, setModelType] = useState<ModelType>()  const [isModalOpen, setIsModalOpen] = useState(false)// 当前行数据const [rowData, setRowData] = useState<any>({})// 展开收起const handleExpand = () => {setIsExpand(!isExpand)setIsExpandLength(isExpand ? 3 : formList.length)}// 查询const handleSearch = () => {getData()}// 重置const handleReset = () => {form.resetFields()setPageNumber(1)setPageSize(10)getData()}// 分页const onPageChange = (page: number, pageSize: number) => {setPageNumber(page)setPageSize(pageSize)}const getData = useCallback(async () => {const query = { pageNumber, pageSize, ...form.getFieldsValue(true) }const res = await pageApi.getList(query);setTableList(res.records)setTotal(res.total)}, [pageNumber, pageSize, form, pageApi]);useEffect(() => {getData()}, [getData, pageNumber, pageSize])// 新增const addClick = () => {setIsModalOpen(true)setModelType(DialogType.ADD)}// 编辑const editClick = (row) => {setRowData(row)setIsModalOpen(true)setModelType(DialogType.EDIT)}// 批量删除const deleteBatchClick = (row: React.Key[]) => {if(!row || row.length === 0) {return messageApi.warning('请选择要删除的数据')}confirm({title: '提示',icon: <ExclamationCircleFilled />,content: '是否删除所选中数据?',onOk: async() => {try {await pageApi.delete(row)messageApi.success('删除成功')getData()} catch (error: any) {messageApi.error(error)}},onCancel() {},});}// 删除const deleteClick = (row) => {confirm({title: '提示',icon: <ExclamationCircleFilled />,content: '是否删除所选中数据?',onOk: async() => {try {await pageApi.delete([row.id])messageApi.success('删除成功')getData()} catch (error: any) {messageApi.error(error)}},onCancel() {},});}// 弹框确定const onConfirm = async (form, type) => {try {if(type === DialogType.ADD) {await pageApi.add(form)} else {await pageApi.edit(form)}messageApi.success('操作成功')setIsModalOpen(false)getData()} catch (error: any) {messageApi.error(error)}}// 弹框取消const onCancel = () => {setIsModalOpen(false)}// 暴露出去useImperativeHandle(ref, () => ({editClick: editClick,deleteClick: deleteClick,getData: getData}))return (<div className='crud-container'>{contextHolder}<Splitter style={{ height: '100%' }}>{/* 左侧树 */}{pageLeftTree && <Splitter.Panel defaultSize="15%" min="15%" max="70%"><div className='tree-page'><TreePage {...pageLeftTree } form={form} getData={getData} /></div></Splitter.Panel>}<Splitter.Panel><div className='right-page'>{/* 表单搜索条件 */}<div className='search-form'><Form{...pageSearch.formConfig}form={form}name="control-hooks"className='form-box'><Row gutter={20}>{formList.slice(0, isExpandLength).map((item, index) => { const Component = item.componentreturn (<Col span={8} key={index}><Form.Item{...item.formItemConfig}><Component { ...item.componentConfig} /></Form.Item></Col>);})}</Row></Form><Flex gap="small" wrap>{ pageSearch.formList.length > 3 && <Button icon={isExpand ? <UpOutlined /> : <DownOutlined />} onClick={ handleExpand }>{ isExpand ? '收起' : '展开'}</Button>}<Button onClick={handleReset}>重置</Button><Button type="primary" onClick={handleSearch}>查询</Button></Flex></div><Divider size="small" />{/* 批量操作按钮 */}<Flex gap="small" wrap>{ pageBatchButtons.map((item, index) => {return <>{ item.type && item.type === 'slot' ? item.render() : <Button key={index} {...item.config } onClick={() => item.click({ addClick, deleteBatchClick })}>{ item.label }</Button>  }</>})}</Flex>{/* 表格 */}<div className='table-container'><Table{...pageTable.tableConfig}borderedrowKey="id"className="table"size="small"columns={pageTable.columns} dataSource={tableList} pagination={false}/><Pagination{...pageTable.paginationConfig}total={total}showSizeChangershowQuickJumperonChange={onPageChange}defaultCurrent={pageNumber}defaultPageSize={pageSize}showTotal={(total) => `${total}`}/></div></div></Splitter.Panel></Splitter>{/* 弹框 */}<DialogModal config={dialogFormListConfig} rowData={rowData} modelType={modelType} isModalOpen={isModalOpen} onConfirm={onConfirm} onCancel={onCancel} /></div>);
}export default forwardRef(Authority);

弹框组件

import { Modal, Form, Row, Col } from 'antd'
import { DialogType } from '@/enums/commonEnum'
import { useEffect } from 'react'
const DialogModal = (props) => {const { isModalOpen, onCancel, onConfirm, config, modelType, rowData } = propsconst [form] = Form.useForm();type ShowType = 'addShow' | 'editShow' | 'viewShow' | boolean;useEffect(() => {if(modelType === DialogType.EDIT) {form.setFieldsValue(rowData)} else if(modelType === DialogType.ADD) {form.resetFields()}})const modalTitle = () => {return modelType === DialogType.ADD ? '新增' : modelType === DialogType.EDIT ? '编辑' : '查看'}const handleOk = () => {if(typeof onConfirm === 'function') {form.validateFields().then(() => {onConfirm(form.getFieldsValue(true), modelType)})}}const handleCancel = () => {if(typeof onCancel === 'function') {form.resetFields();onCancel()}}// 表单是否展示const isShow = (type: ShowType) => {if(!type) return true;const typeMap = {[DialogType.ADD]: 'addShow',[DialogType.EDIT]: 'editShow',[DialogType.VIEW]: 'viewShow'};if (typeof type === 'boolean') {return type;}const currentType = typeMap[modelType];return currentType ? type.includes(currentType) : true;}return (<Modal{...config?.modalConfig}title={modalTitle()}open={isModalOpen}onOk={handleOk}onCancel={handleCancel}width={800}><Form{...config?.formConfig}form={form}className='form-box'><Row gutter={20}>{config?.formList?.map((item) => { const { component: Component, formItemConfig, componentConfig } = item;if (!isShow(componentConfig?.editShow)) {return null;}const itemKey = item.id || formItemConfig.name || componentConfig.key || item.label;return (<Col span={12} key={itemKey}><Form.Item {...formItemConfig}><Component {...componentConfig} /></Form.Item></Col>);})}</Row></Form></Modal>)
}export default DialogModal;
http://www.dtcms.com/a/464848.html

相关文章:

  • 10-支持向量机(SVM):讲解基于最大间隔原则的分类算法
  • 微算法科技(NASDAQ:MLGO)开发延迟和隐私感知卷积神经网络分布式推理,助力可靠人工智能系统技术
  • 【Qt开发】输入类控件(六)-> QDial
  • 在JavaScript / HTML中,Chrome报错此服务器无法证实它就是xxxxx - 它的安全证书没有指定主题备用名称
  • 如何建一个免费的网站流量对网站排名的影响因素
  • PawSQL宣布支持DB2数据库SQL审核和性能优化
  • 在JavaScript / HTML中,div容器在内容过多时不显示超出的部分
  • webrtc弱网-RobustThroughputEstimator源码分析与算法原理
  • WPF依赖属性
  • 数据可视化 ECharts
  • javascript 性能优化实例一则
  • mapbox基础,使用矢量切片服务(pbf)加载line线图层
  • LLVM(Low Level Virtual Machine)介绍
  • Docker 一键部署指南:GitLab、Nacos、Redis、MySQL 与 MinIO 全解析
  • HDLBit 个人记录
  • 基于Jetson+FPGA+GMSL+AI的自动驾驶数据采集解决方案
  • 0006.C#学习笔记3-- HTML和CSS
  • 基于X86+FPGA+GPU的自动驾驶数据回灌测试解决方案
  • 在JavaScript / HTML中,Chrome报错Refused to execute inline script
  • 自动驾驶的“虚拟驾校”如何炼成?
  • 自动驾驶传感器数据录制过程中的五大系统性挑战
  • 学校网站建设开题报告书wordpress 发布说说
  • 企业如何减少由于数据不一致带来的运营成本?
  • 安卓开发APP应用程序和苹果iOS开发APP应用程序有什么区别?
  • Mac 上用 Homebrew 安装 JDK 8(适配 zsh 终端)完整教程
  • 利用小偷程序做网站企业网站开发建设
  • K8S基本命令操作
  • 【kubernetes/k8s源码分析】kube-controller-manager之node controller源码分析
  • SMOTE 算法详解:解决不平衡数据问题的有效工具
  • HGDB集群(安全版)repmgr手动切换主备库