react使用antd-design动态渲染组件,封装通用modal弹出form表单组件、table组件(传数据出页面)

react使用antd-design封装通用modal弹出form表单组件、table组件并附带1.upload上传图片转base64、2.批量插入excel表格数据

页面展示效果
在这里插入图片描述

在这里插入图片描述

第一步项目中创建CommonForm.js文件对antd-design中Form组件封装

import { Image, Form, Input, Button, Radio, Select, TimePicker, Checkbox, Upload, message } from "antd";
import React, { Component } from "react";
import { InboxOutlined } from '@ant-design/icons';
import RichText from "../RichText/RichText";
const layout = {
    labelCol: { span: 6 },
    wrapperCol: { span: 12 },
};
const tailLayout = {
    wrapperCol: {
        offset: 6,
        span: 12,
    },
};
const CheckboxGroup = Checkbox.Group;
const url = "http://127.0.0.1:5001/";
class CommonForm extends Component {
    constructor(props) {
        super(props)
        const excelName = this.props.excelName  //当前导出excel的文件名称(由)
        this.state = {
            url: "",
            pr: {
                customRequest: this.customRequest,
                showUploadList: false, // 不展示文件列表
                beforeUpload: this.beforeUpload
            },
            prexcel: {
                // 发到后台的文件参数名
                name: 'file',
                // 接受的文件类型
                accept: '.xls,.xlsx',
                // 上传的地址
                action: url + "api/ExcelFile",
                // 是否展示上传的文件
                showUploadList: false,
                // 上传的参数
                data: {
                    type:excelName
                },
                // 设置上传的请求头部,IE10 以上有效
                headers: {
                    authorization: 'authorization-text',
                },
                // 上传文件前的钩子函数
                beforeUpload() {
                    message.loading('正在导入中...');
                    return true;
                },
                // 上传文件改变时的状态
                onChange(info) {
                    if (info.file.status !== 'uploading') {
                        console.log(info.file, info.fileList);
                    }
                    if (info.file.status === 'done') {
                        if (info.file.response.code !== 200) {
                            setTimeout(() => {
                                message.destroy();
                                message.error(info.file.response.message);
                            });
                        } else {
                            this.props.importSuccessCallback && this.props.importSuccessCallback();
                            setTimeout(() => {
                                message.destroy();
                                message.success('导入成功');
                            });
                        }
                    } else if (info.file.status === 'error') {
                        setTimeout(() => {
                            message.destroy();
                            message.error('导入失败');
                        });
                    }
                },

            }

        };

    }

    /**
    获取file,通过FileReader获取图片的 base64
*/
    customRequest = (option) => {
        const formData = new FormData();
        formData.append("files[]", option.file);
        const reader = new FileReader();
        reader.readAsDataURL(option.file);
        reader.onloadend = (e) => {
            this.setState({
                url: e.target.result
            })

            //将base64前面类型截取
            let noPrefix = e.target.result.replace(/^data:image\/\w+;base64,/, '')
            
            this.props.base64url(noPrefix); //将处理好的base64传回当前调用的组件
            // console.log(e.target.result);// 打印图片的base64
            if (e && e.target && e.target.result) {
                option.onSuccess();
            }
        };
    }

    /***
        上传验证格式及大小
    */
    beforeUpload = (file) => {
        const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
        if (!isJpgOrPng) {
            message.error("只能上传JPG或PNG文件!");
            return false;
        }
        const isLt2M = file.size / 1024 / 1024 / 1024 <= 500;
        if (!isLt2M) {
            message.error("图片大小需小于500kb!");
            return false;
        }
        return isJpgOrPng && isLt2M;
    }




    formRef = React.createRef()
    onFinish = (values) => {
        this.props.Modal.submit(values)
    }
    onValuesChange = (values, allValues) => {
        if (this.props.FormOnChange) {
            this.props.FormOnChange(allValues)
        }
    }
    normFile = (e) => {
        if (Array.isArray(e)) {
            return e;
        }

        return e && e.fileList;
    };
    componentDidMount() {
        this.setState({
            url: ""
        })
    }

