antd form Form Data Echo Operation

  • 2021-09-12 00:00:13
  • OfStack

index page has one table and one new button. Click the new button or table edit to pop up the form module. If it is editing, the data in the corresponding table will be echoed


//index Page 
import React from 'react'
import { Table, Button, message, Input, Select, Modal, } from 'antd';
const Option = Select.Option;
import AddOrEdit from './AddOrEdit '
class List extends React.Component {
 constructor(props) {
 super(props);
 }
 state = {
 id: "",
 selectOpt: {
  getPopupContainer: () => {
  return this.refs.myForm
  }
 },
 tableOption: {
  // Header 
  columns: [
  { title: ' Name of Employee ', key: 'workerName', dataIndex: 'workerName' },
  { title: ' Employee number ', key: 'workNumber', dataIndex: 'workNumber' },
  {
   title: " Operation ", key: 'action', className: 'columnsCenter', render: (text, record) => {
   return (
    <a title=" Edit " type="edit" onClick={this.addOrEditClick.bind(this, record)}> Edit </a>
   )
   }
  }
  ],
  dataSource: [], // Table total data 
  loading: false,
  scroll: { x: 1600 },
  // Paging initial data 
  pagination: {
  current: 1, pageSize: 10, total: 0, showTotal: total => ` Altogether  ${total}  Article `
  }
 },
 // Edit form details 
 dataForm: {
  data: [],
  model: {
  id: { value: undefined },
  workerName: { value: undefined },// Name of Employee 
  workNumber: { value: undefined }// Employee number 
  },
  param: {}
 },
 //form Form module 
 modalOption: {
  title: " Add / Modify ",
  visible: false,
  footer: null,
  destroyOnClose: true,
  width: 900
 },
 }
 // Edit data echo 
 addOrEditClick(record) {
 const self = this;
 let { modalOption, dataForm } = this.state;
 dataForm.param = JSON.parse(JSON.stringify(dataForm.model));
 // If you edit the pop-up form and the data is echoed, otherwise it is added 
 if (record.id) {
  api.get(APIS.yluAssessTarget + record.id).then(function (response) {
  const data = response.data.data;
  dataForm.param.id.value = data.id;
  // To 
  dataForm.param.workerName.value = data.workerName;
  dataForm.param.workNumber.value = data.workNumber;
  modalOption.visible = true;
  self.setState({ modalOption, dataForm });
  });
 } else {
  modalOption.visible = true;
  self.setState({ modalOption });
 }
 }
 // Paging 
 onTableChange(pagination, filters, sorte) {
 if (pagination.current) {
  let { tableOption, searchObj } = this.state;
  tableOption.pagination.current = pagination.current;
  tableOption.pagination.pageSize = pagination.pageSize;
  this.setState({ tableOption });
 }
 this.loadTable();
 };
 /**
 *  Initialization list 
 */
 loadTable() {
 let self = this, { tableOption } = this.state;
 tableOption.loading = true;
 self.setState({ tableOption });
 api.post(APIS.yluAssessTargetSearch + '?current=' + tableOption.pagination.current + '&pageSize=' + tableOption.pagination.pageSize, {
  data: {
  companyName: " Query parameters "// Branch name 
  }
 }).then(function (response) {
  tableOption.dataSource = response.data.data.
  tableOption.pagination.total = response.data.data.total;
 }).finally(() => {
  tableOption.loading = false;
  self.setState({ tableOption, notDataLevelGroup, searchObj });
 });
 }
 render() {
 const self = this;
 let { tableOption, modalOption, dataForm } = this.state;
 return (
  <div>
  <Button size="small" type="primary" onClick={this.addOrEditClick.bind(this, 0)} > Add </Button>
  <Table {...tableOption} bordered onChange={this.onTableChange.bind(this)} />
  <Modal {...modalOption} >
   {modalOption.visible ? <AddOrEdit {...dataForm} /> : null}
  </Modal>
  </div>

 )
 }
 componentDidMount() {
 this.loadTable();
 }
}


