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 相关文章推荐
基于jquery的横向滚动条(滑动条)
Feb 24 Javascript
js window.open弹出新的网页窗口
Jan 16 Javascript
js中的preventDefault与stopPropagation详解
Jan 29 Javascript
jQuery回调函数的定义及用法实例
Dec 23 Javascript
jquery插件hiAlert实现网页对话框美化
May 03 Javascript
jQuery操作基本控件方法实例分析
Dec 31 Javascript
javascript实现tab响应式切换特效
Jan 29 Javascript
jQuery操作cookie
Aug 08 Javascript
详解用Node.js实现Restful风格webservice
Sep 29 Javascript
详解Vue.js 响应接口
Jul 04 Javascript
谈谈JavaScript令人迷惑的==与+
Aug 31 Javascript
vue使用swiper实现左右滑动切换图片
Oct 16 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
日本十大惊悚动漫
2020/03/04 日漫
功能强大的php文件上传类
2016/08/29 PHP
汉化英文版的Dreamweaver CS5并自动提示jquery
2010/11/25 Javascript
jquery ui对话框实例代码
2013/05/10 Javascript
基于jQuery实现响应式圆形图片轮播特效
2015/11/25 Javascript
AngularJS 面试题集锦
2016/09/06 Javascript
微信公众号  提示:Unauthorized API function 问题解决方法
2016/12/05 Javascript
Bootstrap基本样式学习笔记之表格(2)
2016/12/07 Javascript
EasyUI学习之DataGird分页显示数据
2016/12/29 Javascript
AngularJs 利用百度地图API 定位当前位置 获取地址信息
2017/01/18 Javascript
解决vue router使用 history 模式刷新后404问题
2017/07/19 Javascript
React进阶学习之组件的解耦之道
2017/08/07 Javascript
js时间戳与日期格式之间相互转换
2017/12/11 Javascript
vue中v-cloak解决刷新或者加载出现闪烁问题(显示变量)
2018/04/20 Javascript
记录vue项目中遇到的一点小问题
2019/05/14 Javascript
vue项目中引入Sass实例方法
2019/08/27 Javascript
详解element-ui中表单验证的三种方式
2019/09/18 Javascript
JavaScript enum枚举类型定义及使用方法
2020/05/15 Javascript
浅谈终端直接执行py文件,不需要python命令
2017/01/23 Python
Flask框架工厂函数用法实例分析
2019/05/25 Python
Django集成搜索引擎Elasticserach的方法示例
2019/06/04 Python
python命令 -u参数用法解析
2019/10/24 Python
python 多进程队列数据处理详解
2019/12/23 Python
python绘制封闭多边形教程
2020/02/18 Python
PyQt5实现画布小程序
2020/05/30 Python
python--shutil移动文件到另一个路径的操作
2020/07/13 Python
Python进行特征提取的示例代码
2020/10/15 Python
英国顶级家庭折扣店:The Works
2017/09/06 全球购物
美国婴儿用品及配件购买网站:Munchkin
2019/04/03 全球购物
考生诚信考试承诺书
2014/05/23 职场文书
2014房屋登记授权委托书
2014/10/13 职场文书
幼儿园三八妇女节活动总结
2015/02/06 职场文书
2015年党员个人工作总结
2015/05/13 职场文书
小学教师教育随笔
2015/08/14 职场文书
如何利用pygame实现打飞机小游戏
2021/05/30 Python
go web 预防跨站脚本的实现方式
2021/06/11 Golang