import React, { Component } from 'react' import { Button, Drawer, message as Message, Modal } from 'antd' import { cloneDeep, isEqual } from 'lodash' /** * 渲染对话框 * @param {*} props * @param {*} on * @param {*} childWithProps * @returns */ function renderModal(props, on, childWithProps) { on = { ...on, onCancel: () => this.onClose(), } return ( {childWithProps} ) } /** * 渲染抽屉 * @param {*} props * @param {*} on * @param {*} childWithProps * @returns */ function renderDrawer(props, on, childWithProps) { on = { ...on, onClose: () => this.onClose(), } // react在这里会对该组件不存在的props抛出异常 ;['action', 'onSuccess', 'onOk', 'confirmLoading'].forEach(p => { delete props[p] }) return ( on.onClose()}>
{childWithProps}
) } export default class ModalForm extends Component { state = { // 弹窗显示/隐藏 visible: false, // 提交状态 confirmLoading: false, } // 子元素实例 childNode = React.createRef() // 弹窗类型 type = 'modal' // 从外部传入的数据 data = null // 数据结构调整后的快照 snapshot = null // 完成操作 action = async () => {} // 是否在关闭时校验数据改变 compareOnClose = true constructor(props) { super(props) if (this.props.type) { if (!['modal', 'drawer'].includes(this.props.type)) throw new Error('props [type] error') this.type = this.props.type } if (this.props.action) { this.action = this.props.action } if (typeof this.props.compareOnClose === 'boolean') { this.compareOnClose = this.props.compareOnClose } } /** * 打开弹窗 * @param {*} data */ open = (data = {}) => { this.data = data this.setState({ visible: true }) } /** * 关闭弹窗 */ close = () => { this.setState({ visible: false }) } /** * 子元素创建后回调 * 对子元素数据进行填充,(如需关闭时对比)之后再获取结构调整后的数据快照 * @returns */ onCreated = async () => { const body = this.childNode.current if (!body || !body.fillData) return await body.fillData(this.data) // 保存此时的form内容为快照 if (this.compareOnClose && body.form && body.form.current) { this.snapshot = cloneDeep(body.form.current.getFieldsValue()) } } /** * 取消编辑 * (如需关闭时对比)获取当前数据结构与快照对比 * @returns */ onClose = async () => { const body = this.childNode.current if (!body) { this.close() return } if (this.compareOnClose && body.form && body.form.current) { const formData = body.form.current.getFieldsValue() if (!isEqual(this.snapshot, formData)) { Modal.confirm({ title: '是否确认关闭', content: '当前内容已更改,是否确认不保存并且关闭', onOk: () => { this.close() }, }) return } } this.close() } /** * 完成编辑 * 校验并获取结构调整后的数据,调用this.action进行操作 * @returns */ onOk = async () => { const body = this.childNode.current if (!body || !this.action || !body.getData) return this.setState({ confirmLoading: true }) try { const postData = await body.getData() const result = await this.action(postData) if (!result || result.success) { if (result && result.success) { Message.success(this.props.successMessage || '保存成功') } this.close() if (typeof this.props.onSuccess === 'function') { this.props.onSuccess(postData) } } } finally { this.setState({ confirmLoading: false }) } } render() { const props = { ...this.props, visible: this.state.visible, destroyOnClose: true, confirmLoading: this.state.confirmLoading, } const on = { onOk: () => this.onOk(), } const childWithProps = React.cloneElement(React.Children.only(this.props.children), { created: childNode => { this.childNode.current = childNode this.onCreated() }, }) return this.type === 'modal' ? renderModal.call(this, props, on, childWithProps) : renderDrawer.call(this, props, on, childWithProps) } }