//form Form page , When you click Edit or Add, it will pop up, and when you edit, a drop-down box will be displayed value The value is the current value of the table 1 The value corresponding to the bar data 
// Right select Inside value Value with getFieldDecorator Bind 
import React from 'react'
import { Table, Button, Select, Form, message, Row, Col, } from 'antd';
const Option = Select.Option;
class AddOrEdit extends React.Component {
 // Submit to save 
 handleSubmit(e) {
 e.preventDefault();
 const self = this;
 this.props.form.validateFieldsAndScroll((err, values) => {
  if (!err) {
  // Submit to save 
  api.post(APIS.yluAssessTarget, {
   data: {
   ...values,
   }
  }).then(res => {
   message.success(res.data.message)
  }).finally(() => {
   self.setState({ addOrEditFooterLoading: false })
  })
  }
 });
 }
 render() {
 const { workerNameList, workNumberList} = this.state;
 const { getFieldDecorator } = this.props.form;
 const reqMeg = ' Cannot be empty ';
 const renderOption = (arr, code, name) => arr ? arr.map((item, index) => {
  return (<Option key={index + item[code]} value={typeof (item[code]) === 'number' ? item[code].toString() : item[code]}>{item[name]}</Option>)
 }) : null

 return (
  <Form styleName="form_box" onSubmit={this.handleSubmit.bind(this)} >
  <Col {...span24}>
   <FormItem label=" Name of Employee " {...formItemLayout} hasFeedback>
   {getFieldDecorator('workerName', {
    rules: [{ required: true, message: reqMeg }]
   })(<Select
    placeholder=" Please select "
   >
    {renderOption(workerNameList, 'workCode', 'name')}
   </Select>)}
   </FormItem>
  </Col>
  <Col {...span24}>
   <FormItem label=" Employee number " {...formItemLayout} hasFeedback>
   {getFieldDecorator('workNumber', {
    rules: [{ required: true, message: reqMeg }]
   })(<Select
    placeholder=" Please select "
   >
    {renderOption(workNumberList, 'workNumber', 'name')}
   </Select>)}
   </FormItem>
  </Col>
  </Form>
 )
 }
}
export default AddOrEdit;

Supplementary knowledge: a-upload components in Ant Design Vue implement the front and back end processing scheme of file list upload and update echo through axios

Preface

In the rapid development of enterprise applications, we need to complete some functions as soon as possible. If you use Ant Design Vue, you can't wait to find an article that can cure all diseases when developing the related functions of uploading files to the form. It is precisely because of this that this article was born, and you are willing to use this article to solve your worries.

Scheme design

Front-end scheme design

Rewrite the file upload mode of a-upload and use axios to upload

Select a file and upload it immediately. The front end records name and uid after uploading successfully, and constructs an instance of File for echoing the uploaded file list of a-upload components

Turn the file list into an uid list to be processed by the backend before submission

Back-end scheme design

Provides an interface for uploading a single file. After each file is selected, it will be uploaded to the interface and written into the file data table of the database

After the new form data is created, bind the current entity record to the uploaded file list

After updating the form data, all the file lists of the entity records are detected, the file lists of uid that are not in the list are deleted, and then all the uid file records in the list are bound with the current entity records

New and updated 1-dimensional treatment scheme

Because the update form needs to be formatted in the same way as the newly selected file after reading the old data, the processing flow here is 1, the data echoed is 1, and the submitted form is also submitted to the existing uid list in the file table, so the data structure here is 1, and the processing will be more concise and clear.

Let the code speak

In order to make it easy for you to understand, the code is directly on, hoping to make the whole thing clear.

Build a form


<a-form :form="form"> 
 <a-form-item label=" Name " style="margin-bottom: 0;"> 
 <a-input v-decorator="['name', {rules: [{required: true, message: ' Please enter a name! '}]}]" /> 
 </a-form-item>
 <a-form-item> 
 <a-upload 
 :multiple="true" 
 :fileList="downloadFiles" 
 :remove="handleDownloadFileRemove" 
 :customRequest="downloadFilesCustomRequest" 
 > 
 <a-button class="upload-btn"> <a-icon type="upload" >  Related downloads  </a-button> 
 </a-upload> 
 </a-form-item>
</a-form>

Write js code

Request token, header, baseUrl, etc. of the back-end interface. I have already configured it in the 1 setup of axios by default

To simplify axios related operations, we encapsulate axios as follows (you can also use axios completely to commit data directly, etc.):


