日常ProComponent(Ant Design Pro)

ProComponent就是算是对antd的又一次集成和封装,减少了前端对于细节和联动的处理,总之就是用起来特别爽。
那这里就不对ProComponent做过多介绍了,我们直奔主题,如何使用,或者说如何更优雅、更方便的使用组件和编写代码一直是任何一位程序员的核心追求,我也是PiuPiuPiu~!
columns的配置 treeSelect request可以用来调接口获取值
labelInValue:是设置的取到的是这个表单项值的对象,不仅仅包括value,下面的例子取到的就是fieldNames对象

{ title: '区域', dataIndex: 'areaIds', hideInTable: true, valueType: 'treeSelect', request: async () => { let res = await areaSituation(); if (res?.status == '00') { return res.data; } }, fieldProps: { showArrow: false, filterTreeNode: true, showSearch: true, dropdownMatchSelectWidth: false, autoClearSearchValue: true, treeNodeFilterProp: 'title', labelInValue: true, fieldNames: { label: 'title', lvl: 'lvl', value: 'nodeId', children: 'childrenList', }, onSelect: (_, dataObj) => { setAreaIds([]); let arr = []; let getData = https://www.it610.com/article/(data) => { arr = [...arr, data?.nodeId]; if (data?.childrenList.length > 0) { data?.childrenList?.forEach((item) => { getData(item); }); } }; getData(dataObj); setAreaIds(arr); }, }, },

dateTimeRange ProFormDateTimePicker这个是可取值到年月日时分秒
ProFormDatePicker 是支持到年月日
可用moment设置初始值,
这个默认取得值是一个数组 如果搜索后端需要的这个时间字段不是数组而是其他的两个字段;可用下面的写法
{ title: '操作时间', dataIndex: 'actTime', hideInTable: true, valueType: 'dateTimeRange', // initialValue: [moment().subtract(30, 'days'), moment()], fieldProps: { placeholder: ['入库开始时间', '入库结束时间'], }, search: { transform: (value) => { return { startTime: value[0], endTime: value[1], }; }, }, },

radio status可设置渲染到table的状态
sorter表格的某一项排序
{ title: '提成方式', dataIndex: 'commissionMode', sorter: true, formItemProps:{ initialValue:1, }, valueType: 'radio', valueEnum: { 0: '固定', 1: '比例' }, },{ title: '状态', dataIndex: 'taskState', key: 'taskState', valueEnum: { false: { text: '失败', status: 'error' }, true: { text: '成功', status: 'success' }, }, hideInSearch: true, },

renderFormItem 可用SelectAccount直接渲染组件在单列表框里面 比如在EditableProTable里面,
当然这里是用在搜索框的(还是提倡用valueType的方式,但是如果在多个地方使用,封装成组件这样使用也是上选)
{ title: '冷藏费记账账户', dataIndex: 'coldStorageFeeAccountId', formItemProps: { rules: [{ required: true }] }, renderFormItem: (_, { type, ...rest }) => (), },

digit 渲染成只能输入数字的搜索框
{ title: '件数', dataIndex: 'quantity', valueType: 'digit', fieldProps: { precision: 0, min: 1 }, formItemProps: { rules: [{ required: true }] }, },

或者可自定义在search和table的title文字不一样 fieldProps:可设置搜素框的状态
{ title: (_, type) => (type === 'table' ? '操作账号' : ''), dataIndex: 'operatorMobile', key: 'operatorMobile', //fieldProps: { readOnly: true, placeholder: '请先选择杂费' }, fieldProps: { placeholder: '操作人账号', }, },

ProForm表单项 ProFormDependency 可用来监听表单项的某一项改变之后所做的操作,
name为什么是数组呢?
  • 是因为在表单提交的时候呢contractType是作为inboundAppointment对象的一个属性值进行提交的,
  • 这样写的好处就是前端在提交的函数中不用再重新组装一下这个提交参数了
{({ inboundAppointment }) => { if ( inboundAppointment?.contractType == '1' || inboundAppointment?.contractType == '0' ) { return (', label: '大于' }, { value: '<', label: '小于' }, ]} placeholder="请选择合同" /> ); } }}

ProFormFieldSet 上面我们说到name设置成数组的形式,可以帮我们省略组装参数的操作。
那这个更厉害了,可以帮我们提前组装或者拆分提交表单的参数。
那我们看一下官方这里是怎么说的:“ProFormFieldSet 可以将内部的多个 children 的值组合并且存储在 ProForm 中,并且可以通过 transform 在提交时转化”,
言而简之,就是我刚说的意思,对吧~
下面的例子也就是将取到的SelectSubject 对象值进行拆分,保存在ProForm中。
({ subjectName: v[0]?.label, subjectId: v[0]?.value })} label="费用类型" rules={[{ required: true }]} >

ProFormText ProForm.Group ProFormDateTimePicker ProFormText一个简单的表单项
ProFormDateTimePicker:时间选择器年月日可精确到时分秒
ProForm.Group: 可将表单项在空间范围内允许的情况下,做一行展示
const [time, setTime] = useState([moment().startOf('year'), moment().endOf('year')])

ProFormDigit 一个只能输入数字的表单项

ProFormGroup 列表项归类

DrawerForm
const [form] = ProForm.useForm(); { return [ , ]; }, }} width={'70%'} layout="horizontal" form={form} title="客户账单明细" visible={visible} onVisibleChange={setVisible} drawerProps={{ destroyOnClose: true, }} />

ProDescriptions 官方言:高级描述列表组件,提供一个更加方便快速的方案来构建描述列表。
我是用在列表项的详情里面的,通table的用法类似。
(), }, { span: 3, render: () => (), }, { span: 3, render: () => (), }, { title: '相关附件', dataIndex: 'filePath', span: 3, render: (text) => { // let dataArr = text?.includes(',') ? text?.split(',') : [text]; // return ( //<> //{dataArr?.map((item, index) => { //return ( // //{item.name} // //); //})} // // ); }, }, { title: '备注', dataIndex: 'remark', span: 3 }, ]} />

ProTable EditableProTable 两种表格, 一种用的最多的普通表格,一种是可编辑的表格
使用相似度很高。
ProTable 这个ProTable的配置有意思的地方有三:
  1. params自带pageSize,pageNumber
  2. rowSelection可做批量配置操作
  3. 只有单个条件搜索的时候可search设置为false,options的search单独设置,那如果你需要多个条件搜索的时候,可单独对搜索框做一些定制化配置
    当然作为一个高级定制化组件,只有这么些集成肯定是不够的,
高级配置
tableExtraRender
这是配置table列表上部,搜索区域的下部的中间区域,当然如果你有把这个移动到最顶部的需求,可利用css样式去覆盖,倾囊写上
( )} //search={{ //labelWidth: 0, // collapsed: false, // collapseRender: false, // }} rowKey="id" scroll={{ x: 960 }} columns={[ { title: '商品名称', dataIndex: 'goodsName' }, { title: '所属分类', dataIndex: 'category' }, ]} params={{ status: 0 }} request={async (params = {}) => { const json = await getGlobalCfgGoodsPageList(params); return { data: json.records, page: params.current, success: true, total: json.total, }; }} rowSelection={{ selectedRowKeys, onChange: (keys) => setSelectedRowKeys(keys), }} search={false} toolBarRender={false} options={{ search: { name: 'goodsName', placeholder: '请输入商品名称', }, }} />//css样式 .inListContent { .ant-pro-table { display: flex; flex-direction: column; } .ant-pro-table-search { order: 2; } .ant-pro-table-extra { order: 1; } .ant-pro-card { order: 3; } }

EditableProTable 这个组件的使用场景一般是在修改或添加的弹框中使用居多,不要问我怎么知道,因为我常用~
1.trigger="onValuesChange":保证了我当前的诸如DrawerForm类似的form组件可实时拿到这个EditableProTable的值,比如下面在onfinsh中拿到的就是inboundGoodsList的值
2.recordCreatorProps:是手动填加列表的一些配置
3.editable:是编辑的一些配置
{ let res = await getBasicGoodsPageList({ current: 1, pageSize: 999, projectId: initialState?.project?.projectId, }); if (res.status == '00') { return res?.records?.map((item) => { return { label: item.goodsName, value: item.id, }; }); } }, fieldProps: () => { return { labelInValue: true, }; }, }, { title: '件重(件/kg)', dataIndex: 'packageUnit', formItemProps: { rules: [{ required: true }] }, valueType: 'digit', fieldProps: { precision: 0, min: 1 }, }, { title: '重量(kg)', dataIndex: 'weight', editable: false, valueType: 'digit', renderText: (_, record, index) => { if (record.quantity && record.packageUnit) { return Math.round(record.quantity * record.packageUnit); } }, }, { title: '生产日期', dataIndex: 'productionDate', valueType: 'date', width: 200 }, { title: '操作', width: 50, valueType: 'option' }, ]} recordCreatorProps={{ newRecordType: 'dataSource', record: () => ({ id: Date.now(), }), }} editable={{ type: 'multiple', form: tableForm, editableKeys, onChange: setEditableRowKeys, actionRender: (row, _, dom) => { return [dom.delete]; }, }} />

EditableProTable作为这个组件库我觉得最牛逼的组件,虽然使用起来很爽,但是还是有点点坑的存在的:
联动效果来说:当我联动的是一个设置了不能编辑的一项,那这个联动效果会失效,什么意思呢,好的,那上代码:
{ title: '杂费', dataIndex: 'poundage', valueType: "select", request: async () => { let res = await getPoundageList({ projectId: initialState?.project?.projectId }) if (res.status == "00") { return res?.data?.map(item => { return { label: item.name, value: item.id } }) } }, fieldProps: (_, { rowIndex }) => { return { onChange: async (value) => { debugger let res = await getPoundageDetail(value) if (res.status == "00") { let { mode, chargeDescribe } = res?.obj // tableRef?.current?.setRowData(rowIndex,{ //modeDescribe: mode.toString(), //chargeDescribe: chargeDescribe || "" // }) const data = https://www.it610.com/article/form.getFieldValue('inboundPoundageItemList') data[rowIndex].modeDescribe = mode.toString() data[rowIndex].chargeDescribe = chargeDescribe form.setFieldsValue({ inboundPoundageItemList: data, }) } } } } },

一开始我尝试使用setRowData对当前这一行的其他项做联动数据修改,但是失效的,
这里通俗讲就是:他的编辑和不能编辑是对应的两个表单,当我编辑可编辑的这个表单,是设置不了数据到不可编辑的那个表单的,
对,那怎么办?
从数据源处下手呗:form.getFieldValue得到数据修改完之后
form.setFieldsValue重新赋值给这个EditableProTable对应的表单项
ModalForm 这样使用trigger的好处:是组件的状态visible不需要从外部传入了,
只要引入这个组件,这个组件内部维护这个状态。
submitter:可以自定义这个表单的确认按钮和取消按钮的文字
导入} submitter={{ searchConfig: { submitText: '导入', resetText: '取消', }, }} onFinish={async (values) => onSubmit()} >

【日常ProComponent(Ant Design Pro)】这篇文章写的慢,有用心在写,如果帮助到你,或者让你有所领悟,还希望可以不吝 点赞关注~

    推荐阅读