Antd Upload 和 Antd Form 结合的踩坑记录
今天弄了半天这个上传组件结合表单组件的问题。
这个上传文件列表,如果是当前正在修改或者上传成功,当然是可以正常工作的,但是想要增加一个功能:
下次打开 Modal 时,表单字段中的上传文件字段,可以默认回显文件列表(该列表是 Upload 组件内部实现的)。
由于该 Upload 组件已经使用 Form 组件统一代理,所以需要通过 initialValue
字段进行初始值的设定(如果有的话)。当然也可以不代理,单独处理,但这样最终提交数据还是要再增加上去,而且还需要自行实现必填项的校验。
此时既要照顾到 Upload 自身所需字段(特别是 uid 字段),又要迎合最终向后端提交附件时方便新老文件统一处理(通过 JSON.stringify() 的第二个过滤器参数进行处理)。
import React from 'react';
import {
message,
Modal,
Row,
Col,
Form,
Select,
Button,
Input,
Spin,
Radio,
DatePicker,
Upload,
Icon
} from 'antd';
import moment from 'moment';
const FormItem = Form.Item;
const Option = Select.Option;
const TextArea = Input.TextArea;
class MakeBill extends React.Component {
state = {
loading: false,
disabledOk: false,
confirmLoading: false,
fileList: [],
}
handleSubmit = () => {
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
this.setState({ loading: true, confirmLoading: true });
const submitInfo = JSON.parse(JSON.stringify(values, (key, value) => {
if (key === 'pay_time') {
return moment(value).format('YYYY-MM-DD');
} else if (key === 'attachments') {
return value.map(f => ({ ...f.saveParams, type: 1 }));
}
return value;
}));
commerceApi.saveInvoiceOfFinance(submitInfo).then(result => {
message.success('提交成功!');
this.props.form.resetFields();
this.props.onClose('refresh');
this.setState({ loading: false, confirmLoading: false });
}, () => {
this.setState({ loading: false, confirmLoading: false });
});
}
});
}
closeForm = () => {
this.props.form.resetFields();
this.props.onClose();
}
getContactInfo = (id) => {
commerceApi.getContactDetail({ id, isedit: true }, (result) => {
this.setState({ relationContactInfo: result });
});
}
render() {
let { loading, disabledOk, confirmLoading, fileList } = this.state;
let { form, show, incomeId, busId, details } = this.props;
let _this = this;
const { getFieldDecorator } = form;
if (!Object.keys(details).length) { // 如果没有历史数据,则需要提供一些默认值
details['invoice_type'] = 0;
}
const formItemLayout = {
labelCol: {
sm: { span: 8 },
},
wrapperCol: {
sm: { span: 16 },
},
};
const fullLayout = {
labelCol: {
sm: { span: 4 },
},
wrapperCol: {
sm: { span: 20 },
},
};
/**
* 上传组件操作思路:
* 当文件大于10M时,在调接口前,就提示报错,并且调用onRemove移除
*/
const props = {
accept: ".rar,.zip,.doc,.docx,.pdf,.jpg,.png",
name: 'file',
action: '/cmp/crm/upload',
beforeUpload(file) {
const isLt10M = file.size / 1024 / 1024 <= 10;
if (!isLt10M) {
message.error("文件大小限制在10M以下!");
this.onRemove(file);
return false;
}
},
onRemove(file) {
_this.setState({ fileList: fileList.filter(item => item.name !== file.name) }, () => {
_this.props.form.setFieldsValue({ fileList: fileList });
});
},
onChange(info) { // 上传中、完成、失败都会调用这个函数
let curFileList = info.fileList;
curFileList = curFileList.map((file) => {
if (file.response) {
// 这里上传组件回调的数据,有些是提供给上传组件自身使用的,所以不能不要
// 而需要向后端提交的数据这里提前封装起来,以方便最终的提交
let saveParams = {};
saveParams["filename"] = file.response.data[0].filename;
saveParams["url"] = file.response.data[0].url;
saveParams["size"] = file.response.data[0].size;
file["saveParams"] = saveParams;
file['url'] = file.response.data[0].url;
}
return file;
});
curFileList = curFileList.filter(file => {
if (file.size / 1024 / 1024 <= 10) {
if (file.response) {
return file.response.code === 0;
}
return true;
} else {
return false;
}
});
_this.setState({ fileList: curFileList });
},
// fileList: fileList, // 上传组件已使用Form进行代理,所以不要再直接设置
};
return (
<div>
{
show ? <Modal
wrapClassName="vertical-center-modal"
className="company-form-modal"
title="申请发票"
visible={show}
width={750}
maskClosable={false}
onCancel={this.closeForm}
footer={[
<Button key="cancel" onClick={this.closeForm}>取消</Button>,
<Button key="confirm" type="primary" loading={confirmLoading} disabled={disabledOk} onClick={this.handleSubmit}>确定</Button>
]}>
<Spin spinning={loading}>
<div className="modal-content-wrap">
<Form>
<Row>
<FormItem {...fullLayout} label="证明材料">
{getFieldDecorator('attachments', {
initialValue: (details.attachments || []).map(f => ({
// 为了提供给上传组件回显
uid: f.id, // 这是上传组件规定的文件唯一标识,内部会提供给Form以便正常渲染回显列表
name: f.filename,
status: 'done',
url: f.url,
// 为了迎合最终向后端提交附件时方便新老文件统一处理
saveParams: {
filename: f.filename,
url: f.url,
size: f.size
}
})),
rules: [{
required: true, message: '请上传证明材料'
}],
valuePropName: 'fileList',
getValueFromEvent: (e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
}
})(
<Upload {...props}>
<Button>
<Icon type="upload" /> 上传文件
</Button>
<p className="upload-desc">支持扩展名:.rar .zip .doc .pdf .jpg .png</p>
<p className="upload-desc">材料包括:合同,验收单,订单截图,打款记录</p>
</Upload>
)}
</FormItem>
</Row>
</Form>
</div>
</Spin>
</Modal> : null
}
</div>
)
}
}
export default Form.create()(MakeBill);