const dibootApi = {
 get (url, params) { 
 return axios.get(url, { 
 params 
 }) 
 }, 
 upload(url, formData) { 
 return service({ 
 url, 
 method: 'POST', 
 data: formData 
 }) 
 }
}
export default dibootApi

By default, we need to upload 1 file list in demo entity


export default {
 name: 'demoForm',
 data () {
 title: ' New ',    //  Feature title of the form 
 form: this.$form.createForm(this), //  Form data initialization, nothing to say 
 model: {},    //  If you are updating the form, put the previous data here to initialize the display of the data 
 downloadFiles: []    //  List of files that have been uploaded 
 },
 methods: {
 //  When the form is initially opened (if the form is updated, the relevant data needs to be read out first) 
 async open (id) { 
  if (id === undefined) { 
  //  No id Data is considered as new  
  this.model = {} 
  this.afterOpen() 
  } else { 
  //  Otherwise, it is treated as an update  
  const res = await dibootApi.get(`/${this.name}/${id}`) 
  if (res.code === 0) { 
  this.model = res.data 
  this.title = ' Edit ' 
  this.afterOpen(id) 
  } else { 
  this.$notification.error({ 
   message: ' Failed to get data ', 
   description: res.msg 
  }) 
  } 
  } 
 },
 //  Update the action of the form after reading data 
 afterOpen (id) { 
  //  After obtaining the record information, the related operation of file list is echoed 
  dibootApi.post(`/demo/getFiles/${id}`).then(res => { 
  if (res.code === 0){ 
   if (res.data.downloadFile !== undefined){ 
   res.data.downloadFile.forEach(data => { 
    this.downloadFiles.push(this.fileFormatter(data)) 
   }) 
   }
  } 
  }) 
 },
 //  Rewrite a-upload How to upload files based on 
 downloadFilesCustomRequest (data) { 
  this.saveFile(data) 
 }, 
 //  Upload and save files 
 saveFile (data){ 
  const formData = new FormData() 
  formData.append('file', data.file) 
  dibootApi.upload('/demo/upload', formData).then((res) => { 
  if (res.code === 0){ 
   let file = this.fileFormatter(res.data) 
   //  After uploading a single file, the file will be sent to the first a-upload Actions in the uploaded files list of the component 
   this.downloadFiles.push(file) 
  } else { 
   this.$message.error(res.msg) 
  } 
  }) 
 },
 //  Format the data returned after uploading successfully, and format a-upload The format that can be displayed in the uploaded list (this format is given in the official document) 
 fileFormatter(data) { 
  let file = { 
  uid: data.uuid, //  File only 1 Identity, recommended to be set to negative, prevented and internally generated  id  Conflict  
  name: data.name, //  Filename  
  status: 'done', //  Status: uploading done error removed 
  response: '{"status": "success"}', //  Server response content  
  } 
  return file 
 },
 //  Yes, when deleting an uploaded file, it is called here 
 handleDownloadFileRemove (file) { 
  const index = this.downloadFiles.indexOf(file) 
  const newFileList = this.downloadFiles.slice() 
  newFileList.splice(index, 1) 
  this.downloadFiles = newFileList 
 },
 //  Form verification depends on him, but it is still possible to submit the 1 Some data do some hands and feet 
 validate () { 
  return new Promise((resolve, reject) => { 
  this.form.validateFields((err, fieldsValue) => { 
   if (!err) { 
   //  Set up the list of uploaded files  
   const downloadFiles = this.downloadFiles.map(o => { 
    return o.uid 
   }) 
   const values = { 
    ...fieldsValue, 
    'downloadFiles': downloadFiles
   } 
   resolve(values) 
   } else { 
   reject(err) 
   }
  }) 
  }) 
 },
 //  Actions related to form submission 
 async onSubmit () { 
  const values = await this.validate() 
  try { 
  let result = {} 
  if (this.model.id === undefined) { 
   //  Add this record  
   result = await this.add(values) 
  } else { 
   //  Update the record  
   values['id'] = this.model.id 
   result = await this.update(values) 
  } 

  //  Execute the submitted successfully 1 Series of follow-up operations  
  this.submitSuccess(result) 
  } catch (e) { 
  //  Object that failed to perform the commit 1 Series of follow-up operations  
  this.submitFailed(e) 
  } 
 },
 //  Operation of adding data 
 async add (values) {
  ....
 },
 //  The operation of updating data 
 async update (values) {
  ...
 }
 }
}

