antd form表單數(shù)據(jù)回顯操作
index頁(yè)面有一個(gè)表格,有一個(gè)新增按鈕,點(diǎn)擊新增按鈕或表格編輯彈出表單模塊,如果是編輯,會(huì)回顯對(duì)應(yīng)的表格中的數(shù)據(jù)
//index頁(yè)面
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: '員工工號(hào)', 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: [], //表格總數(shù)據(jù)
loading: false,
scroll: { x: 1600 },
//分頁(yè)初始數(shù)據(jù)
pagination: {
current: 1, pageSize: 10, total: 0, showTotal: total => `共 ${total} 條`
}
},
//編輯表單詳細(xì)信息
dataForm: {
data: [],
model: {
id: { value: undefined },
workerName: { value: undefined },//員工姓名
workNumber: { value: undefined }//員工工號(hào)
},
param: {}
},
//form表單模塊
modalOption: {
title: "新增/修改",
visible: false,
footer: null,
destroyOnClose: true,
width: 900
},
}
//編輯數(shù)據(jù)回顯
addOrEditClick(record) {
const self = this;
let { modalOption, dataForm } = this.state;
dataForm.param = JSON.parse(JSON.stringify(dataForm.model));
//如果是編輯彈出表單并且數(shù)據(jù)回顯,否則就是新增
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 });
}
}
//分頁(yè)
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: "查詢(xún)參數(shù)"http://分公司名
}
}).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表單頁(yè),點(diǎn)擊編輯或新增的時(shí)候會(huì)彈出,并且編輯的時(shí)候下拉框value值就為表格當(dāng)前的這一條數(shù)據(jù)對(duì)應(yīng)的值
//對(duì)select里面的value值用getFieldDecorator進(jìn)行綁定
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="請(qǐng)選擇"
>
{renderOption(workerNameList, 'workCode', 'name')}
</Select>)}
</FormItem>
</Col>
<Col {...span24}>
<FormItem label="員工工號(hào)" {...formItemLayout} hasFeedback>
{getFieldDecorator('workNumber', {
rules: [{ required: true, message: reqMeg }]
})(<Select
placeholder="請(qǐng)選擇"
>
{renderOption(workNumberList, 'workNumber', 'name')}
</Select>)}
</FormItem>
</Col>
</Form>
)
}
}
export default AddOrEdit;
補(bǔ)充知識(shí):Ant Design Vue 中a-upload組件通過(guò)axios實(shí)現(xiàn)文件列表上傳與更新回顯的前后端處理方案
前言
在企業(yè)應(yīng)用的快速開(kāi)發(fā)中,我們需要盡快的完成一些功能。如果您使用了Ant Design Vue,在進(jìn)行表單的文件上傳相關(guān)功能開(kāi)發(fā)的時(shí)候,您肯定迫不及待地需要找到一篇包治百病的文章,正是如此,才有了該文的誕生,愿以此文解君憂(yōu)。
方案設(shè)計(jì)
前端方案設(shè)計(jì)
重寫(xiě)a-upload的文件上傳方式,使用axios來(lái)進(jìn)行上傳
選擇一個(gè)文件后立即進(jìn)行上傳,前端記錄上傳成功后的name和uid,并構(gòu)建一個(gè)File實(shí)例,用于a-upload組件的已上傳文件列表的回顯
提交前讓文件列表轉(zhuǎn)化為要后端要處理的uid列表
后端方案設(shè)計(jì)
提供一個(gè)統(tǒng)一上傳單個(gè)文件的接口,每個(gè)文件選擇后自動(dòng)上傳都將上傳到該接口,并寫(xiě)入到數(shù)據(jù)庫(kù)的file數(shù)據(jù)表中
對(duì)表單數(shù)據(jù)新建完成后,對(duì)上傳的文件列表進(jìn)行當(dāng)前實(shí)體記錄的綁定
對(duì)表單數(shù)據(jù)更新完成后,檢測(cè)該實(shí)體記錄的所有文件列表,對(duì)沒(méi)有在該列表中的uid的文件列表進(jìn)行刪除,然后對(duì)該列表中所有的uid文件記錄進(jìn)行當(dāng)前實(shí)體記錄的綁定
新建與更新的一致性處理方案
因?yàn)楦卤韱卧谧x取舊數(shù)據(jù)后,需要與新選擇文件進(jìn)行同樣的格式化處理,這里的處理流程一樣,進(jìn)行回顯的數(shù)據(jù)是一樣的,提交表單也都是提交file表中已經(jīng)存在的uid列表,所以這里的數(shù)據(jù)結(jié)構(gòu)是一致的,處理起來(lái)將會(huì)更加簡(jiǎn)潔明了。
讓代碼說(shuō)話(huà)
為了讓各位看官老爺們便于理解,直接上代碼,希望能將整件事說(shuō)明白。
構(gòu)建表單
<a-form :form="form">
<a-form-item label="名稱(chēng)" style="margin-bottom: 0;">
<a-input v-decorator="['name', {rules: [{required: true, message: '請(qǐng)輸入名稱(chēng)!'}]}]" />
</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" > 相關(guān)下載 </a-button>
</a-upload>
</a-form-item>
</a-form>
編寫(xiě)js代碼
請(qǐng)求后端接口的token、header以及baseUrl等我已默認(rèn)您已經(jīng)在axios的統(tǒng)一設(shè)置中已經(jīng)配置好了
為了簡(jiǎn)化axios相關(guān)操作,我們將axios進(jìn)行了如下封裝(您也可以按此完全使用axios來(lái)直接對(duì)數(shù)據(jù)進(jìn)行提交等):
const dibootApi = {
get (url, params) {
return axios.get(url, {
params
})
},
upload(url, formData) {
return service({
url,
method: 'POST',
data: formData
})
}
}
export default dibootApi
我們默認(rèn)為demo實(shí)體中需要上傳一些文件列表
export default {
name: 'demoForm',
data () {
title: '新建', // 該表單的功能標(biāo)題
form: this.$form.createForm(this), // 表單數(shù)據(jù)初始化,沒(méi)什么好說(shuō)的
model: {}, // 如果是更新表單,之前的數(shù)據(jù)放到這里,來(lái)做數(shù)據(jù)初始化顯示之用
downloadFiles: [] // 已經(jīng)上傳的文件列表
},
methods: {
// 初始打開(kāi)的表單時(shí)的處理(如果是更新表單,這里首先需要讀取出相關(guān)數(shù)據(jù))
async open (id) {
if (id === undefined) {
// 沒(méi)有id數(shù)據(jù)則認(rèn)為是新建
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: '獲取數(shù)據(jù)失敗',
description: res.msg
})
}
}
},
// 更新表單在讀取數(shù)據(jù)完成后的操作
afterOpen (id) {
// 獲取該記錄信息后,回顯文件列表相關(guān)操作
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))
})
}
}
})
},
// 重寫(xiě)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)
// 上傳單個(gè)文件后,將該文件會(huì)先到a-upload組件的已上傳文件列表中的操作
this.downloadFiles.push(file)
} else {
this.$message.error(res.msg)
}
})
},
// 對(duì)上傳成功返回的數(shù)據(jù)進(jìn)行格式化處理,格式化a-upload能顯示在已上傳列表中的格式(這個(gè)格式官方文檔有給出的)
fileFormatter(data) {
let file = {
uid: data.uuid, // 文件唯一標(biāo)識(shí),建議設(shè)置為負(fù)數(shù),防止和內(nèi)部產(chǎn)生的 id 沖突
name: data.name, // 文件名
status: 'done', // 狀態(tài)有:uploading done error removed
response: '{"status": "success"}', // 服務(wù)端響應(yīng)內(nèi)容
}
return file
},
// 沒(méi)錯(cuò),刪除某個(gè)已上傳的文件的時(shí)候,就是調(diào)用的這里
handleDownloadFileRemove (file) {
const index = this.downloadFiles.indexOf(file)
const newFileList = this.downloadFiles.slice()
newFileList.splice(index, 1)
this.downloadFiles = newFileList
},
// 表單校驗(yàn)就靠他了,不過(guò)這里面還是可以對(duì)需要提交的一些數(shù)據(jù)做些手腳的
validate () {
return new Promise((resolve, reject) => {
this.form.validateFields((err, fieldsValue) => {
if (!err) {
// 設(shè)置上傳文件列表
const downloadFiles = this.downloadFiles.map(o => {
return o.uid
})
const values = {
...fieldsValue,
'downloadFiles': downloadFiles
}
resolve(values)
} else {
reject(err)
}
})
})
},
// 表單提交的相關(guān)操作
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)
}
// 執(zhí)行提交成功的一系列后續(xù)操作
this.submitSuccess(result)
} catch (e) {
// 執(zhí)行提交失敗的一系列后續(xù)操作
this.submitFailed(e)
}
},
// 新增數(shù)據(jù)的操作
async add (values) {
....
},
// 更新數(shù)據(jù)的操作
async update (values) {
...
}
}
}
編寫(xiě)SpringBoot相關(guān)的接口代碼
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, "上傳文件成功");
}
/***
* 創(chuàng)建成功后的相關(guān)處理
* @param entity
* @return
*/
@Override
protected String afterCreated(BaseEntity entity) throws Exception {
DemoDTO demoDTO = (DemoDTO) entity;
// 更新文件關(guān)聯(lián)信息
demoService.updateFiles(new ArrayList<String>(){{
addAll(demoDTO.getDownloadFiles());
}}, demoDTO.getId(), true);
return null;
}
/***
* 更新成功后的相關(guān)處理
* @param entity
* @return
*/
@Override
protected String afterUpdated(BaseEntity entity) throws Exception {
DemoDTO demoDTO = (DemoDTO) entity;
// 更新文件關(guān)聯(lián)信息
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, "請(qǐng)上傳圖片");
}
String fileName = file.getOriginalFilename();
String ext = fileName.substring(fileName.lastIndexOf(".")+1);
String newFileName = S.newUuid() + "." + ext;
//TODO: 需要對(duì)合法的文件類(lèi)型進(jìn)行驗(yàn)證
if(FileHelper.isImage(ext)){
throw new BusinessException(Status.FAIL_OPERATION, "請(qǐng)上傳合法的文件類(lèi)型");
};
// 說(shuō)明:此處為我們的處理流程,看官們需要根據(jù)自己的需求來(lái)對(duì)文件進(jìn)行保存及處理(之后我們的File組件開(kāi)源之后也可以按照此處的處理)
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) {
// 如果不是創(chuàng)建,需要?jiǎng)h除不在列表中的file記錄
if (!isCreate){
fileService.deleteEntities(Wrappers.<File>lambdaQuery().notIn(File::getUuid, uuids));
}
// 進(jìn)行相關(guān)更新
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, "更新文件信息失敗");
}
}
提示
該文章所有代碼皆為方案示例,其中有些許刪減,不確保能直接運(yùn)行,如果各位有好的想法,歡迎一起探討。
以上這篇antd form表單數(shù)據(jù)回顯操作就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue動(dòng)態(tài)設(shè)置img的src路徑實(shí)例
今天小編就為大家分享一篇vue動(dòng)態(tài)設(shè)置img的src路徑實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
vue中報(bào)錯(cuò)Duplicate?keys?detected:'1'.?This?may?c
我們?cè)趘ue開(kāi)發(fā)過(guò)程中常會(huì)遇到一些錯(cuò)誤,這篇文章主要給大家介紹了關(guān)于vue中報(bào)錯(cuò)Duplicate?keys?detected:‘1‘.?This?may?cause?an?update?error的解決方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03
vue+iview 兼容IE11瀏覽器的實(shí)現(xiàn)方法
這篇文章主要介紹了vue+iview 兼容IE11瀏覽器的實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
VUEJS實(shí)戰(zhàn)之構(gòu)建基礎(chǔ)并渲染出列表(1)
這篇文章主要為大家詳細(xì)介紹了VUEJS實(shí)戰(zhàn)之構(gòu)建基礎(chǔ)并渲染出列表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06
詳解如何解決vue開(kāi)發(fā)請(qǐng)求數(shù)據(jù)跨域的問(wèn)題(基于瀏覽器的配置解決)
這篇文章主要介紹了詳解如何解決vue開(kāi)發(fā)請(qǐng)求數(shù)據(jù)跨域的問(wèn)題(基于瀏覽器的配置解決),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-11
詳解vuex 中的 state 在組件中如何監(jiān)聽(tīng)
本篇文章主要介紹了詳解vuex 中的 state 在組件中如何監(jiān)聽(tīng),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
vue給對(duì)象動(dòng)態(tài)添加屬性和值的實(shí)例
今天小編就為大家分享一篇vue給對(duì)象動(dòng)態(tài)添加屬性和值的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
Vue3父子組件傳參有關(guān)sync修飾符的用法詳解
這篇文章主要給大家介紹關(guān)于前端Vue3父子組件傳參有關(guān)sync修飾符的用法詳細(xì)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09