    //根据传回来的类型进行分类标签创建
    render() {

        return (
            <>
                <Form
                    ref={this.formRef}
                    {...layout}
                    // labelCol={this.props.isInline ? {span: 24,off  }: { span: 4 }}
                    // wrapperCol={this.props.isInline ? { span: 24 }: { span: 12 }}
                    name="basic"
                    key="basic"
                    layout={this.props.isInline ? "inline" : "horizontal"}
                    onFinish={this.onFinish}
                    onValuesChange={this.onValuesChange}
                    initialValues={this.props.defaultValue}
                    
                >
                    {
                        this.props.Form.length ? (
                            this.props.Form.map((item, i) => {
                                return this.createForm(item, i)
                            })
                        ) : (
                            <>
                            </>
                        )
                    }
                    <Form.Item {...tailLayout} >
                        <Button key="button" type="primary"  htmlType="submit" >确定</Button>
                    </Form.Item>
                </Form>
            </>
        )
    }
    copyFormValue(item) {
        setTimeout(() => {
            const key = item.name
            var obj = {}
            obj[key] = item.value
            this.formRef.current.setFieldsValue(obj)
        }, 100);
    }
    onChange(checkedValues) {
        // console.log('checked = ', checkedValues);
    }

    createForm(item, i) {
        this.copyFormValue(item)
        switch (item.type) {
            case "input":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    rules={[{ required: item.isRequired, message: `请输入您的${item.label}` }]}
                >

                    <Input placeholder={item.placeholder} disabled={item.isDisable} />
                </Form.Item>
            case "radio":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    rules={[{ required: item.isRequired, message: `请选择您的${item.label}` }]}
                >
                    {
                        item.isGroup ? (
                            <Radio.Group placeholder={item.placeholder}>
                                {
                                    item.radioArr.map((radio, index) => {
                                        return (
                                            <Radio key={index} value={radio.value}>{radio.label}</Radio>
                                        )
                                    })
                                }
                            </Radio.Group>

                        ) : (
                            <>
                                {/* 
                                {
                                    radio:{
                                        label:"",
                                        value:""
                                    }
                                }
                             */}
                                <Radio value={item.radio.value}>{item.radio.label}</Radio>
                            </>
                        )
                    }

                </Form.Item>
            case "select":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    rules={[{ required: item.isRequired, message: `请选择您的${item.label}` }]}
                >
                    <Select
                        placeholder="akjsgdjahgsdjh"
                        onChange={item.onChange}>
                        {
                            item.option.length ? (
                                item.option.map((select, index) => {
                                    return (
                                        <Select.Option key={index} value={select.id}>{select.Name}</Select.Option>
                                    )
                                })
                            ) : (
                                <>
                                    return (
                                    <Select.Option key="none" value="">暂无数据</Select.Option>
                                    )
                                </>
                            )
                        }
                    </Select>
                </Form.Item>
            case "textarea":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    rules={[{ required: item.isRequired, message: `请输入您的${item.label}` }]}
                >
                    <Input.TextArea placeholder={item.placeholder} />
                </Form.Item>
            case "upload":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    rules={[{ required: item.isRequired, message: `请选择要上传的图片` }]}
                    valuePropName="fileList" getValueFromEvent={this.normFile}
                >
                    <Upload.Dragger  {...this.state.pr}>
                        <p className="ant-upload-drag-icon">
                            <InboxOutlined />
                        </p>
                        <p className="ant-upload-text">单击或拖动文件到该区域进行上传</p>
                        <p className="ant-upload-hint">支持单个或批量上传</p>
                        <Image preview={false} src={this.state.url} />
                    </Upload.Dragger>
                </Form.Item>
            // 多选
            case "multiple":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    rules={[{ required: item.isRequired, message: `请选择您的${item.label}` }]}
                >
                </Form.Item>
            //checkbox
            case "checkbox":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    rules={[{ required: item.isRequired, message: `请选择您的${item.label}` }]}
                >
                    <CheckboxGroup placeholder={item.placeholder} defaultValue={item.defaultValue} options={item.option} onChange={this.onChange} />
                </Form.Item>
            //checkbox
            case "timepicker":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    rules={[{ required: item.isRequired, message: `请选择您的${item.label}` }]}
                >
                    <TimePicker placeholder={item.placeholder} onChange={item.onChange} />
                </Form.Item>
            case "richtext":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    rules={[{ message: `请选择您的${item.label}` }]}
                >
                    <RichText that={this.props.that} ></RichText>
                </Form.Item>
            case "uploadexcel":
                return <Form.Item
                    label={item.label}
                    name={item.name}
                    key={i}
                    valuePropName="fileList" getValueFromEvent={this.normFile}
                >
                    <Upload.Dragger {...this.state.prexcel}>
                        <p className="ant-upload-drag-icon">
                            <InboxOutlined />
                        </p>
                        <p className="ant-upload-text">单击或拖动文件到该区域进行上传</p>
                        <p className="ant-upload-hint">支持单个或批量上传</p>
                    </Upload.Dragger>
                </Form.Item>
            default:
                return (
                    <>
                    </>
                )
        }
    }
}

export default CommonForm;

第二步创建CommonModal.js对antd-design中Table组件进行封装

import React, { Component } from 'react';
import { Table, Button, Row, Col, Form, Input, DatePicker } from 'antd';
import "./CommonTable.css"
import { Fragment } from 'react';
import ExportJsonExcel from 'js-export-excel'; //引入导出excel表格控件
const style = { padding: '8px 0' };


class CommonTable extends Component {
  constructor(props) {
    super(props)
    this.state = {
      filteredInfo: null,
      sortedInfo: null,
      current: 1,
      ordersUpdated: [{
        vslName: "S",
        docId: "!",
        test: "asdjhagsdjh"
      }],
      selectedRowKeys: [],//选中行数组
    };
  }
  componentDidMount() {

  }
  handleChange = (pagination, filters, sorter) => {
    console.log(pagination, filters, sorter)
    this.setState({
      filteredInfo: filters,
      sortedInfo: sorter,
    });
  };

  //导出excel



  clearFilters = () => {
    this.setState({ filteredInfo: null });
  };

  clearAll = () => {
    this.setState({
      filteredInfo: null,
      sortedInfo: null,
    });
  };

  setAgeSort = () => {
    this.setState({
      sortedInfo: {
        order: 'descend',
        columnKey: 'age',
      },
    });
  };
  onChange = (page, pagesize) => {
    this.setState({
      current: page,
    });
    // eslint-disable-next-line
    if (this.props.totalpage != undefined) {
      this.props.that.initFun(page, pagesize)
    }
  };
  createForm(item, i) {
    switch (item.type) {
      case "input":
        return <Form.Item
          label={item.label}
          name={item.name}
          key={i}
          rules={[{ required: item.isRequired, message: `请输入您的${item.label}` }]}
        >
          <Input placeholder={item.placeholder} disabled={item.isDisable} />
        </Form.Item>
      case "timepicker":
        return <Form.Item
          label={item.label}
          name={item.name}
          key={i}
          rules={[{ required: item.isRequired, message: `请输入您的${item.label}` }]}
        >
          <DatePicker placeholder={item.placeholder} />
        </Form.Item>
      default:
        break;
    }
  }
  onFinish = (values) => {
    this.props.queryTable(values)
  }
  reload = () => {
    this.props.reloadFun();
  }
  //选中行数据‘
  onSelectChange = selectedRowKeys => {
    console.log('selectedRowKeys changed: ', selectedRowKeys);
    this.setState({
      selectedRowKeys
    })
  };
  ExportToExcel = (tabledata) => {
    var option = {}
    let resdata = []
    let sheetfilter = []
    let sheetheader = []


    tabledata.forEach(element => {
      this.state.selectedRowKeys.forEach(item => {
        // eslint-disable-next-line
        if (element.id == item) {
          resdata.push(element)
        }
      })
    });


    this.props.TableColumns.forEach(element => {
      sheetfilter.push(element.dataIndex)
      sheetheader.push(element.title)
    });
    console.log(this.props.excelName)
    option.fileName = this.props.excelName  //导出的Excel文件名
    option.datas = [
      {
        sheetData: resdata,
        sheetName: 'sheet',
        sheetFilter: sheetfilter,
        sheetHeader: sheetheader,
      }
    ]

    var toExcel = new ExportJsonExcel(option);
    toExcel.saveExcel();
  }

  //配置table全选

  render() {
    const { selectedRowKeys } = this.state;
    const rowSelection = {
      selectedRowKeys,
      onChange: this.onSelectChange,
      selections: [
        Table.SELECTION_ALL,
        Table.SELECTION_INVERT,
        Table.SELECTION_NONE,
        {
          key: 'odd',
          text: 'Select Odd Row',
          onSelect: changableRowKeys => {
            let newSelectedRowKeys = [];
            newSelectedRowKeys = changableRowKeys.filter((key, index) => {
              if (index % 2 !== 0) {
                return false;
              }
              return true;
            });
            this.setState({ selectedRowKeys: newSelectedRowKeys });
          },
        },
        {
          key: 'even',
          text: 'Select Even Row',
          onSelect: changableRowKeys => {
            let newSelectedRowKeys = [];
            newSelectedRowKeys = changableRowKeys.filter((key, index) => {
              if (index % 2 !== 0) {
                return true;
              }
              return false;
            });
            this.setState({ selectedRowKeys: newSelectedRowKeys });
          },
        },
      ],
    }
    return (
      <>
        <Row justify="space-between" align="center" style={style} >
          {
            this.props.ButtonArr ? (
              this.props.ButtonArr.map((item, i) => {
                return (
                  <Col span={1} key={i}  flex={1}>
                    <Button type={item.type} onClick={item.ClickFun}>{item.ButtonText}</Button>
                  </Col>

                )
              })
            ) : (
              <Fragment />
            )
          }

          <Form
            layout="inline"
            ref={this.formRef}
            // labelCol={this.props.isInline ? {span: 24,off  }: { span: 4 }}
            // wrapperCol={this.props.isInline ? { span: 24 }: { span: 12 }}
            name="basic"
            key="basic"
            onFinish={this.onFinish}
          >

            {
              this.props.searchOption ? (
                this.props.searchOption.map((item, i) => {
                  return this.createForm(item, i)
                })
              ) : (
                <>
                </>
              )
            }
            {
              this.props.searchOption ? (
                <Form.Item>
                  <Row>
                    <Col style={{
                      marginRight: "10px"
                    }}>
                      <Button key="button" type="primary" htmlType="submit">查询</Button>
                    </Col>
                    <Col>
                      <Button key="clearbutton" onClick={this.reload}>重置</Button>
                    </Col>
                  </Row>
                </Form.Item>


              ) : (
                <Fragment />
              )
            }
            <Form.Item>
              <Button key="daochu" type="danger" onClick={() => { this.ExportToExcel(this.props.TableData) }}>导出 Excel</Button>
            </Form.Item>

          </Form>
        </Row>

        <Table
          scroll
          bordered
          rowSelection={rowSelection}
          loading={this.props.Loading}
          columns={this.props.TableColumns}
          dataSource={this.props.TableData}
          pagination={{
            showSizeChanger: true,
            showQuickJumper: true,
            current: this.state.current,
            total: this.props.totalpage,
            onChange: this.onChange,
            pageSizeOptions: [10, 20, 50, 100]
          }}
        />
      </>
    );
  }
}

export default CommonTable;

第三步创建CommonModal.js对antd-design中Modal组件进行封装

import React, { Component } from 'react';
import { Modal } from 'antd';
import  CommonForm  from "../Form/CommonForm";
//import CommonTable from '../Table/CommonTable';
//(CommonTable为通用封装的table组件)
import { Fragment } from 'react';
class CommonModal extends Component {
    // eslint-disable-next-line
    constructor(props){
        super(props)
    }
    render() {
        return( <>
            <Modal
                title={this.props.Modal.title} //弹出框title
                visible={this.props.Modal.isOpen} //弹出框是否打开
                footer={null} //弹出框底部按钮
                onCancel={this.props.Modal.cancel} //弹出框取消事件
                width={this.props.Modal.width} //弹出框的宽度
                centered={true}
                
            >
            <CommonForm
            excelName={this.props.excelName} //需要批量上传的excel参数
            that={this.props.that} //传入父组件 ,作用:可调用父组件中的属性及方法
            FormOnChange={this.props.FormOnChange} //监听表单值变化事件
            base64url={this.props.base64url} //为父组件base64传值
            initForm={this.props.initForm} 
            Form={this.props.Form} 
            isInline = {this.props.isInline} 
            Modal={this.props.Modal} 
            ></CommonForm>
            
            </Modal>
        </>
        )
    }
};
export default CommonModal;

第四步:调用页面中使用

