关于 make-app-filter
面向 Make App 列表筛选功能集成的技能,涵盖搜索编译、高级筛选、Preset 持久化及 Service 筛选载荷。它按搜索模式区分实现要求,并规定桌面、平板与手机界面的不同联动方式。
主要功能
- 01区分仅搜索与高级筛选模式
- 02集成筛选编译器、控制器和面板
- 03保存、加载及清除 Entity Preset 筛选
- 04连接桌面表头筛选与工具栏面板
- 05按设备形态规定筛选入口和布局
- 06发送未经改写的 Service 筛选表达式
适用场景
- 01为 Make 记录列表添加关键词搜索
- 02实现高级条件筛选及 Preset 恢复
- 03将 CanvasTable 表头筛选接入统一状态
- 04适配手机筛选面板与筛选载荷
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ qfeius/ make-platform-skills --skill make-app-filter安装后在 Claude Code 中输入/make-app-filter确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlreferences/filter-model.mdheader-table-linkage.mdoperator-matrix.mdpackage-integration.mdpreset-integration.mdservice-translation.mdtesting-and-pitfalls.mdui-style.md详细介绍
make-app-filter
用于 Make App 筛选。仅进行关键词搜索、发送 filter.expression 的列表会使用包编译器,但不会启用高级筛选。使用高级筛选、条件构建器、表格筛选或 CanvasTable 表头“按该字段筛选”的桌面/平板列表,构成一项集成式功能:
- 基于
@qfei-design/make-app-filter的工具栏高级筛选 - 由宿主负责的 CanvasTable 表头筛选 UI/菜单
- 将表头“按该字段筛选”连接到同一个包控制器和工具栏面板
- Entity Preset 高级筛选的保存、加载、水合和清除行为
- Service
filter.expression载荷集成
启用高级筛选时,手机端使用相同的包控制器、Preset 和 Service filter.expression,但在紧凑型手机工具栏中只显示中等尺寸的筛选触发器,并在 @qfei-design/make-app-mobile/primitives 的 MobileFilterSheet 中使用 AdvancedFilterPanel layout="mobile"。手机端 Select 控件使用其 /pickers 入口中的 MobileFilterSelect;桌面/平板端控件继续使用现有 UI 库。手机顶部筛选不需要 CanvasTable 表头联动,也不得挂载隐藏 CanvasTable 来满足桌面合同。
在桌面/平板端,不要只在 Make 记录列表页中实现高级筛选或表头筛选。两者必须同时实现,或者都不实现。
此技能负责消费端的包集成约定、高级筛选行为、字段支持、Entity Preset 筛选持久化、Service 筛选载荷形状、宿主负责的表头联动语义、URL/深层链接筛选回显以及筛选专项测试。它使用 make-app-permission 提供的列表访问状态;不定义权限策略。它不负责排序(make-app-sort)、分组(make-app-group)、页面外壳/布局(makeui)、CanvasTable 渲染内部实现或表头菜单 API 细节(canvas-table-integration)、Service 路由实现(make-app-service)、身份验证(make-app-auth)、运行时打包(make-app-runtime)、DSL 建模(makedsl)或 Make CLI 执行(makecli)。
能力模式
按照工作流程操作前,先选择模式。以下面板、控制器、筛选 Preset 和移动端布局要求仅适用于 advanced-filter,除非另有明确说明。
| 模式 | 查询 | 筛选 Preset | UI 和包门槛 |
|---|---|---|---|
search-only | compileListFilter({ fields, searchText }) | 不执行筛选 Preset GET/PATCH 或水合 | 无控制器、面板或移动端布局门槛;使用包核心编译器 |
advanced-filter | compileListFilter({ fields, searchText, advancedFilter }) | 首次查询记录前先 GET/水合;仅在确认后 PATCH 筛选维度 | 使用包控制器和面板;手机端必须使用公开的 layout="mobile" |
search-only 不会在没有筛选 UI 的情况下加载或应用已保存的高级筛选表达式。如果排序或分组独立需要共享 Entity Preset,其自身协调器仍可加载该 Preset;启用高级筛选前,本技能不会使用其 filter 维度。两种模式仍须遵守列表访问门槛,并将包编译器的结果原样发送给 Service。
快速开始
- 将任何包含“筛选”“高级筛选”“条件筛选”“表格筛选”“表头筛选”“列头筛选”或“按字段筛选”的 Make 记录列表请求视为同一项筛选需求。桌面端/平板端需同时实现由软件包支持的工具栏高级筛选和 CanvasTable 表头联动。手机端使用由软件包支持的顶部筛选入口,不与 CanvasTable/表头联动。
- 定位宿主 UI 软件包,通常为
apps/ui/package.json。如果不存在 UI 软件包,请停止并报告缺少宿主软件包。 - 对于仅使用编译器或桌面端/平板端的场景,确保已安装
@qfei-design/make-app-filter@^1.0.0。手机端高级筛选需在通过宿主兼容性检查后,同时使用@qfei-design/make-app-filter@^1.1.0和@qfei-design/make-app-mobile@^0.1.11。前者提供 32px 的middle控件和作用域限定于移动端的控件类;后者提供MobileFilterSheet、MobileFilterSelect和日期触发器className。检查已解析的筛选软件包公开的 React 声明中是否包含"mobile"布局;较早的筛选软件包版本 1.0.0–1.0.3 不包含该布局。仅使用搜索的手机端列表只需公开的核心编译器,无需通过任一移动面板门槛。不要改用默认/堆叠布局,也不要手写软件包内部实现。 - 编写代码前先阅读软件包文档。优先阅读已安装软件包的文档;如果宿主正在软件包仓库中开发,则阅读源代码文档。
- 在高级筛选模式下,在宿主 UI 入口中仅导入一次
@qfei-design/make-app-filter/styles.css;仅使用搜索编译器时无需面板样式。 - 两种模式都使用软件包核心编译器。高级筛选模式还会使用软件包的面板、控制器、适配器、校验和 CEL 解析 API。不要在宿主中复制或手写这些功能。
- 在高级筛选模式下,将特定于展示的工具栏触发器、桌面端 Popover 或手机端
MobileFilterSheet、已应用状态、候选项 API、Service 请求适配器,以及桌面端/平板端 CanvasTable 表头筛选 UI/菜单保留在宿主中。手机面板传入layout="mobile",并接收一个仅供移动端使用、采用MobileFilterSelect的组件适配器;面板高度和滚动边界由软件包的 Sheet 负责。仅搜索模式没有面板界面。在桌面端/平板端组件适配器中,只为实际的“选择字段”选项添加默认的 Make 字段类型图标;运算符、值和候选项选项保持不变。手机端字段选项保留纯文本。 - 在桌面端/平板端,将表头中的“按该字段筛选”连接到同一个软件包控制器/面板;不要创建独立的仅限表头的状态,也不要本地实现筛选。手机端没有表头入口。
- 遵循后端记录列表筛选契约:Service 发送
filter: { expression },空表达式表示无筛选,字段支持情况必须与运行时元数据和软件包公开 API 一致。原样提交compileListFilter的输出;绝不要在宿主中重写 CEL/DNF。 - 对于实体对象列表,使用
make-app-permission提供的列表访问权限门控。仅在启用高级筛选且允许列表访问时,才在首次记录查询前加载当前 Entity Preset,并使用软件包公开 API,在权限感知的{ enabled, entityKey, generation }上下文中还原已保存的筛选条件。仅搜索模式不加载或还原筛选 Preset,工具栏搜索仅在当前会话有效。 - 确认筛选时,仅 PATCH Preset 的
filter维度。成功后同步更新已应用状态;让记录查询响应已应用状态,而不要在持久化回调中重新加载。失败时保留原有已应用筛选和当前草稿。 - 如果可写列表使用
make-app-actions,则传递成功应用的筛选代次,使操作能够在新查询生效前清除选择,并使待处理的预检/提交操作失效。编辑草稿、取消以及保存/应用失败时,保留当前操作选择。 - 在高级筛选模式下,保留所需的固定三区域布局:顶部固定表头、可滚动的条件主体和底部固定页脚。条件行滚动时,表头/页脚控件必须保持可见。
- 完成前,验证软件包编译、空筛选省略、Service 载荷格式以及两种模式下的列表访问行为。对于仅搜索模式,验证不会 GET/PATCH 筛选 Preset、不会还原筛选条件、不会显示面板,也无需通过移动端布局门槛。对于高级筛选,还需验证固定面板布局、搜索合并、Preset 保存/加载/清除、草稿确认/放弃、候选项、桌面端/平板端表头联动、手机端不使用 CanvasTable、嵌套选择器层叠、32px 面板控件、远程搜索期间已选值的回显、软件包/后端字段支持差异,以及条件触发的操作选择失效处理。
Package 安装前检查
新建的 Make App 和正在进行明确运行时迁移的 App 使用 make-app-runtime 运行时契约:工作区根目录声明 "packageManager": "[email protected]" 和 "engines": { "node": "22.20.0", "pnpm": "10.20.0" },并通过 corepack pnpm 执行 package 操作。对于这些 App,应在实际 UI package 中安装依赖,例如在其目录中运行 corepack pnpm add @qfei-design/make-app-filter@^1.0.0;没有锁文件的新 App 必须先声明运行时并生成 pnpm 工作区。
现有 Make App 在筛选器相关工作期间保留其已声明的运行时。安装或升级之前,应找到 UI package 和工作区根目录,检查 packageManager、Node 引擎、React/React DOM 对等依赖、现有锁文件以及仓库既定的安装/CI 工作流。使用匹配的现有包管理器和工作区目标:
pnpm-lock.yaml搭配兼容的 pnpm 声明/工作流:通过 Corepack 使用该项目声明的 pnpm 版本,将@qfei-design/make-app-filter@^1.0.0添加到 UI package。package-lock.json搭配兼容的 npm 声明/工作流:使用现有的 npm 工作区安装命令指定 UI package;如果仓库不是工作区,则从该 package 目录安装。yarn.lock搭配兼容的 Yarn 声明/工作流:使用现有的 Yarn 工作区添加命令指定 UI package;如果仓库不是工作区,则从该 package 目录添加。保留项目的 Yarn 版本和配置。
不要仅仅为了添加筛选功能而改写现有 App 的 packageManager、Node 选择、工作区布局或锁文件类型。绝不要生成第二个锁文件。如果声明、锁文件、CI 工作流、Node/对等依赖约束或目标工作区之间存在冲突,或者现有 App 没有明确的安装工作流,请停止并向 make-app-runtime 报告兼容性阻碍;不要悄悄迁移,也不要将 corepack pnpm 强行用于 npm/Yarn 项目。手机筛选器 package 升级也遵循相同的检查要求。
对于手机高级筛选,使用相同的现有包管理器和目标 UI package,同时安装 @qfei-design/make-app-filter@^1.1.0 和 @qfei-design/make-app-mobile@^0.1.11。上述 ^1.0.0 示例仍是通用的编译器/桌面基线。检查锁文件实际解析出的版本;仅声明版本范围并不能证明已安装这两项手机功能。
将任何已弃用的 1.0 之前的 package 依赖迁移到
@qfei-design/make-app-filter@^1.0.0,并同时更新公开导入。如果已在使用无关的高级筛选 package,请停止并先征求意见。不要回退到 1.0 之前的版本。
已安装 1.0.0+ package 的必需读取流程:
node_modules/@qfei-design/make-app-filter/package.ai.json- 解析
package.ai.json.readOrder,并将每个条目解析为相对于node_modules/@qfei-design/make-app-filter的路径。 - 确认每个引用的文件都存在于已安装的 package 中,然后再依赖其中的内容。
- 按声明的顺序读取其余条目,跳过已读取的
package.ai.json条目。
package.ai.json.readOrder 是唯一可信来源。不要硬编码 docs/、examples/ 或其他 package 内部文档路径。直接在 package 仓库中操作时,应从仓库根目录解析相同的条目。如果已安装的 package 版本低于 1.0.0,请先升级,不要依赖旧版 package 文档或推断其内部结构。
主题参考索引
| 任务 / 主题 | 阅读 |
|---|---|
不使用高级筛选,通过 filter.expression 进行关键词搜索 | references/service-translation.md;使用 references/filter-model.md 中仅编译器的路径 |
| 软件包安装、导入、宿主 / 软件包边界 | references/package-integration.md |
| 筛选器 IR、控制器草稿 / 确认语义、搜索合并、URL 回显 | references/filter-model.md |
| 运行时字段能力、运算符 / 值编辑器 API 和候选值 | references/operator-matrix.md |
| 宿主 Popover / 容器、触发器、面板尺寸、验证视觉效果 | references/ui-style.md |
| 筛选面板中默认的桌面端 / 平板端字段选择图标 | makeui 字段类型图标规范 |
| CanvasTable 表头更多菜单和高级筛选关联 | references/header-table-linkage.md |
| 服务筛选规范和 CEL 表达式载荷 | references/service-translation.md |
| 高级筛选的 Entity Preset 加载、水合、保存屏障、清除、过期请求 | references/preset-integration.md |
| 测试、冒烟检查、常见回归问题 | references/testing-and-pitfalls.md |
| 后端 Record 筛选规范、CEL 子集、DateRange / File / Lookup / 系统变量 | 使用 makedsl;阅读其 EntityDataFilterUsage 参考文档 |
分组路径表达式组合和 record-groups groupFilter | 使用 make-app-group;复用此 Skill 的 DNF 表达式规则 |
| 工具栏位置和周围的页面布局 | 使用 makeui |
CanvasTable suffixRender 机制 | 使用 canvas-table-integration |
| 服务路由实现和适配器测试 | 使用 make-app-service |
| 可写列表选择操作和已应用查询失效处理 | 使用 make-app-actions |
硬性规则
- 不要在宿主应用中重新实现 Make 高级筛选。软件包已提供的功能,不要手写 Filter IR 辅助工具、运算符矩阵、校验器、CEL 编译器/解析器或高级筛选面板。
- 不要只部分交付高级筛选。两种模式都使用软件包编译器和 Service 表达式载荷;高级筛选模式还要使用软件包控制器。桌面/平板高级筛选需要实现 CanvasTable 表头 UI 和联动。手机高级筛选仅使用顶部工具栏的筛选入口和适配移动设备的面板;不需要也不应渲染 CanvasTable 表头联动。
- 手机高级筛选需要使用上文所列版本中的公开
"mobile"面板布局、MobileFilterSheet、MobileFilterSelect和AdvancedFilterPanel layout="mobile"。在窄视口中使用桌面 Popover、layout="default",或通过 CSS 缩窄条件行,都不算移动端适配。保留桌面/平板的 Popover 接线和布局规则,并在升级共享筛选软件包后检查其渲染控件。仅搜索模式不需要移动面板布局或软件包的移动端筛选组件。 - 新集成使用
@qfei-design/make-app-filter的核心 API;高级筛选集成还需使用@qfei-design/make-app-filter/react和可选的@qfei-design/make-app-filter/adapters/antd。 - 高级筛选集成只需导入一次
@qfei-design/make-app-filter/styles.css。仅使用搜索编译器时不需要面板样式。宿主 CSS 可以设置外层浮层/容器的样式,但除非要修复宿主特有的容器问题,否则不得分叉修改软件包内部实现。 - 新筛选输出使用
filter: { expression: string }。如果compileListFilter返回undefined,则省略filter。 compileListFilter是面向宿主的唯一搜索/高级筛选编译器。原样发送其结果;不要在宿主代码中解析、拆分或改写 CEL/DNF。- 后端 Record 列表处理程序只读取
Expression对象中的filter.expression,并将缺失、null或空白表达式视为无筛选条件。 - 不要发送
filter: []、filter: {}、{ expression: "" }、空白原始筛选字符串或旧版对象数组 DSL。 - 不要在本地筛选 Make 记录列表。列表筛选必须通过 Service/后端筛选 API 完成。
- 筛选字段来自规范化后的运行时对象/字段元数据。不要将
apps/dsl/**、复制的 YAML、行样本或硬编码演示数据用作运行时筛选元数据。 - 宿主字段类型注册表可以帮助规范化共享的运行时元数据,但不得据此决定筛选运算符或值编辑器。将字段传给软件包,并使用其能力 API 作为筛选的唯一事实来源。
- 筛选 Lookup 时,先从完整的运行时架构中解析
relationKey、对侧 Entity 和targetFieldKey,再将字段元数据传给软件包。在 Filter IR 和 CEL 表达式中保留源 Lookup 字段键;目标字段元数据仅用于控制运算符、值和校验。 - 用户和部门筛选值是身份标识,而非显示名称。候选项来源应遵循
makeui/make-app-service负责的宿主契约;不要在此 Skill 中定义传输路由。 - 不要从字段架构的
options、当前表格行、本地数组或显示标签中获取用户/部门选项。远程候选项加载期间,可以合并当前已应用的值以保持标签可见。 - 后端 Record 筛选支持 DateRange、File 和 Lookup 语义,但只有在
@qfei-design/make-app-filter公开 API 支持相应字段/运算符组合时,UI 才能显示该字段。如果后端文档与软件包能力不一致,应停止并升级/修复软件包,或报告不匹配;不要手写 CEL,也不要猜测软件包内部实现。 - 在高级筛选模式下,每次 Entity 或权限启用状态发生变化时,都要递增单调递增的请求代数,并重置宿主面板状态。仅在保存完成时比较
entityKey并不安全,因为旧的A -> B -> A结果,或权限撤销前产生的结果,看起来可能仍是当前结果。仅搜索模式仍需使过期的记录查询响应失效,但不应创建面板状态。 - 在高级筛选模式下,使用已提交上下文重置机制,例如带键包装器加布局副作用清理。不要在 React 渲染期间修改请求代数、保存状态或上下文引用。
- 在高级筛选模式下,如果当前软件包不支持已保存的 CEL,则在后端请求中继续使用其原始表达式,使触发器保持明显的激活状态,并显示兼容性警告,直到显式替换或清除操作成功保存。
- 在高级筛选模式下,不受支持的软件包字段必须从桌面/平板和手机的字段选择器,以及桌面/平板表头的“按该字段筛选”中隐藏;对于未知字段、无效字段键或软件包不支持的字段/运算符组合,不得调用
openWithField。 - 在桌面/平板上,表头菜单筛选属于宿主集成。它会通过软件包控制器追加草稿条件,并打开同一个工具栏筛选面板。它不得立即提交、重新加载记录或创建独立的表头状态;手机端没有表头菜单。
- 在桌面/平板上,表格滚动、对象切换、点击外部区域或卸载时,都必须关闭任何表头菜单,并将表头后缀图标恢复为仅悬停时显示的状态。
- 高级筛选面板必须采用固定的三分区基线布局:固定页眉、可滚动主体和固定页脚。若添加/确认/清除操作会随条件一起滚出视野,则属于就绪阻断项,不得报告为就绪、完成或已交付。
- 仅在启用高级筛选时,才将其表达式保存在当前用户的 Entity Preset 中,并在首次查询记录前加载和填充 Preset 筛选条件。仅搜索模式不得读取、填充或写入筛选 Preset。
- Preset 写入必须采用稀疏方式。保存筛选时只发送
{ filter },绝不发送可能已过期的sort或group。 - 先保存,再应用。Preset 保存失败时,保留之前已应用的筛选条件、已打开的面板和当前草稿;不得重新加载记录。
- 如果存在
make-app-actions,只有成功应用的筛选代数才能清除其选择并使待处理操作失效。草稿编辑、取消面板、校验失败、Preset 保存失败和列表查询失败,都不得清除或重新定义当前操作选择。 - 清除高级筛选时使用
filter: null。工具栏关键字搜索仅限会话内使用,不得持久化。 - 禁用列表访问时,阻止新的架构和记录请求,并使进行中的结果失效。在高级筛选模式下,还要阻止 Preset GET/PATCH、关闭筛选界面,并在
entityKey或权限启用状态发生变化后忽略过期的 Preset 加载/保存响应。仅搜索模式没有筛选 Preset 请求或需要关闭的筛选界面。
默认行为
- 高级筛选 UI 是所有展示模式下的可选产品功能。只有在用户请求或项目中已确立该功能时,才生成其触发器和面板;仅启用标准手机视图不会添加它们。对于发送
filter.expression的纯搜索列表,使用compileListFilter({ fields, searchText }),不添加筛选触发器、面板、筛选 Preset GET/PATCH 或数据回填;省略advancedFilter,而不是传入显式的 undefined 值。当高级筛选属于功能范围时,手机端也应适配该功能,不要留下无法正常使用的手机触发器。 - 高级筛选一旦纳入功能范围,就使用由 package 支持的控制器、
AdvancedFilterPanel、草稿生命周期、固定的页眉/主体/页脚、字段控件和 Servicefilter.expression。桌面端/平板端使用工具栏触发器、承载弹层的 Popover,以及 CanvasTable 表头的openWithField关联。手机端使用顶部工具栏的筛选入口,并在MobileFilterSheet中使用 package 的layout="mobile";它不需要 CanvasTable、表头或表头关联。 - 在桌面端/平板端,高级筛选面板必须明确保留三个区域:顶部固定的页眉,左侧为
筛选,右侧为清空所有;中间主体仅包含条件行/组,并且是唯一可垂直滚动的区域;底部固定的页脚,左侧为+ 添加条件和+ 添加条件组,右侧为确认。手机端保留固定的三个区域,但在MobileFilterSheet中使用 package 的layout="mobile"默认文案(设置筛选条件和完成);不要将桌面端标签或行内样式强加到该模式。 - 宿主将搜索文本与高级筛选状态分开保存。纯搜索模式使用
compileListFilter({ fields, searchText });高级筛选模式通过compileListFilter({ fields, searchText, advancedFilter })组合已应用的筛选条件和搜索文本。 - 关闭所属的桌面端/平板端 Popover 或手机端 Sheet 且未确认时,通过 package 控制器的重置流程丢弃未确认的草稿更改。
- 清除操作只更改草稿;只有在当前模式的确认操作(桌面端/平板端的
确认,手机端的完成)成功后,才会影响已应用的筛选条件。 - 对象/实体或权限启用状态发生变化时,清除临时搜索状态并使旧请求失效。在高级筛选模式下,还要清除筛选/面板状态,并且仅在已启用访问权限时重新加载 Entity Preset;表头状态也要清除,并在挂载时重置桌面端/平板端表格的对象级临时状态。手机端没有表头筛选 UI。纯搜索模式不会重新加载筛选 Preset。
协作规则
- 与
makeui协作:使用makeui实现桌面端/平板端工具栏、独立的手机顶部筛选入口、页面框架、外围布局和候选来源 UI 契约;本技能负责筛选行为和包集成。 - 与
canvas-table-integration协作:使用该技能实现 CanvasTable 的suffixRender和表头菜单机制;本技能负责主机端“按该字段筛选”操作与基于包的高级筛选控制器之间的交互。 - 与
make-app-service协作:本技能定义筛选查询和 Preset 筛选语义;服务路由验证、适配器日志记录和 Make 请求细节由服务负责。 - 与
make-app-sort协作:启用高级筛选时,筛选和排序共用一个由父级管理的 Entity Preset 协调器和加载生命周期,但分别更新各自维度。仅搜索不占用 Preset 筛选维度。本技能不定义排序 UI 或排序验证。 - 与
make-app-group协作:筛选和分组共用表达式语法;启用高级筛选时,两者共用 Preset 生命周期,但分别更新各自维度。本技能负责全局filter.expression;make-app-group负责临时路径groupFilter的组合和记录分组时机。 - 与
make-app-permission协作:在两种能力模式下都使用已解析的列表访问权限门控;高级筛选还会将其启用状态纳入 Preset 请求代次。本技能不定义权限策略或权限端点。 - 与
make-app-actions协作:仅适用于使用操作工作流的可写列表;在新查询可执行操作之前,传递已成功应用的筛选代次,以便操作清除所选项并使待处理工作失效。草稿和失败路径会保留所选项;本技能不会直接操作 CanvasTable 选择 API。 - 与
makedsl协作:阅读EntityDataFilterUsage.md,确认后端筛选语义,例如 DNF、系统变量、DateRange/File/Lookup、空筛选处理和错误情况。不要使用本技能生成 DSL。