Write interface code related to SpringBoot

DemoController


/*** 
 *  Get a list of file information  
 * @param id 
 * @return 
 * @throws Exception 
 */
@PostMapping("/getFiles/{id}") 
public JsonResult getFilesMap(@PathVariable("id") Serializable id) throws Exception{ 
 List<File> files = fileService.getEntityList( 
  Wrappers.<File>lambdaQuery() 
   .eq(File::getRelObjType, Demo.class.getSimpleName()) 
   .eq(File::getRelObjId, id) 
 ); 
 return new JsonResult(Status.OK, files); 
}

/*** 
 *  Upload a file  
 * @param file 
 * @param request 
 * @return 
 * @throws Exception 
 */
@PostMapping("/upload") 
public JsonResult upload(@RequestParam("file") MultipartFile file) throws Exception { 
 File fileEntity = demoService.uploadFile(file); 
 return new JsonResult(Status.OK, fileEntity, " Upload File Successfully "); 
}

/***
*  Related processing after successful creation 
* @param entity
* @return
*/
@Override
protected String afterCreated(BaseEntity entity) throws Exception {
 DemoDTO demoDTO = (DemoDTO) entity;
 //  Update file association information 
 demoService.updateFiles(new ArrayList<String>(){{
 addAll(demoDTO.getDownloadFiles());
 }}, demoDTO.getId(), true);
 return null;
}

/***
*  Related processing after successful update 
* @param entity
* @return
*/
@Override
protected String afterUpdated(BaseEntity entity) throws Exception {
 DemoDTO demoDTO = (DemoDTO) entity;
 //  Update file association information 
 demoService.updateFiles(new ArrayList<String>(){{
 addAll(demoDTO.getDownloadFiles());
 }}, demoDTO.getId(), false);
 return null;
}

DemoService


@Override 
public File uploadFile(MultipartFile file) { 
 if(V.isEmpty(file)){ 
 throw new BusinessException(Status.FAIL_OPERATION, " Please upload pictures "); 
 } 
 String fileName = file.getOriginalFilename(); 
 String ext = fileName.substring(fileName.lastIndexOf(".")+1); 
 String newFileName = S.newUuid() + "." + ext; 
 //TODO:  Validation of legitimate file types is required  
 if(FileHelper.isImage(ext)){ 
 throw new BusinessException(Status.FAIL_OPERATION, " Please upload a valid file type "); 
 }; 
 
 //  Description: Here is our processing flow, and the readers need to save and process the documents according to their own needs (after that, our File After the component is open source, you can also follow the processing here.) 
 String filePath = FileHelper.saveFile(file, newFileName); 
 if(V.isEmpty(filePath)){ 
 throw new BusinessException(Status.FAIL_OPERATION, " Picture upload failed "); 
 } 
 
 File fileEntity = new File(); 
 fileEntity.setRelObjType(Demo.class.getSimpleName()); 
 fileEntity.setFileType(ext); 
 fileEntity.setName(fileName); 
 fileEntity.setPath(filePath); 
 String link = "/file/download/" + D.getYearMonth() + "_" + newFileName; 
 fileEntity.setLink(link); 
 
 boolean success = fileService.createEntity(fileEntity); 
 if (!success){ 
 throw new BusinessException(Status.FAIL_OPERATION, " Failed to upload file "); 
 } 
 return fileEntity; 
} 
 
@Override 
public void updateFiles(List<String> uuids, Long currentId, boolean isCreate) { 
 //  If it is not created, you need to delete the file Record  
 if (!isCreate){ 
 fileService.deleteEntities(Wrappers.<File>lambdaQuery().notIn(File::getUuid, uuids)); 
 } 
 //  Make relevant updates  
 boolean success = fileService.updateEntity( 
  Wrappers.<File>lambdaUpdate() 
   .in(File::getUuid, uuids) 
   .set(File::getRelObjType, Demo.class.getSimpleName()) 
   .set(File::getRelObjId, currentId)); 
 if (!success){ 
 throw new BusinessException(Status.FAIL_OPERATION, " Failed to update file information "); 
 } 
}

Prompt

This article all code is the program example, which has some deletions, does not ensure that can run directly, if you have a good idea, welcome a discussion.


Related articles: