antd form表单数据回显操作


Posted in Javascript onNovember 02, 2020

index页面有一个表格,有一个新增按钮,点击新增按钮或表格编辑弹出表单模块,如果是编辑,会回显对应的表格中的数据

//index页面
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: {
  //表头
  columns: [
  { title: '员工姓名', key: 'workerName', dataIndex: 'workerName' },
  { title: '员工工号', key: 'workNumber', dataIndex: 'workNumber' },
  {
   title: "操作", key: 'action', className: 'columnsCenter', render: (text, record) => {
   return (
    <a title="编辑" type="edit" onClick={this.addOrEditClick.bind(this, record)}>编辑</a>
   )
   }
  }
  ],
  dataSource: [], //表格总数据
  loading: false,
  scroll: { x: 1600 },
  //分页初始数据
  pagination: {
  current: 1, pageSize: 10, total: 0, showTotal: total => `共 ${total} 条`
  }
 },
 //编辑表单详细信息
 dataForm: {
  data: [],
  model: {
  id: { value: undefined },
  workerName: { value: undefined },//员工姓名
  workNumber: { value: undefined }//员工工号
  },
  param: {}
 },
 //form表单模块
 modalOption: {
  title: "新增/修改",
  visible: false,
  footer: null,
  destroyOnClose: true,
  width: 900
 },
 }
 //编辑数据回显
 addOrEditClick(record) {
 const self = this;
 let { modalOption, dataForm } = this.state;
 dataForm.param = JSON.parse(JSON.stringify(dataForm.model));
 //如果是编辑弹出表单并且数据回显,否则就是新增
 if (record.id) {
  api.get(APIS.yluAssessTarget + record.id).then(function (response) {
  const data = response.data.data;
  dataForm.param.id.value = data.id;
  //给
  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 });
 }
 }
 //分页
 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();
 };
 /**
 * 初始化列表
 */
 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: "查询参数"//分公司名
  }
 }).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)} >新增</Button>
  <Table {...tableOption} bordered onChange={this.onTableChange.bind(this)} />
  <Modal {...modalOption} >
   {modalOption.visible ? <AddOrEdit {...dataForm} /> : null}
  </Modal>
  </div>

 )
 }
 componentDidMount() {
 this.loadTable();
 }
}
//form表单页,点击编辑或新增的时候会弹出,并且编辑的时候下拉框value值就为表格当前的这一条数据对应的值
//对select里面的value值用getFieldDecorator进行绑定
import React from 'react'
import { Table, Button, Select, Form, message, Row, Col, } from 'antd';
const Option = Select.Option;
class AddOrEdit extends React.Component {
 //提交保存
 handleSubmit(e) {
 e.preventDefault();
 const self = this;
 this.props.form.validateFieldsAndScroll((err, values) => {
  if (!err) {
  //提交保存
  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 = '不能为空';
 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="员工姓名" {...formItemLayout} hasFeedback>
   {getFieldDecorator('workerName', {
    rules: [{ required: true, message: reqMeg }]
   })(<Select
    placeholder="请选择"
   >
    {renderOption(workerNameList, 'workCode', 'name')}
   </Select>)}
   </FormItem>
  </Col>
  <Col {...span24}>
   <FormItem label="员工工号" {...formItemLayout} hasFeedback>
   {getFieldDecorator('workNumber', {
    rules: [{ required: true, message: reqMeg }]
   })(<Select
    placeholder="请选择"
   >
    {renderOption(workNumberList, 'workNumber', 'name')}
   </Select>)}
   </FormItem>
  </Col>
  </Form>
 )
 }
}
export default AddOrEdit;

补充知识:Ant Design Vue 中a-upload组件通过axios实现文件列表上传与更新回显的前后端处理方案

前言

在企业应用的快速开发中,我们需要尽快的完成一些功能。如果您使用了Ant Design Vue,在进行表单的文件上传相关功能开发的时候,您肯定迫不及待地需要找到一篇包治百病的文章,正是如此,才有了该文的诞生,愿以此文解君忧。

方案设计

前端方案设计

重写a-upload的文件上传方式,使用axios来进行上传

选择一个文件后立即进行上传,前端记录上传成功后的name和uid,并构建一个File实例,用于a-upload组件的已上传文件列表的回显

提交前让文件列表转化为要后端要处理的uid列表

后端方案设计

提供一个统一上传单个文件的接口,每个文件选择后自动上传都将上传到该接口,并写入到数据库的file数据表中

对表单数据新建完成后,对上传的文件列表进行当前实体记录的绑定

对表单数据更新完成后,检测该实体记录的所有文件列表,对没有在该列表中的uid的文件列表进行删除,然后对该列表中所有的uid文件记录进行当前实体记录的绑定

新建与更新的一致性处理方案

因为更新表单在读取旧数据后,需要与新选择文件进行同样的格式化处理,这里的处理流程一样,进行回显的数据是一样的,提交表单也都是提交file表中已经存在的uid列表,所以这里的数据结构是一致的,处理起来将会更加简洁明了。

让代码说话

为了让各位看官老爷们便于理解,直接上代码,希望能将整件事说明白。

构建表单

<a-form :form="form"> 
 <a-form-item label="名称" style="margin-bottom: 0;"> 
 <a-input v-decorator="['name', {rules: [{required: true, message: '请输入名称!'}]}]" /> 
 </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" > 相关下载 </a-button> 
 </a-upload> 
 </a-form-item>
</a-form>

编写js代码

请求后端接口的token、header以及baseUrl等我已默认您已经在axios的统一设置中已经配置好了

为了简化axios相关操作,我们将axios进行了如下封装(您也可以按此完全使用axios来直接对数据进行提交等):

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

我们默认为demo实体中需要上传一些文件列表

export default {
 name: 'demoForm',
 data () {
 title: '新建',    // 该表单的功能标题
 form: this.$form.createForm(this), // 表单数据初始化,没什么好说的
 model: {},    // 如果是更新表单,之前的数据放到这里,来做数据初始化显示之用
 downloadFiles: []    // 已经上传的文件列表
 },
 methods: {
 // 初始打开的表单时的处理(如果是更新表单,这里首先需要读取出相关数据)
 async open (id) { 
  if (id === undefined) { 
  // 没有id数据则认为是新建 
  this.model = {} 
  this.afterOpen() 
  } else { 
  // 否则作为更新处理 
  const res = await dibootApi.get(`/${this.name}/${id}`) 
  if (res.code === 0) { 
  this.model = res.data 
  this.title = '编辑' 
  this.afterOpen(id) 
  } else { 
  this.$notification.error({ 
   message: '获取数据失败', 
   description: res.msg 
  }) 
  } 
  } 
 },
 // 更新表单在读取数据完成后的操作
 afterOpen (id) { 
  // 获取该记录信息后,回显文件列表相关操作
  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)) 
   }) 
   }
  } 
  }) 
 },
 // 重写a-upload的文件上传处理方式
 downloadFilesCustomRequest (data) { 
  this.saveFile(data) 
 }, 
 // 上传并保存文件
 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) 
   // 上传单个文件后,将该文件会先到a-upload组件的已上传文件列表中的操作
   this.downloadFiles.push(file) 
  } else { 
   this.$message.error(res.msg) 
  } 
  }) 
 },
 // 对上传成功返回的数据进行格式化处理,格式化a-upload能显示在已上传列表中的格式(这个格式官方文档有给出的)
 fileFormatter(data) { 
  let file = { 
  uid: data.uuid, // 文件唯一标识,建议设置为负数,防止和内部产生的 id 冲突 
  name: data.name, // 文件名 
  status: 'done', // 状态有:uploading done error removed 
  response: '{"status": "success"}', // 服务端响应内容 
  } 
  return file 
 },
 // 没错,删除某个已上传的文件的时候,就是调用的这里
 handleDownloadFileRemove (file) { 
  const index = this.downloadFiles.indexOf(file) 
  const newFileList = this.downloadFiles.slice() 
  newFileList.splice(index, 1) 
  this.downloadFiles = newFileList 
 },
 // 表单校验就靠他了,不过这里面还是可以对需要提交的一些数据做些手脚的
 validate () { 
  return new Promise((resolve, reject) => { 
  this.form.validateFields((err, fieldsValue) => { 
   if (!err) { 
   // 设置上传文件列表 
   const downloadFiles = this.downloadFiles.map(o => { 
    return o.uid 
   }) 
   const values = { 
    ...fieldsValue, 
    'downloadFiles': downloadFiles
   } 
   resolve(values) 
   } else { 
   reject(err) 
   }
  }) 
  }) 
 },
 // 表单提交的相关操作
 async onSubmit () { 
  const values = await this.validate() 
  try { 
  let result = {} 
  if (this.model.id === undefined) { 
   // 新增该记录 
   result = await this.add(values) 
  } else { 
   // 更新该记录 
   values['id'] = this.model.id 
   result = await this.update(values) 
  } 

  // 执行提交成功的一系列后续操作 
  this.submitSuccess(result) 
  } catch (e) { 
  // 执行提交失败的一系列后续操作 
  this.submitFailed(e) 
  } 
 },
 // 新增数据的操作
 async add (values) {
  ....
 },
 // 更新数据的操作
 async update (values) {
  ...
 }
 }
}

