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 Event学习第九章 鼠标事件
Feb 08 Javascript
再谈javascript面向对象编程
Mar 18 Javascript
深入理解javascript的执行顺序
Apr 04 Javascript
简单易用的倒计时js代码
Aug 04 Javascript
Bootstrap每天必学之缩略图与警示窗
Nov 29 Javascript
JavaScript中创建对象的模式汇总
Apr 19 Javascript
由浅入深剖析Angular表单验证
Jul 14 Javascript
js微信分享API
Oct 11 Javascript
jQuery实现自动调用和触发某个事件的方法
Nov 18 Javascript
vue中用动态组件实现选项卡切换效果
Mar 25 Javascript
Element的el-tree控件后台数据结构的生成以及方法的抽取
Mar 05 Javascript
解决vue项目本地启动时无法携带cookie的问题
Feb 06 Vue.js
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
详解:――如何将图片储存在数据库里
2006/12/05 PHP
批量去除PHP文件中bom的PHP代码
2012/03/13 PHP
php页面缓存ob系列函数介绍
2012/10/18 PHP
PHP获取文件扩展名的方法实例总结
2017/06/10 PHP
yii2 url重写并隐藏index.php方法
2018/12/10 PHP
浅谈Laravel模板实体转义带来的坑
2019/10/22 PHP
extjs 学习笔记(二) Ext.Element类
2009/10/13 Javascript
JavaScript 组件之旅(一)分析和设计
2009/10/28 Javascript
基于jquery实现的可以编辑选择的下拉框的代码
2010/11/19 Javascript
jQuery EasyUI API 中文文档 - MenuButton菜单按钮使用介绍
2011/10/06 Javascript
JavaScript中valueOf函数与toString方法深入理解
2012/12/02 Javascript
JQuery中使用Ajax赋值给全局变量失败异常的解决方法
2014/08/18 Javascript
Jquery ajax 同步阻塞引起的UI线程阻塞问题
2015/11/17 Javascript
关于验证码在IE中不刷新的快速解决方法
2016/09/23 Javascript
vue 中自定义指令改变data中的值
2017/06/02 Javascript
js实现水平滚动菜单导航
2017/07/21 Javascript
Node.js学习之查询字符串解析querystring详解
2017/09/28 Javascript
微信小程序实现animation动画
2018/01/26 Javascript
npm全局模块卸载及默认安装目录修改方法
2018/05/15 Javascript
js input输入百分号保存数据库失败的解决方法
2018/05/26 Javascript
详解Vue2.5+迁移至Typescript指南
2019/08/01 Javascript
js判断非127开头的IP地址的实例代码
2020/01/05 Javascript
vue实现简易图片左右旋转,上一张,下一张组件案例
2020/07/31 Javascript
JS实现拖动模糊框特效
2020/08/25 Javascript
Python操作MySQL模拟银行转账
2018/03/12 Python
python2.7和NLTK安装详细教程
2018/09/19 Python
Jupyter Notebook折叠输出的内容实例
2020/04/22 Python
英国最大的经认证的有机超市:Planet Organic
2018/02/02 全球购物
学生实习推荐信范文
2013/11/26 职场文书
大学生精神文明先进个人事迹材料
2014/05/02 职场文书
红色旅游心得体会
2014/09/03 职场文书
感恩教师节演讲稿
2014/09/03 职场文书
大学生年度个人总结
2015/02/15 职场文书
2016年妇联“6﹒26国际禁毒日”宣传活动总结
2016/04/05 职场文书
如何撰写出一份完美的商业计划书?
2019/07/12 职场文书
浅谈MySQL next-key lock 加锁范围
2021/06/07 MySQL