关于 sap-fiori-add-visual-filter
sap-fiori-add-visual-filter 用于为 SAP Fiori OData V4 应用添加柱形图或折线图可视筛选器,指导 CAP 与 ABAP RAP 实现,包括注解、manifest 配置、激活和验证。
主要功能
- 01添加柱形图或折线图筛选器
- 02配置 CAP 聚合和注解
- 03设置 ABAP RAP 图表注解
- 04配置 manifest 控制设置
- 05验证激活状态和 OData 元数据
适用场景
- 01为 CAP Fiori 应用添加图表筛选器
- 02在 ABAP RAP 应用中实现可视筛选器
- 03排查筛选器注解缺失或不匹配
MCP 相关
该技能要求在 VS Code 中使用 Fiori MCP Server 修改 Fiori 应用。对于 ABAP RAP,还说明使用 ABAP ADT MCP 激活 ABAP 对象。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ sap/ open-ux-tools --skill sap-fiori-add-visual-filter安装后在 Claude Code 中输入/sap-fiori-add-visual-filter确认已加载。
详细介绍
SAP Fiori 可视化筛选器
用途
在筛选栏或值帮助对话框中添加基于图表的筛选器(柱状图/折线图)(OData V4)。
前提条件
CAP 项目:
- ✅ VS Code 或 SAP Business Application Studio (BAS) - 两种环境均受支持
- ✅ Fiori MCP Server - 修改 Fiori 应用所必需(仅限 VS Code)
ABAP RAP 项目:
- ✅ 仅限 VS Code - ABAP Development Tools 扩展仅适用于 VS Code
- ✅ Fiori MCP Server - 修改 Fiori 应用所必需
- ✅ ABAP Development Tools for VS Code 扩展 - 后端开发所必需(包含用于 RAP 操作的 ADT MCP 服务)
必须:首先收集所需输入
如果提示中缺少以下任何输入,请停止并向用户询问所有这些输入:
- 实体 - 要添加可视化筛选器的实体
- 维度字段 - 用于筛选的字段(例如 Category、Status、Destination)
- 度量字段 - 要聚合的数值字段(例如 Amount、TotalPrice、ReservationPrice)
- 聚合方法 - 聚合方式(请参阅下方的有效值)
- 图表类型 - 柱状图或折线图(默认推荐柱状图)
在确认所有输入之前,请勿继续实施。
⚠️ 折线图维度类型限制: ChartType: #Line 仅支持类型为 Edm.Date、Edm.TimeOfDay 或 Edm.DateTimeOffset 的维度。如果请求的维度是其他类型(例如 Status、Category 等字符串/关联代码),请改用 #Bar,或先向用户确认该维度字段属于日期/时间类型,再继续操作。
CAP 实现
启用聚合(必须)
@Aggregation.ApplySupported: {
Transformations: ['aggregate','groupby'],
AggregatableProperties: [{ Property: Amount }],
GroupableProperties: [Category]
}
聚合属性(度量)
Analytics.AggregatedProperty #Amount_sum : {
$Type: 'Analytics.AggregatedPropertyType',
Name: 'Amount_sum',
AggregatableProperty: Amount,
AggregationMethod: 'sum',
![@Common.Label]: 'Total Amount'
}
有效的 AggregationMethod 值(小写字符串):
sum- 非空值的总和min- 非空值中的最小值max- 非空值中的最大值average- 非空值的总和除以非空值的数量countdistinct- 非空值中不同值的数量
⚠️ 关键: 必须是小写字符串(例如 'sum'),不能是枚举(例如 #SUM)。使用枚举会导致 SQL 生成错误。
图表注解
UI.Chart #visualFilter : {
ChartType: #Bar,
Dimensions: [Category],
DynamicMeasures: ['@Analytics.AggregatedProperty#Amount_sum']
}
✅ 使用 DynamicMeasures
PresentationVariant
UI.PresentationVariant #visualFilter: {
Visualizations: ['@UI.Chart#visualFilter']
}
标量属性与受管关联维度
注解位置取决于维度在 CAP 模型中的声明方式:
- 直接标量属性可以内联添加注解。例如,
Category : String(80)是一个实际的实体元素,因此应在annotate ... with { ... }块中使用Category @Common.ValueList #visualFilter。 - 受管关联则有所不同。例如,
Category : Association to Categories会生成本地外键Category_code;Category_code并非源实体中已声明的元素,因此无法在该块中内联添加注解。
对于标量 Category 维度,以下写法有效:
annotate MyService.Entity with {
Category @Common.ValueList #visualFilter: {
$Type: 'Common.ValueListType',
CollectionPath: 'Entity',
PresentationVariantQualifier: 'visualFilter',
Parameters: [
{ $Type: 'Common.ValueListParameterInOut',
LocalDataProperty: Category, ValueListProperty: 'Category' }
]
};
};
如果可视化筛选器的维度是受管 Category 关联,请使用下文所述的单独关联键目标。不要在实体注解块中将目标替换为 Category_code。
⚠️ 维度是托管关联外键(例如 Category_code、Status_ID)
当维度字段是托管关联自动生成的外键列时(例如,来自 Category : Association to Categories 的 Category_code),不能在实体的 annotate ... with { ... } 块中内联添加注解——该处无法看到外键列。CDS 编译器会报错:
Element "Category_code" has not been found
✅ 正确: 使用单独的 annotate 语句,并以关联本身为目标——编译器会将其重写到外键列:
// Compiles to target Travels/Category_code in $metadata
annotate MyService.Entity:Category with @(
Common.ValueList #visualFilter: {
$Type : 'Common.ValueListType',
CollectionPath : 'Entity',
PresentationVariantQualifier: 'visualFilter',
Parameters : [
{ $Type: 'Common.ValueListParameterInOut',
LocalDataProperty: Category_code, ValueListProperty: 'Category_code' }
]
}
);
要点:
- 目标语法:
annotate <Service>.<Entity>:<assoc>——对于托管的一对一关联,编译器会将关联上的注解复制/重写到其生成的本地外键元素。这符合文档所述的 CAP 编译器行为(参见 CAP 文档中的“Managed Associations”)。如果其他注解(例如Common.Label、Common.Text)已在其他位置以同一关联为目标,它们会在$metadata中合并到单个Annotations Target="...Entity/<assoc>_code"块中。如有疑问,请使用cds compile --to edmx验证。 LocalDataProperty和ValueListProperty都使用外键列名称(例如Category_code),而不是关联名称。CollectionPath是包含图表数据的同一个实体集(自引用),而不是代码列表实体集。
❌ 错误: 在实体块中内联添加注解——无法编译:
annotate MyService.Entity with { ... } {
Category_code @Common.ValueList #visualFilter: { ... }; // ❌ Element not found
};
SelectionFields
UI.SelectionFields: [Category]
Manifest 配置(强制要求)
下方的共享 Manifest 配置部分适用于 CAP 和 RAP。
ABAP RAP 实现(4 个步骤)
关键:绝不编辑 metadata.xml——它是只读文件!
⚠️ 实施前检查清单——验证后再实施
以下任意一项缺失都会导致可视化筛选器失效:
- 在投影视图(ZC_*)上设置
@OData.applySupportedForAggregation: #FULL - 在度量字段上设置
@Aggregation.default: #SUM(或 #AVG、#MIN、#MAX) - 在元数据扩展中设置带正确限定符的
@UI.chart注解 - 在维度字段上设置
@UI.selectionField - 在 annotation.xml 中添加前端
Common.ValueList注解 - 在 Manifest 中设置带可视化筛选器设置的
controlConfiguration - 激活所有 CDS 对象
1. 后端投影视图(强制要求)——启用聚合支持
⚠️ 关键:必须设置 @OData.applySupportedForAggregation 注解
未设置此注解时:
- OData 服务将不支持聚合
- 可视化筛选器将无法加载
- 图表注解将被忽略
设置位置:
- ✅ 必须设置在投影视图(ZC_* 或 ZZZC_*)上,并使用
TRANSACTIONAL_QUERY契约 - ❌ 不得设置在接口视图(ZR_* 或 ZZZR_*)上
正确示例:
// MANDATORY! Must be present!
@OData.applySupportedForAggregation: #FULL
define root view entity ZC_ENTITY
provider contract TRANSACTIONAL_QUERY
as projection on ZR_ENTITY
{
@Aggregation.default: #SUM // Specify aggregation method for measure
Amount;
Category; // Dimension field (no aggregation annotation needed)
}
错误示例:
// ❌ WRONG - Don't put on interface view
// WRONG PLACE!
@OData.applySupportedForAggregation: #FULL
define root view entity ZR_ENTITY
as select from TABLE
2. 后端元数据扩展(强制要求)——添加 Chart、PresentationVariant 和 SelectionField 注解
⚠️ 关键:@UI.chart 和 @UI.presentationVariant 是实体级(标头)注解。
将它们放在标头块中——位于 annotate view ZC_ENTITY with 之前(与 @UI.headerInfo.* 并列),不要放在 { ... } 字段块中,也不要放在字段上(例如维度字段)。
将 @UI.chart 附加到字段会导致激活失败,并报错:Annotation 'UI.chart.qualifier' used at wrong position (wrong scope)。
// ↓↓↓ HEADER SCOPE: these go BEFORE `annotate view`, never on a field ↓↓↓
@UI.chart: [{
qualifier: 'visualFilter',
chartType: #BAR,
dimensions: ['Category'],
measures: ['Amount']
}]
@UI.presentationVariant: [{
qualifier: 'visualFilter',
visualizations: [{
type: #AS_CHART,
qualifier: 'visualFilter'
}]
}]
annotate view ZC_ENTITY with
{
@UI.selectionField: [{ position: 10 }]
Category;
@EndUserText.label: 'Amount'
Amount;
}
3. 前端(annotation.xml)——添加 ValueList
维度字段上的 ValueList 注解:
<Annotations Target="<YourServiceNamespace>.<YourEntityType>/Category">
<Annotation Term="Common.ValueList" Qualifier="visualFilter">
<Record Type="Common.ValueListType">
<PropertyValue Property="CollectionPath" String="<YourEntitySet>"/>
<PropertyValue Property="PresentationVariantQualifier" String="visualFilter"/>
<PropertyValue Property="Parameters">
<Collection>
<Record Type="Common.ValueListParameterInOut">
<PropertyValue Property="LocalDataProperty" PropertyPath="Category"/>
<PropertyValue Property="ValueListProperty" String="Category"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
</Annotations>
重要: 替换占位符:
<YourServiceNamespace>- 例如,com.sap.gateway.srvd.ztravel.v0001<YourEntityType>- 例如,TravelType<YourEntitySet>- 例如,Travel
4. 验证激活的注解(必须)
激活 DDLS 和 DDLX 后,验证更改已生效:
⚠️ 重要:DDLS 和 DDLX 是不同的对象
投影视图(DDLS 文件)和元数据扩展(DDLX 文件)是两个独立的 ABAP 开发对象,只是实体名称相同。
要点:
- DDLS = 数据定义(投影视图)——包含实体定义、关联、字段和数据注解
- DDLX = 元数据扩展——包含 UI 注解(@UI.chart、@UI.presentationVariant、字段标签等)
- 两者必须分别激活——激活其中一个不会激活另一个
- 两者都必须存在,视觉筛选器才能正常工作
激活:
- 使用 ABAP ADT MCP 激活 ABAP 对象
- 将 DDLS 文件和 DDLX 文件分别激活
验证步骤:
-
验证激活状态:
- 检查激活工具输出中是否有成功消息
- 确认激活过程中没有报告错误
- DDLS 和 DDLX 都必须显示已成功激活
-
检查 OData $metadata:
- 在浏览器中打开服务 URL:
<service-url>/$metadata - 搜索:
<Annotation Term="UI.Chart" Qualifier="visualFilter"> - 同时验证:
<Annotation Term="UI.PresentationVariant" Qualifier="visualFilter"> - 如果 $metadata 中缺少这些注解,则表示 DDLX 未激活,或者需要重新发布服务绑定
- 在浏览器中打开服务 URL:
5. Manifest 配置(必须)
使用下方的共享 Manifest 配置部分。
Manifest 配置(CAP 和 RAP 通用)
完整的 manifest.json 结构:
"sap.ui5": {
"routing": {
"targets": {
"<YourListReport>": { // Replace with your actual List Report target name
"type": "Component",
"name": "sap.fe.templates.ListReport",
"options": {
"settings": {
"contextPath": "/<YourEntitySet>", // Replace with your entity set path
"controlConfiguration": {
"@com.sap.vocabularies.UI.v1.SelectionFields": {
"layout": "CompactVisual",
"initialLayout": "Visual",
"filterFields": {
"Category": {
"visualFilter": {
"valueList": "com.sap.vocabularies.Common.v1.ValueList#visualFilter"
}
}
}
}
}
}
}
}
}
}
}
路径: sap.ui5.routing.targets.<ListReport>.options.settings.controlConfiguration
视觉筛选器设置应放在 controlConfiguration 下,而不是直接放在 settings 下。
重要占位符:
<YourListReport>- 你的列表报告目标名称(例如,TravelList)<YourEntitySet>- 你的实体集路径(例如,/Travel)Category- 你的维度字段名称visualFilter- 必须与注解中的限定符一致
重要:Manifest 配置结构
视觉筛选器设置应放在 controlConfiguration 下,不能直接放在 settings 下!
测试
有关详细的测试说明,请参阅 sap-fiori-app-development 技能中的应用预览指南部分,其中包括:
- 使用监视脚本测试 CAP 项目
- 使用实时后端与模拟模式测试独立 Fiori 项目
- 后端更改后的元数据刷新流程
主要区别
CAP:
- 在 CDS 中定义聚合和度量
- 使用 DynamicMeasures
- 在同一位置定义聚合和图表
RAP:
- 仅在后端 CDS 中定义聚合
- 使用 Measures(而不是 DynamicMeasures)
- 元数据为只读
常见错误
- 后端更改未激活。
- Chart、ValueList、PresentationVariant 和 manifest 之间的限定符不匹配
- manifest 中的路径错误(使用完整的词汇路径)
- 缺少 SelectionField 注解
- 度量字段不是数值类型
- manifest 中缺少紧凑型视觉布局配置
CAP:
- 尝试在
annotate ... with { ... }中内联注解托管关联的外键列(例如Status_code)——会出现Element "..._code" has not been found错误。请改用单独的annotate Service.Entity:assoc with (...)语句(参见上文“维度是托管关联外键”)。
RAP:
- 缺少后端聚合支持
- 使用 DynamicMeasures 而不是 Measures
- 在后端而不是前端添加 Common.ValueList(ValueList 必须放在前端 annotation.xml 中)
- 直接在 CDS 投影视图中添加 UI 注解,而不是添加到元数据扩展中
- 尝试使用 @Consumption.valueHelpDefinition 实现视觉筛选器(该注解用于值帮助对话框,而非视觉筛选器)
最佳实践
- 测试前,务必在 ADT MCP 中激活后端更改
- 每个可视化筛选器使用 1 个维度 + 1 个度量
- 优先使用柱状图,以提高可读性
- 在所有注解中保持限定符名称一致
- 使用不同的数据量进行测试
- 务必在清单中包含 layout: "CompactVisual" 和 initialLayout: "Visual"
RAP 特定说明:
- 有条件时,务必使用 ADT MCP 修改后端文件
- 图表 + PresentationVariant → 后端元数据扩展(.ddlx.acds)
- Common.ValueList → 前端 annotation.xml(不能位于后端)
参考资料
- SAP Fiori Elements 可视化筛选器文档:https://ui5.sap.com/#/topic/5ea9bb1d544a42eabf71822a8a2cb753
- ABAP RAP 聚合支持:https://help.sap.com/docs/abap-cloud/abap-rap/projection-view