编写SpringBoot相关的接口代码

DemoController

/*** 
 * 获取文件信息列表 
 * @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); 
}

/*** 
 * 上传文件 
 * @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, "上传文件成功"); 
}

/***
* 创建成功后的相关处理
* @param entity
* @return
*/
@Override
protected String afterCreated(BaseEntity entity) throws Exception {
 DemoDTO demoDTO = (DemoDTO) entity;
 // 更新文件关联信息
 demoService.updateFiles(new ArrayList<String>(){{
 addAll(demoDTO.getDownloadFiles());
 }}, demoDTO.getId(), true);
 return null;
}

/***
* 更新成功后的相关处理
* @param entity
* @return
*/
@Override
protected String afterUpdated(BaseEntity entity) throws Exception {
 DemoDTO demoDTO = (DemoDTO) entity;
 // 更新文件关联信息
 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, "请上传图片"); 
 } 
 String fileName = file.getOriginalFilename(); 
 String ext = fileName.substring(fileName.lastIndexOf(".")+1); 
 String newFileName = S.newUuid() + "." + ext; 
 //TODO: 需要对合法的文件类型进行验证 
 if(FileHelper.isImage(ext)){ 
 throw new BusinessException(Status.FAIL_OPERATION, "请上传合法的文件类型"); 
 }; 
 
 // 说明:此处为我们的处理流程,看官们需要根据自己的需求来对文件进行保存及处理(之后我们的File组件开源之后也可以按照此处的处理)
 String filePath = FileHelper.saveFile(file, newFileName); 
 if(V.isEmpty(filePath)){ 
 throw new BusinessException(Status.FAIL_OPERATION, "图片上传失败"); 
 } 
 
 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, "上传文件失败"); 
 } 
 return fileEntity; 
} 
 
