5.1 界面与流程改造
5.1.1 在列表工具栏放置操作按钮
给
src/pages/MemberList/index.tsx
中的ProTable
增加一个属性toolBarRender={() => [
<Button
type="primary"
key="primary"
onClick={() => {
setFormState({ showModal: true, operation: 'create',record: {
//所有需要设置默认值的都可以放在这里
nationality: 0,
education: 6,
degree: 1,
party: 0,
email: '',
}})
}}
>
<PlusOutlined /> 新建
</Button>,
]}
这里我们给多数非必填内容都设置了初始默认值(没有给
email
设置默认值是为了演示下一节的重置效果),这样做有两个好处:一是设置为最常用的值有助于减少用户操作次数,二是默认的情况下,ProForm
的属性omiNil
的默认值为true
,这时所有的值为undefined
的变量都不会传递给onFinshed
函数,这就增加了对后端逻辑完整性的考验(尽管后端程序无论如何都需要完整的判断逻辑)。当然,还需要引入使用的图标
import { ExclamationCircleOutlined, PlusOutlined } from '@ant-design/icons';
完成以后,列表的上方可以看到一个按钮
点击它,应该看到下面的对话框
5.1.2 修正数据重置功能
在“增加会员”的对话框中,填写一部分内容之后点击“重置”按钮,只会把写在
setFormState
参数中的字段进行重置,在本例中就是当我们填写了邮件地址之后,其内容不会被重置操作情况(想想看为什么?),为了真正的实现重置(把填写的内容都恢复为初始状态),需要修正MemberDataForm.tsx
中的重置功能。
在MemberDataForm.tsx
中引用FormInstance
、定义函数resetFormDate
并且修改useEffect
的定义
import { message, Form, Button, FormInstance } from "antd";
const resetFormDate = (theForm: FormInstance | undefined) => {
if(operation == 'edit')
theForm?.setFieldsValue(record);
else
theForm?.resetFields();
}
useEffect(() => {
if (form && visible)
resetFormDate(form)
}, [visible]);
然后给ModalForm增加初始化属性
<ModalForm
...
+ initialValues={record}
最后修改重置按钮的响应函数
onClick={() => {
const { form } = props
- form?.setFieldsValue(record)
+ resetFormDate(form)
setDataChanged(false)
}}
5.2 完成网络请求和数据模拟
5.2.1 增加网络请求函数
在api/member.ts
中增加新的函数
export async function addMember(data: TYPE.Member) {
return request('/api/member/add', {
method: 'POST',
data: {
...data
}
});
}
在MemberDataForm.tsx
中引入该函数
import { addMember, updateMember } from "@/services/api/member";
修改MemberDataForm.tsx
中onFinish
的try .. catch
部分代码
try {
if(operation === 'edit')
await updateMember(result);
else
await addMember(result);
message.success('保存成功,即将刷新',1);
handleResponse(true);
} catch (error) {
handleResponse(false);
}
5.2.2 模拟添加数据
在mock中增加如下的函数
function create(req: Request, res: Response, u: string) {
const record = {...req.body}
let max = 0
for( let member of memberListDataSource){
const { id=0 } = member;
max = (max < id)? id : max
}
record.id = max + 99
memberListDataSource.reverse()
memberListDataSource.push(record)
memberListDataSource.reverse()
const result = {
success: true,
}
return res.json(result);
}
export default {
'POST /api/member/add': create,
5.3 实现对话框数据间的依赖联动
首先在
utils/utils.ts
中增加一个从身份证号中提取出生日期的函数import moment from 'moment';
export function getBirthdayFromId(idNumber: string) {
let dateString = ''
if(idNumber != undefined) {
dateString = (idNumber as string).substr(6,8)
switch(dateString.length) {
case 8:
break;
case 7:
dateString += '1'
break;
case 6:
dateString += '01'
break;
case 5:
dateString += '101'
break;
case 4:
dateString += '0101'
break;
case 0:
dateString = ''
break;
default:
dateString = dateString.padEnd(4,'0') + '0101'
}
}
return (dateString!='')? moment(dateString) : null;
}
然后在对话框中引用它
import { getOptionsFormValueEnum, getBirthdayFromId } from '@/utils/utils'
在官方文档中认为在实现组件联动的时候,“
ProFormDependency
绝对是最好的选择”,但实际上,这种方式比较适合用于控制某些组件是否出现,以及控制纯文字(label
)的内容。如果需要控制组件字段的实际值,不要使用**ProFormDependency**
,应该在onValuesChange
中实现数据间的依赖逻辑。onValuesChange={(changedValus) => {
if(!dataChanged)
setDataChanged(true)
if(operation == 'create' && changedValus['identityNumber'] != undefined) {
const identityNumber = changedValus['identityNumber']
form.setFieldsValue({
birthday: getBirthdayFromId(identityNumber),
gender: ((identityNumber as string)?.length > 16)? (2 - parseInt((identityNumber as string)[16]) % 2) : 0,
})
}
}}
关于的
ProFormDependency
具体用法可见官方代码示例给被动改变数值的组件增加
disabled
属性,禁止用户直接操作其内容 ```diff<ProFormDatePicker name="birthday" label="出生日期" width="sm"
- disabled={operation === ‘create’} … … <ProFormSelect name=”gender” label=”性别” placeholder=”选择性别” width={64} options={getOptionsFormValueEnum(genderEnum)}
- disabled={operation === ‘create’} ``` 这里有两个重要提醒:
- 使用
disabled
属性而不是readonly
属性,因为前者会保留组件完整的外观合大小,后者则会把组件变成纯文本的形式。 - 我们这里设计的逻辑是在创建数据时执行生日、性别与身份证号的强逻辑联系,但在修改数据时完全放开,给用户随意修改的权力,这里除了展示不同的软件功能以外,还因为项目实践中确实存在因身份证编码出错而不匹配的情况,此时确实需要有修改的手段。
5.4 小结
本章涉及的的内容也非常多,所以一定要按照本章的内容逐步完成每个步骤,并且理解每条语句的作用,一定不要简单的复制粘贴。
版权说明:本文由北京朗思云网科技股份有限公司原创,向互联网开放全部内容但保留所有权力。