@hzab/list-render
v1.12.12
Published
列表与表格渲染
Downloads
1,190
Readme
@hzab/list-render
列表组件,支持传入 schema 进行 CURD 相关组件(列表、新增、编辑、删除)的渲染
- Schema JSON 配置工具:内网仓库 formily-designable-ui
(需另行 clone,在其目录内执行
npm i/npm run dev启动配置界面)- 官方在线配置地址(配置响应器存在白屏 bug):https://designable-antd.formilyjs.org/
目录
- 安装
- 组件:Tips / 示例 / ListRender Attributes / Table ref Methods
- 编辑模式 editMode
- Schema:Schema Scope / 响应器中可用的参数
- DataModel
- 常见问题 FAQ
- 相关文档
安装
pnpm add @hzab/list-render本包同时发布到公共 npm(registry.npmjs.org,public access)与企业私有源(ld / old)。
默认源可直接安装,无需额外配置;若团队要求走内网源,见消费方接入指南。
消费方需自备 peerDependencies:@formily/core、@formily/json-schema、@formily/react、@formily/reactive、@hzab/data-model、@hzab/edit-table、@hzab/form-render、@hzab/formily-result-utils、@hzab/schema-descriptions、@hzab/utils、antd、array-move、c-formily-antd、react、react-dom、react-sortable-hoc(本包不会随包安装)。
⚠️
@formily/*必须全树唯一、且版本为精确2.3.1(不要写^/>=):c-formily-antd与@hzab/form-render内部就锁定2.3.1。 若把它交给 npm 按范围自动安装,顶层会拿到最新版(2.3.7)并与那些精确2.3.1各自嵌套,同一棵树里出现 2~4 份@formily/react→FormContext分裂 → 打开表单弹层即抛TypeError: Cannot read properties of null (reading 'createField')。 排查与处置见消费方接入指南 §7.1。
引入方式见下方「组件」章节。
发布形态:本包在本仓以源码直出方式发布——
main指向src,由消费方打包器编译 TypeScript 与.less样式;@hzab/list-render/src/*深路径同样可直接引用。随包发布的dist/仅用于 类型解析(types→dist/index.d.ts),不是运行时入口。消费方需要承担的编译责任见 消费方接入指南 §4。
组件
Tips
- antd 组件样式需要手动引入(本包只随包发布自己的
.less,不引入 antd 样式) - 相关文档可查看 docs 中的文件,索引见 docs/README.md
model必须在组件内部(useMemo/useDataModel)创建,不要定义在组件外部,否则会出现「切换页面后上次搜索条件仍在」的 query 残留,详见 常见问题 FAQ
示例
import { useMemo } from "react";
import ListRender, { DataModel } from "@hzab/list-render";
const listDM = useMemo(
() =>
new DataModel({
getListApi: "/api/v1/userinfo",
// 可用于替代 getList 的函数,处理自定义数据
getListFunc() {
return new Promise((resolve) => {
resolve({
list: [{ id: 1, menuName: "name" }],
pagination: { total: 1, current: 1 },
});
});
},
createApi: "/api/v1/userinfo",
getApi: "/api/v1/userinfo/:id",
updateApi: "/api/v1/userinfo/:id",
deleteApi: "/api/v1/userinfo/:id",
}),
[],
);
// testSchema 为 formily 生成的 schema json(见上方 Schema JSON 配置工具)
<ListRender schema={testSchema} model={listDM} />;API
ListRender Attributes
- 默认值均取自源码解构默认值;「必须」列的空白表示非必填。
hasEdit/hasDel/hasDetail/hasDelTips由 tableConf(表格布局)或 cardConf(卡片布局)读取, 见对应子表——作为顶层 props 传入不会生效。
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
| --------------------------- | ------------------------- | ---- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| layout | string | 否 | default | 列表渲染类型:default 表格 / card 卡片栅格 |
| className | string | 否 | - | 外层 div className |
| idKey | string | 否 | id | 唯一值字段的 key(行 key、详情/编辑/删除请求入参都用它) |
| schema | Object | 是 | - | 字段描述文件,包含各个字段的信息(formily schema JSON) |
| model | Object | 是 | - | 数据模型,包含 CURD 接口信息,传入 DataModel 的实例 |
| isPatchUpdate | boolean | 否 | false | 编辑提交接口是否使用 patch 发起请求(走 model.patch / model.patchMap) |
| list | Array | 否 | - | 本地数据源;未提供 model.getList 时使用,并按 hasPagination 决定是否前端切片分页 |
| closeAutoRequest | Boolean | 否 | false | 是否关闭加载完毕后自动发起请求。true 时组件 didMount 不自动发起请求 |
| hasQuery | Boolean | 否 | true | 是否包含搜索、筛选框、搜索按钮等 |
| verticalHeader | Boolean | 否 | false | 搜索项和新增按钮是否处于不同的行等 |
| search | String | 否 | - | 传入空字符串时,不包含搜索框;传入非空字符串时,显示搜索框,同时传入的字符串作为搜索框的占位符(固定字段名为 search) |
| filters | Array | 否 | [] | 字符串数组,可以包含要筛选的字段 key 值(schema 中的 name),或者字符串 '$timerange'(时间范围筛选专用) |
| queryConf | Object | 否 | {} | 设置 query 参数的 key |
| createText | String/ReactNode | 否 | 新增 | 新增按钮文案(i18n.createText 优先于此值) |
| hasCreate | Boolean | 否 | true | 是否显示新增按钮 |
| hasAction | Boolean | 否 | true | 是否在表格的最右增加一个“操作”列(卡片布局为卡片头部操作区);hasAction 为 true 时,tableConf/cardConf 的 hasEdit/hasDel/hasDetail 才会生效 |
| tableConf | Object | 否 | {} | Table 相关配置,见 tableConf(编辑/删除/详情按钮开关也在其中) |
| tableProps | Object | 否 | {} | 直接传给 Table 的 props,相关 API 可直接参考 antd table 组件(在内部配置之后展开,可覆盖内部值) |
| cardConf | Object | 否 | {} | Card 相关配置,见 cardConf |
| cardProps | Object | 否 | {} | 直接传给 cardRender 的 props,因内部渲染使用的是详情组件,相关 API 可直接参考 @hzab/schema-descriptions 组件 |
| fetchOnEdit | Boolean | 否 | true | 展示编辑弹框时,是否会调用一次详情接口进行回填;若为 false,则会使用表格列表接口返回的 row 数据进行回填 |
| fetchById | Boolean | 否 | true | 详情/编辑请求是否以 id 作为入参的 key;为 false 时改用 idKey 的值作为 key |
| modalMode | string | 否 | dialog | 新增/编辑表单、详情 展示模式: dialog drawer |
| modalConf | Object | 否 | {} | modal/Drawer 配置对象,见 modalConf |
| modalDetailProps | Object | 否 | {} | modal descriptions 配置对象(透传给 @hzab/schema-descriptions) |
| modalFormProps | Object | 否 | {} | modal/drawer fromRender 配置对象(透传给 @hzab/form-render) |
| modalProps | Object | 否 | {} | modal/drawer 配置对象(透传给 antd Modal/Drawer,如 maskClosable、getContainer) |
| schemaScope | Object | 否 | {} | formRender schemaScope props |
| components | Object | 否 | {} | formRender components props 自定义组件(查询、表格、表单共用) |
| detailComponents | Object | 否 | {} | descriptions components props 自定义组件(仅详情渲染) |
| hasPagination | Boolean | 否 | true | 是否显示分页 |
| paginationConf | Object | 否 | {} | 可自定义 Pagination props,进行 pagination 相关设置,见 paginationConf |
| formInitialValues | Object | 否 | {} | 给新增、编辑对话框中的表单增加默认值 |
| Slots | Object | 否 | {} | 组件插槽,见 Slots 插槽 |
| getFieldListOpt | Object | 否 | {} | getFieldList opt 参数,见 getFieldListOpt |
| onGetListEnd | Function | 否 | - | 请求列表成功返回的回调,参数为 { list, pagination } |
| onCreateSuc | Function | 否 | - | 新增成功返回的回调 |
| onEditSuc | Function | 否 | - | 编辑成功返回的回调 |
| onDelSuc | Function | 否 | - | 删除成功返回的回调 |
| onFormModalClose | Function | 否 | - | 表单/详情弹窗关闭回调(旧名 onFormDialogClose,二者取其一) |
| modalFormMount | Function | 否 | - | 新增、编辑、详情弹窗 Form 渲染完成回调(旧名 dialogFormMount) |
| msgConf | Object | 否 | {} | 新增、编辑、删除、列表查询,详情查询的报错 msg 提示设置(传给 message.error({ ...msgConf, content })) |
| i18n | Object | 否 | {} | 文案配置,见 i18n |
| queryFormInitialValues | Object | 否 | {} | 列表上方查询 Form 默认值 |
| queryFormIsExtendModelQuery | Boolean | 否 | false | 列表上方查询 Form 默认值是否继承 model.query |
| useFormData | boolean | 否 | - | 是否使用 form data 提交数据(未传时回退 dialogConf.useFormData / modalConf.useFormData) |
| editMode | modal/line/line-cell/cell | 否 | modal | 编辑模式,见 编辑模式 editMode |
| canEditCallback | Function | 否 | - | 行内编辑模式下按单元格判定是否可编辑:(record, field, dataIndex) => boolean,返回 false 时该单元格不可编辑 |
| cellEditTableProps | Object | 否 | {} | tableConf.isCellEditTable 为 true 时,透传给 @hzab/edit-table 的 CellEditTable |
| appendUrlQuery | boolean | 否 | false | 筛选条件改变时是否将参数(对象形式)设置到 url query 中(仅 hash 路由生效,见常见问题) |
| appendUrlQueryKey | string | 否 | URL_PARAM_NAME = "defaultSearchParams" | 自定义设置 url query 对象参数的 key |
| hasFilterTag | boolean | 否 | false | 是否在搜索区下方展示已选筛选条件 Tag,可单个关闭并自动重新查询 |
| onEditReqVerify | Function | 否 | - | 编辑态保存时额外的规则校验函数,返回 Promise 的 resolve 或 reject 用于继续执行或停止执行 |
- fetchOnEdit 展示编辑弹框时,是否会调用一次详情接口进行回填(某些场景下,列表接口只返回部分部分字段,只有详情接口会返回全部字段);若为 false,则会使用表格列表接口返回的 row 数据进行回填
- 旧命名别名:
dialogConf/dialogFormProps/dialogProps/dialogDetailProps/dialogFormMount/onFormDialogClose与对应的modal*合并后生效,且modal*优先(如{ ...dialogFormProps, ...modalFormProps })。新代码请直接使用modal*。
tableConf
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
| ----------------- | ---------------- | ---- | --------------- | -------------------------------------------------------------------------------------------------------- |
| colConf | Object | | {} | 指定各列的配置(比如列宽),key 为字段的 name。可以指定名为 “_$actions”的字段来设置“操作”列,见下方子表 |
| rowSelection | Object | | {} | 选择功能的配置。参考 antd table rowSelection 参数 |
| scroll | Object | | {} | 表格是否可滚动,也可以指定滚动区域的宽、高。参考 antd table scroll 参数 |
| expandable | Object | | {} | 配置展开属性。参考 antd table expandable 参数 |
| onRow | Function | | {} | 设置行属性。参考 antd table onRow 参数 |
| hasEdit | Boolean/Function | | true | 是否显示「编辑」按钮;函数入参 (record, index),返回 false 时该行不显示 |
| hasDel | Boolean/Function | | true | 是否显示「删除」按钮;函数同上 |
| hasDetail | Boolean/Function | | false | 是否显示「详情」按钮;函数同上(默认不显示,需要显式开启) |
| hasDelTips | String/Function | | "确认删除该项?" | 删除确认文案;函数入参 (record, index),可返回该行的提示文案 |
| orderColType | string | | - | 序号列数据类型:page(按当前页的序号)、all(按所有页的序号) |
| orderColWidth | string/number | | - | 序号列 width 的参数 |
| tableEmptyValue | string/number | | undefined | table 列表空值展示数 |
| isTableSortXIdex | Boolean | | false | table 列表列排序是否按照 x-index 排序 |
| isShowTableFilter | Boolean | | false | 是否显示表格右上角「显示过滤项 / 显示列」设置 |
| isCellEditTable | Boolean | | false | 是否改用 @hzab/edit-table 的 CellEditTable 渲染表格(配套 cellEditTableProps) |
| dragColConf | Object | | undefined | 拖拽列的配置 |
| isDargTable | Boolean | | undefined | 是否开启表格拖拽排序(源码拼写如此) |
| dargEndBack | function | | undefined | 拖拽结束回调,参数为 (newList, query)(源码拼写如此) |
tableConf.colConf[xxx]
xxx为 schema 字段 name;_$actions用于操作列(其width会作为操作列容器宽度)。
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
| --------------- | --------------- | ---- | --------- | ------------------------------------------------------------------------------------------- |
| title | string/Function | | - | 覆盖列标题(函数返回值作为标题) |
| width | string/number | | - | 当前列宽度 |
| ellipsis | boolean/Object | | - | 当前列是否超出隐藏,true 或 { showTitle: true } 开启超出隐藏 |
| emptyValue | string/number | | undefined | 该列空值展示(优先级:列配置 > schema 的 emptyValue > tableConf.tableEmptyValue) |
| showMode | string | | - | 用 @hzab/formily-result-utils 的 EnumRender 渲染,指定枚举展示模式 |
| showTags | boolean | | - | 便捷开关,等价于 showMode=tags |
| showPrefixNode | boolean | | - | 便捷开关,等价于 showMode=prefixNode(Switch 字段默认开启) |
| enumRenderProps | Object | | - | 传给 EnumRender 的额外 props |
| onCell | Function | | - | 自定义 onCell,入参会额外带上 _field(已合并最新 fieldSchema);返回值与 antd onCell 一致 |
| 其他键 | - | | - | 其余键整体透传给 antd Table column,如 fixed、align、sorter |
cardConf
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
| -------------- | ---------------- | ---- | --------------- | ------------------------------------------------------------------------------------------------------------------- |
| CardItemRender | React 组件 | | - | 自定义渲染卡片,入参 { item, index, functionProps },其中 functionProps 为 { onEdit, onDel, onSearch, getList } |
| columns | Number | | 3 | 栅格列数(内部作为 CSS grid 的列数) |
| hasEdit | Boolean/Function | | true | 同 tableConf.hasEdit |
| hasDel | Boolean/Function | | true | 同 tableConf.hasDel |
| hasDetail | Boolean/Function | | false | 同 tableConf.hasDetail(默认不显示) |
| hasDelTips | String/Function | | "确认删除该项?" | 同 tableConf.hasDelTips |
| colConf | Object | | {} | 同 tableConf.colConf;卡片布局当前只读取 _$actions 的 width |
cardConf.colConf[xxx]
- 与上文
tableConf.colConf[xxx]同构;卡片布局当前只用到_$actions的width。
queryConf
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
| ----------------- | ----------------------------------------- | ---- | ------ | ---------------------------------------------------------------------------------------------- |
| hasReset | boolean | | false | 是否有重置按钮 |
| isSelectSearch | boolean | | true | Select 是否支持搜索 |
| isRmDefault | boolean | | false | 是否去除默认值 |
| isRmValidator | boolean | | false | 是否去除校验 |
| isChangeSubmit | boolean | | true | 是否支持改变提交 |
| isEnterSubmit | boolean | | true | 是否支持回车提交 |
| selectList | Array | | [] | 追加到默认 ["Select", "Radio.Group", "Checkbox.Group"] 的组件列表(命中则转换为 Select) |
| inputList | Array | | [] | 追加到默认 ["NumberPicker"] 的组件列表(命中则转换为 Input) |
| customSubmitList | Array<{component:string,event:string}> | | | 自定义提交触发函数的列表 [{component: 'test', event: 'onTest'}] |
| replaceComList | Array<{name:string,"x-component":string}> | | | 通过 name 替换过滤项中组件 schema 对象逻辑。注意 name 必传,不传会把所有同类型 component 替换 |
| queryMap | Function | | - | query 数据提交前的处理函数 |
| beforeQuerySearch | Function | Promise<boolean> | | - | 点击搜索按钮前触发的函数 |
modalConf
- 作用于新增/编辑表单弹层(FormModal)与详情弹层(DetailModal);与旧名
dialogConf合并时modalConf优先。
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
| ------------ | -------------- | ---- | ------ | ----------------------------------------------------------------------------------------------- |
| width | number/string | 否 | 720 | 弹窗宽度 |
| okText | string | 否 | 确 定 | 弹窗底部确定按钮文案(详情弹层为「关 闭」) |
| cancelText | string | 否 | 取 消 | 弹窗底部取消按钮文案 |
| footer | Array/Function | 否 | - | 自定义弹窗底部按钮;函数入参 { cancel, onOk, close, formRef, validate, scenario, options } |
| beforeSubmit | Function | 否 | - | 提交前的回调 (formValues, { cancel, formRef, scenario }),return false 表示拦截,不进行请求 |
| useFormData | boolean | 否 | - | 等价于顶层 useFormData(未传顶层时可在此配置) |
| title | Object | 否 | - | 配置弹窗标题,见下方 modalConf.title |
modalConf.title
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 | | ---------- | -------- | ---- | ------ | ---------------------------------------------- | | createText | string | 否 | 新增 | 新增弹窗标题 | | createKey | string | 否 | - | 新增弹窗标题 key,取自初始值 formInitialValues | | editText | string | 否 | 编辑 | 编辑弹窗标题 | | editKey | string | 否 | - | 编辑弹窗标题 key,取自当前选中行的 key 的对应值 | | detailText | string | 否 | 详情 | 详情弹窗标题 | | detailKey | string | 否 | - | 详情弹窗标题 key,取自当前选中行的 key 的对应值 |
model
model为 DataModel 实例(由@hzab/data-model提供,本包已export *再导出);组件实际调用的方法为getList/get/create/update(isPatchUpdate时为patch)/delete。- 全量参数见下文 DataModel 属性 Props 与
@hzab/data-model的 README。
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 | | -------- | -------- | ---- | ------ | -------------------------------------------- | | query | Object | 否 | {} | get 请求参数(分页参数由组件内部维护并合并) |
i18n
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 | | ----------- | -------- | ---- | ------------- | --------------------- | | createText | string | 否 | 新增 | 新增按钮文案 | | tableEdit | string | 否 | 编辑 | 表格编辑按钮文案 | | tableDel | string | 否 | 删除 | 表格删除按钮文案 | | tableDetail | string | 否 | 详情 | 表格/卡片详情按钮文案 | | tableDelTip | string | 否 | 确认删除该项? | 表格删除提示文案 |
Slots 插槽
- 用于在指定位置添加所需的组件
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
| ------------------ | -------- | ---- | ------ | --------------------------------------------------------------------------------------------------------------- |
| headerActionPrefix | Function | 否 | - | 新增按钮左侧插槽,入参 { onCreate, onSearch, getList, i18n } |
| headerActionSuffix | Function | 否 | - | 新增按钮右侧插槽,入参同上 |
| HeaderOthersSuffix | Function | 否 | - | 表格和搜索项之间的插槽,入参 { onSearch, getList } |
| tableActionsSlot | Function | 否 | - | 操作列插槽,会覆盖操作列,入参 { text, record, index, onEdit, onDel, onSearch, getList }(卡片布局无 text) |
| actionPrefixSlot | Function | 否 | - | 操作列 详情按钮左侧插槽,入参同 tableActionsSlot |
| actionCenterSlot | Function | 否 | - | 操作列 编辑、删除按钮中间插槽,入参同上 |
| actionSuffixSlot | Function | 否 | - | 操作列 删除按钮右侧插槽,入参同上 |
| FormSlot | Function | 否 | - | 替换新增、编辑弹窗内的表单,入参 { ...ListRender props, formRef, scenario, schema } |
| modalFooterPre | Function | 否 | - | 新增、编辑、详情弹窗按钮左侧插槽,入参 { options } |
| modalFooterCenter | Function | 否 | - | 新增、编辑弹窗按钮中间插槽,入参 { options }(详情弹层不渲染此插槽) |
| modalFooterSuffix | Function | 否 | - | 新增、编辑、详情弹窗按钮右侧插槽,入参 { options } |
| [字段 name] | Function | 否 | - | 以 schema 字段 name 为 key 的插槽,用于自定义该列单元格渲染,入参 { text, record, index, field, fieldSchema } |
options为弹层操作集合:表单弹层为{ cancel, onOk, close, formRef, validate, scenario },详情弹层为{ close, formRef, scenario }。
// Slots 按需添加
const Slots = {
headerActionPrefix() {
return (<div>headerActionPrefix</div>)
},
actionPrefixSlot(props) {
const { text, record, index, onEdit, onDel } = props;
return (<div>actionPrefixSlot</div>)
},
modalFooterPre(props) {
const {
cancel,
onOk,
close,
formRef,
validate,
} = props?.options || {};
return (<div>modalFooterPre</div>)
}
};
<ListRender schema={schema} model={listDM} Slots={Slots} />- 字段级插槽(key 为 schema 字段 name)用于自定义某列的单元格渲染:
const Slots = {
// 字段 name 为 status 的列
status(props) {
const { text, record, index, field, fieldSchema } = props;
return <Tag>{text}</Tag>;
},
};
<ListRender schema={schema} model={listDM} Slots={Slots} />dialogConf
- 旧命名,与 modalConf 合并后生效(
{ ...props.dialogConf, ...modalConf },即modalConf优先)。 新代码请使用modalConf;同名键的取值与默认值完全一致。
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 | | ------------ | -------------- | ---- | ------ | --------------------------------------------------- | | width | number/string | 否 | 720 | 弹窗宽度 | | okText | string | 否 | 确 定 | 弹窗底部确定按钮文案 | | cancelText | string | 否 | 取 消 | 弹窗底部取消按钮文案 | | footer | Array/Function | 否 | - | 自定义弹窗底部按钮 | | beforeSubmit | Function | 否 | - | 提交前的回调, return false; 表示拦截,不进行请求。 |
paginationConf
- 默认参数参考 antd pagination 组件;其余键(如 showSizeChanger、showQuickJumper)会透传给 antd Pagination。
pageSizeOptions默认值随layout变化:default为[10, 20, 50, 100],card为[9, 18, 54, 99]。
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 | | --------------- | -------- | ---- | ------------------------------------------------ | --------------------------------------------------------------------- | | pageSizeOptions | Array | 否 | [10, 20, 50, 100](card 布局为 [9, 18, 54, 99]) | 可选 pageSize 数组 | | isAllSelect | boolean | 否 | false | 是否使用全部(会在 pageSizeOptions 末尾追加「全部」选项) | | isAllSelectKey | string | 否 | "isAllSelect" | 选中全部时告知后端的字段名称,实际值为 true(同时 pageSize 不再发送) |
getFieldListOpt
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
| ----------- | ----------- | ---- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| boxList | Array/false | 否 | [] | 表格列解析时追加到内置容器白名单 ["FormGrid", "FormGrid.GridColumn"],如 "Card";传 false 关闭递归(FormGrid 内字段会被当成普通列) |
| schemaScope | Object | 否 | - | 由组件内部注入(无需手传),用于解析列 title 中的 {{ }} 表达式 |
Table ref Methods
- 可使用 ref 获取并触发执行;
onSearch/getList/onEdit均返回 Promise。
| 函数名 | 参数 | 说明 |
| ----------------- | ---------------- | ----------------------------------------------------------------------------------------- |
| onSearch | (query, opt) | 重置页码至 1,并刷新列表 |
| getList | query | 获取当前页列表数据(query 会与查询表单缓存、分页参数合并) |
| onQueryFormSubmit | (query, isReset) | 查询表单提交回调;isReset 为 true 时清空 url query 中的查询参数 |
| forceUpdate | - | 强制重渲染列表,解决枚举数据渲染不正常的问题 |
| formModalRef | - | 新增、编辑 弹窗 form-modal 的 ref(含 show / close / cancel / onOk / formRef / validate) |
| formDialogRef | - | formModalRef 的别名 |
| queryRef | - | 筛选条件 query-render 的 ref(queryRef.current.formRef.current.formRender 为查询表单) |
| tableRef | - | 表格渲染实例,含 onEditByTable、cellEditTableRef、columns |
| onCreate | - | 手动触发新增按钮相关操作 |
| onEdit | row | 手动触发编辑按钮相关操作(fetchOnEdit 为 true 时先请求详情再回填/进入编辑态) |
| onDel | row | 手动触发删除按钮相关操作 |
- onSearch opt
- isSaveQuery 是否保存传入的 query 值(默认 true)
- isMergeQuery 是否合并上一次保存的 query 值(默认 true)
编辑模式 editMode
- 由
editMode控制,取值与行为如下(默认modal):
| 取值 | 编辑入口 | 保存操作 | 说明 |
| --------- | ---------------------------------- | ------------------------- | --------------------------------------------------------- |
| modal | 操作列「编辑」按钮 | 弹窗底部确定按钮 | 默认;弹窗/抽屉内编辑,fetchOnEdit 决定是否先拉详情回填 |
| line | 操作列「编辑」按钮 | 操作列变为「保存 / 取消」 | 整行进入编辑态,单元格内不显示确认图标 |
| line-cell | 单元格内的编辑图标(或双击单元格) | 单元格内「✓ / ✕」图标 | 单元格级编辑,操作列不再显示「编辑」按钮 |
| cell | 单元格内的编辑图标(或双击单元格) | 单元格内「✓ / ✕」图标 | 同一行可只编辑单个单元格(editing 精确到 dataIndex) |
- 行内编辑模式下(line / line-cell / cell)还可通过以下方式控制可编辑性:
tableConf.hasEdit:整表编辑权限(Boolean 或(record, index) => boolean)canEditCallback:单元格级判定(record, field, dataIndex) => boolean- schema 字段的
x-pattern: disabled / readOnly、x-display: none:该字段不可编辑
- 行内保存会走
onEditSubmit:isPatchUpdate决定调用model.patch还是model.update, 并先经过model.patchMap/model.updateMap、onEditReqVerify(返回 reject 即中止)与useFormData处理。
Schema
- 字段文档:https://react.formilyjs.org/api/shared/schema#%E5%86%85%E7%BD%AE%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%BD%9C%E7%94%A8%E5%9F%9F
Schema Scope
- 用于传入参数给到响应器使用
常用示例
字段显隐 x-display
- visible: 显示(默认状态)
- hidden: 半隐藏。字段可赋值,可监听,但表单项隐藏
- none: 全隐藏。字段完全不可用。
{
"form": {
"labelCol": 6,
"wrapperCol": 12
},
"schema": {
"type": "object",
"properties": {
"test": {
"type": "string",
"title": "Input",
"x-decorator": "FormItem",
"x-component": "Input",
"x-validator": [],
"x-component-props": {},
"x-decorator-props": {},
"x-reactions": {},
"x-designable-id": "1zlm9bu3fpg",
"x-index": 0,
"name": "test",
"x-display": "none"
}
},
"x-designable-id": "ldzb3lu81dx"
}
}字段在表格中隐藏 inTable
- true: 在表格中展示(默认)
- false: 在表格中隐藏(卡片布局同样生效)
{
"form": {},
"schema": {
"type": "object",
"properties": {
"test": {
"type": "string",
"title": "Input",
"x-decorator": "FormItem",
"x-component": "Input",
"x-validator": [],
"x-component-props": {},
"x-decorator-props": {},
"x-reactions": {},
"x-designable-id": "1zlm9bu3fpg",
"x-index": 0,
"name": "test",
"inTable": false
}
},
"x-designable-id": "ldzb3lu81dx"
}
}字段动态显隐——响应器
编辑表单中才显示
- 通过 scenario 获取当前表单环境变量
- 属性响应中,显示/隐藏配置:scenario === 'edit'
{
"form": {},
"schema": {
"type": "object",
"properties": {
"test": {
"type": "string",
"title": "Input",
"x-decorator": "FormItem",
"x-component": "Input",
"x-validator": [],
"x-component-props": {},
"x-decorator-props": {},
"x-reactions": {
"dependencies": [
{
"property": "value",
"type": "any"
}
],
"fulfill": {
"state": {
//当涉及三层及以上的时,请使用 display,3依赖于2,2依赖于1时,编辑设置值时,3依赖于2的赋值,不会捕捉到
// 例:"display": "{{$deps.hasECert === 1 ? \"visible\" : \"hidden\"}}"
"visible": "{{scenario === 'edit'}}"
}
}
},
"x-designable-id": "1zlm9bu3fpg",
"x-index": 0,
"name": "test"
}
},
"x-designable-id": "ldzb3lu81dx"
}
}响应器中可用的参数
- 完整配置流程与场景示例见 docs/effect.md;响应器写法本身参考 formily Schema 内表达式作用域。
| 参数名 | 说明 | | ----------- | ------------------------------------------------------------------------------------------------------------------------- | | scenario | 环境参数,当前环境:create(新增表单)、edit(编辑表单)、detail(详情)、query(查询表单)、table-render(表格列与卡片) | | $self | 代表当前字段实例,可以在普通属性表达式中使用,也能在 x-reactions 中使用 | | $form | 代表当前 Form 实例,可以在普通属性表达式中使用,也能在 x-reactions 中使用 | | $deps | 只能在 x-reactions 中的表达式消费,与 x-reactions 定义的 dependencies 对应,数组顺序一致 | | $values | 代表顶层表单数据,可以在普通属性表达式中使用,也能在 x-reactions 中使用 | | $observable | 用于创建响应式对象,使用方式与 observable 一致 | | $memo | 用于创建持久引用数据,使用方式与 autorun.memo 一致 | | $effect | 用于响应 autorun 第一次执行的下一个微任务时机与响应 autorun 的 dispose,使用方式与 autorun.effect 一致 | | $props | 用于对当前字段实例设置组件 props |
DataModel
Tips
- 若存在 axios 相关配置失效的问题,请选择以下任意一种方式解决;
- 在入口文件设置 DataModel 默认的 axios 为已配置好的 axios;
- 在入口文件对 DataModel 的 axios 进行配置;
// 设置 DataModel 默认的 axios 为已配置好的 axios;
import axios from "axios";
import { setDefaultAxios } from "@hzab/list-render";
setDefaultAxios(axios);// 配置 DataModel 的 axios;
import axios from "axios";
import { axios as ax } from "@hzab/list-render";
setAxRequest(axios);
setAxRequest(ax);
setAxResponse(axios);
setAxResponse(ax);
// axios 守卫
export function setAxRequest(_ax) {
_ax.interceptors.request.use((config) => {
const { url = "" } = config;
if (/^\/api\/v\d+\/user\//.test(url)) {
} else if (url.startsWith("/api")) {
config.baseURL = cfg.businessApi;
}
return config;
});
}
// 请求到结果的拦截处理;
export function setAxResponse(_ax) {
_ax.interceptors.response.use(
(res) => {
// const navigateApi = useNavigate()
// const locationApi = useLocation();
if (res.data.code == 401) {
message.error(res._message || "验证信息失效,请重新登录");
// TODO: 页面跳转
return res;
}
return res;
},
(error) => {
console.error("Error axios response: ", error);
message.error(error._message || "网络异常,请稍后再试");
},
);
}
export function setAxToken(_ax, token) {
_ax.defaults.headers.Authorization = token;
}
export function setAxiosToken(token) {
setAxToken(ax, token);
setAxToken(axios, token);
}
export default axios;使用
import { DataModel } from "@hzab/list-render";
// 生成实例
const dataModel = new DataModel({
createApi: "api",
createMap(data) {
return data;
},
getApi: "api",
getMap(res) {
return res;
},
getListApi: "getListApi",
getListMap(item) {
return item;
},
updateApi: "updateApi",
updateMap(data) {
return data;
},
deleteApi: "deleteApi",
multipleDeleteApi: "multipleDeleteApi",
query: { pageNumber: 1, pageSize: 10 },
axiosConf: {
timeout: 10000,
},
});
// 调用方式(方法名与 DataModel 一致)
async function test() {
const createRes = await dataModel.create();
const getRes = await dataModel.get();
const getListRes = await dataModel.getList();
const updateRes = await dataModel.update();
const deleteRes = await dataModel.delete();
const multipleDeleteRes = await dataModel.multipleDelete();
}属性 Props
- 下表为
list-render用到的常用参数速查;完整参数表(各接口独立的 axiosConf、ReqMap/ResMap、 handleResponse、isResponse、isResponseData、useDataModel 等)见@hzab/data-model的 README。
| 属性名称 | 属性类型 | 必须 | 默认值 | 描述 |
| ----------------- | -------- | ---- | ------ | ----------------------------------------------------------------------- |
| createApi | String | | - | 新增 post 请求的 api |
| createMap | Function | | - | post 请求提交前的处理函数 |
| getApi | String | | - | get 请求的 api |
| getMap | Function | | - | 处理 get 返回结果,处理完需要把结果返回 |
| getListApi | String | | - | getList 获取列表的 api,返回列表数据和 pagination 数据 |
| getListMap | Function | | - | getList 结果 map 的回调函数,参数为结果每一项数据,处理完需要把结果返回 |
| getListFunc | Function | | - | 可用于替代 getList 的函数,处理自定义数据,参数为 query |
| updateApi | String | | - | put 请求的 api |
| updateMap | Function | | - | put 请求提交前的处理函数 |
| patchApi | String | | - | patch 请求的 api(isPatchUpdate 为 true 时使用) |
| patchMap | Function | | - | patch 请求提交前的处理函数 |
| deleteApi | String | | - | delete 请求的 api |
| multipleDeleteApi | String | | - | 批量删除请求的 api,使用的 axios({ method: 'DELETE' }) 发请求 |
| query | Object | | - | get 请求的参数 |
| axiosConf | Object | | - | axios 的配置项 |
常见问题 FAQ
1. 为什么 model 必须定义在组件内部?
- 若把
model定义在页面文件最外层(组件函数外部),设置搜索条件后切换到其他页面再切回来, 上次的搜索条件(model.query)仍然存在,列表会带着旧条件发起请求。 - 请在组件内用
useMemo创建,或直接使用@hzab/data-model的useDataModel:
// ✅ 推荐:组件内创建
function Page() {
const listDM = useMemo(() => new DataModel({ getListApi: "/api/v1/userinfo" }), []);
return <ListRender schema={schema} model={listDM} />;
}
// ❌ 不推荐:定义在组件外部,切换页面后 query 残留
const listDM = new DataModel({ getListApi: "/api/v1/userinfo" });2. 列表请求参数是怎么拼出来的?
- 合并顺序为
{ ...查询表单缓存, ...传入的 query, ...分页参数 },后者覆盖前者; 即同名的分页键(pageNum / pageSize)始终以组件内部状态为准。 $timerange仅用于查询表单,提交前会被删除,并拆成beginTime/endTime两个字段。
3. 接口报错没有提示,或想改提示样式?
- 列表、详情、新增、编辑、删除的失败都会走 antd
message.error,可用msgConf传 message 配置 (内部默认附加className: "list-render-err-message",可被msgConf.className覆盖):
<ListRender schema={schema} model={listDM} msgConf={{ duration: 5 }} />4. 编辑弹窗里显示的是列表行的旧数据?
- 默认
fetchOnEdit为 true:打开编辑弹窗会先请求详情接口回填;若列表接口已返回完整字段, 可传fetchOnEdit={false}直接用行数据回填。 - 详情请求的入参 key 默认为
id;后端要求用其他字段名时传fetchById={false}, 此时改用idKey对应的值作为 key。
5. 刷新列表有哪些方式?
ref.current.onSearch(query):重置页码到 1 后请求(查询表单提交走的就是它)ref.current.getList():按当前查询条件与页码请求ref.current.forceUpdate():只重渲染已有数据,适合枚举/字典数据更新后刷新单元格展示
6. hasEdit / hasDel / hasDetail 传了没生效?
- 这四个开关由
tableConf(表格布局)或cardConf(卡片布局)读取,顶层传入不会生效; 其中hasDetail默认不显示,需要显式开启:
<ListRender
schema={schema}
model={listDM}
tableConf={{ hasDetail: true, hasEdit: (record) => record.status === 1 }}
/>- 另外
hasAction={false}会让整个操作列不渲染,此时上述开关都无意义。
7. appendUrlQuery 没有写入地址栏?
- 该能力基于
window.location.hash实现(写入#/path?defaultSearchParams=<encodeURIComponent(JSON)>), 只在 hash 路由下生效;history 路由不会写入。参数 key 可用appendUrlQueryKey自定义。 - 空值(空字符串 / 空数组 / null)不会写入;清空 Input、Select、DatePicker、DatePicker.RangePicker 时会从 url 中移除对应字段。
8. 卡片布局的分页选项为什么和其他布局不一样?
pageSizeOptions默认值随layout变化:default为[10, 20, 50, 100],card为[9, 18, 54, 99]; 显式传paginationConf.pageSizeOptions可覆盖。
相关文档
| 文档 | 内容 |
| -------------------------------------------------- | ------------------------------------------------------------- |
| docs/README.md | 本包文档索引 |
| docs/table.md | 表格相关:筛选、顶部操作栏、手动请求、编辑模式、新增/编辑表单 |
| docs/form-linkage.md | 表单联动:表单项显隐、按其他字段改变数值与选项 |
| docs/remote-data.md | 远程数据源:Select / TreeSelect 动态取数 |
| docs/effect.md | 配置响应器:可用参数、属性响应与 $effect 场景 |
| CHANGELOG.md | 版本变更记录 |
| 消费方接入指南 | 安装源、src 直出包的编译责任、peerDependencies |
| 源仓同步规则 | 本包与源仓 list-render-pc 的同步规则 |
