写点什么

低码平台标准列表页落地实践,同事直呼好活

  • 2022-11-08
    湖南
  • 本文字数:4229 字

    阅读完需:约 14 分钟

低码平台标准列表页落地实践,同事直呼好活

最近在研究 B 端产品在低码平台上的落地实践,打算先从列表页入手。因为绝大多数 B 端产品都会有一个列表页作为操作动线的起点,它们具有非常大的共性,比较适合低码搭建。本文试图总结绝大多数列表页产品的共性,用于搭建一个比较通用的列表页低码模板。

列表页的产品功能

筛选与搜索

用户只关心自己想关心的数据,过滤掉自己不关心的数据。为了满足这个实际的用户需求,列表页通常会有筛选和搜索的功能。

筛选

筛选指的是通过一系列的筛选条件组合,最终形成一个多维度的筛选条件。

筛选有多种产品形态。最常见的就是「多个输入框、下拉菜单、时间选择器的组合」。还有一种是「使用 Tab 来控制显示不同的筛选条件」

最后一种是“标签”的形式,比如“最近 3 个月创建”,“审批中”等等,做得高级一点的产品,用户可以根据所有的筛选条件,自己创建属于自己的常用标签。标签其实是快捷操作的概念,可能不止是筛选的组合,还有可能加上排序的能力。

搜索

而搜索分为两类,一类是简单搜索,适用于绝大多数场景。它的产品形态就是一个简单的输入框,用户可以输入关键字,没有任何反馈,和筛选项一起,组成数据过滤的最终条件。简单搜索有可能会分字段搜索,比如按名称搜索、按 code 搜索等。


另一类是复杂搜索,它有实时反馈,会根据关键字返回数据的列表和个性化预览,甚至是智能推荐,复杂搜索通常底层是搜索引擎实现。

分页和排序

列表页一定是要支持分页的。分页有几个核心的参数:每页的数量,当前页码,总页码(或总数)。其中,每页的数量和当前页码是用户选择的,而总页码是后端返回的。

分页和排序一般是在一起的。就算没有排序条件,那一定会有一个默认的排序方式(id、创建时间等),这样底层才能实现分页。

分页会有「页码过大导致性能低下」的问题。普遍的有两种解决方式:

  • 用户不能直接选比较大的页码,只能小幅度往后挪,具体可以参考谷歌搜索的实现

  • 前端传入后端一个 lastId,代表上一页的最后 id,初始值为 0,用这个 id 去作为一种过滤条件

如果是后端关系型数据库,数据量比较大,后端想要性能好,一般会给能排序的字段建立索引。但如果是在分库分表的设计下,更适合把数据同步到搜索引擎,走搜索引擎。

批量操作

表格是数据的聚合。批量操作可以提升用户的使用效率。比如:批量修改状态、批量删除、批量导出等。批量操作一般是表格每行左边有一个多选框,让用户可以勾选多条数据,然后做某个操作。比较通用的操作是删除和导出。但也有很多特定的业务操作,通常是用表格上方的按钮来触发。

导出

导出一般指的是把数据导出到一个 excel 表格中。导出一般有多种范围:

  • 导出库内所有数据

  • 导出当前搜索条件的所有数据

  • 导出自己勾选的数据

导出一般比较耗时,所以异步设计得比较多。比如发送导出的文件链接到聊天框,或者去一个导出任务中心查看导出进度和下载。

数据权限体系

一个复杂的系统往往会有多人的数据。其中就涉及到数据权限体系了。数据权限体系可能是复杂的,可能与角色、数据维度或状态等有关。数据权限影响数据的展示和数据的操作按钮。

数据权限体系有两种设计。一种是“所见即所得”,用户看见的数据一定是他有权限的,能看到的操作按钮一定是他有权限操作的。这种用户体验好,但后端实现会比较复杂,需要后端过滤数据、组装操作按钮的显隐规则,权限复杂一点的甚至有可能对性能有影响。

另一种是数据和操作按钮的显示与特定的用户无关,但在列表页不显示重要的数据或脱敏展示,在实际操作的时候再校验权限,无权限的话,再提醒用户。这种设计后端实现简单,在查询的时候不需要考虑用户的权限,操作的权限校验也只收敛到写接口,但用户体验会差一点。

我自己之前做的一个项目管理系统,就是用的第一种方式,用户看到的数据是自己作为创建人或协作人的数据,且有父子项目的权限联动,还有管理员角色的考虑,实现起来有点复杂,逻辑维护成本都比较大。如果条件允许的话,希望产品同学还是可以多考虑第二种方式~

通用的写操作:增删改

列表页一定会有很多按钮。其中创建按钮应该是在表格上方的,而编辑按钮和删除按钮是在表格行中的操作区。

增删改查是基本每个业务都会遇到的通用接口。其中添加和编辑应该是几乎一模一样的表单和字段,只是编辑有唯一主键,而添加没有。

在添加和编辑的表单中,可能也会有一些枚举选项,或者搜索别的领域的数据出来选择,作为一个字段关联到自己要创建的对象中去。

如果表单的字段过多,可以添加分组进行引导,比如分步骤填写,横向的或者纵向的多步骤填写表单都有,具体看团队的设计规范。表单的字段之间也可能有交互的联动逻辑,可能前面填写的东西,会影响后面的表单内容渲染。

删除一般要支持批量删除,且删除后不可从产品正常的操作中恢复。如果要恢复,那就不要叫删除了,改为失效等状态更合适。

列表页的标准接口定义

通过定义一系列列表页的标准接口。具体的业务来实现这个标准接口。这样在根据模板创建具体的列表页实例时,选择一套实现接口,就可以快速关联和生成具体的列表页。

枚举接口

列表页会有一些筛选项是枚举的形式。在传统的低码平台,这些枚举可以用拖拉拽的可视化方式搭建。但如果想要更自动化一些,可以定义一个获取枚举列表的标准接口,用于自动渲染筛选项,也可以用于创建表单。


struct GenerateRequest { 1: string tenant // 租户 2: string groupCode // 套件code } struct EnumFieldWithChildren { 1: string key // 唯一键 2: string label // 展示标签 3: string remark // 注释 4: list<EnumFieldWithChildren> children // 子枚举 } struct QueryEnumResponse { 1: string key // 枚举的key 2: string label // 枚举的展示标签 3: bool filter // 是否是筛选项 4: bool tab // 是否是tab标签 5: string filter_key // 筛选传给后端的key 6: bool multi_select // 是否可以多选 7: list<EnumFieldWithChildren> items // 枚举值列表 }
list<QueryEnumResponse> QueryEnum(1: GenerateRequest req)(api.post="/standard/query_enum")


复制代码

查询与排序接口


struct QueryListRequest { 1: list<QueryListParam> params // 过滤条件 2: string order // 排序 3: i32 page_size // 每页大小 4: i32 page // 当前页码 5: i64 last_id // 上页最大id 100: BaseReuest base } struct QueryListParam { 1: string key // 筛选key 2: string value // 筛选值 3: QueryParamType type // 筛选类型 } enum QueryParamType { EQ // 相等 IN // 符合条件中的一个 GT // 大于 LT // 小于 SEARCH // 搜索 } struct QueryListResponse { 1: i32 code 2: string msg 3: QueryListRes data } struct QueryListRes { 1: i64 total // 总数 2: list<Object> items // 数据,json格式 }

QueryListResponse QueryList(1: QueryListRequest req)(api.post="/standard/query_list")

复制代码

->

注:这里查询结果用的是 Object 格式,代表它应该是一个通用的抽象模型描述。在标准接口的实现中,它应该被替换成对应的实现的结构体。

<-

增删改接口

创建和编辑都是传入一个模型对象。而删除只需要传入唯一键就可以了。创建可以返回唯一键,用于跳转到详情页等场景。

struct CreateDataRequest {    1: Object data // 数据,无数据唯一键    100: BaseReuest base}
struct CreateDataResponse { 1: string data // 唯一键 99: string code // 错误码 100: string msg // 错误信息}

struct EditDataRequest { 1: Object data // 数据,有数据唯一键 100: BaseReuest base}
struct DeleteDataRequest { 1: string code // 数据唯一键,可以是id,也可以是业务code,根据模型的定义来 100: BaseReuest base}
CreateDataResponse CreateData(1: CreateDataRequest req)(api.post="/standard/create_data") BaseResponse EditData(1: EditDataRequest req)(api.post="/standard/edit_data") BaseResponse DeleteData(1: DeleteDataRequest req)(api.post="/standard/delete_data")

复制代码

批量操作接口


struct BatchOperationRequest { 1: list<string> codes // 批量操作的唯一键 2: string operation // 具体的操作指令 3: string params // 操作参数,如:批量修改数据到具体的某个状态 }
BaseResponse BatchOperation(1: BatchOperationRequest req)(api.post="/standard/batch_operation")
复制代码

批量操作接口可用于批量删除、批量改状态的业务操作。也可以用于批量导出,但如果导出需要按照当前的搜索条件来的话,可能使用查询列表那种参数格式会跟好一点,这里不赘述。

一些问题的补充思考 &讨论

数据权限如何做更好?

前面讨论了数据权限体系。具体如何实现「取决于后端的接口实现」,对于接口定义来说是没有区别的。脱敏展示也是后端脱敏后返回比较安全。

搜索要分维度吗?

有时候搜索可能不止一个维度,筛选区可能会有多个搜索框。比如:按订单名称搜索,按商家名称搜索,按达人名称搜索等,返回同时满足多个维度的搜索条件的数据。

所以如果考虑通用的话,标准接口的定义需要支持多维度搜索,本文中的接口定义也是这么做的。

标签筛选如何实现?

标签筛选可以前端拖拽配置,也可以后端通过接口返回。通过接口返回可能是搭建更高效的方式,具体的实现思路是,新开一个筛选项配置的接口,返回的标签的 tag 和对应的 filter params,查询列表的时候传入就可以了,这里不做单独定义。

除了接口定义,还需要模型定义吗

列表页的字段类型、label,创建和编辑表单的字段类型、label 都需要能够从一个地方获取到这些元信息。如果只有接口定义,可能需要解析接口的字段类型、字段名、字段注释等信息,可能需要自己写或者复用一套接口解析引擎。

如果使用单独的模型定义,实现成本会更低,但维护成本会变大,尤其是列表页模型、创建和编辑模型不完全一样的时候,可能需要维护多套模型的元数据,增加维护成本。

原文:https://mp.weixin.qq.com/s/BN1yfKA4xwwsl62e6Q8Uow

如果感觉本文对你有帮助,点赞关注支持一下,想要了解更多 Java 后端,大数据,算法领域最新资讯可以关注我公众号【架构师老毕】私信 666 还可获取更多 Java 后端,大数据,算法 PDF+大厂最新面试题整理+视频精讲

用户头像

需要资料添加小助理vx:bjmsb1226 2021-10-15 加入

爱生活爱编程

评论

发布
暂无评论
低码平台标准列表页落地实践,同事直呼好活_Java_Java全栈架构师_InfoQ写作社区