@Override 
public void updateFiles(List<String> uuids, Long currentId, boolean isCreate) { 
 // 如果不是创建,需要删除不在列表中的file记录 
 if (!isCreate){ 
 fileService.deleteEntities(Wrappers.<File>lambdaQuery().notIn(File::getUuid, uuids)); 
 } 
 // 进行相关更新 
 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, "更新文件信息失败"); 
 } 
}

提示

该文章所有代码皆为方案示例,其中有些许删减,不确保能直接运行,如果各位有好的想法,欢迎一起探讨。

以上这篇antd form表单数据回显操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript笔试题目附答案@20081025_jb51.net
Oct 26 Javascript
自己整理的一个javascript日期处理函数
Oct 16 Javascript
jquery中实现简单的tabs插件功能的代码
Mar 02 Javascript
关于jQuery中.attr()和.prop()的问题探讨
Sep 06 Javascript
用jquery方法操作radio使其默认选项是否
Sep 10 Javascript
javascript异步处理工作机制详解
Apr 13 Javascript
jquery控制页面部分刷新的方法
Jun 24 Javascript
Bootstrap响应式导航由768px变成992px的实现代码
Jun 15 Javascript
AngularJS ng-repeat指令及Ajax的应用实例分析
Jul 06 Javascript
使用travis-ci如何持续部署node.js应用详解
Jul 30 Javascript
webpack4+Vue搭建自己的Vue-cli项目过程分享
Aug 29 Javascript
微信小程序数据统计和错误统计的实现方法
Jun 26 Javascript
antd Select下拉菜单动态添加option里的内容操作
Nov 02 #Javascript
Vue中使用Echarts仪表盘展示实时数据的实现
Nov 01 #Javascript
JavaScript实现刮刮乐效果
Nov 01 #Javascript
微信小程序实现单个或多个倒计时功能
Nov 01 #Javascript
微信小程序实现页面监听自定义组件的触发事件
Nov 01 #Javascript
uniapp微信小程序实现一个页面多个倒计时
Nov 01 #Javascript
uni-app使用countdown插件实现倒计时
Nov 01 #Javascript
You might like
Bo-Blog专用的给Windows服务器的IIS Rewrite程序
2007/08/26 PHP
php+html5使用FormData对象提交表单及上传图片的方法
2015/02/11 PHP
php实现概率性随机抽奖代码
2016/01/02 PHP
php redis实现对200w用户的即时推送
2017/03/04 PHP
浅谈PHP中pack、unpack的详细用法
2018/03/12 PHP
大家未必知道的Js技巧收藏
2008/04/07 Javascript
基于jquery的防止大图片撑破页面的实现代码(立即缩放)
2011/10/24 Javascript
table行随鼠标移动变色示例
2014/05/07 Javascript
JavaScript实现的使用键盘控制人物走动实例
2014/08/27 Javascript
详解NodeJs支付宝移动支付签名及验签
2017/01/06 NodeJs
JavaScript实现图片的放大缩小及拖拽功能示例
2019/05/14 Javascript
小程序如何自主实现拦截器的示例代码
2019/11/04 Javascript
js实现拖拽与碰撞检测
2020/09/18 Javascript
原生JavaScript实现拖动校验功能
2020/09/29 Javascript
Python2.x和3.x下maketrans与translate函数使用上的不同
2015/04/13 Python
Python中time模块和datetime模块的用法示例
2016/02/28 Python
详解python的webrtc库实现语音端点检测
2017/05/31 Python
浅谈Pandas中map, applymap and apply的区别
2018/04/10 Python
对Python3中bytes和HexStr之间的转换详解
2018/12/04 Python
pytorch 预训练层的使用方法
2019/08/20 Python
解决Django no such table: django_session的问题
2020/04/07 Python
python 读取.nii格式图像实例
2020/07/01 Python
毕业生怎样写好自荐信
2013/11/11 职场文书
军训学生自我鉴定
2014/02/12 职场文书
三分钟演讲稿范文
2014/04/24 职场文书
结婚保证书范文
2014/04/29 职场文书
预备党员转正考核材料
2014/06/03 职场文书
镇创先争优活动总结
2014/08/28 职场文书
颂军魂爱军营演讲稿
2014/09/13 职场文书
2015年爱牙日活动总结
2015/03/23 职场文书
公司2015年终工作总结
2015/05/26 职场文书
周一问候语大全
2015/11/10 职场文书
青年文明号创建口号大全
2015/12/25 职场文书
pytorch中的numel函数用法说明
2021/05/13 Python
OpenCV 图像梯度的实现方法
2021/07/25 Python
苹果可能正在打击不进行更新的 App
2022/04/24 数码科技