import React, { Component } from 'react';
import CommonTable from "../../Components/Table/CommonTable"
import CommonModal from "../../Components/Modal/CommonModal"
import CommonDelete from "../../Components/Modal/CommonDelete" //(CommonDelete 可以自行删掉,封装的一个小弹窗)
import { Space, message } from "antd"
import {
    API_GET_ROLE, API_ADD_ROLE,
    API_GET_ROLE_AUTH,
    API_UPDATE_ROLE,
    API_UPDATE_ROLE_AUTH
} from '../../Helper/Role'; //这里全部是接口
class RoleList extends Component {
    constructor(props) {
        super(props)
        this.state = {
            TableData: [],
            TableColumns: [],   
            searchOption: [],
            ButtonArr: [],
            Modal: {
                title: "",
                isOpen: false,
                width: 0,
                submit: Function,
                cancel: Function
            },
            DeleteModal: {},
            Form: [],
            Loading: true,
            excelName:"角色列表"
        }

    }
    SetAuth = async (row) => {
       console.log("这里是操作中的按钮的方法")
    }
    EditTableFun = (row) => {
        this.setState({
            Form: [
                {
                    type: "input",
                    name: "name",
                    label: "角色名称",
                    value: row.name
                },
                {
                    type: "textarea",
                    name: "note",
                    label: "角色备注",
                    value: row.note
                },

            ],
            Modal: {
                title: "编辑角色",
                isOpen: true,
                width: 600,
                submit: async (values) => {
                    console.log(values.name)
                    console.log(values.note)
                    //这个是按钮的点击方法
                },
                cancel: () => {
                //这个是弹窗取消事件
                    let originModal = this.state.Modal
                    originModal.isOpen = false;
                    this.setState({
                        Modal: originModal
                    })
                },
                row: row
            }
        })
    }
    //点击查询事件 
    async queryTable(values) {
        //这个是查询按钮
        // eslint-disable-next-line
        if (values.name == undefined) {
            message.error("查询字段不能为空!")
            return
        }
        let res = await API_GET_ROLE({ name: values.name });
        switch (res.data.response) {
            case "success":
                this.that.setState({
                    TableData: res.data.results
                })
                //console.log(this.that.state)
                break;
            default:
                break;
        }
    }
    async reloadFun() {
        //console.log("重置")
        let res = await API_GET_ROLE();
        switch (res.data.response) {
            case "success":
                this.that.setState({
                    TableData: res.data.results
                })
                break;
            default:
                break;
        }
    }
    cancel() {
        let originModal = this.state.Modal
        originModal.isOpen = false;
        this.setState({
            Modal: originModal
        })
        this.initFun();
    }
    isDeleteWin(row) {
        //弹出确认框
       console.log("这个是删除事件")
    }
    async initFun() {
    	//初始化table数据事件
        const res = await API_GET_ROLE({})
        console.log(res)
        switch (res.data.response) {
            case "success":
                console.log("给table表格赋值")
                this.setState({
                    Loading: false,
                    TableData: res.data.results,
                })
                break;
            default:
                this.setState({
                    Loading: false
                })
                break;
        }
    }
    componentDidMount() {
    	//请求数据存放table
        this.initFun();
        //初始化页面所需组件
        this.setState({
            Loading: false,
            TableData: [],
            TableColumns: [
                {
                    title: '角色名称',
                    dataIndex: 'name',
                    width: 180
                },
                {
                    title: '备注',
                    dataIndex: 'note',
                },
                {
                    title: '操作',
                    key: 'action',
                    fixed: 'right',
                    width: 200,
                    render: (text, row) => (
                        <Space size="middle">
                            {/* eslint-disable-next-line */}
                            <a onClick={() => { this.SetAuth(row) }}>设置权限</a>
                            {/* eslint-disable-next-line */}
                            <a onClick={() => { this.EditTableFun(row) }}>编辑</a>
                            {/* eslint-disable-next-line */}
                            <a onClick={() => { this.isDeleteWin(row) }}>删除</a>
                        </Space>
                    ),
                }
            ],
            //这个是table上方按钮数组
            ButtonArr: [
                {
                    ButtonText: "添加角色",
                    type: "primary",
                    ClickFun: () => {
                        //打开添加人员的窗口
                        this.setState({
                            Form: [
                                {
                                    type: "input",
                                    name: "name",
                                    label: "角色名称",
                                    isRequired: true,
                                    value: ""
                                },
                                {
                                    type: "textarea",
                                    name: "note",
                                    isRequired: false,
                                    label: "角色备注",
                                    value: ""
                                },
                            ],
                            Modal: {
                                title: "添加角色",
                                isOpen: true,
                                width: 600,
                                submit: async (values) => {
               
                                    const res = await API_ADD_ROLE({
                                        Name: values.name,
                                        Note: values.note,
                                    });
                                    switch (res.data.response) {
                                        case "success":
                                            message.success("添加成功");
                                            //刷新table
                                            this.cancel();
                                            break;
                                        default:
                                            message.error(res.data.results);
                                            break;
                                    }
                                },
                                cancel: () => {
                                    let originModal = this.state.Modal
                                    originModal.isOpen = false;
                                    this.setState({
                                        Modal: originModal
                                    })
                                }
                            }
                        })
                    }
                }
            ],
            //searchOption搜索栏form元素
            searchOption: [
                {
                    type: "input",
                    name: "name",
                    isRequired: false,
                    label: "角色名称",
                    placeholder: "请输入角色名称",
                    value: ""
                },
            ]
        })
    }



    render() {
        return (
            <>
                <CommonDelete Modal={this.state.DeleteModal}></CommonDelete>
                <CommonModal Form={this.state.Form} Modal={this.state.Modal}></CommonModal>
                <CommonTable
                excelName={this.state.excelName}
                    initFun={this.initFun}
                    queryTable={this.queryTable}
                    Loading={this.state.Loading}
                    searchOption={this.state.searchOption}
                    that={this}
                    ButtonArr={this.state.ButtonArr}
                    TableColumns={this.state.TableColumns}
                    reloadFun={this.reloadFun}
                    TableData={this.state.TableData}></CommonTable>
            </>
        )
    }
}
export default RoleList;

满足基本管理系统需求,如需加功能,可在封装组件中直接编写,此demo没有样式,样式自加

  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

与诸君共勉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值