213 lines
5.4 KiB
JavaScript
213 lines
5.4 KiB
JavaScript
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 (
|
|
<Modal className="yo-modal-form" {...props} {...on}>
|
|
{childWithProps}
|
|
</Modal>
|
|
)
|
|
}
|
|
|
|
/**
|
|
* 渲染抽屉
|
|
* @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 (
|
|
<Drawer className="yo-drawer-form" {...props} onClose={() => on.onClose()}>
|
|
<div className="yo-drawer-form--body">{childWithProps}</div>
|
|
<div className="ant-drawer-footer">
|
|
<Button onClick={on.onClose}>取消</Button>
|
|
<Button loading={this.state.confirmLoading} onClick={on.onOk} type="primary">
|
|
确定
|
|
</Button>
|
|
</div>
|
|
</Drawer>
|
|
)
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|