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没有样式,样式自加