Antd Upload 和 Antd Form 結合的踩坑記錄

今天弄了半天這個上傳組件結合表單組件的問題。react

這個上傳文件列表,若是是當前正在修改或者上傳成功,固然是能夠正常工做的,可是想要增長一個功能:
下次打開 Modal 時,表單字段中的上傳文件字段,能夠默認回顯文件列表(該列表是 Upload 組件內部實現的)。後端

因爲該 Upload 組件已經使用 Form 組件統一代理,因此須要經過 initialValue 字段進行初始值的設定(若是有的話)。固然也能夠不代理,單獨處理,但這樣最終提交數據仍是要再增長上去,並且還須要自行實現必填項的校驗。antd

此時既要照顧到 Upload 自身所需字段(特別是 uid 字段),又要迎合最終向後端提交附件時方便新老文件統一處理(經過 JSON.stringify() 的第二個過濾器參數進行處理)。app

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);
相關文章
相關標籤/搜索